summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorKenneth R Westerback <krw@cvs.openbsd.org>2013-05-12 19:33:02 +0000
committerKenneth R Westerback <krw@cvs.openbsd.org>2013-05-12 19:33:02 +0000
commitfd46a7c12944886430fb10ddf806e223aa230bc9 (patch)
treeb05cc52f79728b8338a9799a5e09582326928de5 /sys
parent3e93135628fb4a111c002c250e8aac3bb3cef8fe (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@
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/sparc64/dev/vdsk.c22
-rw-r--r--sys/dev/pci/vioblk.c22
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);
}
{