Blame view

drivers/scsi/scsi.c 18.1 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
11f610edf   Simon Glass   dm: scsi: Separat...
2
3
4
  /*
   * (C) Copyright 2001
   * Denis Peter, MPL AG Switzerland
11f610edf   Simon Glass   dm: scsi: Separat...
5
6
7
   */
  
  #include <common.h>
535556b2a   Simon Glass   dm: scsi: Add sup...
8
  #include <dm.h>
168068fb3   Simon Glass   env: Move env_set...
9
  #include <env.h>
11f610edf   Simon Glass   dm: scsi: Separat...
10
11
  #include <pci.h>
  #include <scsi.h>
e8a016b53   Michal Simek   dm: Add support f...
12
13
  #include <dm/device-internal.h>
  #include <dm/uclass-internal.h>
11f610edf   Simon Glass   dm: scsi: Separat...
14

e8a016b53   Michal Simek   dm: Add support f...
15
  #if !defined(CONFIG_DM_SCSI)
099c239d6   Simon Glass   dm: scsi: Indent ...
16
17
18
19
  # ifdef CONFIG_SCSI_DEV_LIST
  #  define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST
  # else
  #  ifdef CONFIG_SATA_ULI5288
11f610edf   Simon Glass   dm: scsi: Separat...
20

099c239d6   Simon Glass   dm: scsi: Indent ...
21
22
  #   define SCSI_VEND_ID 0x10b9
  #   define SCSI_DEV_ID  0x5288
11f610edf   Simon Glass   dm: scsi: Separat...
23

099c239d6   Simon Glass   dm: scsi: Indent ...
24
25
26
27
28
  #  elif !defined(CONFIG_SCSI_AHCI_PLAT)
  #   error no scsi device defined
  #  endif
  # define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID}
  # endif
e8a016b53   Michal Simek   dm: Add support f...
29
  #endif
11f610edf   Simon Glass   dm: scsi: Separat...
30

7337fcd8c   Simon Glass   dm: scsi: Drop sc...
31
32
  #if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) && \
  	!defined(CONFIG_DM_SCSI)
11f610edf   Simon Glass   dm: scsi: Separat...
33
34
  const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST };
  #endif
b9560ad64   Simon Glass   dm: scsi: Drop th...
35
  static struct scsi_cmd tempccb;	/* temporary scsi command buffer */
11f610edf   Simon Glass   dm: scsi: Separat...
36
37
  
  static unsigned char tempbuff[512]; /* temporary data buffer */
e8a016b53   Michal Simek   dm: Add support f...
38
  #if !defined(CONFIG_DM_SCSI)
11f610edf   Simon Glass   dm: scsi: Separat...
39
40
41
42
43
  static int scsi_max_devs; /* number of highest available scsi device */
  
  static int scsi_curr_dev; /* current device */
  
  static struct blk_desc scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE];
e8a016b53   Michal Simek   dm: Add support f...
44
  #endif
11f610edf   Simon Glass   dm: scsi: Separat...
45
46
  
  /* almost the maximum amount of the scsi_ext command.. */
4ff572830   Faiz Abbas   scsi: Add max_byt...
47
  #define SCSI_MAX_BLK 0xFFFF
11f610edf   Simon Glass   dm: scsi: Separat...
48
  #define SCSI_LBA48_READ	0xFFFFFFF
b9560ad64   Simon Glass   dm: scsi: Drop th...
49
  static void scsi_print_error(struct scsi_cmd *pccb)
a6fb185c7   Simon Glass   scsi: Drop scsi_p...
50
51
52
  {
  	/* Dummy function that could print an error for debugging */
  }
11f610edf   Simon Glass   dm: scsi: Separat...
53
  #ifdef CONFIG_SYS_64BIT_LBA
b9560ad64   Simon Glass   dm: scsi: Drop th...
54
55
  void scsi_setup_read16(struct scsi_cmd *pccb, lbaint_t start,
  		       unsigned long blocks)
11f610edf   Simon Glass   dm: scsi: Separat...
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
  {
  	pccb->cmd[0] = SCSI_READ16;
  	pccb->cmd[1] = pccb->lun << 5;
  	pccb->cmd[2] = (unsigned char)(start >> 56) & 0xff;
  	pccb->cmd[3] = (unsigned char)(start >> 48) & 0xff;
  	pccb->cmd[4] = (unsigned char)(start >> 40) & 0xff;
  	pccb->cmd[5] = (unsigned char)(start >> 32) & 0xff;
  	pccb->cmd[6] = (unsigned char)(start >> 24) & 0xff;
  	pccb->cmd[7] = (unsigned char)(start >> 16) & 0xff;
  	pccb->cmd[8] = (unsigned char)(start >> 8) & 0xff;
  	pccb->cmd[9] = (unsigned char)start & 0xff;
  	pccb->cmd[10] = 0;
  	pccb->cmd[11] = (unsigned char)(blocks >> 24) & 0xff;
  	pccb->cmd[12] = (unsigned char)(blocks >> 16) & 0xff;
  	pccb->cmd[13] = (unsigned char)(blocks >> 8) & 0xff;
  	pccb->cmd[14] = (unsigned char)blocks & 0xff;
  	pccb->cmd[15] = 0;
  	pccb->cmdlen = 16;
  	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
  	debug("scsi_setup_read16: cmd: %02X %02X startblk %02X%02X%02X%02X%02X%02X%02X%02X blccnt %02X%02X%02X%02X
  ",
  	      pccb->cmd[0], pccb->cmd[1],
  	      pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
  	      pccb->cmd[6], pccb->cmd[7], pccb->cmd[8], pccb->cmd[9],
  	      pccb->cmd[11], pccb->cmd[12], pccb->cmd[13], pccb->cmd[14]);
  }
  #endif
66c54f1a3   Faiz Abbas   scsi: Simplify sc...
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  static void scsi_setup_inquiry(struct scsi_cmd *pccb)
  {
  	pccb->cmd[0] = SCSI_INQUIRY;
  	pccb->cmd[1] = pccb->lun << 5;
  	pccb->cmd[2] = 0;
  	pccb->cmd[3] = 0;
  	if (pccb->datalen > 255)
  		pccb->cmd[4] = 255;
  	else
  		pccb->cmd[4] = (unsigned char)pccb->datalen;
  	pccb->cmd[5] = 0;
  	pccb->cmdlen = 6;
  	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
  }
  
  #ifdef CONFIG_BLK
b9560ad64   Simon Glass   dm: scsi: Drop th...
99
  static void scsi_setup_read_ext(struct scsi_cmd *pccb, lbaint_t start,
545a28471   Michal Simek   scsi: Make privat...
100
  				unsigned short blocks)
11f610edf   Simon Glass   dm: scsi: Separat...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  {
  	pccb->cmd[0] = SCSI_READ10;
  	pccb->cmd[1] = pccb->lun << 5;
  	pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff;
  	pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff;
  	pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff;
  	pccb->cmd[5] = (unsigned char)start & 0xff;
  	pccb->cmd[6] = 0;
  	pccb->cmd[7] = (unsigned char)(blocks >> 8) & 0xff;
  	pccb->cmd[8] = (unsigned char)blocks & 0xff;
  	pccb->cmd[6] = 0;
  	pccb->cmdlen = 10;
  	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
  	debug("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X
  ",
  	      pccb->cmd[0], pccb->cmd[1],
  	      pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
  	      pccb->cmd[7], pccb->cmd[8]);
  }
b9560ad64   Simon Glass   dm: scsi: Drop th...
120
  static void scsi_setup_write_ext(struct scsi_cmd *pccb, lbaint_t start,
545a28471   Michal Simek   scsi: Make privat...
121
  				 unsigned short blocks)
11f610edf   Simon Glass   dm: scsi: Separat...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
  {
  	pccb->cmd[0] = SCSI_WRITE10;
  	pccb->cmd[1] = pccb->lun << 5;
  	pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff;
  	pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff;
  	pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff;
  	pccb->cmd[5] = (unsigned char)start & 0xff;
  	pccb->cmd[6] = 0;
  	pccb->cmd[7] = ((unsigned char)(blocks >> 8)) & 0xff;
  	pccb->cmd[8] = (unsigned char)blocks & 0xff;
  	pccb->cmd[9] = 0;
  	pccb->cmdlen = 10;
  	pccb->msgout[0] = SCSI_IDENTIFY;  /* NOT USED */
  	debug("%s: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X
  ",
  	      __func__,
  	      pccb->cmd[0], pccb->cmd[1],
  	      pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
  	      pccb->cmd[7], pccb->cmd[8]);
  }
535556b2a   Simon Glass   dm: scsi: Add sup...
142
143
  static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
  		       void *buffer)
11f610edf   Simon Glass   dm: scsi: Separat...
144
  {
535556b2a   Simon Glass   dm: scsi: Add sup...
145
  	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
4682c8a19   Simon Glass   dm: scsi: Add a d...
146
  	struct udevice *bdev = dev->parent;
4ff572830   Faiz Abbas   scsi: Add max_byt...
147
148
  	struct scsi_platdata *uc_plat = dev_get_uclass_platdata(bdev);
  	lbaint_t start, blks, max_blks;
11f610edf   Simon Glass   dm: scsi: Separat...
149
150
  	uintptr_t buf_addr;
  	unsigned short smallblks = 0;
b9560ad64   Simon Glass   dm: scsi: Drop th...
151
  	struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;
11f610edf   Simon Glass   dm: scsi: Separat...
152
153
  
  	/* Setup device */
cdb93b276   Michal Simek   scsi: Simplify sc...
154
155
  	pccb->target = block_dev->target;
  	pccb->lun = block_dev->lun;
11f610edf   Simon Glass   dm: scsi: Separat...
156
157
158
  	buf_addr = (unsigned long)buffer;
  	start = blknr;
  	blks = blkcnt;
4ff572830   Faiz Abbas   scsi: Add max_byt...
159
160
161
162
  	if (uc_plat->max_bytes_per_req)
  		max_blks = uc_plat->max_bytes_per_req / block_dev->blksz;
  	else
  		max_blks = SCSI_MAX_BLK;
11f610edf   Simon Glass   dm: scsi: Separat...
163
164
165
166
  	debug("
  scsi_read: dev %d startblk " LBAF
  	      ", blccnt " LBAF " buffer %lx
  ",
cdb93b276   Michal Simek   scsi: Simplify sc...
167
  	      block_dev->devnum, start, blks, (unsigned long)buffer);
11f610edf   Simon Glass   dm: scsi: Separat...
168
169
  	do {
  		pccb->pdata = (unsigned char *)buf_addr;
8fbac8e23   Faiz Abbas   scsi: Add dma dir...
170
  		pccb->dma_dir = DMA_FROM_DEVICE;
11f610edf   Simon Glass   dm: scsi: Separat...
171
172
173
  #ifdef CONFIG_SYS_64BIT_LBA
  		if (start > SCSI_LBA48_READ) {
  			unsigned long blocks;
4ff572830   Faiz Abbas   scsi: Add max_byt...
174
  			blocks = min_t(lbaint_t, blks, max_blks);
cdb93b276   Michal Simek   scsi: Simplify sc...
175
  			pccb->datalen = block_dev->blksz * blocks;
11f610edf   Simon Glass   dm: scsi: Separat...
176
177
178
179
180
  			scsi_setup_read16(pccb, start, blocks);
  			start += blocks;
  			blks -= blocks;
  		} else
  #endif
4ff572830   Faiz Abbas   scsi: Add max_byt...
181
182
183
  		if (blks > max_blks) {
  			pccb->datalen = block_dev->blksz * max_blks;
  			smallblks = max_blks;
11f610edf   Simon Glass   dm: scsi: Separat...
184
  			scsi_setup_read_ext(pccb, start, smallblks);
4ff572830   Faiz Abbas   scsi: Add max_byt...
185
186
  			start += max_blks;
  			blks -= max_blks;
11f610edf   Simon Glass   dm: scsi: Separat...
187
  		} else {
cdb93b276   Michal Simek   scsi: Simplify sc...
188
  			pccb->datalen = block_dev->blksz * blks;
11f610edf   Simon Glass   dm: scsi: Separat...
189
190
191
192
193
194
  			smallblks = (unsigned short)blks;
  			scsi_setup_read_ext(pccb, start, smallblks);
  			start += blks;
  			blks = 0;
  		}
  		debug("scsi_read_ext: startblk " LBAF
dee37fc99   Masahiro Yamada   Remove <inttypes....
195
196
  		      ", blccnt %x buffer %lX
  ",
11f610edf   Simon Glass   dm: scsi: Separat...
197
  		      start, smallblks, buf_addr);
4682c8a19   Simon Glass   dm: scsi: Add a d...
198
  		if (scsi_exec(bdev, pccb)) {
11f610edf   Simon Glass   dm: scsi: Separat...
199
200
201
202
203
204
205
  			scsi_print_error(pccb);
  			blkcnt -= blks;
  			break;
  		}
  		buf_addr += pccb->datalen;
  	} while (blks != 0);
  	debug("scsi_read_ext: end startblk " LBAF
dee37fc99   Masahiro Yamada   Remove <inttypes....
206
207
  	      ", blccnt %x buffer %lX
  ", start, smallblks, buf_addr);
11f610edf   Simon Glass   dm: scsi: Separat...
208
209
210
211
212
213
  	return blkcnt;
  }
  
  /*******************************************************************************
   * scsi_write
   */
535556b2a   Simon Glass   dm: scsi: Add sup...
214
215
  static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
  			const void *buffer)
11f610edf   Simon Glass   dm: scsi: Separat...
216
  {
535556b2a   Simon Glass   dm: scsi: Add sup...
217
  	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
4682c8a19   Simon Glass   dm: scsi: Add a d...
218
  	struct udevice *bdev = dev->parent;
4ff572830   Faiz Abbas   scsi: Add max_byt...
219
220
  	struct scsi_platdata *uc_plat = dev_get_uclass_platdata(bdev);
  	lbaint_t start, blks, max_blks;
11f610edf   Simon Glass   dm: scsi: Separat...
221
222
  	uintptr_t buf_addr;
  	unsigned short smallblks;
b9560ad64   Simon Glass   dm: scsi: Drop th...
223
  	struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;
11f610edf   Simon Glass   dm: scsi: Separat...
224

11f610edf   Simon Glass   dm: scsi: Separat...
225
  	/* Setup device */
cdb93b276   Michal Simek   scsi: Simplify sc...
226
227
  	pccb->target = block_dev->target;
  	pccb->lun = block_dev->lun;
11f610edf   Simon Glass   dm: scsi: Separat...
228
229
230
  	buf_addr = (unsigned long)buffer;
  	start = blknr;
  	blks = blkcnt;
4ff572830   Faiz Abbas   scsi: Add max_byt...
231
232
233
234
  	if (uc_plat->max_bytes_per_req)
  		max_blks = uc_plat->max_bytes_per_req / block_dev->blksz;
  	else
  		max_blks = SCSI_MAX_BLK;
11f610edf   Simon Glass   dm: scsi: Separat...
235
236
237
  	debug("
  %s: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx
  ",
cdb93b276   Michal Simek   scsi: Simplify sc...
238
  	      __func__, block_dev->devnum, start, blks, (unsigned long)buffer);
11f610edf   Simon Glass   dm: scsi: Separat...
239
240
  	do {
  		pccb->pdata = (unsigned char *)buf_addr;
8fbac8e23   Faiz Abbas   scsi: Add dma dir...
241
  		pccb->dma_dir = DMA_TO_DEVICE;
4ff572830   Faiz Abbas   scsi: Add max_byt...
242
243
244
  		if (blks > max_blks) {
  			pccb->datalen = block_dev->blksz * max_blks;
  			smallblks = max_blks;
11f610edf   Simon Glass   dm: scsi: Separat...
245
  			scsi_setup_write_ext(pccb, start, smallblks);
4ff572830   Faiz Abbas   scsi: Add max_byt...
246
247
  			start += max_blks;
  			blks -= max_blks;
11f610edf   Simon Glass   dm: scsi: Separat...
248
  		} else {
cdb93b276   Michal Simek   scsi: Simplify sc...
249
  			pccb->datalen = block_dev->blksz * blks;
11f610edf   Simon Glass   dm: scsi: Separat...
250
251
252
253
254
  			smallblks = (unsigned short)blks;
  			scsi_setup_write_ext(pccb, start, smallblks);
  			start += blks;
  			blks = 0;
  		}
dee37fc99   Masahiro Yamada   Remove <inttypes....
255
256
  		debug("%s: startblk " LBAF ", blccnt %x buffer %lx
  ",
11f610edf   Simon Glass   dm: scsi: Separat...
257
  		      __func__, start, smallblks, buf_addr);
4682c8a19   Simon Glass   dm: scsi: Add a d...
258
  		if (scsi_exec(bdev, pccb)) {
11f610edf   Simon Glass   dm: scsi: Separat...
259
260
261
262
263
264
  			scsi_print_error(pccb);
  			blkcnt -= blks;
  			break;
  		}
  		buf_addr += pccb->datalen;
  	} while (blks != 0);
dee37fc99   Masahiro Yamada   Remove <inttypes....
265
266
  	debug("%s: end startblk " LBAF ", blccnt %x buffer %lX
  ",
11f610edf   Simon Glass   dm: scsi: Separat...
267
268
269
  	      __func__, start, smallblks, buf_addr);
  	return blkcnt;
  }
66c54f1a3   Faiz Abbas   scsi: Simplify sc...
270
  #endif
11f610edf   Simon Glass   dm: scsi: Separat...
271

7337fcd8c   Simon Glass   dm: scsi: Drop sc...
272
273
  #if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) && \
  	!defined(CONFIG_DM_SCSI)
11f610edf   Simon Glass   dm: scsi: Separat...
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  void scsi_init(void)
  {
  	int busdevfunc = -1;
  	int i;
  	/*
  	 * Find a device from the list, this driver will support a single
  	 * controller.
  	 */
  	for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
  		/* get PCI Device ID */
  #ifdef CONFIG_DM_PCI
  		struct udevice *dev;
  		int ret;
  
  		ret = dm_pci_find_device(scsi_device_list[i].vendor,
  					 scsi_device_list[i].device, 0, &dev);
  		if (!ret) {
  			busdevfunc = dm_pci_get_bdf(dev);
  			break;
  		}
  #else
  		busdevfunc = pci_find_device(scsi_device_list[i].vendor,
  					     scsi_device_list[i].device,
  					     0);
  #endif
  		if (busdevfunc != -1)
  			break;
  	}
  
  	if (busdevfunc == -1) {
  		printf("Error: SCSI Controller(s) ");
  		for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
  			printf("%04X:%04X ",
  			       scsi_device_list[i].vendor,
  			       scsi_device_list[i].device);
  		}
  		printf("not found
  ");
  		return;
  	}
  #ifdef DEBUG
  	else {
  		printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)
  ",
  		       scsi_device_list[i].vendor,
  		       scsi_device_list[i].device,
  		       (busdevfunc >> 16) & 0xFF,
  		       (busdevfunc >> 11) & 0x1F,
  		       (busdevfunc >> 8) & 0x7);
  	}
  #endif
  	bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci");
  	scsi_low_level_init(busdevfunc);
8eab1a58d   Simon Glass   dm: scsi: Documen...
327
  	scsi_scan(true);
11f610edf   Simon Glass   dm: scsi: Separat...
328
329
330
  	bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI);
  }
  #endif
11f610edf   Simon Glass   dm: scsi: Separat...
331
332
333
  /* copy src to dest, skipping leading and trailing blanks
   * and null terminate the string
   */
545a28471   Michal Simek   scsi: Make privat...
334
335
  static void scsi_ident_cpy(unsigned char *dest, unsigned char *src,
  			   unsigned int len)
11f610edf   Simon Glass   dm: scsi: Separat...
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
  {
  	int start, end;
  
  	start = 0;
  	while (start < len) {
  		if (src[start] != ' ')
  			break;
  		start++;
  	}
  	end = len-1;
  	while (end > start) {
  		if (src[end] != ' ')
  			break;
  		end--;
  	}
  	for (; start <= end; start++)
  		*dest ++= src[start];
  	*dest = '\0';
  }
4682c8a19   Simon Glass   dm: scsi: Add a d...
355
356
  static int scsi_read_capacity(struct udevice *dev, struct scsi_cmd *pccb,
  			      lbaint_t *capacity, unsigned long *blksz)
11f610edf   Simon Glass   dm: scsi: Separat...
357
358
359
360
361
362
363
364
365
366
  {
  	*capacity = 0;
  
  	memset(pccb->cmd, '\0', sizeof(pccb->cmd));
  	pccb->cmd[0] = SCSI_RD_CAPAC10;
  	pccb->cmd[1] = pccb->lun << 5;
  	pccb->cmdlen = 10;
  	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
  
  	pccb->datalen = 8;
f6580ef39   Simon Glass   dm: scsi: Adjust ...
367
  	if (scsi_exec(dev, pccb))
11f610edf   Simon Glass   dm: scsi: Separat...
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
  		return 1;
  
  	*capacity = ((lbaint_t)pccb->pdata[0] << 24) |
  		    ((lbaint_t)pccb->pdata[1] << 16) |
  		    ((lbaint_t)pccb->pdata[2] << 8)  |
  		    ((lbaint_t)pccb->pdata[3]);
  
  	if (*capacity != 0xffffffff) {
  		/* Read capacity (10) was sufficient for this drive. */
  		*blksz = ((unsigned long)pccb->pdata[4] << 24) |
  			 ((unsigned long)pccb->pdata[5] << 16) |
  			 ((unsigned long)pccb->pdata[6] << 8)  |
  			 ((unsigned long)pccb->pdata[7]);
  		return 0;
  	}
  
  	/* Read capacity (10) was insufficient. Use read capacity (16). */
  	memset(pccb->cmd, '\0', sizeof(pccb->cmd));
  	pccb->cmd[0] = SCSI_RD_CAPAC16;
  	pccb->cmd[1] = 0x10;
  	pccb->cmdlen = 16;
  	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
  
  	pccb->datalen = 16;
8fbac8e23   Faiz Abbas   scsi: Add dma dir...
392
  	pccb->dma_dir = DMA_FROM_DEVICE;
f6580ef39   Simon Glass   dm: scsi: Adjust ...
393
  	if (scsi_exec(dev, pccb))
11f610edf   Simon Glass   dm: scsi: Separat...
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
  		return 1;
  
  	*capacity = ((uint64_t)pccb->pdata[0] << 56) |
  		    ((uint64_t)pccb->pdata[1] << 48) |
  		    ((uint64_t)pccb->pdata[2] << 40) |
  		    ((uint64_t)pccb->pdata[3] << 32) |
  		    ((uint64_t)pccb->pdata[4] << 24) |
  		    ((uint64_t)pccb->pdata[5] << 16) |
  		    ((uint64_t)pccb->pdata[6] << 8)  |
  		    ((uint64_t)pccb->pdata[7]);
  
  	*blksz = ((uint64_t)pccb->pdata[8]  << 56) |
  		 ((uint64_t)pccb->pdata[9]  << 48) |
  		 ((uint64_t)pccb->pdata[10] << 40) |
  		 ((uint64_t)pccb->pdata[11] << 32) |
  		 ((uint64_t)pccb->pdata[12] << 24) |
  		 ((uint64_t)pccb->pdata[13] << 16) |
  		 ((uint64_t)pccb->pdata[14] << 8)  |
  		 ((uint64_t)pccb->pdata[15]);
  
  	return 0;
  }
  
  
  /*
   * Some setup (fill-in) routines
   */
b9560ad64   Simon Glass   dm: scsi: Drop th...
421
  static void scsi_setup_test_unit_ready(struct scsi_cmd *pccb)
11f610edf   Simon Glass   dm: scsi: Separat...
422
423
424
425
426
427
428
429
430
431
  {
  	pccb->cmd[0] = SCSI_TST_U_RDY;
  	pccb->cmd[1] = pccb->lun << 5;
  	pccb->cmd[2] = 0;
  	pccb->cmd[3] = 0;
  	pccb->cmd[4] = 0;
  	pccb->cmd[5] = 0;
  	pccb->cmdlen = 6;
  	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
  }
0b3a58eee   Michal Simek   scsi: Separate SC...
432
433
434
435
436
437
  /**
   * scsi_init_dev_desc_priv - initialize only SCSI specific blk_desc properties
   *
   * @dev_desc: Block device description pointer
   */
  static void scsi_init_dev_desc_priv(struct blk_desc *dev_desc)
92ca476c3   Michal Simek   scsi: Extract blo...
438
439
440
  {
  	dev_desc->target = 0xff;
  	dev_desc->lun = 0xff;
92ca476c3   Michal Simek   scsi: Extract blo...
441
442
443
444
445
446
447
  	dev_desc->log2blksz =
  		LOG2_INVALID(typeof(dev_desc->log2blksz));
  	dev_desc->type = DEV_TYPE_UNKNOWN;
  	dev_desc->vendor[0] = 0;
  	dev_desc->product[0] = 0;
  	dev_desc->revision[0] = 0;
  	dev_desc->removable = false;
92ca476c3   Michal Simek   scsi: Extract blo...
448
  }
e8a016b53   Michal Simek   dm: Add support f...
449
  #if !defined(CONFIG_DM_SCSI)
0b3a58eee   Michal Simek   scsi: Separate SC...
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
  /**
   * scsi_init_dev_desc - initialize all SCSI specific blk_desc properties
   *
   * @dev_desc: Block device description pointer
   * @devnum: Device number
   */
  static void scsi_init_dev_desc(struct blk_desc *dev_desc, int devnum)
  {
  	dev_desc->lba = 0;
  	dev_desc->blksz = 0;
  	dev_desc->if_type = IF_TYPE_SCSI;
  	dev_desc->devnum = devnum;
  	dev_desc->part_type = PART_TYPE_UNKNOWN;
  
  	scsi_init_dev_desc_priv(dev_desc);
  }
e8a016b53   Michal Simek   dm: Add support f...
466
  #endif
bccfd9e96   Michal Simek   scsi: Move pccb b...
467

570712f4b   Michal Simek   scsi: Extract dev...
468
469
470
  /**
   * scsi_detect_dev - Detect scsi device
   *
bccfd9e96   Michal Simek   scsi: Move pccb b...
471
   * @target: target id
e39cecfda   Jean-Jacques Hiblot   scsi: make the LU...
472
   * @lun: target lun
570712f4b   Michal Simek   scsi: Extract dev...
473
   * @dev_desc: block device description
570712f4b   Michal Simek   scsi: Extract dev...
474
475
   *
   * The scsi_detect_dev detects and fills a dev_desc structure when the device is
e39cecfda   Jean-Jacques Hiblot   scsi: make the LU...
476
   * detected.
570712f4b   Michal Simek   scsi: Extract dev...
477
478
479
   *
   * Return: 0 on success, error value otherwise
   */
4682c8a19   Simon Glass   dm: scsi: Add a d...
480
481
  static int scsi_detect_dev(struct udevice *dev, int target, int lun,
  			   struct blk_desc *dev_desc)
570712f4b   Michal Simek   scsi: Extract dev...
482
483
484
485
  {
  	unsigned char perq, modi;
  	lbaint_t capacity;
  	unsigned long blksz;
b9560ad64   Simon Glass   dm: scsi: Drop th...
486
  	struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;
d48f00ed1   Faiz Abbas   scsi: Retry inqui...
487
  	int count, err;
570712f4b   Michal Simek   scsi: Extract dev...
488

bccfd9e96   Michal Simek   scsi: Move pccb b...
489
  	pccb->target = target;
e39cecfda   Jean-Jacques Hiblot   scsi: make the LU...
490
  	pccb->lun = lun;
570712f4b   Michal Simek   scsi: Extract dev...
491
492
  	pccb->pdata = (unsigned char *)&tempbuff;
  	pccb->datalen = 512;
8fbac8e23   Faiz Abbas   scsi: Add dma dir...
493
  	pccb->dma_dir = DMA_FROM_DEVICE;
570712f4b   Michal Simek   scsi: Extract dev...
494
  	scsi_setup_inquiry(pccb);
f6580ef39   Simon Glass   dm: scsi: Adjust ...
495
  	if (scsi_exec(dev, pccb)) {
570712f4b   Michal Simek   scsi: Extract dev...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
  		if (pccb->contr_stat == SCSI_SEL_TIME_OUT) {
  			/*
  			  * selection timeout => assuming no
  			  * device present
  			  */
  			debug("Selection timeout ID %d
  ",
  			      pccb->target);
  			return -ETIMEDOUT;
  		}
  		scsi_print_error(pccb);
  		return -ENODEV;
  	}
  	perq = tempbuff[0];
  	modi = tempbuff[1];
  	if ((perq & 0x1f) == 0x1f)
  		return -ENODEV; /* skip unknown devices */
  	if ((modi & 0x80) == 0x80) /* drive is removable */
  		dev_desc->removable = true;
  	/* get info for this device */
  	scsi_ident_cpy((unsigned char *)dev_desc->vendor,
  		       &tempbuff[8], 8);
  	scsi_ident_cpy((unsigned char *)dev_desc->product,
  		       &tempbuff[16], 16);
  	scsi_ident_cpy((unsigned char *)dev_desc->revision,
  		       &tempbuff[32], 4);
  	dev_desc->target = pccb->target;
  	dev_desc->lun = pccb->lun;
d48f00ed1   Faiz Abbas   scsi: Retry inqui...
524
525
526
527
528
529
530
531
  	for (count = 0; count < 3; count++) {
  		pccb->datalen = 0;
  		scsi_setup_test_unit_ready(pccb);
  		err = scsi_exec(dev, pccb);
  		if (!err)
  			break;
  	}
  	if (err) {
570712f4b   Michal Simek   scsi: Extract dev...
532
533
534
535
536
537
538
  		if (dev_desc->removable) {
  			dev_desc->type = perq;
  			goto removable;
  		}
  		scsi_print_error(pccb);
  		return -EINVAL;
  	}
4682c8a19   Simon Glass   dm: scsi: Add a d...
539
  	if (scsi_read_capacity(dev, pccb, &capacity, &blksz)) {
570712f4b   Michal Simek   scsi: Extract dev...
540
541
542
543
544
545
546
  		scsi_print_error(pccb);
  		return -EINVAL;
  	}
  	dev_desc->lba = capacity;
  	dev_desc->blksz = blksz;
  	dev_desc->log2blksz = LOG2(dev_desc->blksz);
  	dev_desc->type = perq;
570712f4b   Michal Simek   scsi: Extract dev...
547
548
549
  removable:
  	return 0;
  }
11f610edf   Simon Glass   dm: scsi: Separat...
550
551
552
553
  /*
   * (re)-scan the scsi bus and reports scsi device info
   * to the user if mode = 1
   */
e8a016b53   Michal Simek   dm: Add support f...
554
  #if defined(CONFIG_DM_SCSI)
8eab1a58d   Simon Glass   dm: scsi: Documen...
555
  static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose)
d52063b84   Jean-Jacques Hiblot   scsi: dm: split s...
556
557
558
559
560
561
562
563
564
565
566
567
  {
  	int ret;
  	struct udevice *bdev;
  	struct blk_desc bd;
  	struct blk_desc *bdesc;
  	char str[10];
  
  	/*
  	 * detect the scsi driver to get information about its geometry (block
  	 * size, number of blocks) and other parameters (ids, type, ...)
  	 */
  	scsi_init_dev_desc_priv(&bd);
4682c8a19   Simon Glass   dm: scsi: Add a d...
568
  	if (scsi_detect_dev(dev, id, lun, &bd))
d52063b84   Jean-Jacques Hiblot   scsi: dm: split s...
569
570
571
572
573
574
575
576
577
  		return -ENODEV;
  
  	/*
  	* Create only one block device and do detection
  	* to make sure that there won't be a lot of
  	* block devices created
  	*/
  	snprintf(str, sizeof(str), "id%dlun%d", id, lun);
  	ret = blk_create_devicef(dev, "scsi_blk", str, IF_TYPE_SCSI, -1,
5fe7702ec   Jean-Jacques Hiblot   blk: dm: make blk...
578
  			bd.blksz, bd.lba, &bdev);
d52063b84   Jean-Jacques Hiblot   scsi: dm: split s...
579
580
581
582
583
584
585
586
587
588
589
590
591
592
  	if (ret) {
  		debug("Can't create device
  ");
  		return ret;
  	}
  
  	bdesc = dev_get_uclass_platdata(bdev);
  	bdesc->target = id;
  	bdesc->lun = lun;
  	bdesc->removable = bd.removable;
  	bdesc->type = bd.type;
  	memcpy(&bdesc->vendor, &bd.vendor, sizeof(bd.vendor));
  	memcpy(&bdesc->product, &bd.product, sizeof(bd.product));
  	memcpy(&bdesc->revision, &bd.revision,	sizeof(bd.revision));
d52063b84   Jean-Jacques Hiblot   scsi: dm: split s...
593

8eab1a58d   Simon Glass   dm: scsi: Documen...
594
  	if (verbose) {
90037d4c7   Heinrich Schuchardt   dm: scsi: report ...
595
  		printf("  Device %d: ", bdesc->devnum);
d52063b84   Jean-Jacques Hiblot   scsi: dm: split s...
596
597
598
599
  		dev_print(bdesc);
  	}
  	return 0;
  }
5c5617631   Simon Glass   dm: scsi: Split o...
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
  int scsi_scan_dev(struct udevice *dev, bool verbose)
  {
  	struct scsi_platdata *uc_plat; /* scsi controller platdata */
  	int ret;
  	int i;
  	int lun;
  
  	/* probe SCSI controller driver */
  	ret = device_probe(dev);
  	if (ret)
  		return ret;
  
  	/* Get controller platdata */
  	uc_plat = dev_get_uclass_platdata(dev);
  
  	for (i = 0; i < uc_plat->max_id; i++)
  		for (lun = 0; lun < uc_plat->max_lun; lun++)
  			do_scsi_scan_one(dev, i, lun, verbose);
  
  	return 0;
  }
8eab1a58d   Simon Glass   dm: scsi: Documen...
621
  int scsi_scan(bool verbose)
e8a016b53   Michal Simek   dm: Add support f...
622
  {
e8a016b53   Michal Simek   dm: Add support f...
623
624
625
  	struct uclass *uc;
  	struct udevice *dev; /* SCSI controller */
  	int ret;
8eab1a58d   Simon Glass   dm: scsi: Documen...
626
  	if (verbose)
e8a016b53   Michal Simek   dm: Add support f...
627
628
  		printf("scanning bus for devices...
  ");
f8f41ae66   Michal Simek   scsi: dm: Unbind ...
629
  	blk_unbind_all(IF_TYPE_SCSI);
e8a016b53   Michal Simek   dm: Add support f...
630
631
632
633
634
  	ret = uclass_get(UCLASS_SCSI, &uc);
  	if (ret)
  		return ret;
  
  	uclass_foreach_dev(dev, uc) {
5c5617631   Simon Glass   dm: scsi: Split o...
635
  		ret = scsi_scan_dev(dev, verbose);
e8a016b53   Michal Simek   dm: Add support f...
636
637
  		if (ret)
  			return ret;
e8a016b53   Michal Simek   dm: Add support f...
638
639
640
641
642
  	}
  
  	return 0;
  }
  #else
8eab1a58d   Simon Glass   dm: scsi: Documen...
643
  int scsi_scan(bool verbose)
11f610edf   Simon Glass   dm: scsi: Separat...
644
  {
570712f4b   Michal Simek   scsi: Extract dev...
645
646
  	unsigned char i, lun;
  	int ret;
11f610edf   Simon Glass   dm: scsi: Separat...
647

8eab1a58d   Simon Glass   dm: scsi: Documen...
648
  	if (verbose)
11f610edf   Simon Glass   dm: scsi: Separat...
649
650
  		printf("scanning bus for devices...
  ");
92ca476c3   Michal Simek   scsi: Extract blo...
651
652
  	for (i = 0; i < CONFIG_SYS_SCSI_MAX_DEVICE; i++)
  		scsi_init_dev_desc(&scsi_dev_desc[i], i);
11f610edf   Simon Glass   dm: scsi: Separat...
653
654
  	scsi_max_devs = 0;
  	for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) {
11f610edf   Simon Glass   dm: scsi: Separat...
655
  		for (lun = 0; lun < CONFIG_SYS_SCSI_MAX_LUN; lun++) {
90037d4c7   Heinrich Schuchardt   dm: scsi: report ...
656
657
658
  			struct blk_desc *bdesc = &scsi_dev_desc[scsi_max_devs];
  
  			ret = scsi_detect_dev(NULL, i, lun, bdesc);
570712f4b   Michal Simek   scsi: Extract dev...
659
  			if (ret)
11f610edf   Simon Glass   dm: scsi: Separat...
660
  				continue;
90037d4c7   Heinrich Schuchardt   dm: scsi: report ...
661
  			part_init(bdesc);
570712f4b   Michal Simek   scsi: Extract dev...
662

8eab1a58d   Simon Glass   dm: scsi: Documen...
663
  			if (verbose) {
90037d4c7   Heinrich Schuchardt   dm: scsi: report ...
664
665
  				printf("  Device %d: ", bdesc->devnum);
  				dev_print(bdesc);
8eab1a58d   Simon Glass   dm: scsi: Documen...
666
  			}
11f610edf   Simon Glass   dm: scsi: Separat...
667
668
669
670
671
672
673
674
675
676
677
  			scsi_max_devs++;
  		} /* next LUN */
  	}
  	if (scsi_max_devs > 0)
  		scsi_curr_dev = 0;
  	else
  		scsi_curr_dev = -1;
  
  	printf("Found %d device(s).
  ", scsi_max_devs);
  #ifndef CONFIG_SPL_BUILD
018f53032   Simon Glass   env: Rename commo...
678
  	env_set_ulong("scsidevs", scsi_max_devs);
11f610edf   Simon Glass   dm: scsi: Separat...
679
  #endif
c002e39ae   Michal Simek   scsi: Change scsi...
680
  	return 0;
11f610edf   Simon Glass   dm: scsi: Separat...
681
  }
e8a016b53   Michal Simek   dm: Add support f...
682
  #endif
11f610edf   Simon Glass   dm: scsi: Separat...
683

535556b2a   Simon Glass   dm: scsi: Add sup...
684
685
686
687
688
689
690
691
692
693
694
695
  #ifdef CONFIG_BLK
  static const struct blk_ops scsi_blk_ops = {
  	.read	= scsi_read,
  	.write	= scsi_write,
  };
  
  U_BOOT_DRIVER(scsi_blk) = {
  	.name		= "scsi_blk",
  	.id		= UCLASS_BLK,
  	.ops		= &scsi_blk_ops,
  };
  #else
11f610edf   Simon Glass   dm: scsi: Separat...
696
  U_BOOT_LEGACY_BLK(scsi) = {
69c125fe7   Ed Swarthout   dm: scsi: if_type...
697
  	.if_typename	= "scsi",
11f610edf   Simon Glass   dm: scsi: Separat...
698
699
700
701
  	.if_type	= IF_TYPE_SCSI,
  	.max_devs	= CONFIG_SYS_SCSI_MAX_DEVICE,
  	.desc		= scsi_dev_desc,
  };
535556b2a   Simon Glass   dm: scsi: Add sup...
702
  #endif