+2012-01-30 Vladimir Serbinenko <phcoder@gmail.com>
+
+ * grub-core/disk/scsi.c (grub_scsi_read_capacity): Renamed to ...
+ (grub_scsi_read_capacity10): ... this.
+ (grub_scsi_read_capacity16): New function.
+ (grub_scsi_open): Use read_capacity16 if read_capacity10 returned
+ 0xffffffff.
+ Fix off-by-one error.
+ * include/grub/scsi.h (grub_scsi): Rename size to last_block and make it
+ 64-bit unsigned.
+ * include/grub/scsicmd.h (grub_scsi_read_capacity): Rename to ...
+ (grub_scsi_read_capacity10): ... this.
+ (grub_scsi_read_capacity_data): Rename to ...
+ (grub_scsi_read_capacity10_data): ... this. Rename size to last_block.
+ (grub_scsi_read_capacity16): New struct.
+ (grub_scsi_read_capacity16_data): Likewise.
+ (grub_scsi_cmd_t): Rename grub_scsi_cmd_read_capacity to
+ grub_scsi_cmd_read_capacity10.
+ New command grub_scsi_cmd_read_capacity16.
+
2012-01-30 Vladimir Serbinenko <phcoder@gmail.com>
SCSI >2TiB support.
/* Read the capacity and block size of SCSI. */
static grub_err_t
-grub_scsi_read_capacity (grub_scsi_t scsi)
+grub_scsi_read_capacity10 (grub_scsi_t scsi)
{
- struct grub_scsi_read_capacity rc;
- struct grub_scsi_read_capacity_data rcd;
+ struct grub_scsi_read_capacity10 rc;
+ struct grub_scsi_read_capacity10_data rcd;
grub_err_t err;
grub_err_t err_sense;
- rc.opcode = grub_scsi_cmd_read_capacity;
+ rc.opcode = grub_scsi_cmd_read_capacity10;
rc.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
rc.logical_block_addr = 0;
rc.reserved1 = 0;
if (err)
return err;
- scsi->size = grub_be_to_cpu32 (rcd.size);
+ scsi->last_block = grub_be_to_cpu32 (rcd.last_block);
+ scsi->blocksize = grub_be_to_cpu32 (rcd.blocksize);
+
+ return GRUB_ERR_NONE;
+}
+
+/* Read the capacity and block size of SCSI. */
+static grub_err_t
+grub_scsi_read_capacity16 (grub_scsi_t scsi)
+{
+ struct grub_scsi_read_capacity16 rc;
+ struct grub_scsi_read_capacity16_data rcd;
+ grub_err_t err;
+ grub_err_t err_sense;
+
+ rc.opcode = grub_scsi_cmd_read_capacity16;
+ rc.lun = (scsi->lun << GRUB_SCSI_LUN_SHIFT) | 0x10;
+ rc.logical_block_addr = 0;
+ rc.alloc_len = grub_cpu_to_be32 (sizeof (rcd));
+ rc.PMI = 0;
+ rc.control = 0;
+
+ err = scsi->dev->read (scsi, sizeof (rc), (char *) &rc,
+ sizeof (rcd), (char *) &rcd);
+
+ /* Each SCSI command should be followed by Request Sense.
+ If not so, many devices STALLs or definitely freezes. */
+ err_sense = grub_scsi_request_sense (scsi);
+ if (err_sense != GRUB_ERR_NONE)
+ grub_errno = err;
+/* err_sense is ignored for now and Request Sense Data also... */
+
+ if (err)
+ return err;
+
+ scsi->last_block = grub_be_to_cpu64 (rcd.last_block);
scsi->blocksize = grub_be_to_cpu32 (rcd.blocksize);
return GRUB_ERR_NONE;
grub_errno = GRUB_ERR_NONE;
/* Read capacity of media */
- err = grub_scsi_read_capacity (scsi);
+ err = grub_scsi_read_capacity10 (scsi);
if (err)
{
grub_free (scsi);
- grub_dprintf ("scsi", "READ CAPACITY failed\n");
+ grub_dprintf ("scsi", "READ CAPACITY10 failed\n");
return err;
}
- disk->total_sectors = scsi->size;
+ if (scsi->last_block == 0xffffffff)
+ {
+ err = grub_scsi_read_capacity16 (scsi);
+ if (err)
+ {
+ grub_free (scsi);
+ grub_dprintf ("scsi", "READ CAPACITY16 failed\n");
+ return err;
+ }
+ }
+
+ disk->total_sectors = scsi->last_block + 1;
if (scsi->blocksize & (scsi->blocksize - 1) || !scsi->blocksize)
{
grub_free (scsi);
scsi->blocksize);
}
for (disk->log_sector_size = 0;
- (1 << disk->log_sector_size) < scsi->blocksize;
+ (1U << disk->log_sector_size) < scsi->blocksize;
disk->log_sector_size++);
- grub_dprintf ("scsi", "blocks=%u, blocksize=%u\n",
- scsi->size, scsi->blocksize);
+ grub_dprintf ("scsi", "last_block=%" PRIuGRUB_UINT64_T ", blocksize=%u\n",
+ scsi->last_block, scsi->blocksize);
grub_dprintf ("scsi", "Disk total sectors = %llu\n",
(unsigned long long) disk->total_sectors);
/* there can be additional sense field */
} __attribute__((packed));
-struct grub_scsi_read_capacity
+struct grub_scsi_read_capacity10
{
grub_uint8_t opcode;
grub_uint8_t lun; /* 7-5 LUN, 4-1 reserved, 0 reserved */
grub_uint16_t pad; /* To be ATAPI compatible */
} __attribute__((packed));
-struct grub_scsi_read_capacity_data
+struct grub_scsi_read_capacity10_data
{
- grub_uint32_t size;
+ grub_uint32_t last_block;
+ grub_uint32_t blocksize;
+} __attribute__((packed));
+
+struct grub_scsi_read_capacity16
+{
+ grub_uint8_t opcode;
+ grub_uint8_t lun; /* 7-5 LUN, 4-0 0x10 */
+ grub_uint64_t logical_block_addr; /* only if PMI=1 */
+ grub_uint32_t alloc_len;
+ grub_uint8_t PMI;
+ grub_uint8_t control;
+} __attribute__((packed));
+
+struct grub_scsi_read_capacity16_data
+{
+ grub_uint64_t last_block;
grub_uint32_t blocksize;
+ grub_uint8_t pad[20];
} __attribute__((packed));
struct grub_scsi_read10
grub_scsi_cmd_test_unit_ready = 0x00,
grub_scsi_cmd_request_sense = 0x03,
grub_scsi_cmd_inquiry = 0x12,
- grub_scsi_cmd_read_capacity = 0x25,
+ grub_scsi_cmd_read_capacity10 = 0x25,
grub_scsi_cmd_read10 = 0x28,
grub_scsi_cmd_write10 = 0x2a,
grub_scsi_cmd_read16 = 0x88,
grub_scsi_cmd_write16 = 0x8a,
+ grub_scsi_cmd_read_capacity16 = 0x9e,
grub_scsi_cmd_read12 = 0xa8,
grub_scsi_cmd_write12 = 0xaa,
} grub_scsi_cmd_t;