diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2013-05-12 19:33:02 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2013-05-12 19:33:02 +0000 |
commit | fd46a7c12944886430fb10ddf806e223aa230bc9 (patch) | |
tree | b05cc52f79728b8338a9799a5e09582326928de5 | |
parent | 3e93135628fb4a111c002c250e8aac3bb3cef8fe (diff) |
Handle big (a.k.a. >2TB) disks by adding logic to handle the 12 and 16
byte scsi read/write commands.
Issue pointed out by John Morrissey via bugs@. Problem reproduced and
fix tested by sf@ on vioblk.
ok sf@ kettenis@
-rw-r--r-- | sys/arch/sparc64/dev/vdsk.c | 22 | ||||
-rw-r--r-- | sys/dev/pci/vioblk.c | 22 |
2 files changed, 40 insertions, 4 deletions
diff --git a/sys/arch/sparc64/dev/vdsk.c b/sys/arch/sparc64/dev/vdsk.c index a12e88f819d..e9506e0a4a0 100644 --- a/sys/arch/sparc64/dev/vdsk.c +++ b/sys/arch/sparc64/dev/vdsk.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vdsk.c,v 1.32 2012/11/21 23:02:37 kettenis Exp $ */ +/* $OpenBSD: vdsk.c,v 1.33 2013/05/12 19:33:01 krw Exp $ */ /* * Copyright (c) 2009, 2011 Mark Kettenis * @@ -922,6 +922,8 @@ vdsk_scsi_cmd(struct scsi_xfer *xs) { struct scsi_rw *rw; struct scsi_rw_big *rwb; + struct scsi_rw_12 *rw12; + struct scsi_rw_16 *rw16; u_int64_t lba; u_int32_t sector_count; uint8_t operation; @@ -929,10 +931,14 @@ vdsk_scsi_cmd(struct scsi_xfer *xs) switch (xs->cmd->opcode) { case READ_BIG: case READ_COMMAND: + case READ_12: + case READ_16: operation = VD_OP_BREAD; break; case WRITE_BIG: case WRITE_COMMAND: + case WRITE_12: + case WRITE_16: operation = VD_OP_BWRITE; break; @@ -966,14 +972,26 @@ vdsk_scsi_cmd(struct scsi_xfer *xs) return; } + /* + * READ/WRITE/SYNCHRONIZE commands. SYNCHRONIZE CACHE has same + * layout as 10-byte READ/WRITE commands. + */ if (xs->cmdlen == 6) { rw = (struct scsi_rw *)xs->cmd; lba = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff); sector_count = rw->length ? rw->length : 0x100; - } else { + } else if (xs->cmdlen == 10) { rwb = (struct scsi_rw_big *)xs->cmd; lba = _4btol(rwb->addr); sector_count = _2btol(rwb->length); + } else if (xs->cmdlen == 12) { + rw12 = (struct scsi_rw_12 *)xs->cmd; + lba = _4btol(rw12->addr); + sector_count = _4btol(rw12->length); + } else if (xs->cmdlen == 16) { + rw16 = (struct scsi_rw_16 *)xs->cmd; + lba = _8btol(rw16->addr); + sector_count = _4btol(rw16->length); } { diff --git a/sys/dev/pci/vioblk.c b/sys/dev/pci/vioblk.c index 6fdbf797ba8..4493d009f34 100644 --- a/sys/dev/pci/vioblk.c +++ b/sys/dev/pci/vioblk.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vioblk.c,v 1.3 2012/12/05 23:20:21 deraadt Exp $ */ +/* $OpenBSD: vioblk.c,v 1.4 2013/05/12 19:33:01 krw Exp $ */ /* * Copyright (c) 2012 Stefan Fritsch. @@ -316,6 +316,8 @@ vioblk_scsi_cmd(struct scsi_xfer *xs) { struct scsi_rw *rw; struct scsi_rw_big *rwb; + struct scsi_rw_12 *rw12; + struct scsi_rw_16 *rw16; u_int64_t lba = 0; u_int32_t sector_count; uint8_t operation; @@ -324,11 +326,15 @@ vioblk_scsi_cmd(struct scsi_xfer *xs) switch (xs->cmd->opcode) { case READ_BIG: case READ_COMMAND: + case READ_12: + case READ_16: operation = VIRTIO_BLK_T_IN; isread = 1; break; case WRITE_BIG: case WRITE_COMMAND: + case WRITE_12: + case WRITE_16: operation = VIRTIO_BLK_T_OUT; isread = 0; break; @@ -362,14 +368,26 @@ vioblk_scsi_cmd(struct scsi_xfer *xs) return; } + /* + * READ/WRITE/SYNCHRONIZE commands. SYNCHRONIZE CACHE has same + * layout as 10-byte READ/WRITE commands. + */ if (xs->cmdlen == 6) { rw = (struct scsi_rw *)xs->cmd; lba = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff); sector_count = rw->length ? rw->length : 0x100; - } else { + } else if (xs->cmdlen == 10) { rwb = (struct scsi_rw_big *)xs->cmd; lba = _4btol(rwb->addr); sector_count = _2btol(rwb->length); + } else if (xs->cmdlen == 12) { + rw12 = (struct scsi_rw_12 *)xs->cmd; + lba = _4btol(rw12->addr); + sector_count = _4btol(rw12->length); + } else if (xs->cmdlen == 16) { + rw16 = (struct scsi_rw_16 *)xs->cmd; + lba = _8btol(rw16->addr); + sector_count = _4btol(rw16->length); } { |