svn commit: r268674 - in stable/10/sys/cam: ctl scsi

Alexander Motin mav at FreeBSD.org
Tue Jul 15 16:53:05 UTC 2014


Author: mav
Date: Tue Jul 15 16:53:04 2014
New Revision: 268674
URL: http://svnweb.freebsd.org/changeset/base/268674

Log:
  MFC r268096, r268306, r268361:
  Add more formal and strict command parsing and validation.
  
  For every supported command define CDB length and mask of bits that are
  allowed to be set.  This allows to remove bunch of checks through the code
  and still make the validation more strict.  To properly do it for commands
  supporting multiple service actions, formalize their parsing by adding
  subtables for each of such commands.
  
  As visible effect, this change allows to add support for REPORT SUPPORTED
  OPERATION CODES command, reporting to client all the data about supported
  SCSI commands, except timeouts.

Modified:
  stable/10/sys/cam/ctl/ctl.c
  stable/10/sys/cam/ctl/ctl_cmd_table.c
  stable/10/sys/cam/ctl/ctl_private.h
  stable/10/sys/cam/scsi/scsi_all.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/cam/ctl/ctl.c
==============================================================================
--- stable/10/sys/cam/ctl/ctl.c	Tue Jul 15 16:49:35 2014	(r268673)
+++ stable/10/sys/cam/ctl/ctl.c	Tue Jul 15 16:53:04 2014	(r268674)
@@ -392,7 +392,7 @@ static ctl_action ctl_check_ooa(struct c
 static int ctl_check_blocked(struct ctl_lun *lun);
 static int ctl_scsiio_lun_check(struct ctl_softc *ctl_softc,
 				struct ctl_lun *lun,
-				struct ctl_cmd_entry *entry,
+				const struct ctl_cmd_entry *entry,
 				struct ctl_scsiio *ctsio);
 //static int ctl_check_rtr(union ctl_io *pending_io, struct ctl_softc *softc);
 static void ctl_failover(void);
@@ -430,6 +430,12 @@ static void ctl_enqueue_incoming(union c
 static void ctl_enqueue_rtr(union ctl_io *io);
 static void ctl_enqueue_done(union ctl_io *io);
 static void ctl_enqueue_isc(union ctl_io *io);
+static const struct ctl_cmd_entry *
+    ctl_get_cmd_entry(struct ctl_scsiio *ctsio);
+static const struct ctl_cmd_entry *
+    ctl_validate_command(struct ctl_scsiio *ctsio);
+static int ctl_cmd_applicable(uint8_t lun_type,
+    const struct ctl_cmd_entry *entry);
 
 /*
  * Load the serialization table.  This isn't very pretty, but is probably
@@ -622,11 +628,9 @@ ctl_isc_event_handler(ctl_ha_channel cha
 			memcpy(io->scsiio.cdb, msg_info.scsi.cdb,
 			       CTL_MAX_CDBLEN);
 			if (ctl_softc->ha_mode == CTL_HA_MODE_XFER) {
-				struct ctl_cmd_entry *entry;
-				uint8_t opcode;
+				const struct ctl_cmd_entry *entry;
 
-				opcode = io->scsiio.cdb[0];
-				entry = &ctl_cmd_table[opcode];
+				entry = ctl_get_cmd_entry(&io->scsiio);
 				io->io_hdr.flags &= ~CTL_FLAG_DATA_MASK;
 				io->io_hdr.flags |=
 					entry->flags & CTL_FLAG_DATA_MASK;
@@ -4973,50 +4977,11 @@ ctl_scsi_release(struct ctl_scsiio *ctsi
 	ctl_softc = control_softc;
 
 	switch (ctsio->cdb[0]) {
-	case RELEASE: {
-		struct scsi_release *cdb;
-
-		cdb = (struct scsi_release *)ctsio->cdb;
-		if ((cdb->byte2 & 0x1f) != 0) {
-			ctl_set_invalid_field(ctsio,
-					      /*sks_valid*/ 1,
-					      /*command*/ 1,
-					      /*field*/ 1,
-					      /*bit_valid*/ 0,
-					      /*bit*/ 0);
-			ctl_done((union ctl_io *)ctsio);
-			return (CTL_RETVAL_COMPLETE);
-		}
-		break;
-	}
 	case RELEASE_10: {
 		struct scsi_release_10 *cdb;
 
 		cdb = (struct scsi_release_10 *)ctsio->cdb;
 
-		if ((cdb->byte2 & SR10_EXTENT) != 0) {
-			ctl_set_invalid_field(ctsio,
-					      /*sks_valid*/ 1,
-					      /*command*/ 1,
-					      /*field*/ 1,
-					      /*bit_valid*/ 1,
-					      /*bit*/ 0);
-			ctl_done((union ctl_io *)ctsio);
-			return (CTL_RETVAL_COMPLETE);
-
-		}
-
-		if ((cdb->byte2 & SR10_3RDPTY) != 0) {
-			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->byte2 & SR10_LONGID)
 			longid = 1;
 		else
@@ -5110,49 +5075,11 @@ ctl_scsi_reserve(struct ctl_scsiio *ctsi
 	ctl_softc = control_softc;
 
 	switch (ctsio->cdb[0]) {
-	case RESERVE: {
-		struct scsi_reserve *cdb;
-
-		cdb = (struct scsi_reserve *)ctsio->cdb;
-		if ((cdb->byte2 & 0x1f) != 0) {
-			ctl_set_invalid_field(ctsio,
-					      /*sks_valid*/ 1,
-					      /*command*/ 1,
-					      /*field*/ 1,
-					      /*bit_valid*/ 0,
-					      /*bit*/ 0);
-			ctl_done((union ctl_io *)ctsio);
-			return (CTL_RETVAL_COMPLETE);
-		}
-		resv_id = cdb->resv_id;
-		length = scsi_2btoul(cdb->length);
-		break;
-	}
 	case RESERVE_10: {
 		struct scsi_reserve_10 *cdb;
 
 		cdb = (struct scsi_reserve_10 *)ctsio->cdb;
 
-		if ((cdb->byte2 & SR10_EXTENT) != 0) {
-			ctl_set_invalid_field(ctsio,
-					      /*sks_valid*/ 1,
-					      /*command*/ 1,
-					      /*field*/ 1,
-					      /*bit_valid*/ 1,
-					      /*bit*/ 0);
-			ctl_done((union ctl_io *)ctsio);
-			return (CTL_RETVAL_COMPLETE);
-		}
-		if ((cdb->byte2 & SR10_3RDPTY) != 0) {
-			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->byte2 & SR10_LONGID)
 			longid = 1;
 		else
@@ -5265,35 +5192,6 @@ ctl_start_stop(struct ctl_scsiio *ctsio)
 		return (CTL_RETVAL_COMPLETE);
 	}
 
-	/*
-	 * We don't support the power conditions field.  We need to check
-	 * this prior to checking the load/eject and start/stop bits.
-	 */
-	if ((cdb->how & SSS_PC_MASK) != SSS_PC_START_VALID) {
-		ctl_set_invalid_field(ctsio,
-				      /*sks_valid*/ 1,
-				      /*command*/ 1,
-				      /*field*/ 4,
-				      /*bit_valid*/ 1,
-				      /*bit*/ 4);
-		ctl_done((union ctl_io *)ctsio);
-		return (CTL_RETVAL_COMPLETE);
-	}
-
-	/*
-	 * Media isn't removable, so we can't load or eject it.
-	 */
-	if ((cdb->how & SSS_LOEJ) != 0) {
-		ctl_set_invalid_field(ctsio,
-				      /*sks_valid*/ 1,
-				      /*command*/ 1,
-				      /*field*/ 4,
-				      /*bit_valid*/ 1,
-				      /*bit*/ 1);
-		ctl_done((union ctl_io *)ctsio);
-		return (CTL_RETVAL_COMPLETE);
-	}
-
 	if ((lun->flags & CTL_LUN_PR_RESERVED)
 	 && ((cdb->how & SSS_START)==0)) {
 		uint32_t residx;
@@ -5391,7 +5289,6 @@ ctl_sync_cache(struct ctl_scsiio *ctsio)
 	struct ctl_softc *ctl_softc;
 	uint64_t starting_lba;
 	uint32_t block_count;
-	int reladr, immed;
 	int retval;
 
 	CTL_DEBUG_PRINT(("ctl_sync_cache\n"));
@@ -5399,20 +5296,12 @@ ctl_sync_cache(struct ctl_scsiio *ctsio)
 	lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
 	ctl_softc = control_softc;
 	retval = 0;
-	reladr = 0;
-	immed = 0;
 
 	switch (ctsio->cdb[0]) {
 	case SYNCHRONIZE_CACHE: {
 		struct scsi_sync_cache *cdb;
 		cdb = (struct scsi_sync_cache *)ctsio->cdb;
 
-		if (cdb->byte2 & SSC_RELADR)
-			reladr = 1;
-
-		if (cdb->byte2 & SSC_IMMED)
-			immed = 1;
-
 		starting_lba = scsi_4btoul(cdb->begin_lba);
 		block_count = scsi_2btoul(cdb->lb_count);
 		break;
@@ -5421,12 +5310,6 @@ ctl_sync_cache(struct ctl_scsiio *ctsio)
 		struct scsi_sync_cache_16 *cdb;
 		cdb = (struct scsi_sync_cache_16 *)ctsio->cdb;
 
-		if (cdb->byte2 & SSC_RELADR)
-			reladr = 1;
-
-		if (cdb->byte2 & SSC_IMMED)
-			immed = 1;
-
 		starting_lba = scsi_8btou64(cdb->begin_lba);
 		block_count = scsi_4btoul(cdb->lb_count);
 		break;
@@ -5438,41 +5321,6 @@ ctl_sync_cache(struct ctl_scsiio *ctsio)
 		break; /* NOTREACHED */
 	}
 
-	if (immed) {
-		/*
-		 * We don't support the immediate bit.  Since it's in the
-		 * same place for the 10 and 16 byte SYNCHRONIZE CACHE
-		 * commands, we can just return the same error in either
-		 * case.
-		 */
-		ctl_set_invalid_field(ctsio,
-				      /*sks_valid*/ 1,
-				      /*command*/ 1,
-				      /*field*/ 1,
-				      /*bit_valid*/ 1,
-				      /*bit*/ 1);
-		ctl_done((union ctl_io *)ctsio);
-		goto bailout;
-	}
-
-	if (reladr) {
-		/*
-		 * We don't support the reladr bit either.  It can only be
-		 * used with linked commands, and we don't support linked
-		 * commands.  Since the bit is in the same place for the
-		 * 10 and 16 byte SYNCHRONIZE CACHE * commands, we can
-		 * just return the same error in either case.
-		 */
-		ctl_set_invalid_field(ctsio,
-				      /*sks_valid*/ 1,
-				      /*command*/ 1,
-				      /*field*/ 1,
-				      /*bit_valid*/ 1,
-				      /*bit*/ 0);
-		ctl_done((union ctl_io *)ctsio);
-		goto bailout;
-	}
-
 	/*
 	 * We check the LBA and length, but don't do anything with them.
 	 * A SYNCHRONIZE CACHE will cause the entire cache for this lun to
@@ -5659,16 +5507,6 @@ ctl_read_buffer(struct ctl_scsiio *ctsio
 		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);
@@ -5727,16 +5565,6 @@ ctl_write_buffer(struct ctl_scsiio *ctsi
 		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);
@@ -7053,7 +6881,7 @@ ctl_read_capacity(struct ctl_scsiio *cts
 	return (CTL_RETVAL_COMPLETE);
 }
 
-static int
+int
 ctl_read_capacity_16(struct ctl_scsiio *ctsio)
 {
 	struct scsi_read_capacity_16 *cdb;
@@ -7117,37 +6945,7 @@ ctl_read_capacity_16(struct ctl_scsiio *
 }
 
 int
-ctl_service_action_in(struct ctl_scsiio *ctsio)
-{
-	struct scsi_service_action_in *cdb;
-	int retval;
-
-	CTL_DEBUG_PRINT(("ctl_service_action_in\n"));
-
-	cdb = (struct scsi_service_action_in *)ctsio->cdb;
-
-	retval = CTL_RETVAL_COMPLETE;
-
-	switch (cdb->service_action) {
-	case SRC16_SERVICE_ACTION:
-		retval = ctl_read_capacity_16(ctsio);
-		break;
-	default:
-		ctl_set_invalid_field(/*ctsio*/ ctsio,
-				      /*sks_valid*/ 1,
-				      /*command*/ 1,
-				      /*field*/ 1,
-				      /*bit_valid*/ 1,
-				      /*bit*/ 4);
-		ctl_done((union ctl_io *)ctsio);
-		break;
-	}
-
-	return (retval);
-}
-
-int
-ctl_maintenance_in(struct ctl_scsiio *ctsio)
+ctl_report_tagret_port_groups(struct ctl_scsiio *ctsio)
 {
 	struct scsi_maintenance_in *cdb;
 	int retval;
@@ -7160,7 +6958,7 @@ ctl_maintenance_in(struct ctl_scsiio *ct
 	struct scsi_target_port_descriptor  *tp_desc_ptr1_1, *tp_desc_ptr1_2,
 	                                    *tp_desc_ptr2_1, *tp_desc_ptr2_2;
 
-	CTL_DEBUG_PRINT(("ctl_maintenance_in\n"));
+	CTL_DEBUG_PRINT(("ctl_report_tagret_port_groups\n"));
 
 	cdb = (struct scsi_maintenance_in *)ctsio->cdb;
 	softc = control_softc;
@@ -7168,17 +6966,6 @@ ctl_maintenance_in(struct ctl_scsiio *ct
 
 	retval = CTL_RETVAL_COMPLETE;
 
-	if ((cdb->byte2 & SERVICE_ACTION_MASK) != SA_RPRT_TRGT_GRP) {
-		ctl_set_invalid_field(/*ctsio*/ ctsio,
-				      /*sks_valid*/ 1,
-				      /*command*/ 1,
-				      /*field*/ 1,
-				      /*bit_valid*/ 1,
-				      /*bit*/ 4);
-		ctl_done((union ctl_io *)ctsio);
-		return(retval);
-	}
-
 	single = ctl_is_single;
 	if (single)
         	num_target_port_groups = NUM_TARGET_PORT_GROUPS - 1;
@@ -7294,6 +7081,217 @@ ctl_maintenance_in(struct ctl_scsiio *ct
 }
 
 int
+ctl_report_supported_opcodes(struct ctl_scsiio *ctsio)
+{
+	struct ctl_lun *lun;
+	struct scsi_report_supported_opcodes *cdb;
+	const struct ctl_cmd_entry *entry, *sentry;
+	struct scsi_report_supported_opcodes_all *all;
+	struct scsi_report_supported_opcodes_descr *descr;
+	struct scsi_report_supported_opcodes_one *one;
+	int retval;
+	int alloc_len, total_len;
+	int opcode, service_action, i, j, num;
+
+	CTL_DEBUG_PRINT(("ctl_report_supported_opcodes\n"));
+
+	cdb = (struct scsi_report_supported_opcodes *)ctsio->cdb;
+	lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
+
+	retval = CTL_RETVAL_COMPLETE;
+
+	opcode = cdb->requested_opcode;
+	service_action = scsi_2btoul(cdb->requested_service_action);
+	switch (cdb->options & RSO_OPTIONS_MASK) {
+	case RSO_OPTIONS_ALL:
+		num = 0;
+		for (i = 0; i < 256; i++) {
+			entry = &ctl_cmd_table[i];
+			if (entry->flags & CTL_CMD_FLAG_SA5) {
+				for (j = 0; j < 32; j++) {
+					sentry = &((const struct ctl_cmd_entry *)
+					    entry->execute)[j];
+					if (ctl_cmd_applicable(
+					    lun->be_lun->lun_type, sentry))
+						num++;
+				}
+			} else {
+				if (ctl_cmd_applicable(lun->be_lun->lun_type,
+				    entry))
+					num++;
+			}
+		}
+		total_len = sizeof(struct scsi_report_supported_opcodes_all) +
+		    num * sizeof(struct scsi_report_supported_opcodes_descr);
+		break;
+	case RSO_OPTIONS_OC:
+		if (ctl_cmd_table[opcode].flags & CTL_CMD_FLAG_SA5) {
+			ctl_set_invalid_field(/*ctsio*/ ctsio,
+					      /*sks_valid*/ 1,
+					      /*command*/ 1,
+					      /*field*/ 2,
+					      /*bit_valid*/ 1,
+					      /*bit*/ 2);
+			ctl_done((union ctl_io *)ctsio);
+			return (CTL_RETVAL_COMPLETE);
+		}
+		total_len = sizeof(struct scsi_report_supported_opcodes_one) + 32;
+		break;
+	case RSO_OPTIONS_OC_SA:
+		if ((ctl_cmd_table[opcode].flags & CTL_CMD_FLAG_SA5) == 0 ||
+		    service_action >= 32) {
+			ctl_set_invalid_field(/*ctsio*/ ctsio,
+					      /*sks_valid*/ 1,
+					      /*command*/ 1,
+					      /*field*/ 2,
+					      /*bit_valid*/ 1,
+					      /*bit*/ 2);
+			ctl_done((union ctl_io *)ctsio);
+			return (CTL_RETVAL_COMPLETE);
+		}
+		total_len = sizeof(struct scsi_report_supported_opcodes_one) + 32;
+		break;
+	default:
+		ctl_set_invalid_field(/*ctsio*/ ctsio,
+				      /*sks_valid*/ 1,
+				      /*command*/ 1,
+				      /*field*/ 2,
+				      /*bit_valid*/ 1,
+				      /*bit*/ 2);
+		ctl_done((union ctl_io *)ctsio);
+		return (CTL_RETVAL_COMPLETE);
+	}
+
+	alloc_len = scsi_4btoul(cdb->length);
+
+	ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO);
+
+	ctsio->kern_sg_entries = 0;
+
+	if (total_len < alloc_len) {
+		ctsio->residual = alloc_len - total_len;
+		ctsio->kern_data_len = total_len;
+		ctsio->kern_total_len = total_len;
+	} else {
+		ctsio->residual = 0;
+		ctsio->kern_data_len = alloc_len;
+		ctsio->kern_total_len = alloc_len;
+	}
+	ctsio->kern_data_resid = 0;
+	ctsio->kern_rel_offset = 0;
+
+	switch (cdb->options & RSO_OPTIONS_MASK) {
+	case RSO_OPTIONS_ALL:
+		all = (struct scsi_report_supported_opcodes_all *)
+		    ctsio->kern_data_ptr;
+		num = 0;
+		for (i = 0; i < 256; i++) {
+			entry = &ctl_cmd_table[i];
+			if (entry->flags & CTL_CMD_FLAG_SA5) {
+				for (j = 0; j < 32; j++) {
+					sentry = &((const struct ctl_cmd_entry *)
+					    entry->execute)[j];
+					if (!ctl_cmd_applicable(
+					    lun->be_lun->lun_type, sentry))
+						continue;
+					descr = &all->descr[num++];
+					descr->opcode = i;
+					scsi_ulto2b(j, descr->service_action);
+					descr->flags = RSO_SERVACTV;
+					scsi_ulto2b(sentry->length,
+					    descr->cdb_length);
+				}
+			} else {
+				if (!ctl_cmd_applicable(lun->be_lun->lun_type,
+				    entry))
+					continue;
+				descr = &all->descr[num++];
+				descr->opcode = i;
+				scsi_ulto2b(0, descr->service_action);
+				descr->flags = 0;
+				scsi_ulto2b(entry->length, descr->cdb_length);
+			}
+		}
+		scsi_ulto4b(
+		    num * sizeof(struct scsi_report_supported_opcodes_descr),
+		    all->length);
+		break;
+	case RSO_OPTIONS_OC:
+		one = (struct scsi_report_supported_opcodes_one *)
+		    ctsio->kern_data_ptr;
+		entry = &ctl_cmd_table[opcode];
+		goto fill_one;
+	case RSO_OPTIONS_OC_SA:
+		one = (struct scsi_report_supported_opcodes_one *)
+		    ctsio->kern_data_ptr;
+		entry = &ctl_cmd_table[opcode];
+		entry = &((const struct ctl_cmd_entry *)
+		    entry->execute)[service_action];
+fill_one:
+		if (ctl_cmd_applicable(lun->be_lun->lun_type, entry)) {
+			one->support = 3;
+			scsi_ulto2b(entry->length, one->cdb_length);
+			one->cdb_usage[0] = opcode;
+			memcpy(&one->cdb_usage[1], entry->usage,
+			    entry->length - 1);
+		} else
+			one->support = 1;
+		break;
+	}
+
+	ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
+	ctsio->be_move_done = ctl_config_move_done;
+
+	ctl_datamove((union ctl_io *)ctsio);
+	return(retval);
+}
+
+int
+ctl_report_supported_tmf(struct ctl_scsiio *ctsio)
+{
+	struct ctl_lun *lun;
+	struct scsi_report_supported_tmf *cdb;
+	struct scsi_report_supported_tmf_data *data;
+	int retval;
+	int alloc_len, total_len;
+
+	CTL_DEBUG_PRINT(("ctl_report_supported_tmf\n"));
+
+	cdb = (struct scsi_report_supported_tmf *)ctsio->cdb;
+	lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
+
+	retval = CTL_RETVAL_COMPLETE;
+
+	total_len = sizeof(struct scsi_report_supported_tmf_data);
+	alloc_len = scsi_4btoul(cdb->length);
+
+	ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO);
+
+	ctsio->kern_sg_entries = 0;
+
+	if (total_len < alloc_len) {
+		ctsio->residual = alloc_len - total_len;
+		ctsio->kern_data_len = total_len;
+		ctsio->kern_total_len = total_len;
+	} else {
+		ctsio->residual = 0;
+		ctsio->kern_data_len = alloc_len;
+		ctsio->kern_total_len = alloc_len;
+	}
+	ctsio->kern_data_resid = 0;
+	ctsio->kern_rel_offset = 0;
+
+	data = (struct scsi_report_supported_tmf_data *)ctsio->kern_data_ptr;
+	data->byte1 |= RST_ATS | RST_LURS | RST_TRS;
+
+	ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
+	ctsio->be_move_done = ctl_config_move_done;
+
+	ctl_datamove((union ctl_io *)ctsio);
+	return (retval);
+}
+
+int
 ctl_persistent_reserve_in(struct ctl_scsiio *ctsio)
 {
 	struct scsi_per_res_in *cdb;
@@ -7329,18 +7327,8 @@ retry:
 	case SPRI_RC: /* report capabilities */
 		total_len = sizeof(struct scsi_per_res_cap);
 		break;
-	case SPRI_RS: /* read full status */
 	default:
-		mtx_unlock(&lun->lun_lock);
-		ctl_set_invalid_field(ctsio,
-				      /*sks_valid*/ 1,
-				      /*command*/ 1,
-				      /*field*/ 1,
-				      /*bit_valid*/ 1,
-				      /*bit*/ 0);
-		ctl_done((union ctl_io *)ctsio);
-		return (CTL_RETVAL_COMPLETE);
-		break; /* NOTREACHED */
+		panic("Invalid PR type %x", cdb->action);
 	}
 	mtx_unlock(&lun->lun_lock);
 
@@ -8049,28 +8037,6 @@ ctl_persistent_reserve_out(struct ctl_sc
 		}
 	}
 
-	switch (cdb->action & SPRO_ACTION_MASK) {
-	case SPRO_REGISTER:
-	case SPRO_RESERVE:
-	case SPRO_RELEASE:
-	case SPRO_CLEAR:
-	case SPRO_PREEMPT:
-	case SPRO_REG_IGNO:
-		break;
-	case SPRO_REG_MOVE:
-	case SPRO_PRE_ABO:
-	default:
-		ctl_set_invalid_field(/*ctsio*/ ctsio,
-				      /*sks_valid*/ 1,
-				      /*command*/ 1,
-				      /*field*/ 1,
-				      /*bit_valid*/ 1,
-				      /*bit*/ 0);
-		ctl_done((union ctl_io *)ctsio);
-		return (CTL_RETVAL_COMPLETE);
-		break; /* NOTREACHED */
-	}
-
 	param_len = scsi_4btoul(cdb->length);
 
 	if ((ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) == 0) {
@@ -8439,19 +8405,8 @@ ctl_persistent_reserve_out(struct ctl_sc
 			return (CTL_RETVAL_COMPLETE);
 		break;
 	}
-	case SPRO_REG_MOVE:
-	case SPRO_PRE_ABO:
 	default:
-		free(ctsio->kern_data_ptr, M_CTL);
-		ctl_set_invalid_field(/*ctsio*/ ctsio,
-				      /*sks_valid*/ 1,
-				      /*command*/ 1,
-				      /*field*/ 1,
-				      /*bit_valid*/ 1,
-				      /*bit*/ 0);
-		ctl_done((union ctl_io *)ctsio);
-		return (CTL_RETVAL_COMPLETE);
-		break; /* NOTREACHED */
+		panic("Invalid PR type %x", cdb->action);
 	}
 
 done:
@@ -8600,7 +8555,7 @@ ctl_read_write(struct ctl_scsiio *ctsio)
 	struct ctl_lba_len_flags *lbalen;
 	uint64_t lba;
 	uint32_t num_blocks;
-	int reladdr, fua, dpo, ebp;
+	int fua, dpo;
 	int retval;
 	int isread;
 
@@ -8608,10 +8563,8 @@ ctl_read_write(struct ctl_scsiio *ctsio)
 
 	CTL_DEBUG_PRINT(("ctl_read_write: command: %#x\n", ctsio->cdb[0]));
 
-	reladdr = 0;
 	fua = 0;
 	dpo = 0;
-	ebp = 0;
 
 	retval = CTL_RETVAL_COMPLETE;
 
@@ -8659,17 +8612,11 @@ ctl_read_write(struct ctl_scsiio *ctsio)
 
 		cdb = (struct scsi_rw_10 *)ctsio->cdb;
 
-		if (cdb->byte2 & SRW10_RELADDR)
-			reladdr = 1;
 		if (cdb->byte2 & SRW10_FUA)
 			fua = 1;
 		if (cdb->byte2 & SRW10_DPO)
 			dpo = 1;
 
-		if ((cdb->opcode == WRITE_10)
-		 && (cdb->byte2 & SRW10_EBP))
-			ebp = 1;
-
 		lba = scsi_4btoul(cdb->addr);
 		num_blocks = scsi_2btoul(cdb->length);
 		break;
@@ -8699,8 +8646,6 @@ ctl_read_write(struct ctl_scsiio *ctsio)
 
 		cdb = (struct scsi_rw_12 *)ctsio->cdb;
 
-		if (cdb->byte2 & SRW12_RELADDR)
-			reladdr = 1;
 		if (cdb->byte2 & SRW12_FUA)
 			fua = 1;
 		if (cdb->byte2 & SRW12_DPO)
@@ -8728,8 +8673,6 @@ ctl_read_write(struct ctl_scsiio *ctsio)
 
 		cdb = (struct scsi_rw_16 *)ctsio->cdb;
 
-		if (cdb->byte2 & SRW12_RELADDR)
-			reladdr = 1;
 		if (cdb->byte2 & SRW12_FUA)
 			fua = 1;
 		if (cdb->byte2 & SRW12_DPO)
@@ -8769,20 +8712,6 @@ ctl_read_write(struct ctl_scsiio *ctsio)
 	 * getting it to do write-through for a particular transaction may
 	 * not be possible.
 	 */
-	/*
-	 * We don't support relative addressing.  That also requires
-	 * supporting linked commands, which we don't do.
-	 */
-	if (reladdr != 0) {
-		ctl_set_invalid_field(ctsio,
-				      /*sks_valid*/ 1,
-				      /*command*/ 1,
-				      /*field*/ 1,
-				      /*bit_valid*/ 1,
-				      /*bit*/ 0);
-		ctl_done((union ctl_io *)ctsio);
-		return (CTL_RETVAL_COMPLETE);
-	}
 
 	/*
 	 * The first check is to make sure we're in bounds, the second
@@ -10332,7 +10261,7 @@ ctl_extent_check(union ctl_io *io1, unio
 static ctl_action
 ctl_check_for_blockage(union ctl_io *pending_io, union ctl_io *ooa_io)
 {
-	struct ctl_cmd_entry *pending_entry, *ooa_entry;
+	const struct ctl_cmd_entry *pending_entry, *ooa_entry;
 	ctl_serialize_action *serialize_row;
 
 	/*
@@ -10405,8 +10334,8 @@ ctl_check_for_blockage(union ctl_io *pen
 	  || (ooa_io->scsiio.tag_type == CTL_TAG_ORDERED)))
 		return (CTL_ACTION_BLOCK);
 
-	pending_entry = &ctl_cmd_table[pending_io->scsiio.cdb[0]];
-	ooa_entry = &ctl_cmd_table[ooa_io->scsiio.cdb[0]];
+	pending_entry = ctl_get_cmd_entry(&pending_io->scsiio);
+	ooa_entry = ctl_get_cmd_entry(&ooa_io->scsiio);
 
 	serialize_row = ctl_serialize_table[ooa_entry->seridx];
 
@@ -10536,9 +10465,8 @@ ctl_check_blocked(struct ctl_lun *lun)
 		case CTL_ACTION_PASS:
 		case CTL_ACTION_SKIP: {
 			struct ctl_softc *softc;
-			struct ctl_cmd_entry *entry;
+			const struct ctl_cmd_entry *entry;
 			uint32_t initidx;
-			uint8_t opcode;
 			int isc_retval;
 
 			/*
@@ -10575,8 +10503,7 @@ ctl_check_blocked(struct ctl_lun *lun)
 				}
 				break;
 			}
-			opcode = cur_blocked->scsiio.cdb[0];
-			entry = &ctl_cmd_table[opcode];
+			entry = ctl_get_cmd_entry(&cur_blocked->scsiio);
 			softc = control_softc;
 
 			initidx = ctl_get_initindex(&cur_blocked->io_hdr.nexus);
@@ -10624,7 +10551,7 @@ ctl_check_blocked(struct ctl_lun *lun)
  */
 static int
 ctl_scsiio_lun_check(struct ctl_softc *ctl_softc, struct ctl_lun *lun,
-		     struct ctl_cmd_entry *entry, struct ctl_scsiio *ctsio)
+    const struct ctl_cmd_entry *entry, struct ctl_scsiio *ctsio)
 {
 	int retval;
 
@@ -10984,8 +10911,7 @@ static int
 ctl_scsiio_precheck(struct ctl_softc *ctl_softc, struct ctl_scsiio *ctsio)
 {
 	struct ctl_lun *lun;
-	struct ctl_cmd_entry *entry;
-	uint8_t opcode;
+	const struct ctl_cmd_entry *entry;
 	uint32_t initidx, targ_lun;
 	int retval;
 
@@ -10993,8 +10919,6 @@ ctl_scsiio_precheck(struct ctl_softc *ct
 
 	lun = NULL;
 
-	opcode = ctsio->cdb[0];
-
 	targ_lun = ctsio->io_hdr.nexus.targ_mapped_lun;
 	if ((targ_lun < CTL_MAX_LUNS)
 	 && (ctl_softc->ctl_luns[targ_lun] != NULL)) {
@@ -11013,13 +10937,27 @@ ctl_scsiio_precheck(struct ctl_softc *ct
 			if (lun->be_lun->lun_type == T_PROCESSOR) {
 				ctsio->io_hdr.flags |= CTL_FLAG_CONTROL_DEV;
 			}
+
+			/*
+			 * Every I/O goes into the OOA queue for a
+			 * particular LUN, and stays there until completion.
+			 */
+			mtx_lock(&lun->lun_lock);
+			TAILQ_INSERT_TAIL(&lun->ooa_queue, &ctsio->io_hdr,
+			    ooa_links);
 		}
 	} else {
 		ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr = NULL;
 		ctsio->io_hdr.ctl_private[CTL_PRIV_BACKEND_LUN].ptr = NULL;
 	}
 
-	entry = &ctl_cmd_table[opcode];
+	/* Get command entry and return error if it is unsuppotyed. */
+	entry = ctl_validate_command(ctsio);
+	if (entry == NULL) {
+		if (lun)
+			mtx_unlock(&lun->lun_lock);
+		return (retval);
+	}
 
 	ctsio->io_hdr.flags &= ~CTL_FLAG_DATA_MASK;
 	ctsio->io_hdr.flags |= entry->flags & CTL_FLAG_DATA_MASK;
@@ -11043,43 +10981,15 @@ ctl_scsiio_precheck(struct ctl_softc *ct
 		CTL_DEBUG_PRINT(("ctl_scsiio_precheck: bailing out due to invalid LUN\n"));
 		return (retval);
 	} else {
-		mtx_lock(&lun->lun_lock);
-
-		/*
-		 * Every I/O goes into the OOA queue for a particular LUN, and
-		 * stays there until completion.
-		 */
-		TAILQ_INSERT_TAIL(&lun->ooa_queue, &ctsio->io_hdr, ooa_links);
-
 		/*
 		 * Make sure we support this particular command on this LUN.
 		 * e.g., we don't support writes to the control LUN.
 		 */
-		switch (lun->be_lun->lun_type) {
-		case T_PROCESSOR:
-		 	if (((entry->flags & CTL_CMD_FLAG_OK_ON_PROC) == 0)
-			 && ((entry->flags & CTL_CMD_FLAG_OK_ON_ALL_LUNS)
-			      == 0)) {
-				mtx_unlock(&lun->lun_lock);
-				ctl_set_invalid_opcode(ctsio);
-				ctl_done((union ctl_io *)ctsio);
-				return (retval);
-			}
-			break;
-		case T_DIRECT:
-			if (((entry->flags & CTL_CMD_FLAG_OK_ON_SLUN) == 0)
-			 && ((entry->flags & CTL_CMD_FLAG_OK_ON_ALL_LUNS)
-			      == 0)){
-				mtx_unlock(&lun->lun_lock);
-				ctl_set_invalid_opcode(ctsio);
-				ctl_done((union ctl_io *)ctsio);
-				return (retval);
-			}
-			break;
-		default:
+		if (!ctl_cmd_applicable(lun->be_lun->lun_type, entry)) {
 			mtx_unlock(&lun->lun_lock);
-			panic("Unsupported CTL LUN type %d\n",
-			      lun->be_lun->lun_type);
+			ctl_set_invalid_opcode(ctsio);
+			ctl_done((union ctl_io *)ctsio);
+			return (retval);
 		}
 	}
 
@@ -11091,7 +11001,7 @@ ctl_scsiio_precheck(struct ctl_softc *ct
 	 * this initiator, clear it, because it sent down a command other
 	 * than request sense.
 	 */
-	if ((opcode != REQUEST_SENSE)
+	if ((ctsio->cdb[0] != REQUEST_SENSE)
 	 && (ctl_is_set(lun->have_ca, initidx)))
 		ctl_clear_mask(lun->have_ca, initidx);
 
@@ -11187,7 +11097,7 @@ ctl_scsiio_precheck(struct ctl_softc *ct
 		    CTL_HA_STATUS_SUCCESS) {
 			printf("CTL:precheck, ctl_ha_msg_send returned %d\n",
 			       isc_retval);
-			printf("CTL:opcode is %x\n",opcode);
+			printf("CTL:opcode is %x\n", ctsio->cdb[0]);
 		} else {
 #if 0
 			printf("CTL:Precheck sent msg, opcode is %x\n",opcode);
@@ -11242,17 +11152,85 @@ ctl_scsiio_precheck(struct ctl_softc *ct
 	return (retval);
 }
 
+const struct ctl_cmd_entry *
+ctl_get_cmd_entry(struct ctl_scsiio *ctsio)
+{
+	const struct ctl_cmd_entry *entry;
+	int service_action;
+
+	entry = &ctl_cmd_table[ctsio->cdb[0]];
+	if (entry->flags & CTL_CMD_FLAG_SA5) {
+		service_action = ctsio->cdb[1] & SERVICE_ACTION_MASK;
+		entry = &((const struct ctl_cmd_entry *)
+		    entry->execute)[service_action];
+	}
+	return (entry);
+}
+
+const struct ctl_cmd_entry *
+ctl_validate_command(struct ctl_scsiio *ctsio)
+{
+	const struct ctl_cmd_entry *entry;
+	int i;
+	uint8_t diff;
+
+	entry = ctl_get_cmd_entry(ctsio);
+	if (entry->execute == NULL) {
+		ctl_set_invalid_opcode(ctsio);
+		ctl_done((union ctl_io *)ctsio);
+		return (NULL);
+	}
+	KASSERT(entry->length > 0,
+	    ("Not defined length for command 0x%02x/0x%02x",
+	     ctsio->cdb[0], ctsio->cdb[1]));
+	for (i = 1; i < entry->length; i++) {
+		diff = ctsio->cdb[i] & ~entry->usage[i - 1];
+		if (diff == 0)
+			continue;
+		ctl_set_invalid_field(ctsio,
+				      /*sks_valid*/ 1,
+				      /*command*/ 1,
+				      /*field*/ i,
+				      /*bit_valid*/ 1,
+				      /*bit*/ fls(diff) - 1);
+		ctl_done((union ctl_io *)ctsio);
+		return (NULL);
+	}
+	return (entry);
+}
+
+static int
+ctl_cmd_applicable(uint8_t lun_type, const struct ctl_cmd_entry *entry)
+{
+
+	switch (lun_type) {
+	case T_PROCESSOR:
+		if (((entry->flags & CTL_CMD_FLAG_OK_ON_PROC) == 0) &&
+		    ((entry->flags & CTL_CMD_FLAG_OK_ON_ALL_LUNS) == 0))
+			return (0);
+		break;
+	case T_DIRECT:
+		if (((entry->flags & CTL_CMD_FLAG_OK_ON_SLUN) == 0) &&
+		    ((entry->flags & CTL_CMD_FLAG_OK_ON_ALL_LUNS) == 0))
+			return (0);
+		break;
+	default:
+		return (0);
+	}
+	return (1);
+}
+
 static int
 ctl_scsiio(struct ctl_scsiio *ctsio)
 {
 	int retval;
-	struct ctl_cmd_entry *entry;
+	const struct ctl_cmd_entry *entry;
 
 	retval = CTL_RETVAL_COMPLETE;
 
 	CTL_DEBUG_PRINT(("ctl_scsiio cdb[0]=%02X\n", ctsio->cdb[0]));
 
-	entry = &ctl_cmd_table[ctsio->cdb[0]];
+	entry = ctl_get_cmd_entry(ctsio);
 
 	/*
 	 * If this I/O has been aborted, just send it straight to
@@ -11684,15 +11662,13 @@ ctl_handle_isc(union ctl_io *io)
 		free_io = ctl_serialize_other_sc_cmd(&io->scsiio);
 		break;
 	case CTL_MSG_R2R: {
-		uint8_t opcode;
-		struct ctl_cmd_entry *entry;
+		const struct ctl_cmd_entry *entry;
 
 		/*
 		 * This is only used in SER_ONLY mode.
 		 */
 		free_io = 0;
-		opcode = io->scsiio.cdb[0];
-		entry = &ctl_cmd_table[opcode];
+		entry = ctl_get_cmd_entry(&io->scsiio);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list