diff --git a/ChangeLog b/ChangeLog index 5641803dc..38409d405 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2012-01-30 Vladimir Serbinenko + + SCSI >2TiB support. + + * grub-core/disk/scsi.c (grub_scsi_read16): New function. + (grub_scsi_write16): Likewise. + (grub_scsi_read): Use read16 when necessary. + (grub_scsi_write): Likewise. + * include/grub/scsicmd.h (grub_scsi_read16): New struct. + (grub_scsi_write16): Likewise. + (grub_scsi_cmd_t): Add READ16 and WRITE16. + 2012-01-30 Vladimir Serbinenko SCSI write support (for usbms mainly). diff --git a/grub-core/disk/scsi.c b/grub-core/disk/scsi.c index b22f651e9..a1d04f40d 100644 --- a/grub-core/disk/scsi.c +++ b/grub-core/disk/scsi.c @@ -253,6 +253,38 @@ grub_scsi_read12 (grub_disk_t disk, grub_disk_addr_t sector, return err; } +/* Send a SCSI request for DISK: read SIZE sectors starting with + sector SECTOR to BUF. */ +static grub_err_t +grub_scsi_read16 (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, char *buf) +{ + grub_scsi_t scsi; + struct grub_scsi_read16 rd; + grub_err_t err; + grub_err_t err_sense; + + scsi = disk->data; + + rd.opcode = grub_scsi_cmd_read16; + rd.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT; + rd.lba = grub_cpu_to_be64 (sector); + rd.size = grub_cpu_to_be32 (size); + rd.reserved = 0; + rd.control = 0; + + err = scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * scsi->blocksize, buf); + + /* 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... */ + + return err; +} + /* Send a SCSI request for DISK: write the data stored in BUF to SIZE sectors starting with SECTOR. */ static grub_err_t @@ -321,6 +353,39 @@ grub_scsi_write12 (grub_disk_t disk, grub_disk_addr_t sector, } #endif +/* Send a SCSI request for DISK: write the data stored in BUF to SIZE + sectors starting with SECTOR. */ +static grub_err_t +grub_scsi_write16 (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, const char *buf) +{ + grub_scsi_t scsi; + struct grub_scsi_write16 wr; + grub_err_t err; + grub_err_t err_sense; + + scsi = disk->data; + + wr.opcode = grub_scsi_cmd_write16; + wr.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT; + wr.lba = grub_cpu_to_be64 (sector); + wr.size = grub_cpu_to_be32 (size); + wr.reserved = 0; + wr.control = 0; + + err = scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * scsi->blocksize, buf); + + /* 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... */ + + return err; +} + + static int grub_scsi_iterate (int (*hook) (const char *name), @@ -540,13 +605,19 @@ grub_scsi_read (grub_disk_t disk, grub_disk_addr_t sector, switch (scsi->devtype) { case grub_scsi_devtype_direct: - err = grub_scsi_read10 (disk, sector, len, buf); + if (sector >> 32) + err = grub_scsi_read16 (disk, sector, len, buf); + else + err = grub_scsi_read10 (disk, sector, len, buf); if (err) return err; break; case grub_scsi_devtype_cdrom: - err = grub_scsi_read12 (disk, sector, len, buf); + if (sector >> 32) + err = grub_scsi_read16 (disk, sector, len, buf); + else + err = grub_scsi_read12 (disk, sector, len, buf); if (err) return err; break; @@ -617,7 +688,10 @@ grub_scsi_write (grub_disk_t disk __attribute((unused)), switch (scsi->devtype) { case grub_scsi_devtype_direct: - err = grub_scsi_write10 (disk, sector, len, buf); + if (sector >> 32) + err = grub_scsi_write16 (disk, sector, len, buf); + else + err = grub_scsi_write10 (disk, sector, len, buf); if (err) return err; break; diff --git a/include/grub/scsicmd.h b/include/grub/scsicmd.h index 9cc5afe72..c969c394a 100644 --- a/include/grub/scsicmd.h +++ b/include/grub/scsicmd.h @@ -124,6 +124,16 @@ struct grub_scsi_read12 grub_uint8_t control; } __attribute__((packed)); +struct grub_scsi_read16 +{ + grub_uint8_t opcode; + grub_uint8_t lun; + grub_uint64_t lba; + grub_uint32_t size; + grub_uint8_t reserved; + grub_uint8_t control; +} __attribute__((packed)); + struct grub_scsi_write10 { grub_uint8_t opcode; @@ -145,6 +155,16 @@ struct grub_scsi_write12 grub_uint8_t control; } __attribute__((packed)); +struct grub_scsi_write16 +{ + grub_uint8_t opcode; + grub_uint8_t lun; + grub_uint64_t lba; + grub_uint32_t size; + grub_uint8_t reserved; + grub_uint8_t control; +} __attribute__((packed)); + typedef enum { grub_scsi_cmd_test_unit_ready = 0x00, @@ -153,6 +173,8 @@ typedef enum grub_scsi_cmd_read_capacity = 0x25, grub_scsi_cmd_read10 = 0x28, grub_scsi_cmd_write10 = 0x2a, + grub_scsi_cmd_read16 = 0x88, + grub_scsi_cmd_write16 = 0x8a, grub_scsi_cmd_read12 = 0xa8, grub_scsi_cmd_write12 = 0xaa, } grub_scsi_cmd_t;