1 /* scsi.c - scsi support. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008,2009 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/disk.h>
22 #include <grub/kernel.h>
23 #include <grub/misc.h>
25 #include <grub/types.h>
26 #include <grub/scsi.h>
27 #include <grub/scsicmd.h>
28 #include <grub/time.h>
29 #include <grub/i18n.h>
31 GRUB_MOD_LICENSE ("GPLv3+");
34 static grub_scsi_dev_t grub_scsi_dev_list
;
36 const char grub_scsi_names
[GRUB_SCSI_NUM_SUBSYSTEMS
][5] = {
37 [GRUB_SCSI_SUBSYSTEM_USBMS
] = "usb",
38 [GRUB_SCSI_SUBSYSTEM_PATA
] = "ata",
39 [GRUB_SCSI_SUBSYSTEM_AHCI
] = "ahci"
43 grub_scsi_dev_register (grub_scsi_dev_t dev
)
45 dev
->next
= grub_scsi_dev_list
;
46 grub_scsi_dev_list
= dev
;
50 grub_scsi_dev_unregister (grub_scsi_dev_t dev
)
52 grub_scsi_dev_t
*p
, q
;
54 for (p
= &grub_scsi_dev_list
, q
= *p
; q
; p
= &(q
->next
), q
= q
->next
)
63 /* Check result of previous operation. */
65 grub_scsi_request_sense (grub_scsi_t scsi
)
67 struct grub_scsi_request_sense rs
;
68 struct grub_scsi_request_sense_data rsd
;
71 rs
.opcode
= grub_scsi_cmd_request_sense
;
72 rs
.lun
= scsi
->lun
<< GRUB_SCSI_LUN_SHIFT
;
75 rs
.alloc_length
= 0x12; /* XXX: Hardcoded for now */
77 grub_memset (rs
.pad
, 0, sizeof(rs
.pad
));
79 err
= scsi
->dev
->read (scsi
, sizeof (rs
), (char *) &rs
,
80 sizeof (rsd
), (char *) &rsd
);
86 /* Self commenting... */
88 grub_scsi_test_unit_ready (grub_scsi_t scsi
)
90 struct grub_scsi_test_unit_ready tur
;
94 tur
.opcode
= grub_scsi_cmd_test_unit_ready
;
95 tur
.lun
= scsi
->lun
<< GRUB_SCSI_LUN_SHIFT
;
100 grub_memset (tur
.pad
, 0, sizeof(tur
.pad
));
102 err
= scsi
->dev
->read (scsi
, sizeof (tur
), (char *) &tur
,
105 /* Each SCSI command should be followed by Request Sense.
106 If not so, many devices STALLs or definitely freezes. */
107 err_sense
= grub_scsi_request_sense (scsi
);
108 if (err_sense
!= GRUB_ERR_NONE
)
110 /* err_sense is ignored for now and Request Sense Data also... */
115 return GRUB_ERR_NONE
;
118 /* Determine if the device is removable and the type of the device
121 grub_scsi_inquiry (grub_scsi_t scsi
)
123 struct grub_scsi_inquiry iq
;
124 struct grub_scsi_inquiry_data iqd
;
126 grub_err_t err_sense
;
128 iq
.opcode
= grub_scsi_cmd_inquiry
;
129 iq
.lun
= scsi
->lun
<< GRUB_SCSI_LUN_SHIFT
;
132 iq
.alloc_length
= 0x24; /* XXX: Hardcoded for now */
134 grub_memset (iq
.pad
, 0, sizeof(iq
.pad
));
136 err
= scsi
->dev
->read (scsi
, sizeof (iq
), (char *) &iq
,
137 sizeof (iqd
), (char *) &iqd
);
139 /* Each SCSI command should be followed by Request Sense.
140 If not so, many devices STALLs or definitely freezes. */
141 err_sense
= grub_scsi_request_sense (scsi
);
142 if (err_sense
!= GRUB_ERR_NONE
)
144 /* err_sense is ignored for now and Request Sense Data also... */
149 scsi
->devtype
= iqd
.devtype
& GRUB_SCSI_DEVTYPE_MASK
;
150 scsi
->removable
= iqd
.rmb
>> GRUB_SCSI_REMOVABLE_BIT
;
152 return GRUB_ERR_NONE
;
155 /* Read the capacity and block size of SCSI. */
157 grub_scsi_read_capacity10 (grub_scsi_t scsi
)
159 struct grub_scsi_read_capacity10 rc
;
160 struct grub_scsi_read_capacity10_data rcd
;
162 grub_err_t err_sense
;
164 rc
.opcode
= grub_scsi_cmd_read_capacity10
;
165 rc
.lun
= scsi
->lun
<< GRUB_SCSI_LUN_SHIFT
;
166 rc
.logical_block_addr
= 0;
173 err
= scsi
->dev
->read (scsi
, sizeof (rc
), (char *) &rc
,
174 sizeof (rcd
), (char *) &rcd
);
176 /* Each SCSI command should be followed by Request Sense.
177 If not so, many devices STALLs or definitely freezes. */
178 err_sense
= grub_scsi_request_sense (scsi
);
179 if (err_sense
!= GRUB_ERR_NONE
)
181 /* err_sense is ignored for now and Request Sense Data also... */
186 scsi
->last_block
= grub_be_to_cpu32 (rcd
.last_block
);
187 scsi
->blocksize
= grub_be_to_cpu32 (rcd
.blocksize
);
189 return GRUB_ERR_NONE
;
192 /* Read the capacity and block size of SCSI. */
194 grub_scsi_read_capacity16 (grub_scsi_t scsi
)
196 struct grub_scsi_read_capacity16 rc
;
197 struct grub_scsi_read_capacity16_data rcd
;
199 grub_err_t err_sense
;
201 rc
.opcode
= grub_scsi_cmd_read_capacity16
;
202 rc
.lun
= (scsi
->lun
<< GRUB_SCSI_LUN_SHIFT
) | 0x10;
203 rc
.logical_block_addr
= 0;
204 rc
.alloc_len
= grub_cpu_to_be32_compile_time (sizeof (rcd
));
208 err
= scsi
->dev
->read (scsi
, sizeof (rc
), (char *) &rc
,
209 sizeof (rcd
), (char *) &rcd
);
211 /* Each SCSI command should be followed by Request Sense.
212 If not so, many devices STALLs or definitely freezes. */
213 err_sense
= grub_scsi_request_sense (scsi
);
214 if (err_sense
!= GRUB_ERR_NONE
)
216 /* err_sense is ignored for now and Request Sense Data also... */
221 scsi
->last_block
= grub_be_to_cpu64 (rcd
.last_block
);
222 scsi
->blocksize
= grub_be_to_cpu32 (rcd
.blocksize
);
224 return GRUB_ERR_NONE
;
227 /* Send a SCSI request for DISK: read SIZE sectors starting with
228 sector SECTOR to BUF. */
230 grub_scsi_read10 (grub_disk_t disk
, grub_disk_addr_t sector
,
231 grub_size_t size
, char *buf
)
234 struct grub_scsi_read10 rd
;
236 grub_err_t err_sense
;
240 rd
.opcode
= grub_scsi_cmd_read10
;
241 rd
.lun
= scsi
->lun
<< GRUB_SCSI_LUN_SHIFT
;
242 rd
.lba
= grub_cpu_to_be32 (sector
);
244 rd
.size
= grub_cpu_to_be16 (size
);
248 err
= scsi
->dev
->read (scsi
, sizeof (rd
), (char *) &rd
, size
* scsi
->blocksize
, buf
);
250 /* Each SCSI command should be followed by Request Sense.
251 If not so, many devices STALLs or definitely freezes. */
252 err_sense
= grub_scsi_request_sense (scsi
);
253 if (err_sense
!= GRUB_ERR_NONE
)
255 /* err_sense is ignored for now and Request Sense Data also... */
260 /* Send a SCSI request for DISK: read SIZE sectors starting with
261 sector SECTOR to BUF. */
263 grub_scsi_read12 (grub_disk_t disk
, grub_disk_addr_t sector
,
264 grub_size_t size
, char *buf
)
267 struct grub_scsi_read12 rd
;
269 grub_err_t err_sense
;
273 rd
.opcode
= grub_scsi_cmd_read12
;
274 rd
.lun
= scsi
->lun
<< GRUB_SCSI_LUN_SHIFT
;
275 rd
.lba
= grub_cpu_to_be32 (sector
);
276 rd
.size
= grub_cpu_to_be32 (size
);
280 err
= scsi
->dev
->read (scsi
, sizeof (rd
), (char *) &rd
, size
* scsi
->blocksize
, buf
);
282 /* Each SCSI command should be followed by Request Sense.
283 If not so, many devices STALLs or definitely freezes. */
284 err_sense
= grub_scsi_request_sense (scsi
);
285 if (err_sense
!= GRUB_ERR_NONE
)
287 /* err_sense is ignored for now and Request Sense Data also... */
292 /* Send a SCSI request for DISK: read SIZE sectors starting with
293 sector SECTOR to BUF. */
295 grub_scsi_read16 (grub_disk_t disk
, grub_disk_addr_t sector
,
296 grub_size_t size
, char *buf
)
299 struct grub_scsi_read16 rd
;
301 grub_err_t err_sense
;
305 rd
.opcode
= grub_scsi_cmd_read16
;
306 rd
.lun
= scsi
->lun
<< GRUB_SCSI_LUN_SHIFT
;
307 rd
.lba
= grub_cpu_to_be64 (sector
);
308 rd
.size
= grub_cpu_to_be32 (size
);
312 err
= scsi
->dev
->read (scsi
, sizeof (rd
), (char *) &rd
, size
* scsi
->blocksize
, buf
);
314 /* Each SCSI command should be followed by Request Sense.
315 If not so, many devices STALLs or definitely freezes. */
316 err_sense
= grub_scsi_request_sense (scsi
);
317 if (err_sense
!= GRUB_ERR_NONE
)
319 /* err_sense is ignored for now and Request Sense Data also... */
324 /* Send a SCSI request for DISK: write the data stored in BUF to SIZE
325 sectors starting with SECTOR. */
327 grub_scsi_write10 (grub_disk_t disk
, grub_disk_addr_t sector
,
328 grub_size_t size
, const char *buf
)
331 struct grub_scsi_write10 wr
;
333 grub_err_t err_sense
;
337 wr
.opcode
= grub_scsi_cmd_write10
;
338 wr
.lun
= scsi
->lun
<< GRUB_SCSI_LUN_SHIFT
;
339 wr
.lba
= grub_cpu_to_be32 (sector
);
341 wr
.size
= grub_cpu_to_be16 (size
);
345 err
= scsi
->dev
->write (scsi
, sizeof (wr
), (char *) &wr
, size
* scsi
->blocksize
, buf
);
347 /* Each SCSI command should be followed by Request Sense.
348 If not so, many devices STALLs or definitely freezes. */
349 err_sense
= grub_scsi_request_sense (scsi
);
350 if (err_sense
!= GRUB_ERR_NONE
)
352 /* err_sense is ignored for now and Request Sense Data also... */
359 /* Send a SCSI request for DISK: write the data stored in BUF to SIZE
360 sectors starting with SECTOR. */
362 grub_scsi_write12 (grub_disk_t disk
, grub_disk_addr_t sector
,
363 grub_size_t size
, char *buf
)
366 struct grub_scsi_write12 wr
;
368 grub_err_t err_sense
;
372 wr
.opcode
= grub_scsi_cmd_write12
;
373 wr
.lun
= scsi
->lun
<< GRUB_SCSI_LUN_SHIFT
;
374 wr
.lba
= grub_cpu_to_be32 (sector
);
375 wr
.size
= grub_cpu_to_be32 (size
);
379 err
= scsi
->dev
->write (scsi
, sizeof (wr
), (char *) &wr
, size
* scsi
->blocksize
, buf
);
381 /* Each SCSI command should be followed by Request Sense.
382 If not so, many devices STALLs or definitely freezes. */
383 err_sense
= grub_scsi_request_sense (scsi
);
384 if (err_sense
!= GRUB_ERR_NONE
)
386 /* err_sense is ignored for now and Request Sense Data also... */
392 /* Send a SCSI request for DISK: write the data stored in BUF to SIZE
393 sectors starting with SECTOR. */
395 grub_scsi_write16 (grub_disk_t disk
, grub_disk_addr_t sector
,
396 grub_size_t size
, const char *buf
)
399 struct grub_scsi_write16 wr
;
401 grub_err_t err_sense
;
405 wr
.opcode
= grub_scsi_cmd_write16
;
406 wr
.lun
= scsi
->lun
<< GRUB_SCSI_LUN_SHIFT
;
407 wr
.lba
= grub_cpu_to_be64 (sector
);
408 wr
.size
= grub_cpu_to_be32 (size
);
412 err
= scsi
->dev
->write (scsi
, sizeof (wr
), (char *) &wr
, size
* scsi
->blocksize
, buf
);
414 /* Each SCSI command should be followed by Request Sense.
415 If not so, many devices STALLs or definitely freezes. */
416 err_sense
= grub_scsi_request_sense (scsi
);
417 if (err_sense
!= GRUB_ERR_NONE
)
419 /* err_sense is ignored for now and Request Sense Data also... */
426 /* Context for grub_scsi_iterate. */
427 struct grub_scsi_iterate_ctx
429 grub_disk_dev_iterate_hook_t hook
;
433 /* Helper for grub_scsi_iterate. */
435 scsi_iterate (int id
, int bus
, int luns
, void *data
)
437 struct grub_scsi_iterate_ctx
*ctx
= data
;
440 /* In case of a single LUN, just return `usbX'. */
445 sname
= grub_xasprintf ("%s%d", grub_scsi_names
[id
], bus
);
448 ret
= ctx
->hook (sname
, ctx
->hook_data
);
453 /* In case of multiple LUNs, every LUN will get a prefix to
455 for (i
= 0; i
< luns
; i
++)
459 sname
= grub_xasprintf ("%s%d%c", grub_scsi_names
[id
], bus
, 'a' + i
);
462 ret
= ctx
->hook (sname
, ctx
->hook_data
);
471 grub_scsi_iterate (grub_disk_dev_iterate_hook_t hook
, void *hook_data
,
472 grub_disk_pull_t pull
)
474 struct grub_scsi_iterate_ctx ctx
= { hook
, hook_data
};
477 for (p
= grub_scsi_dev_list
; p
; p
= p
->next
)
478 if (p
->iterate
&& (p
->iterate
) (scsi_iterate
, &ctx
, pull
))
485 grub_scsi_open (const char *name
, grub_disk_t disk
)
491 grub_uint64_t maxtime
;
495 nameend
= name
+ grub_strlen (name
) - 1;
496 /* Try to detect a LUN ('a'-'z'), otherwise just use the first
498 if (nameend
>= name
&& *nameend
>= 'a' && *nameend
<= 'z')
500 lun
= *nameend
- 'a';
506 while (nameend
>= name
&& grub_isdigit (*nameend
))
509 if (!nameend
[1] || !grub_isdigit (nameend
[1]))
510 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, "not a SCSI disk");
512 bus
= grub_strtoul (nameend
+ 1, 0, 0);
514 scsi
= grub_malloc (sizeof (*scsi
));
518 for (id
= 0; id
< ARRAY_SIZE (grub_scsi_names
); id
++)
519 if (grub_strncmp (grub_scsi_names
[id
], name
, nameend
- name
) == 0)
522 if (id
== ARRAY_SIZE (grub_scsi_names
))
525 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, "not a SCSI disk");
528 for (p
= grub_scsi_dev_list
; p
; p
= p
->next
)
530 if (p
->open (id
, bus
, scsi
))
532 grub_errno
= GRUB_ERR_NONE
;
536 disk
->id
= grub_make_scsi_id (id
, bus
, lun
);
542 grub_dprintf ("scsi", "dev opened\n");
544 err
= grub_scsi_inquiry (scsi
);
548 grub_dprintf ("scsi", "inquiry failed\n");
552 grub_dprintf ("scsi", "inquiry: devtype=0x%02x removable=%d\n",
553 scsi
->devtype
, scsi
->removable
);
555 /* Try to be conservative about the device types
557 if (scsi
->devtype
!= grub_scsi_devtype_direct
558 && scsi
->devtype
!= grub_scsi_devtype_cdrom
)
561 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
,
562 "unknown SCSI device");
565 /* According to USB MS tests specification, issue Test Unit Ready
567 maxtime
= grub_get_time_ms () + 5000; /* It is safer value */
570 /* Timeout is necessary - for example in case when we have
571 * universal card reader with more LUNs and we have only
572 * one card inserted (or none), so only one LUN (or none)
573 * will be ready - and we want not to hang... */
574 if (grub_get_time_ms () > maxtime
)
576 err
= GRUB_ERR_READ_ERROR
;
578 grub_dprintf ("scsi", "LUN is not ready - timeout\n");
581 err
= grub_scsi_test_unit_ready (scsi
);
583 while (err
== GRUB_ERR_READ_ERROR
);
584 /* Reset grub_errno !
585 * It is set to some error code in loop before... */
586 grub_errno
= GRUB_ERR_NONE
;
588 /* Read capacity of media */
589 err
= grub_scsi_read_capacity10 (scsi
);
593 grub_dprintf ("scsi", "READ CAPACITY10 failed\n");
597 if (scsi
->last_block
== 0xffffffff)
599 err
= grub_scsi_read_capacity16 (scsi
);
603 grub_dprintf ("scsi", "READ CAPACITY16 failed\n");
608 disk
->total_sectors
= scsi
->last_block
+ 1;
609 /* PATA doesn't support more than 32K reads.
610 Not sure about AHCI and USB. If it's confirmed that either of
611 them can do bigger reads reliably this value can be moved to 'scsi'
613 disk
->max_agglomerate
= 32768 >> (GRUB_DISK_SECTOR_BITS
614 + GRUB_DISK_CACHE_BITS
);
616 if (scsi
->blocksize
& (scsi
->blocksize
- 1) || !scsi
->blocksize
)
619 return grub_error (GRUB_ERR_IO
, "invalid sector size %d",
622 for (disk
->log_sector_size
= 0;
623 (1U << disk
->log_sector_size
) < scsi
->blocksize
;
624 disk
->log_sector_size
++);
626 grub_dprintf ("scsi", "last_block=%" PRIuGRUB_UINT64_T
", blocksize=%u\n",
627 scsi
->last_block
, scsi
->blocksize
);
628 grub_dprintf ("scsi", "Disk total sectors = %llu\n",
629 (unsigned long long) disk
->total_sectors
);
631 return GRUB_ERR_NONE
;
635 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, "not a SCSI disk");
639 grub_scsi_close (grub_disk_t disk
)
644 if (scsi
->dev
->close
)
645 scsi
->dev
->close (scsi
);
650 grub_scsi_read (grub_disk_t disk
, grub_disk_addr_t sector
,
651 grub_size_t size
, char *buf
)
658 /* Depending on the type, select a read function. */
659 switch (scsi
->devtype
)
661 case grub_scsi_devtype_direct
:
663 err
= grub_scsi_read16 (disk
, sector
, size
, buf
);
665 err
= grub_scsi_read10 (disk
, sector
, size
, buf
);
670 case grub_scsi_devtype_cdrom
:
672 err
= grub_scsi_read16 (disk
, sector
, size
, buf
);
674 err
= grub_scsi_read12 (disk
, sector
, size
, buf
);
680 return GRUB_ERR_NONE
;
682 #if 0 /* Workaround - it works - but very slowly, from some reason
683 * unknown to me (specially on OHCI). Do not use it. */
684 /* Split transfer requests to device sector size because */
685 /* some devices are not able to transfer more than 512-1024 bytes */
686 grub_err_t err
= GRUB_ERR_NONE
;
688 for ( ; size
; size
--)
690 /* Depending on the type, select a read function. */
691 switch (scsi
->devtype
)
693 case grub_scsi_devtype_direct
:
694 err
= grub_scsi_read10 (disk
, sector
, 1, buf
);
697 case grub_scsi_devtype_cdrom
:
698 err
= grub_scsi_read12 (disk
, sector
, 1, buf
);
701 default: /* This should not happen */
702 return GRUB_ERR_READ_ERROR
;
707 buf
+= scsi
->blocksize
;
715 grub_scsi_write (grub_disk_t disk
,
716 grub_disk_addr_t sector
,
724 if (scsi
->devtype
== grub_scsi_devtype_cdrom
)
725 return grub_error (GRUB_ERR_IO
, N_("cannot write to CD-ROM"));
728 /* Depending on the type, select a read function. */
729 switch (scsi
->devtype
)
731 case grub_scsi_devtype_direct
:
733 err
= grub_scsi_write16 (disk
, sector
, size
, buf
);
735 err
= grub_scsi_write10 (disk
, sector
, size
, buf
);
741 return GRUB_ERR_NONE
;
745 static struct grub_disk_dev grub_scsi_dev
=
748 .id
= GRUB_DISK_DEVICE_SCSI_ID
,
749 .iterate
= grub_scsi_iterate
,
750 .open
= grub_scsi_open
,
751 .close
= grub_scsi_close
,
752 .read
= grub_scsi_read
,
753 .write
= grub_scsi_write
,
759 grub_disk_dev_register (&grub_scsi_dev
);
764 grub_disk_dev_unregister (&grub_scsi_dev
);