aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/hw/blockcmd.c58
-rw-r--r--src/hw/blockcmd.h27
2 files changed, 71 insertions, 14 deletions
diff --git a/src/hw/blockcmd.c b/src/hw/blockcmd.c
index 6b6fea9..f59b2ef 100644
--- a/src/hw/blockcmd.c
+++ b/src/hw/blockcmd.c
@@ -66,6 +66,23 @@ cdb_test_unit_ready(struct disk_op_s *op)
return process_op(op);
}
+static int
+cdb_read_capacity16(struct disk_op_s *op, struct cdbres_read_capacity_16 *data)
+{
+ struct cdb_sai_read_capacity_16 cmd;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.command = CDB_CMD_SERVICE_ACTION_IN;
+ cmd.flags = CDB_CMD_SAI_READ_CAPACITY_16;
+ cmd.len = cpu_to_be32(sizeof(struct cdbres_read_capacity_16));
+ op->command = CMD_SCSI;
+ op->count = 1;
+ op->buf_fl = data;
+ op->cdbcmd = &cmd;
+ op->blocksize = sizeof(*data);
+ return process_op(op);
+}
+
+
// Request capacity
static int
cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data)
@@ -111,12 +128,21 @@ scsi_fill_cmd(struct disk_op_s *op, void *cdbcmd, int maxcdb)
switch (op->command) {
case CMD_READ:
case CMD_WRITE: ;
- struct cdb_rwdata_10 *cmd = cdbcmd;
- memset(cmd, 0, maxcdb);
- cmd->command = (op->command == CMD_READ ? CDB_CMD_READ_10
- : CDB_CMD_WRITE_10);
- cmd->lba = cpu_to_be32(op->lba);
- cmd->count = cpu_to_be16(op->count);
+ if (op->lba < 0xFFFFFFFFULL) {
+ struct cdb_rwdata_10 *cmd = cdbcmd;
+ memset(cmd, 0, maxcdb);
+ cmd->command = (op->command == CMD_READ ? CDB_CMD_READ_10
+ : CDB_CMD_WRITE_10);
+ cmd->lba = cpu_to_be32(op->lba);
+ cmd->count = cpu_to_be16(op->count);
+ } else {
+ struct cdb_rwdata_16 *cmd = cdbcmd;
+ memset(cmd, 0, maxcdb);
+ cmd->command = (op->command == CMD_READ ? CDB_CMD_READ_16
+ : CDB_CMD_WRITE_16);
+ cmd->lba = cpu_to_be64(op->lba);
+ cmd->count = cpu_to_be32(op->count);
+ }
return GET_FLATPTR(op->drive_fl->blksize);
case CMD_SCSI:
if (MODESEGMENT)
@@ -331,18 +357,22 @@ scsi_drive_setup(struct drive_s *drive, const char *s, int prio)
if (ret)
return ret;
- // READ CAPACITY returns the address of the last block.
- // We do not bother with READ CAPACITY(16) because BIOS does not support
- // 64-bit LBA anyway.
- drive->blksize = be32_to_cpu(capdata.blksize);
+ if (be32_to_cpu(capdata.sectors) == 0xFFFFFFFFUL) {
+ dprintf(3, "%s: >2TB Detected trying READCAP(16)\n", s);
+ struct cdbres_read_capacity_16 capdata16;
+ ret = cdb_read_capacity16(&dop, &capdata16);
+ drive->blksize = be32_to_cpu(capdata16.blksize);
+ drive->sectors = be64_to_cpu(capdata16.sectors) + 1;
+ } else {
+ drive->blksize = be32_to_cpu(capdata.blksize);
+ drive->sectors = (u64)be32_to_cpu(capdata.sectors) + 1;
+ }
+
if (drive->blksize != DISK_SECTOR_SIZE) {
dprintf(1, "%s: unsupported block size %d\n", s, drive->blksize);
return -1;
}
- drive->sectors = (u64)be32_to_cpu(capdata.sectors) + 1;
- dprintf(1, "%s blksize=%d sectors=%u\n"
- , s, drive->blksize, (unsigned)drive->sectors);
-
+ dprintf(1, "%s blksize=%d sectors=0x%llx\n", s, drive->blksize, drive->sectors);
// We do not recover from USB stalls, so try to be safe and avoid
// sending the command if the (obsolete, but still provided by QEMU)
// fixed disk geometry page may not be supported.
diff --git a/src/hw/blockcmd.h b/src/hw/blockcmd.h
index f18543e..2683186 100644
--- a/src/hw/blockcmd.h
+++ b/src/hw/blockcmd.h
@@ -18,6 +18,16 @@ struct cdb_rwdata_10 {
u8 pad[6];
} PACKED;
+#define CDB_CMD_READ_16 0x88
+#define CDB_CMD_WRITE_16 0x8A
+struct cdb_rwdata_16 {
+ u8 command;
+ u8 flags;
+ u64 lba;
+ u32 count;
+ u16 reserved_14;
+} PACKED;
+
#define CDB_CMD_READ_CAPACITY 0x25
struct cdb_read_capacity {
@@ -32,6 +42,23 @@ struct cdbres_read_capacity {
u32 blksize;
} PACKED;
+
+#define CDB_CMD_SERVICE_ACTION_IN 0x9E
+#define CDB_CMD_SAI_READ_CAPACITY_16 0x10
+struct cdb_sai_read_capacity_16 {
+ u8 command;
+ u8 flags;
+ u64 lba; //marked as obsolete?
+ u32 len;
+ u16 reserved_14;
+} PACKED;
+
+struct cdbres_read_capacity_16 {
+ u64 sectors;
+ u32 blksize;
+ u8 reserved_12[20];
+} PACKED;
+
#define CDB_CMD_TEST_UNIT_READY 0x00
#define CDB_CMD_INQUIRY 0x12
#define CDB_CMD_REQUEST_SENSE 0x03