blob: 1b9f25ac3316819f20c942910ffc2c1d686320b3 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glassc8e89ab2016-05-01 11:36:09 -06002/*
3 * (C) Copyright 2001
4 * Denis Peter, MPL AG Switzerland
Simon Glassc8e89ab2016-05-01 11:36:09 -06005 */
6
7#include <common.h>
Simon Glass5bf96dc2016-05-01 11:36:24 -06008#include <dm.h>
Simon Glass07dc93c2019-08-01 09:46:47 -06009#include <env.h>
Simon Glassc8e89ab2016-05-01 11:36:09 -060010#include <pci.h>
11#include <scsi.h>
Michal Simekc886f352016-09-08 15:06:45 +020012#include <dm/device-internal.h>
13#include <dm/uclass-internal.h>
Simon Glassc8e89ab2016-05-01 11:36:09 -060014
Michal Simekc886f352016-09-08 15:06:45 +020015#if !defined(CONFIG_DM_SCSI)
Simon Glass0ada8912017-06-14 21:28:35 -060016# ifdef CONFIG_SCSI_DEV_LIST
17# define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST
18# else
19# ifdef CONFIG_SATA_ULI5288
Simon Glassc8e89ab2016-05-01 11:36:09 -060020
Simon Glass0ada8912017-06-14 21:28:35 -060021# define SCSI_VEND_ID 0x10b9
22# define SCSI_DEV_ID 0x5288
Simon Glassc8e89ab2016-05-01 11:36:09 -060023
Simon Glass0ada8912017-06-14 21:28:35 -060024# elif !defined(CONFIG_SCSI_AHCI_PLAT)
25# error no scsi device defined
26# endif
27# define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID}
28# endif
Michal Simekc886f352016-09-08 15:06:45 +020029#endif
Simon Glassc8e89ab2016-05-01 11:36:09 -060030
Simon Glass57e7c2a2017-06-14 21:28:47 -060031#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) && \
32 !defined(CONFIG_DM_SCSI)
Simon Glassc8e89ab2016-05-01 11:36:09 -060033const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST };
34#endif
Simon Glass5fb559d2017-06-14 21:28:30 -060035static struct scsi_cmd tempccb; /* temporary scsi command buffer */
Simon Glassc8e89ab2016-05-01 11:36:09 -060036
37static unsigned char tempbuff[512]; /* temporary data buffer */
38
Michal Simekc886f352016-09-08 15:06:45 +020039#if !defined(CONFIG_DM_SCSI)
Simon Glassc8e89ab2016-05-01 11:36:09 -060040static int scsi_max_devs; /* number of highest available scsi device */
41
42static int scsi_curr_dev; /* current device */
43
44static struct blk_desc scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE];
Michal Simekc886f352016-09-08 15:06:45 +020045#endif
Simon Glassc8e89ab2016-05-01 11:36:09 -060046
47/* almost the maximum amount of the scsi_ext command.. */
48#define SCSI_MAX_READ_BLK 0xFFFF
49#define SCSI_LBA48_READ 0xFFFFFFF
50
Simon Glass5fb559d2017-06-14 21:28:30 -060051static void scsi_print_error(struct scsi_cmd *pccb)
Simon Glass16740982017-06-14 21:28:23 -060052{
53 /* Dummy function that could print an error for debugging */
54}
55
Simon Glassc8e89ab2016-05-01 11:36:09 -060056#ifdef CONFIG_SYS_64BIT_LBA
Simon Glass5fb559d2017-06-14 21:28:30 -060057void scsi_setup_read16(struct scsi_cmd *pccb, lbaint_t start,
58 unsigned long blocks)
Simon Glassc8e89ab2016-05-01 11:36:09 -060059{
60 pccb->cmd[0] = SCSI_READ16;
61 pccb->cmd[1] = pccb->lun << 5;
62 pccb->cmd[2] = (unsigned char)(start >> 56) & 0xff;
63 pccb->cmd[3] = (unsigned char)(start >> 48) & 0xff;
64 pccb->cmd[4] = (unsigned char)(start >> 40) & 0xff;
65 pccb->cmd[5] = (unsigned char)(start >> 32) & 0xff;
66 pccb->cmd[6] = (unsigned char)(start >> 24) & 0xff;
67 pccb->cmd[7] = (unsigned char)(start >> 16) & 0xff;
68 pccb->cmd[8] = (unsigned char)(start >> 8) & 0xff;
69 pccb->cmd[9] = (unsigned char)start & 0xff;
70 pccb->cmd[10] = 0;
71 pccb->cmd[11] = (unsigned char)(blocks >> 24) & 0xff;
72 pccb->cmd[12] = (unsigned char)(blocks >> 16) & 0xff;
73 pccb->cmd[13] = (unsigned char)(blocks >> 8) & 0xff;
74 pccb->cmd[14] = (unsigned char)blocks & 0xff;
75 pccb->cmd[15] = 0;
76 pccb->cmdlen = 16;
77 pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
78 debug("scsi_setup_read16: cmd: %02X %02X startblk %02X%02X%02X%02X%02X%02X%02X%02X blccnt %02X%02X%02X%02X\n",
79 pccb->cmd[0], pccb->cmd[1],
80 pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
81 pccb->cmd[6], pccb->cmd[7], pccb->cmd[8], pccb->cmd[9],
82 pccb->cmd[11], pccb->cmd[12], pccb->cmd[13], pccb->cmd[14]);
83}
84#endif
85
Faiz Abbas76a6fa62019-10-15 18:24:32 +053086static void scsi_setup_inquiry(struct scsi_cmd *pccb)
87{
88 pccb->cmd[0] = SCSI_INQUIRY;
89 pccb->cmd[1] = pccb->lun << 5;
90 pccb->cmd[2] = 0;
91 pccb->cmd[3] = 0;
92 if (pccb->datalen > 255)
93 pccb->cmd[4] = 255;
94 else
95 pccb->cmd[4] = (unsigned char)pccb->datalen;
96 pccb->cmd[5] = 0;
97 pccb->cmdlen = 6;
98 pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
99}
100
101#ifdef CONFIG_BLK
Simon Glass5fb559d2017-06-14 21:28:30 -0600102static void scsi_setup_read_ext(struct scsi_cmd *pccb, lbaint_t start,
Michal Simek9ec32f32016-11-30 11:53:43 +0100103 unsigned short blocks)
Simon Glassc8e89ab2016-05-01 11:36:09 -0600104{
105 pccb->cmd[0] = SCSI_READ10;
106 pccb->cmd[1] = pccb->lun << 5;
107 pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff;
108 pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff;
109 pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff;
110 pccb->cmd[5] = (unsigned char)start & 0xff;
111 pccb->cmd[6] = 0;
112 pccb->cmd[7] = (unsigned char)(blocks >> 8) & 0xff;
113 pccb->cmd[8] = (unsigned char)blocks & 0xff;
114 pccb->cmd[6] = 0;
115 pccb->cmdlen = 10;
116 pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
117 debug("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n",
118 pccb->cmd[0], pccb->cmd[1],
119 pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
120 pccb->cmd[7], pccb->cmd[8]);
121}
122
Simon Glass5fb559d2017-06-14 21:28:30 -0600123static void scsi_setup_write_ext(struct scsi_cmd *pccb, lbaint_t start,
Michal Simek9ec32f32016-11-30 11:53:43 +0100124 unsigned short blocks)
Simon Glassc8e89ab2016-05-01 11:36:09 -0600125{
126 pccb->cmd[0] = SCSI_WRITE10;
127 pccb->cmd[1] = pccb->lun << 5;
128 pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff;
129 pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff;
130 pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff;
131 pccb->cmd[5] = (unsigned char)start & 0xff;
132 pccb->cmd[6] = 0;
133 pccb->cmd[7] = ((unsigned char)(blocks >> 8)) & 0xff;
134 pccb->cmd[8] = (unsigned char)blocks & 0xff;
135 pccb->cmd[9] = 0;
136 pccb->cmdlen = 10;
137 pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
138 debug("%s: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n",
139 __func__,
140 pccb->cmd[0], pccb->cmd[1],
141 pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
142 pccb->cmd[7], pccb->cmd[8]);
143}
144
Simon Glass5bf96dc2016-05-01 11:36:24 -0600145static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
146 void *buffer)
Simon Glassc8e89ab2016-05-01 11:36:09 -0600147{
Simon Glass5bf96dc2016-05-01 11:36:24 -0600148 struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
Simon Glass11b2b622017-06-14 21:28:40 -0600149 struct udevice *bdev = dev->parent;
Simon Glassc8e89ab2016-05-01 11:36:09 -0600150 lbaint_t start, blks;
151 uintptr_t buf_addr;
152 unsigned short smallblks = 0;
Simon Glass5fb559d2017-06-14 21:28:30 -0600153 struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;
Simon Glassc8e89ab2016-05-01 11:36:09 -0600154
155 /* Setup device */
Michal Simekde6840a2016-11-18 16:22:42 +0100156 pccb->target = block_dev->target;
157 pccb->lun = block_dev->lun;
Simon Glassc8e89ab2016-05-01 11:36:09 -0600158 buf_addr = (unsigned long)buffer;
159 start = blknr;
160 blks = blkcnt;
161 debug("\nscsi_read: dev %d startblk " LBAF
162 ", blccnt " LBAF " buffer %lx\n",
Michal Simekde6840a2016-11-18 16:22:42 +0100163 block_dev->devnum, start, blks, (unsigned long)buffer);
Simon Glassc8e89ab2016-05-01 11:36:09 -0600164 do {
165 pccb->pdata = (unsigned char *)buf_addr;
166#ifdef CONFIG_SYS_64BIT_LBA
167 if (start > SCSI_LBA48_READ) {
168 unsigned long blocks;
169 blocks = min_t(lbaint_t, blks, SCSI_MAX_READ_BLK);
Michal Simekde6840a2016-11-18 16:22:42 +0100170 pccb->datalen = block_dev->blksz * blocks;
Simon Glassc8e89ab2016-05-01 11:36:09 -0600171 scsi_setup_read16(pccb, start, blocks);
172 start += blocks;
173 blks -= blocks;
174 } else
175#endif
176 if (blks > SCSI_MAX_READ_BLK) {
Michal Simekde6840a2016-11-18 16:22:42 +0100177 pccb->datalen = block_dev->blksz *
Simon Glassc8e89ab2016-05-01 11:36:09 -0600178 SCSI_MAX_READ_BLK;
179 smallblks = SCSI_MAX_READ_BLK;
180 scsi_setup_read_ext(pccb, start, smallblks);
181 start += SCSI_MAX_READ_BLK;
182 blks -= SCSI_MAX_READ_BLK;
183 } else {
Michal Simekde6840a2016-11-18 16:22:42 +0100184 pccb->datalen = block_dev->blksz * blks;
Simon Glassc8e89ab2016-05-01 11:36:09 -0600185 smallblks = (unsigned short)blks;
186 scsi_setup_read_ext(pccb, start, smallblks);
187 start += blks;
188 blks = 0;
189 }
190 debug("scsi_read_ext: startblk " LBAF
Masahiro Yamadac7570a32018-08-06 20:47:40 +0900191 ", blccnt %x buffer %lX\n",
Simon Glassc8e89ab2016-05-01 11:36:09 -0600192 start, smallblks, buf_addr);
Simon Glass11b2b622017-06-14 21:28:40 -0600193 if (scsi_exec(bdev, pccb)) {
Simon Glassc8e89ab2016-05-01 11:36:09 -0600194 scsi_print_error(pccb);
195 blkcnt -= blks;
196 break;
197 }
198 buf_addr += pccb->datalen;
199 } while (blks != 0);
200 debug("scsi_read_ext: end startblk " LBAF
Masahiro Yamadac7570a32018-08-06 20:47:40 +0900201 ", blccnt %x buffer %lX\n", start, smallblks, buf_addr);
Simon Glassc8e89ab2016-05-01 11:36:09 -0600202 return blkcnt;
203}
204
205/*******************************************************************************
206 * scsi_write
207 */
208
209/* Almost the maximum amount of the scsi_ext command.. */
210#define SCSI_MAX_WRITE_BLK 0xFFFF
211
Simon Glass5bf96dc2016-05-01 11:36:24 -0600212static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
213 const void *buffer)
Simon Glassc8e89ab2016-05-01 11:36:09 -0600214{
Simon Glass5bf96dc2016-05-01 11:36:24 -0600215 struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
Simon Glass11b2b622017-06-14 21:28:40 -0600216 struct udevice *bdev = dev->parent;
Simon Glassc8e89ab2016-05-01 11:36:09 -0600217 lbaint_t start, blks;
218 uintptr_t buf_addr;
219 unsigned short smallblks;
Simon Glass5fb559d2017-06-14 21:28:30 -0600220 struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;
Simon Glassc8e89ab2016-05-01 11:36:09 -0600221
Simon Glassc8e89ab2016-05-01 11:36:09 -0600222 /* Setup device */
Michal Simekde6840a2016-11-18 16:22:42 +0100223 pccb->target = block_dev->target;
224 pccb->lun = block_dev->lun;
Simon Glassc8e89ab2016-05-01 11:36:09 -0600225 buf_addr = (unsigned long)buffer;
226 start = blknr;
227 blks = blkcnt;
228 debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n",
Michal Simekde6840a2016-11-18 16:22:42 +0100229 __func__, block_dev->devnum, start, blks, (unsigned long)buffer);
Simon Glassc8e89ab2016-05-01 11:36:09 -0600230 do {
231 pccb->pdata = (unsigned char *)buf_addr;
232 if (blks > SCSI_MAX_WRITE_BLK) {
Michal Simekde6840a2016-11-18 16:22:42 +0100233 pccb->datalen = (block_dev->blksz *
Simon Glassc8e89ab2016-05-01 11:36:09 -0600234 SCSI_MAX_WRITE_BLK);
235 smallblks = SCSI_MAX_WRITE_BLK;
236 scsi_setup_write_ext(pccb, start, smallblks);
237 start += SCSI_MAX_WRITE_BLK;
238 blks -= SCSI_MAX_WRITE_BLK;
239 } else {
Michal Simekde6840a2016-11-18 16:22:42 +0100240 pccb->datalen = block_dev->blksz * blks;
Simon Glassc8e89ab2016-05-01 11:36:09 -0600241 smallblks = (unsigned short)blks;
242 scsi_setup_write_ext(pccb, start, smallblks);
243 start += blks;
244 blks = 0;
245 }
Masahiro Yamadac7570a32018-08-06 20:47:40 +0900246 debug("%s: startblk " LBAF ", blccnt %x buffer %lx\n",
Simon Glassc8e89ab2016-05-01 11:36:09 -0600247 __func__, start, smallblks, buf_addr);
Simon Glass11b2b622017-06-14 21:28:40 -0600248 if (scsi_exec(bdev, pccb)) {
Simon Glassc8e89ab2016-05-01 11:36:09 -0600249 scsi_print_error(pccb);
250 blkcnt -= blks;
251 break;
252 }
253 buf_addr += pccb->datalen;
254 } while (blks != 0);
Masahiro Yamadac7570a32018-08-06 20:47:40 +0900255 debug("%s: end startblk " LBAF ", blccnt %x buffer %lX\n",
Simon Glassc8e89ab2016-05-01 11:36:09 -0600256 __func__, start, smallblks, buf_addr);
257 return blkcnt;
258}
Faiz Abbas76a6fa62019-10-15 18:24:32 +0530259#endif
Simon Glassc8e89ab2016-05-01 11:36:09 -0600260
Simon Glass57e7c2a2017-06-14 21:28:47 -0600261#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) && \
262 !defined(CONFIG_DM_SCSI)
Simon Glassc8e89ab2016-05-01 11:36:09 -0600263void scsi_init(void)
264{
265 int busdevfunc = -1;
266 int i;
267 /*
268 * Find a device from the list, this driver will support a single
269 * controller.
270 */
271 for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
272 /* get PCI Device ID */
273#ifdef CONFIG_DM_PCI
274 struct udevice *dev;
275 int ret;
276
277 ret = dm_pci_find_device(scsi_device_list[i].vendor,
278 scsi_device_list[i].device, 0, &dev);
279 if (!ret) {
280 busdevfunc = dm_pci_get_bdf(dev);
281 break;
282 }
283#else
284 busdevfunc = pci_find_device(scsi_device_list[i].vendor,
285 scsi_device_list[i].device,
286 0);
287#endif
288 if (busdevfunc != -1)
289 break;
290 }
291
292 if (busdevfunc == -1) {
293 printf("Error: SCSI Controller(s) ");
294 for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
295 printf("%04X:%04X ",
296 scsi_device_list[i].vendor,
297 scsi_device_list[i].device);
298 }
299 printf("not found\n");
300 return;
301 }
302#ifdef DEBUG
303 else {
304 printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n",
305 scsi_device_list[i].vendor,
306 scsi_device_list[i].device,
307 (busdevfunc >> 16) & 0xFF,
308 (busdevfunc >> 11) & 0x1F,
309 (busdevfunc >> 8) & 0x7);
310 }
311#endif
312 bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci");
313 scsi_low_level_init(busdevfunc);
Simon Glass48228732017-06-14 21:28:41 -0600314 scsi_scan(true);
Simon Glassc8e89ab2016-05-01 11:36:09 -0600315 bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI);
316}
317#endif
318
Simon Glassc8e89ab2016-05-01 11:36:09 -0600319/* copy src to dest, skipping leading and trailing blanks
320 * and null terminate the string
321 */
Michal Simek9ec32f32016-11-30 11:53:43 +0100322static void scsi_ident_cpy(unsigned char *dest, unsigned char *src,
323 unsigned int len)
Simon Glassc8e89ab2016-05-01 11:36:09 -0600324{
325 int start, end;
326
327 start = 0;
328 while (start < len) {
329 if (src[start] != ' ')
330 break;
331 start++;
332 }
333 end = len-1;
334 while (end > start) {
335 if (src[end] != ' ')
336 break;
337 end--;
338 }
339 for (; start <= end; start++)
340 *dest ++= src[start];
341 *dest = '\0';
342}
343
Simon Glass11b2b622017-06-14 21:28:40 -0600344static int scsi_read_capacity(struct udevice *dev, struct scsi_cmd *pccb,
345 lbaint_t *capacity, unsigned long *blksz)
Simon Glassc8e89ab2016-05-01 11:36:09 -0600346{
347 *capacity = 0;
348
349 memset(pccb->cmd, '\0', sizeof(pccb->cmd));
350 pccb->cmd[0] = SCSI_RD_CAPAC10;
351 pccb->cmd[1] = pccb->lun << 5;
352 pccb->cmdlen = 10;
353 pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
354
355 pccb->datalen = 8;
Simon Glassa140e862017-06-14 21:28:44 -0600356 if (scsi_exec(dev, pccb))
Simon Glassc8e89ab2016-05-01 11:36:09 -0600357 return 1;
358
359 *capacity = ((lbaint_t)pccb->pdata[0] << 24) |
360 ((lbaint_t)pccb->pdata[1] << 16) |
361 ((lbaint_t)pccb->pdata[2] << 8) |
362 ((lbaint_t)pccb->pdata[3]);
363
364 if (*capacity != 0xffffffff) {
365 /* Read capacity (10) was sufficient for this drive. */
366 *blksz = ((unsigned long)pccb->pdata[4] << 24) |
367 ((unsigned long)pccb->pdata[5] << 16) |
368 ((unsigned long)pccb->pdata[6] << 8) |
369 ((unsigned long)pccb->pdata[7]);
370 return 0;
371 }
372
373 /* Read capacity (10) was insufficient. Use read capacity (16). */
374 memset(pccb->cmd, '\0', sizeof(pccb->cmd));
375 pccb->cmd[0] = SCSI_RD_CAPAC16;
376 pccb->cmd[1] = 0x10;
377 pccb->cmdlen = 16;
378 pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
379
380 pccb->datalen = 16;
Simon Glassa140e862017-06-14 21:28:44 -0600381 if (scsi_exec(dev, pccb))
Simon Glassc8e89ab2016-05-01 11:36:09 -0600382 return 1;
383
384 *capacity = ((uint64_t)pccb->pdata[0] << 56) |
385 ((uint64_t)pccb->pdata[1] << 48) |
386 ((uint64_t)pccb->pdata[2] << 40) |
387 ((uint64_t)pccb->pdata[3] << 32) |
388 ((uint64_t)pccb->pdata[4] << 24) |
389 ((uint64_t)pccb->pdata[5] << 16) |
390 ((uint64_t)pccb->pdata[6] << 8) |
391 ((uint64_t)pccb->pdata[7]);
392
393 *blksz = ((uint64_t)pccb->pdata[8] << 56) |
394 ((uint64_t)pccb->pdata[9] << 48) |
395 ((uint64_t)pccb->pdata[10] << 40) |
396 ((uint64_t)pccb->pdata[11] << 32) |
397 ((uint64_t)pccb->pdata[12] << 24) |
398 ((uint64_t)pccb->pdata[13] << 16) |
399 ((uint64_t)pccb->pdata[14] << 8) |
400 ((uint64_t)pccb->pdata[15]);
401
402 return 0;
403}
404
405
406/*
407 * Some setup (fill-in) routines
408 */
Simon Glass5fb559d2017-06-14 21:28:30 -0600409static void scsi_setup_test_unit_ready(struct scsi_cmd *pccb)
Simon Glassc8e89ab2016-05-01 11:36:09 -0600410{
411 pccb->cmd[0] = SCSI_TST_U_RDY;
412 pccb->cmd[1] = pccb->lun << 5;
413 pccb->cmd[2] = 0;
414 pccb->cmd[3] = 0;
415 pccb->cmd[4] = 0;
416 pccb->cmd[5] = 0;
417 pccb->cmdlen = 6;
418 pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
419}
420
Michal Simek6241b522016-11-30 12:50:58 +0100421/**
422 * scsi_init_dev_desc_priv - initialize only SCSI specific blk_desc properties
423 *
424 * @dev_desc: Block device description pointer
425 */
426static void scsi_init_dev_desc_priv(struct blk_desc *dev_desc)
Michal Simekac0a18d12016-11-18 15:27:00 +0100427{
428 dev_desc->target = 0xff;
429 dev_desc->lun = 0xff;
Michal Simekac0a18d12016-11-18 15:27:00 +0100430 dev_desc->log2blksz =
431 LOG2_INVALID(typeof(dev_desc->log2blksz));
432 dev_desc->type = DEV_TYPE_UNKNOWN;
433 dev_desc->vendor[0] = 0;
434 dev_desc->product[0] = 0;
435 dev_desc->revision[0] = 0;
436 dev_desc->removable = false;
Michal Simekac0a18d12016-11-18 15:27:00 +0100437}
438
Michal Simekc886f352016-09-08 15:06:45 +0200439#if !defined(CONFIG_DM_SCSI)
Michal Simek6241b522016-11-30 12:50:58 +0100440/**
441 * scsi_init_dev_desc - initialize all SCSI specific blk_desc properties
442 *
443 * @dev_desc: Block device description pointer
444 * @devnum: Device number
445 */
446static void scsi_init_dev_desc(struct blk_desc *dev_desc, int devnum)
447{
448 dev_desc->lba = 0;
449 dev_desc->blksz = 0;
450 dev_desc->if_type = IF_TYPE_SCSI;
451 dev_desc->devnum = devnum;
452 dev_desc->part_type = PART_TYPE_UNKNOWN;
453
454 scsi_init_dev_desc_priv(dev_desc);
455}
Michal Simekc886f352016-09-08 15:06:45 +0200456#endif
Michal Simek40917492016-11-18 16:14:24 +0100457
Michal Simekebbde652016-11-18 15:42:13 +0100458/**
459 * scsi_detect_dev - Detect scsi device
460 *
Michal Simek40917492016-11-18 16:14:24 +0100461 * @target: target id
Jean-Jacques Hiblot0c447f02017-04-07 13:42:06 +0200462 * @lun: target lun
Michal Simekebbde652016-11-18 15:42:13 +0100463 * @dev_desc: block device description
Michal Simekebbde652016-11-18 15:42:13 +0100464 *
465 * The scsi_detect_dev detects and fills a dev_desc structure when the device is
Jean-Jacques Hiblot0c447f02017-04-07 13:42:06 +0200466 * detected.
Michal Simekebbde652016-11-18 15:42:13 +0100467 *
468 * Return: 0 on success, error value otherwise
469 */
Simon Glass11b2b622017-06-14 21:28:40 -0600470static int scsi_detect_dev(struct udevice *dev, int target, int lun,
471 struct blk_desc *dev_desc)
Michal Simekebbde652016-11-18 15:42:13 +0100472{
473 unsigned char perq, modi;
474 lbaint_t capacity;
475 unsigned long blksz;
Simon Glass5fb559d2017-06-14 21:28:30 -0600476 struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;
Michal Simekebbde652016-11-18 15:42:13 +0100477
Michal Simek40917492016-11-18 16:14:24 +0100478 pccb->target = target;
Jean-Jacques Hiblot0c447f02017-04-07 13:42:06 +0200479 pccb->lun = lun;
Michal Simekebbde652016-11-18 15:42:13 +0100480 pccb->pdata = (unsigned char *)&tempbuff;
481 pccb->datalen = 512;
482 scsi_setup_inquiry(pccb);
Simon Glassa140e862017-06-14 21:28:44 -0600483 if (scsi_exec(dev, pccb)) {
Michal Simekebbde652016-11-18 15:42:13 +0100484 if (pccb->contr_stat == SCSI_SEL_TIME_OUT) {
485 /*
486 * selection timeout => assuming no
487 * device present
488 */
489 debug("Selection timeout ID %d\n",
490 pccb->target);
491 return -ETIMEDOUT;
492 }
493 scsi_print_error(pccb);
494 return -ENODEV;
495 }
496 perq = tempbuff[0];
497 modi = tempbuff[1];
498 if ((perq & 0x1f) == 0x1f)
499 return -ENODEV; /* skip unknown devices */
500 if ((modi & 0x80) == 0x80) /* drive is removable */
501 dev_desc->removable = true;
502 /* get info for this device */
503 scsi_ident_cpy((unsigned char *)dev_desc->vendor,
504 &tempbuff[8], 8);
505 scsi_ident_cpy((unsigned char *)dev_desc->product,
506 &tempbuff[16], 16);
507 scsi_ident_cpy((unsigned char *)dev_desc->revision,
508 &tempbuff[32], 4);
509 dev_desc->target = pccb->target;
510 dev_desc->lun = pccb->lun;
511
512 pccb->datalen = 0;
513 scsi_setup_test_unit_ready(pccb);
Simon Glassa140e862017-06-14 21:28:44 -0600514 if (scsi_exec(dev, pccb)) {
Michal Simekebbde652016-11-18 15:42:13 +0100515 if (dev_desc->removable) {
516 dev_desc->type = perq;
517 goto removable;
518 }
519 scsi_print_error(pccb);
520 return -EINVAL;
521 }
Simon Glass11b2b622017-06-14 21:28:40 -0600522 if (scsi_read_capacity(dev, pccb, &capacity, &blksz)) {
Michal Simekebbde652016-11-18 15:42:13 +0100523 scsi_print_error(pccb);
524 return -EINVAL;
525 }
526 dev_desc->lba = capacity;
527 dev_desc->blksz = blksz;
528 dev_desc->log2blksz = LOG2(dev_desc->blksz);
529 dev_desc->type = perq;
Michal Simekebbde652016-11-18 15:42:13 +0100530removable:
531 return 0;
532}
533
Simon Glassc8e89ab2016-05-01 11:36:09 -0600534/*
535 * (re)-scan the scsi bus and reports scsi device info
536 * to the user if mode = 1
537 */
Michal Simekc886f352016-09-08 15:06:45 +0200538#if defined(CONFIG_DM_SCSI)
Simon Glass48228732017-06-14 21:28:41 -0600539static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose)
Jean-Jacques Hiblotcdf96eb2017-04-24 11:51:26 +0200540{
541 int ret;
542 struct udevice *bdev;
543 struct blk_desc bd;
544 struct blk_desc *bdesc;
545 char str[10];
546
547 /*
548 * detect the scsi driver to get information about its geometry (block
549 * size, number of blocks) and other parameters (ids, type, ...)
550 */
551 scsi_init_dev_desc_priv(&bd);
Simon Glass11b2b622017-06-14 21:28:40 -0600552 if (scsi_detect_dev(dev, id, lun, &bd))
Jean-Jacques Hiblotcdf96eb2017-04-24 11:51:26 +0200553 return -ENODEV;
554
555 /*
556 * Create only one block device and do detection
557 * to make sure that there won't be a lot of
558 * block devices created
559 */
560 snprintf(str, sizeof(str), "id%dlun%d", id, lun);
561 ret = blk_create_devicef(dev, "scsi_blk", str, IF_TYPE_SCSI, -1,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200562 bd.blksz, bd.lba, &bdev);
Jean-Jacques Hiblotcdf96eb2017-04-24 11:51:26 +0200563 if (ret) {
564 debug("Can't create device\n");
565 return ret;
566 }
567
568 bdesc = dev_get_uclass_platdata(bdev);
569 bdesc->target = id;
570 bdesc->lun = lun;
571 bdesc->removable = bd.removable;
572 bdesc->type = bd.type;
573 memcpy(&bdesc->vendor, &bd.vendor, sizeof(bd.vendor));
574 memcpy(&bdesc->product, &bd.product, sizeof(bd.product));
575 memcpy(&bdesc->revision, &bd.revision, sizeof(bd.revision));
Jean-Jacques Hiblotcdf96eb2017-04-24 11:51:26 +0200576
Simon Glass48228732017-06-14 21:28:41 -0600577 if (verbose) {
Heinrich Schuchardtc5382b72019-02-05 18:06:24 +0100578 printf(" Device %d: ", bdesc->devnum);
Jean-Jacques Hiblotcdf96eb2017-04-24 11:51:26 +0200579 dev_print(bdesc);
580 }
581 return 0;
582}
583
Simon Glass600d0012017-06-14 21:28:45 -0600584int scsi_scan_dev(struct udevice *dev, bool verbose)
585{
586 struct scsi_platdata *uc_plat; /* scsi controller platdata */
587 int ret;
588 int i;
589 int lun;
590
591 /* probe SCSI controller driver */
592 ret = device_probe(dev);
593 if (ret)
594 return ret;
595
596 /* Get controller platdata */
597 uc_plat = dev_get_uclass_platdata(dev);
598
599 for (i = 0; i < uc_plat->max_id; i++)
600 for (lun = 0; lun < uc_plat->max_lun; lun++)
601 do_scsi_scan_one(dev, i, lun, verbose);
602
603 return 0;
604}
605
Simon Glass48228732017-06-14 21:28:41 -0600606int scsi_scan(bool verbose)
Simon Glassc8e89ab2016-05-01 11:36:09 -0600607{
Michal Simekc886f352016-09-08 15:06:45 +0200608 struct uclass *uc;
609 struct udevice *dev; /* SCSI controller */
Michal Simekebbde652016-11-18 15:42:13 +0100610 int ret;
Simon Glassc8e89ab2016-05-01 11:36:09 -0600611
Simon Glass48228732017-06-14 21:28:41 -0600612 if (verbose)
Simon Glassc8e89ab2016-05-01 11:36:09 -0600613 printf("scanning bus for devices...\n");
Michal Simekc886f352016-09-08 15:06:45 +0200614
Michal Simek9c49b8c2017-01-02 09:40:09 +0100615 blk_unbind_all(IF_TYPE_SCSI);
616
Michal Simekc886f352016-09-08 15:06:45 +0200617 ret = uclass_get(UCLASS_SCSI, &uc);
618 if (ret)
619 return ret;
620
621 uclass_foreach_dev(dev, uc) {
Simon Glass600d0012017-06-14 21:28:45 -0600622 ret = scsi_scan_dev(dev, verbose);
Michal Simekc886f352016-09-08 15:06:45 +0200623 if (ret)
624 return ret;
Michal Simekc886f352016-09-08 15:06:45 +0200625 }
626
627 return 0;
628}
629#else
Simon Glass48228732017-06-14 21:28:41 -0600630int scsi_scan(bool verbose)
Michal Simekc886f352016-09-08 15:06:45 +0200631{
632 unsigned char i, lun;
633 int ret;
634
Simon Glass48228732017-06-14 21:28:41 -0600635 if (verbose)
Michal Simekc886f352016-09-08 15:06:45 +0200636 printf("scanning bus for devices...\n");
Michal Simekac0a18d12016-11-18 15:27:00 +0100637 for (i = 0; i < CONFIG_SYS_SCSI_MAX_DEVICE; i++)
638 scsi_init_dev_desc(&scsi_dev_desc[i], i);
639
Simon Glassc8e89ab2016-05-01 11:36:09 -0600640 scsi_max_devs = 0;
641 for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) {
Simon Glassc8e89ab2016-05-01 11:36:09 -0600642 for (lun = 0; lun < CONFIG_SYS_SCSI_MAX_LUN; lun++) {
Heinrich Schuchardtc5382b72019-02-05 18:06:24 +0100643 struct blk_desc *bdesc = &scsi_dev_desc[scsi_max_devs];
644
645 ret = scsi_detect_dev(NULL, i, lun, bdesc);
Michal Simekebbde652016-11-18 15:42:13 +0100646 if (ret)
Simon Glassc8e89ab2016-05-01 11:36:09 -0600647 continue;
Heinrich Schuchardtc5382b72019-02-05 18:06:24 +0100648 part_init(bdesc);
Simon Glassc8e89ab2016-05-01 11:36:09 -0600649
Simon Glass48228732017-06-14 21:28:41 -0600650 if (verbose) {
Heinrich Schuchardtc5382b72019-02-05 18:06:24 +0100651 printf(" Device %d: ", bdesc->devnum);
652 dev_print(bdesc);
Simon Glass48228732017-06-14 21:28:41 -0600653 }
Simon Glassc8e89ab2016-05-01 11:36:09 -0600654 scsi_max_devs++;
655 } /* next LUN */
656 }
657 if (scsi_max_devs > 0)
658 scsi_curr_dev = 0;
659 else
660 scsi_curr_dev = -1;
661
662 printf("Found %d device(s).\n", scsi_max_devs);
663#ifndef CONFIG_SPL_BUILD
Simon Glass4d949a22017-08-03 12:22:10 -0600664 env_set_ulong("scsidevs", scsi_max_devs);
Simon Glassc8e89ab2016-05-01 11:36:09 -0600665#endif
Michal Simek5dc196f2016-11-30 12:12:31 +0100666 return 0;
Simon Glassc8e89ab2016-05-01 11:36:09 -0600667}
Michal Simekc886f352016-09-08 15:06:45 +0200668#endif
Simon Glassc8e89ab2016-05-01 11:36:09 -0600669
Simon Glass5bf96dc2016-05-01 11:36:24 -0600670#ifdef CONFIG_BLK
671static const struct blk_ops scsi_blk_ops = {
672 .read = scsi_read,
673 .write = scsi_write,
674};
675
676U_BOOT_DRIVER(scsi_blk) = {
677 .name = "scsi_blk",
678 .id = UCLASS_BLK,
679 .ops = &scsi_blk_ops,
680};
681#else
Simon Glassc8e89ab2016-05-01 11:36:09 -0600682U_BOOT_LEGACY_BLK(scsi) = {
Ed Swarthout987a9552016-06-01 08:11:24 -0500683 .if_typename = "scsi",
Simon Glassc8e89ab2016-05-01 11:36:09 -0600684 .if_type = IF_TYPE_SCSI,
685 .max_devs = CONFIG_SYS_SCSI_MAX_DEVICE,
686 .desc = scsi_dev_desc,
687};
Simon Glass5bf96dc2016-05-01 11:36:24 -0600688#endif