summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2014-06-26 08:56:36 +0000
committermav <mav@FreeBSD.org>2014-06-26 08:56:36 +0000
commit36b6236db2d8d8fbfada389c6f96e0ca25654fdb (patch)
tree627c8100765a2bb6ef41e9323355766355785fad
parentaedbcf436f4de9b9ce6c1f3c8c59c7f227272461 (diff)
downloadFreeBSD-src-36b6236db2d8d8fbfada389c6f96e0ca25654fdb.zip
FreeBSD-src-36b6236db2d8d8fbfada389c6f96e0ca25654fdb.tar.gz
Add READ BUFFER and improve WRITE BUFFER SCSI commands support.
This gives some use to 512KB per-LUN buffers, allocated for Copan-specific processor code and not used. It allows, for example, to test transport performance and/or correctness without accessing the media, as supported by Linux version of sg3_utils. MFC after: 2 weeks
-rw-r--r--sys/cam/ctl/ctl.c124
-rw-r--r--sys/cam/ctl/ctl_cmd_table.c9
-rw-r--r--sys/cam/ctl/ctl_frontend_iscsi.c1
-rw-r--r--sys/cam/ctl/ctl_private.h1
4 files changed, 113 insertions, 22 deletions
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c
index e5c9e53..7438e79 100644
--- a/sys/cam/ctl/ctl.c
+++ b/sys/cam/ctl/ctl.c
@@ -4854,7 +4854,8 @@ ctl_config_move_done(union ctl_io *io)
/*sks_valid*/ 1,
/*retry_count*/
io->io_hdr.port_status);
- free(io->scsiio.kern_data_ptr, M_CTL);
+ if (io->io_hdr.flags & CTL_FLAG_ALLOCATED)
+ free(io->scsiio.kern_data_ptr, M_CTL);
ctl_done(io);
goto bailout;
}
@@ -4867,7 +4868,8 @@ ctl_config_move_done(union ctl_io *io)
* S/G list. If we start using S/G lists for config data,
* we'll need to know how to clean them up here as well.
*/
- free(io->scsiio.kern_data_ptr, M_CTL);
+ if (io->io_hdr.flags & CTL_FLAG_ALLOCATED)
+ free(io->scsiio.kern_data_ptr, M_CTL);
/* Hopefully the user has already set the status... */
ctl_done(io);
} else {
@@ -5612,26 +5614,40 @@ bailout:
}
int
-ctl_write_buffer(struct ctl_scsiio *ctsio)
+ctl_read_buffer(struct ctl_scsiio *ctsio)
{
- struct scsi_write_buffer *cdb;
- struct copan_page_header *header;
+ struct scsi_read_buffer *cdb;
struct ctl_lun *lun;
- struct ctl_softc *ctl_softc;
int buffer_offset, len;
- int retval;
+ static uint8_t descr[4];
+ static uint8_t echo_descr[4] = { 0 };
- header = NULL;
+ CTL_DEBUG_PRINT(("ctl_read_buffer\n"));
- retval = CTL_RETVAL_COMPLETE;
+ lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
+ cdb = (struct scsi_read_buffer *)ctsio->cdb;
- CTL_DEBUG_PRINT(("ctl_write_buffer\n"));
+ if (lun->flags & CTL_LUN_PR_RESERVED) {
+ uint32_t residx;
- lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
- ctl_softc = control_softc;
- cdb = (struct scsi_write_buffer *)ctsio->cdb;
+ /*
+ * XXX KDM need a lock here.
+ */
+ residx = ctl_get_resindex(&ctsio->io_hdr.nexus);
+ if ((lun->res_type == SPR_TYPE_EX_AC
+ && residx != lun->pr_res_idx)
+ || ((lun->res_type == SPR_TYPE_EX_AC_RO
+ || lun->res_type == SPR_TYPE_EX_AC_AR)
+ && !lun->per_res[residx].registered)) {
+ ctl_set_reservation_conflict(ctsio);
+ ctl_done((union ctl_io *)ctsio);
+ return (CTL_RETVAL_COMPLETE);
+ }
+ }
- if ((cdb->byte2 & RWB_MODE) != RWB_MODE_DATA) {
+ if ((cdb->byte2 & RWB_MODE) != RWB_MODE_DATA &&
+ (cdb->byte2 & RWB_MODE) != RWB_MODE_ECHO_DESCR &&
+ (cdb->byte2 & RWB_MODE) != RWB_MODE_DESCR) {
ctl_set_invalid_field(ctsio,
/*sks_valid*/ 1,
/*command*/ 1,
@@ -5655,7 +5671,7 @@ ctl_write_buffer(struct ctl_scsiio *ctsio)
len = scsi_3btoul(cdb->length);
buffer_offset = scsi_3btoul(cdb->offset);
- if (len > sizeof(lun->write_buffer)) {
+ if (buffer_offset + len > sizeof(lun->write_buffer)) {
ctl_set_invalid_field(ctsio,
/*sks_valid*/ 1,
/*command*/ 1,
@@ -5666,11 +5682,68 @@ ctl_write_buffer(struct ctl_scsiio *ctsio)
return (CTL_RETVAL_COMPLETE);
}
- if (buffer_offset != 0) {
+ if ((cdb->byte2 & RWB_MODE) == RWB_MODE_DESCR) {
+ descr[0] = 0;
+ scsi_ulto3b(sizeof(lun->write_buffer), &descr[1]);
+ ctsio->kern_data_ptr = descr;
+ len = min(len, sizeof(descr));
+ } else if ((cdb->byte2 & RWB_MODE) == RWB_MODE_ECHO_DESCR) {
+ ctsio->kern_data_ptr = echo_descr;
+ len = min(len, sizeof(echo_descr));
+ } else
+ ctsio->kern_data_ptr = lun->write_buffer + buffer_offset;
+ ctsio->kern_data_len = len;
+ ctsio->kern_total_len = len;
+ ctsio->kern_data_resid = 0;
+ ctsio->kern_rel_offset = 0;
+ ctsio->kern_sg_entries = 0;
+ ctsio->be_move_done = ctl_config_move_done;
+ ctl_datamove((union ctl_io *)ctsio);
+
+ return (CTL_RETVAL_COMPLETE);
+}
+
+int
+ctl_write_buffer(struct ctl_scsiio *ctsio)
+{
+ struct scsi_write_buffer *cdb;
+ struct ctl_lun *lun;
+ int buffer_offset, len;
+
+ CTL_DEBUG_PRINT(("ctl_write_buffer\n"));
+
+ lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
+ cdb = (struct scsi_write_buffer *)ctsio->cdb;
+
+ if ((cdb->byte2 & RWB_MODE) != RWB_MODE_DATA) {
+ ctl_set_invalid_field(ctsio,
+ /*sks_valid*/ 1,
+ /*command*/ 1,
+ /*field*/ 1,
+ /*bit_valid*/ 1,
+ /*bit*/ 4);
+ ctl_done((union ctl_io *)ctsio);
+ return (CTL_RETVAL_COMPLETE);
+ }
+ if (cdb->buffer_id != 0) {
+ ctl_set_invalid_field(ctsio,
+ /*sks_valid*/ 1,
+ /*command*/ 1,
+ /*field*/ 2,
+ /*bit_valid*/ 0,
+ /*bit*/ 0);
+ ctl_done((union ctl_io *)ctsio);
+ return (CTL_RETVAL_COMPLETE);
+ }
+
+ len = scsi_3btoul(cdb->length);
+ buffer_offset = scsi_3btoul(cdb->offset);
+
+ if (buffer_offset + len > sizeof(lun->write_buffer)) {
ctl_set_invalid_field(ctsio,
/*sks_valid*/ 1,
/*command*/ 1,
- /*field*/ 3,
+ /*field*/ 6,
/*bit_valid*/ 0,
/*bit*/ 0);
ctl_done((union ctl_io *)ctsio);
@@ -5682,7 +5755,7 @@ ctl_write_buffer(struct ctl_scsiio *ctsio)
* malloc it and tell the caller the data buffer is here.
*/
if ((ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) == 0) {
- ctsio->kern_data_ptr = lun->write_buffer;
+ ctsio->kern_data_ptr = lun->write_buffer + buffer_offset;
ctsio->kern_data_len = len;
ctsio->kern_total_len = len;
ctsio->kern_data_resid = 0;
@@ -6893,6 +6966,7 @@ ctl_mode_sense(struct ctl_scsiio *ctsio)
ctsio->scsi_status = SCSI_STATUS_OK;
+ ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@@ -6952,6 +7026,7 @@ ctl_read_capacity(struct ctl_scsiio *ctsio)
ctsio->scsi_status = SCSI_STATUS_OK;
+ ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@@ -7014,6 +7089,7 @@ ctl_read_capacity_16(struct ctl_scsiio *ctsio)
ctsio->scsi_status = SCSI_STATUS_OK;
+ ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@@ -7184,6 +7260,7 @@ ctl_maintenance_in(struct ctl_scsiio *ctsio)
}
}
+ ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
CTL_DEBUG_PRINT(("buf = %x %x %x %x %x %x %x %x\n",
@@ -7409,6 +7486,7 @@ retry:
}
mtx_unlock(&lun->lun_lock);
+ ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
CTL_DEBUG_PRINT(("buf = %x %x %x %x %x %x %x %x\n",
@@ -9120,6 +9198,7 @@ ctl_report_luns(struct ctl_scsiio *ctsio)
*/
ctsio->scsi_status = SCSI_STATUS_OK;
+ ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@@ -9246,7 +9325,7 @@ ctl_request_sense(struct ctl_scsiio *ctsio)
* parameter data.
*/
ctsio->sense_len = 0;
-
+ ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@@ -9275,6 +9354,7 @@ no_sense:
* autosense in this case. We're reporting sense as parameter data.
*/
ctsio->sense_len = 0;
+ ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@@ -9362,6 +9442,7 @@ ctl_inquiry_evpd_supported(struct ctl_scsiio *ctsio, int alloc_len)
ctsio->scsi_status = SCSI_STATUS_OK;
+ ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@@ -9417,6 +9498,7 @@ ctl_inquiry_evpd_serial(struct ctl_scsiio *ctsio, int alloc_len)
}
ctsio->scsi_status = SCSI_STATUS_OK;
+ ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@@ -9602,6 +9684,7 @@ ctl_inquiry_evpd_devid(struct ctl_scsiio *ctsio, int alloc_len)
ctsio->scsi_status = SCSI_STATUS_OK;
+ ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@@ -9658,6 +9741,7 @@ ctl_inquiry_evpd_block_limits(struct ctl_scsiio *ctsio, int alloc_len)
scsi_u64to8b(UINT64_MAX, bl_ptr->max_write_same_length);
ctsio->scsi_status = SCSI_STATUS_OK;
+ ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@@ -9707,6 +9791,7 @@ ctl_inquiry_evpd_lbp(struct ctl_scsiio *ctsio, int alloc_len)
lbp_ptr->flags = SVPD_LBP_UNMAP | SVPD_LBP_WS16 | SVPD_LBP_WS10;
ctsio->scsi_status = SCSI_STATUS_OK;
+ ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@@ -9989,6 +10074,7 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio)
ctsio->scsi_status = SCSI_STATUS_OK;
if (ctsio->kern_data_len > 0) {
+ ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
} else {
diff --git a/sys/cam/ctl/ctl_cmd_table.c b/sys/cam/ctl/ctl_cmd_table.c
index 7f3c999..7729b7e 100644
--- a/sys/cam/ctl/ctl_cmd_table.c
+++ b/sys/cam/ctl/ctl_cmd_table.c
@@ -314,12 +314,15 @@ struct ctl_cmd_entry ctl_cmd_table[] =
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 3B WRITE BUFFER */
-{ctl_write_buffer, CTL_SERIDX_WRITE, CTL_CMD_FLAG_OK_ON_PROC |
- CTL_FLAG_DATA_OUT,
+{ctl_write_buffer, CTL_SERIDX_MD_SEL, CTL_CMD_FLAG_OK_ON_BOTH |
+ CTL_FLAG_DATA_OUT,
CTL_LUN_PAT_NONE},
/* 3C READ BUFFER */
-{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+{ctl_read_buffer, CTL_SERIDX_MD_SNS, CTL_CMD_FLAG_OK_ON_BOTH |
+ CTL_FLAG_DATA_IN |
+ CTL_CMD_FLAG_ALLOW_ON_PR_RESV,
+ CTL_LUN_PAT_NONE},
/* 3D UPDATE BLOCK */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
diff --git a/sys/cam/ctl/ctl_frontend_iscsi.c b/sys/cam/ctl/ctl_frontend_iscsi.c
index 72f4765..f41bc74 100644
--- a/sys/cam/ctl/ctl_frontend_iscsi.c
+++ b/sys/cam/ctl/ctl_frontend_iscsi.c
@@ -2239,6 +2239,7 @@ cfiscsi_devid(struct ctl_scsiio *ctsio, int alloc_len)
ctsio->scsi_status = SCSI_STATUS_OK;
+ ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
diff --git a/sys/cam/ctl/ctl_private.h b/sys/cam/ctl/ctl_private.h
index d217089..24416ea 100644
--- a/sys/cam/ctl/ctl_private.h
+++ b/sys/cam/ctl/ctl_private.h
@@ -476,6 +476,7 @@ int ctl_scsi_reserve(struct ctl_scsiio *ctsio);
int ctl_start_stop(struct ctl_scsiio *ctsio);
int ctl_sync_cache(struct ctl_scsiio *ctsio);
int ctl_format(struct ctl_scsiio *ctsio);
+int ctl_read_buffer(struct ctl_scsiio *ctsio);
int ctl_write_buffer(struct ctl_scsiio *ctsio);
int ctl_write_same(struct ctl_scsiio *ctsio);
int ctl_unmap(struct ctl_scsiio *ctsio);
OpenPOWER on IntegriCloud