From 9c08ad870748c6d0e97f09c4cedd673b8629e9de Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 30 Jan 2012 18:33:11 +0100 Subject: [PATCH] * 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. --- ChangeLog | 20 +++++++++++++ grub-core/disk/scsi.c | 68 +++++++++++++++++++++++++++++++++++------- include/grub/scsi.h | 6 ++-- include/grub/scsicmd.h | 26 +++++++++++++--- 4 files changed, 102 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index 38409d405..cbf9dc3f4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2012-01-30 Vladimir Serbinenko + + * 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 SCSI >2TiB support. diff --git a/grub-core/disk/scsi.c b/grub-core/disk/scsi.c index a1d04f40d..508bc27f6 100644 --- a/grub-core/disk/scsi.c +++ b/grub-core/disk/scsi.c @@ -153,14 +153,14 @@ grub_scsi_inquiry (grub_scsi_t scsi) /* 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; @@ -182,7 +182,42 @@ grub_scsi_read_capacity (grub_scsi_t scsi) 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; @@ -541,15 +576,26 @@ grub_scsi_open (const char *name, grub_disk_t disk) 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); @@ -557,11 +603,11 @@ grub_scsi_open (const char *name, grub_disk_t disk) 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); diff --git a/include/grub/scsi.h b/include/grub/scsi.h index e10f5e452..13300ca15 100644 --- a/include/grub/scsi.h +++ b/include/grub/scsi.h @@ -94,11 +94,11 @@ struct grub_scsi /* Set to 0 when not removable, 1 when removable. */ int removable; - /* Size of the device in blocks. */ - int size; + /* Size of the device in blocks - 1. */ + grub_uint64_t last_block; /* Size of one block. */ - int blocksize; + grub_uint32_t blocksize; /* Device-specific data. */ void *data; diff --git a/include/grub/scsicmd.h b/include/grub/scsicmd.h index c969c394a..a3e79888a 100644 --- a/include/grub/scsicmd.h +++ b/include/grub/scsicmd.h @@ -85,7 +85,7 @@ struct grub_scsi_request_sense_data /* 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 */ @@ -97,12 +97,29 @@ struct grub_scsi_read_capacity 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_uint8_t opcode; @@ -170,11 +187,12 @@ typedef enum 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;