summaryrefslogtreecommitdiffstats
path: root/sys/cam/ctl/ctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cam/ctl/ctl.c')
-rw-r--r--sys/cam/ctl/ctl.c47
1 files changed, 34 insertions, 13 deletions
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c
index 6e0ff8e3..de8eeb2 100644
--- a/sys/cam/ctl/ctl.c
+++ b/sys/cam/ctl/ctl.c
@@ -5612,20 +5612,43 @@ bailout:
int
ctl_read_buffer(struct ctl_scsiio *ctsio)
{
- struct scsi_read_buffer *cdb;
struct ctl_lun *lun;
- int buffer_offset, len;
+ uint64_t buffer_offset;
+ uint32_t len;
+ uint8_t byte2;
static uint8_t descr[4];
static uint8_t echo_descr[4] = { 0 };
CTL_DEBUG_PRINT(("ctl_read_buffer\n"));
-
lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
- cdb = (struct scsi_read_buffer *)ctsio->cdb;
+ switch (ctsio->cdb[0]) {
+ case READ_BUFFER: {
+ struct scsi_read_buffer *cdb;
- if ((cdb->byte2 & RWB_MODE) != RWB_MODE_DATA &&
- (cdb->byte2 & RWB_MODE) != RWB_MODE_ECHO_DESCR &&
- (cdb->byte2 & RWB_MODE) != RWB_MODE_DESCR) {
+ cdb = (struct scsi_read_buffer *)ctsio->cdb;
+ buffer_offset = scsi_3btoul(cdb->offset);
+ len = scsi_3btoul(cdb->length);
+ byte2 = cdb->byte2;
+ break;
+ }
+ case READ_BUFFER_16: {
+ struct scsi_read_buffer_16 *cdb;
+
+ cdb = (struct scsi_read_buffer_16 *)ctsio->cdb;
+ buffer_offset = scsi_8btou64(cdb->offset);
+ len = scsi_4btoul(cdb->length);
+ byte2 = cdb->byte2;
+ break;
+ }
+ default: /* This shouldn't happen. */
+ ctl_set_invalid_opcode(ctsio);
+ ctl_done((union ctl_io *)ctsio);
+ return (CTL_RETVAL_COMPLETE);
+ }
+
+ if ((byte2 & RWB_MODE) != RWB_MODE_DATA &&
+ (byte2 & RWB_MODE) != RWB_MODE_ECHO_DESCR &&
+ (byte2 & RWB_MODE) != RWB_MODE_DESCR) {
ctl_set_invalid_field(ctsio,
/*sks_valid*/ 1,
/*command*/ 1,
@@ -5636,10 +5659,8 @@ ctl_read_buffer(struct ctl_scsiio *ctsio)
return (CTL_RETVAL_COMPLETE);
}
- len = scsi_3btoul(cdb->length);
- buffer_offset = scsi_3btoul(cdb->offset);
-
- if (buffer_offset + len > CTL_WRITE_BUFFER_SIZE) {
+ if (buffer_offset > CTL_WRITE_BUFFER_SIZE ||
+ buffer_offset + len > CTL_WRITE_BUFFER_SIZE) {
ctl_set_invalid_field(ctsio,
/*sks_valid*/ 1,
/*command*/ 1,
@@ -5650,12 +5671,12 @@ ctl_read_buffer(struct ctl_scsiio *ctsio)
return (CTL_RETVAL_COMPLETE);
}
- if ((cdb->byte2 & RWB_MODE) == RWB_MODE_DESCR) {
+ if ((byte2 & RWB_MODE) == RWB_MODE_DESCR) {
descr[0] = 0;
scsi_ulto3b(CTL_WRITE_BUFFER_SIZE, &descr[1]);
ctsio->kern_data_ptr = descr;
len = min(len, sizeof(descr));
- } else if ((cdb->byte2 & RWB_MODE) == RWB_MODE_ECHO_DESCR) {
+ } else if ((byte2 & RWB_MODE) == RWB_MODE_ECHO_DESCR) {
ctsio->kern_data_ptr = echo_descr;
len = min(len, sizeof(echo_descr));
} else {
OpenPOWER on IntegriCloud