From cb4f4d3c7398a709b48d397e0520ee2509a953a4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 20 May 2012 11:59:10 -0400 Subject: target: move unrelated code out of transport_generic_cmd_sequencer Move all code not related to cdb parsing from transport_generic_cmd_sequencer into target_setup_cmd_from_cdb. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 634d0f3..bb19223 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1418,6 +1418,10 @@ int target_setup_cmd_from_cdb( struct se_cmd *cmd, unsigned char *cdb) { + struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; + u32 pr_reg_type = 0; + u8 alua_ascq = 0; + unsigned long flags; int ret; transport_generic_prepare_cdb(cdb); @@ -1457,6 +1461,58 @@ int target_setup_cmd_from_cdb( * Copy the original CDB into cmd-> */ memcpy(cmd->t_task_cdb, cdb, scsi_command_size(cdb)); + + /* + * Check for an existing UNIT ATTENTION condition + */ + if (core_scsi3_ua_check(cmd, cdb) < 0) { + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_CHECK_CONDITION_UNIT_ATTENTION; + return -EINVAL; + } + + ret = su_dev->t10_alua.alua_state_check(cmd, cdb, &alua_ascq); + if (ret != 0) { + /* + * Set SCSI additional sense code (ASC) to 'LUN Not Accessible'; + * The ALUA additional sense code qualifier (ASCQ) is determined + * by the ALUA primary or secondary access state.. + */ + if (ret > 0) { + pr_debug("[%s]: ALUA TG Port not available, " + "SenseKey: NOT_READY, ASC/ASCQ: " + "0x04/0x%02x\n", + cmd->se_tfo->get_fabric_name(), alua_ascq); + + transport_set_sense_codes(cmd, 0x04, alua_ascq); + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_CHECK_CONDITION_NOT_READY; + return -EINVAL; + } + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; + } + + /* + * Check status for SPC-3 Persistent Reservations + */ + if (su_dev->t10_pr.pr_ops.t10_reservation_check(cmd, &pr_reg_type)) { + if (su_dev->t10_pr.pr_ops.t10_seq_non_holder( + cmd, cdb, pr_reg_type) != 0) { + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT; + cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + return -EBUSY; + } + /* + * This means the CDB is allowed for the SCSI Initiator port + * when said port is *NOT* holding the legacy SPC-2 or + * SPC-3 Persistent Reservation. + */ + } + /* * Setup the received CDB based on SCSI defined opcodes and * perform unit attention, persistent reservations and ALUA @@ -1466,6 +1522,11 @@ int target_setup_cmd_from_cdb( ret = transport_generic_cmd_sequencer(cmd, cdb); if (ret < 0) return ret; + + spin_lock_irqsave(&cmd->t_state_lock, flags); + cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE; + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + /* * Check for SAM Task Attribute Emulation */ @@ -1889,15 +1950,6 @@ static inline unsigned long long transport_lba_64_ext(unsigned char *cdb) return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; } -static void transport_set_supported_SAM_opcode(struct se_cmd *se_cmd) -{ - unsigned long flags; - - spin_lock_irqsave(&se_cmd->t_state_lock, flags); - se_cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE; - spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); -} - /* * Called from Fabric Module context from transport_execute_tasks() * @@ -2370,74 +2422,15 @@ static int target_check_write_same_discard(unsigned char *flags, struct se_devic return 0; } -/* transport_generic_cmd_sequencer(): - * - * Generic Command Sequencer that should work for most DAS transport - * drivers. - * - * Called from target_setup_cmd_from_cdb() in the $FABRIC_MOD - * RX Thread. - * - * FIXME: Need to support other SCSI OPCODES where as well. - */ static int transport_generic_cmd_sequencer( struct se_cmd *cmd, unsigned char *cdb) { struct se_device *dev = cmd->se_dev; struct se_subsystem_dev *su_dev = dev->se_sub_dev; - int ret = 0, sector_ret = 0, passthrough; - u32 sectors = 0, size = 0, pr_reg_type = 0; + int sector_ret = 0, passthrough; + u32 sectors = 0, size = 0; u16 service_action; - u8 alua_ascq = 0; - /* - * Check for an existing UNIT ATTENTION condition - */ - if (core_scsi3_ua_check(cmd, cdb) < 0) { - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = TCM_CHECK_CONDITION_UNIT_ATTENTION; - return -EINVAL; - } - /* - * Check status of Asymmetric Logical Unit Assignment port - */ - ret = su_dev->t10_alua.alua_state_check(cmd, cdb, &alua_ascq); - if (ret != 0) { - /* - * Set SCSI additional sense code (ASC) to 'LUN Not Accessible'; - * The ALUA additional sense code qualifier (ASCQ) is determined - * by the ALUA primary or secondary access state.. - */ - if (ret > 0) { - pr_debug("[%s]: ALUA TG Port not available," - " SenseKey: NOT_READY, ASC/ASCQ: 0x04/0x%02x\n", - cmd->se_tfo->get_fabric_name(), alua_ascq); - - transport_set_sense_codes(cmd, 0x04, alua_ascq); - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = TCM_CHECK_CONDITION_NOT_READY; - return -EINVAL; - } - goto out_invalid_cdb_field; - } - /* - * Check status for SPC-3 Persistent Reservations - */ - if (su_dev->t10_pr.pr_ops.t10_reservation_check(cmd, &pr_reg_type) != 0) { - if (su_dev->t10_pr.pr_ops.t10_seq_non_holder( - cmd, cdb, pr_reg_type) != 0) { - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT; - cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT; - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - return -EBUSY; - } - /* - * This means the CDB is allowed for the SCSI Initiator port - * when said port is *NOT* holding the legacy SPC-2 or - * SPC-3 Persistent Reservation. - */ - } /* * If we operate in passthrough mode we skip most CDB emulation and @@ -2992,7 +2985,7 @@ static int transport_generic_cmd_sequencer( * Reject READ_* or WRITE_* with overflow/underflow for * type SCF_SCSI_DATA_SG_IO_CDB. */ - if (!ret && (dev->se_sub_dev->se_dev_attrib.block_size != 512)) { + if (dev->se_sub_dev->se_dev_attrib.block_size != 512) { pr_err("Failing OVERFLOW/UNDERFLOW for LBA op" " CDB on non 512-byte sector setup subsystem" " plugin: %s\n", dev->transport->name); @@ -3032,8 +3025,7 @@ static int transport_generic_cmd_sequencer( (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB))) goto out_unsupported_cdb; - transport_set_supported_SAM_opcode(cmd); - return ret; + return 0; out_unsupported_cdb: cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; @@ -3967,10 +3959,7 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) spin_unlock_irqrestore(&cmd->t_state_lock, flags); return false; } - /* - * Only perform a possible wait_for_tasks if SCF_SUPPORTED_SAM_OPCODE - * has been set in transport_set_supported_SAM_opcode(). - */ + if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) && !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); -- cgit v0.10.2 From 64f1db38c65fa634f4aa21e0f70480a6b8b4d47c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 20 May 2012 11:59:11 -0400 Subject: target: remove control CDB flags We don't need three flags to classifiy the CDB as we can check for a NULL S/G list for a dataless command, and can infer from the absence of the data flag that we deal with a control CDB. Also remove the _SG_IO from the data CDB flag as all I/O is dont on S/G lists now. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 38dfac2..f65dc9d 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -211,12 +211,11 @@ static void tcm_loop_submission_work(struct work_struct *work) /* * Because some userspace code via scsi-generic do not memset their * associated read buffers, go ahead and do that here for type - * SCF_SCSI_CONTROL_SG_IO_CDB. Also note that this is currently - * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB - * by target core in target_setup_cmd_from_cdb() -> - * transport_generic_cmd_sequencer(). + * non-data CDBs. Also note that this is currently guaranteed to be a + * single SGL for this case by target core in + * target_setup_cmd_from_cdb() -> transport_generic_cmd_sequencer(). */ - if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB && + if (!(se_cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && se_cmd->data_direction == DMA_FROM_DEVICE) { struct scatterlist *sg = scsi_sglist(sc); unsigned char *buf = kmap(sg_page(sg)) + sg->offset; diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 4ce2cf6..bfc7232 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -1042,7 +1042,7 @@ static int pscsi_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, memcpy(pt->pscsi_cdb, cmd->t_task_cdb, scsi_command_size(cmd->t_task_cdb)); - if (cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) { + if (!sgl) { req = blk_get_request(pdv->pdv_sd->request_queue, (data_direction == DMA_TO_DEVICE), GFP_KERNEL); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index bb19223..a181951 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2446,7 +2446,7 @@ static int transport_generic_cmd_sequencer( goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); cmd->t_task_lba = transport_lba_21(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; break; case READ_10: sectors = transport_get_sectors_10(cdb, cmd, §or_ret); @@ -2454,7 +2454,7 @@ static int transport_generic_cmd_sequencer( goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); cmd->t_task_lba = transport_lba_32(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; break; case READ_12: sectors = transport_get_sectors_12(cdb, cmd, §or_ret); @@ -2462,7 +2462,7 @@ static int transport_generic_cmd_sequencer( goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); cmd->t_task_lba = transport_lba_32(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; break; case READ_16: sectors = transport_get_sectors_16(cdb, cmd, §or_ret); @@ -2470,7 +2470,7 @@ static int transport_generic_cmd_sequencer( goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); cmd->t_task_lba = transport_lba_64(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; break; case WRITE_6: sectors = transport_get_sectors_6(cdb, cmd, §or_ret); @@ -2478,7 +2478,7 @@ static int transport_generic_cmd_sequencer( goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); cmd->t_task_lba = transport_lba_21(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; break; case WRITE_10: case WRITE_VERIFY: @@ -2489,7 +2489,7 @@ static int transport_generic_cmd_sequencer( cmd->t_task_lba = transport_lba_32(cdb); if (cdb[1] & 0x8) cmd->se_cmd_flags |= SCF_FUA; - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; break; case WRITE_12: sectors = transport_get_sectors_12(cdb, cmd, §or_ret); @@ -2499,7 +2499,7 @@ static int transport_generic_cmd_sequencer( cmd->t_task_lba = transport_lba_32(cdb); if (cdb[1] & 0x8) cmd->se_cmd_flags |= SCF_FUA; - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; break; case WRITE_16: sectors = transport_get_sectors_16(cdb, cmd, §or_ret); @@ -2509,7 +2509,7 @@ static int transport_generic_cmd_sequencer( cmd->t_task_lba = transport_lba_64(cdb); if (cdb[1] & 0x8) cmd->se_cmd_flags |= SCF_FUA; - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; break; case XDWRITEREAD_10: if ((cmd->data_direction != DMA_TO_DEVICE) || @@ -2520,7 +2520,7 @@ static int transport_generic_cmd_sequencer( goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); cmd->t_task_lba = transport_lba_32(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; /* * Do now allow BIDI commands for passthrough mode. @@ -2548,7 +2548,7 @@ static int transport_generic_cmd_sequencer( * XDWRITE_READ_32 logic. */ cmd->t_task_lba = transport_lba_64_ext(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; /* * Do now allow BIDI commands for passthrough mode. @@ -2578,7 +2578,6 @@ static int transport_generic_cmd_sequencer( } cmd->t_task_lba = get_unaligned_be64(&cdb[12]); - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; if (target_check_write_same_discard(&cdb[10], dev) < 0) goto out_unsupported_cdb; @@ -2608,25 +2607,20 @@ static int transport_generic_cmd_sequencer( /* GPCMD_SEND_KEY from multi media commands */ size = (cdb[8] << 8) + cdb[9]; } - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case MODE_SELECT: size = cdb[4]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case MODE_SELECT_10: size = (cdb[7] << 8) + cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case MODE_SENSE: size = cdb[4]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; if (!passthrough) cmd->execute_cmd = target_emulate_modesense; break; case MODE_SENSE_10: size = (cdb[7] << 8) + cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; if (!passthrough) cmd->execute_cmd = target_emulate_modesense; break; @@ -2635,39 +2629,32 @@ static int transport_generic_cmd_sequencer( case LOG_SELECT: case LOG_SENSE: size = (cdb[7] << 8) + cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case READ_BLOCK_LIMITS: size = READ_BLOCK_LEN; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case GPCMD_GET_CONFIGURATION: case GPCMD_READ_FORMAT_CAPACITIES: case GPCMD_READ_DISC_INFO: case GPCMD_READ_TRACK_RZONE_INFO: size = (cdb[7] << 8) + cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case PERSISTENT_RESERVE_IN: if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) cmd->execute_cmd = target_scsi3_emulate_pr_in; size = (cdb[7] << 8) + cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case PERSISTENT_RESERVE_OUT: if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) cmd->execute_cmd = target_scsi3_emulate_pr_out; size = (cdb[7] << 8) + cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case GPCMD_MECHANISM_STATUS: case GPCMD_READ_DVD_STRUCTURE: size = (cdb[8] << 8) + cdb[9]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case READ_POSITION: size = READ_POSITION_LEN; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case MAINTENANCE_OUT: if (dev->transport->get_device_type(dev) != TYPE_ROM) { @@ -2687,7 +2674,6 @@ static int transport_generic_cmd_sequencer( /* GPCMD_REPORT_KEY from multi media commands */ size = (cdb[8] << 8) + cdb[9]; } - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case INQUIRY: size = (cdb[3] << 8) + cdb[4]; @@ -2697,17 +2683,14 @@ static int transport_generic_cmd_sequencer( */ if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) cmd->sam_task_attr = MSG_HEAD_TAG; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; if (!passthrough) cmd->execute_cmd = target_emulate_inquiry; break; case READ_BUFFER: size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case READ_CAPACITY: size = READ_CAP_LEN; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; if (!passthrough) cmd->execute_cmd = target_emulate_readcapacity; break; @@ -2715,7 +2698,6 @@ static int transport_generic_cmd_sequencer( case SECURITY_PROTOCOL_IN: case SECURITY_PROTOCOL_OUT: size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case SERVICE_ACTION_IN: switch (cmd->t_task_cdb[1] & 0x1f) { @@ -2741,38 +2723,31 @@ static int transport_generic_cmd_sequencer( case WRITE_ATTRIBUTE: size = (cdb[10] << 24) | (cdb[11] << 16) | (cdb[12] << 8) | cdb[13]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case RECEIVE_DIAGNOSTIC: case SEND_DIAGNOSTIC: size = (cdb[3] << 8) | cdb[4]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; /* #warning FIXME: Figure out correct GPCMD_READ_CD blocksize. */ #if 0 case GPCMD_READ_CD: sectors = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; size = (2336 * sectors); - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; #endif case READ_TOC: size = cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case REQUEST_SENSE: size = cdb[4]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; if (!passthrough) cmd->execute_cmd = target_emulate_request_sense; break; case READ_ELEMENT_STATUS: size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case WRITE_BUFFER: size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case RESERVE: case RESERVE_10: @@ -2794,7 +2769,6 @@ static int transport_generic_cmd_sequencer( */ if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) cmd->execute_cmd = target_scsi2_reservation_reserve; - cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; case RELEASE: case RELEASE_10: @@ -2809,7 +2783,6 @@ static int transport_generic_cmd_sequencer( if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) cmd->execute_cmd = target_scsi2_reservation_release; - cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; case SYNCHRONIZE_CACHE: case SYNCHRONIZE_CACHE_16: @@ -2827,7 +2800,6 @@ static int transport_generic_cmd_sequencer( goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); - cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; if (passthrough) break; @@ -2844,7 +2816,6 @@ static int transport_generic_cmd_sequencer( break; case UNMAP: size = get_unaligned_be16(&cdb[7]); - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; if (!passthrough) cmd->execute_cmd = target_emulate_unmap; break; @@ -2861,7 +2832,6 @@ static int transport_generic_cmd_sequencer( } cmd->t_task_lba = get_unaligned_be64(&cdb[2]); - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; if (target_check_write_same_discard(&cdb[1], dev) < 0) goto out_unsupported_cdb; @@ -2881,7 +2851,6 @@ static int transport_generic_cmd_sequencer( } cmd->t_task_lba = get_unaligned_be32(&cdb[2]); - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; /* * Follow sbcr26 with WRITE_SAME (10) and check for the existence * of byte 1 bit 3 UNMAP instead of original reserved field @@ -2900,7 +2869,6 @@ static int transport_generic_cmd_sequencer( case TEST_UNIT_READY: case VERIFY: case WRITE_FILEMARKS: - cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; if (!passthrough) cmd->execute_cmd = target_emulate_noop; break; @@ -2909,7 +2877,6 @@ static int transport_generic_cmd_sequencer( case GPCMD_LOAD_UNLOAD: case GPCMD_SET_SPEED: case MOVE_MEDIUM: - cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; case REPORT_LUNS: cmd->execute_cmd = target_report_luns; @@ -2920,11 +2887,9 @@ static int transport_generic_cmd_sequencer( */ if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) cmd->sam_task_attr = MSG_HEAD_TAG; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case GET_EVENT_STATUS_NOTIFICATION: size = (cdb[7] << 8) | cdb[8]; - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case ATA_16: /* Only support ATA passthrough to pSCSI backends.. */ @@ -2956,7 +2921,6 @@ static int transport_generic_cmd_sequencer( /* BYTE */ size = sectors; } - cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; default: pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode" @@ -2983,7 +2947,7 @@ static int transport_generic_cmd_sequencer( } /* * Reject READ_* or WRITE_* with overflow/underflow for - * type SCF_SCSI_DATA_SG_IO_CDB. + * type SCF_SCSI_DATA_CDB. */ if (dev->se_sub_dev->se_dev_attrib.block_size != 512) { pr_err("Failing OVERFLOW/UNDERFLOW for LBA op" @@ -3003,7 +2967,7 @@ static int transport_generic_cmd_sequencer( cmd->data_length = size; } - if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) { + if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) { printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" " big sectors %u exceeds fabric_max_sectors:" @@ -3022,7 +2986,7 @@ static int transport_generic_cmd_sequencer( /* reject any command that we don't have a handler for */ if (!(passthrough || cmd->execute_cmd || - (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB))) + (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB))) goto out_unsupported_cdb; return 0; @@ -3357,31 +3321,27 @@ int transport_generic_map_mem_to_cmd( if (!sgl || !sgl_count) return 0; - if ((cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) || - (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB)) { - /* - * Reject SCSI data overflow with map_mem_to_cmd() as incoming - * scatterlists already have been set to follow what the fabric - * passes for the original expected data transfer length. - */ - if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { - pr_warn("Rejecting SCSI DATA overflow for fabric using" - " SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC\n"); - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -EINVAL; - } + /* + * Reject SCSI data overflow with map_mem_to_cmd() as incoming + * scatterlists already have been set to follow what the fabric + * passes for the original expected data transfer length. + */ + if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { + pr_warn("Rejecting SCSI DATA overflow for fabric using" + " SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC\n"); + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; + } - cmd->t_data_sg = sgl; - cmd->t_data_nents = sgl_count; + cmd->t_data_sg = sgl; + cmd->t_data_nents = sgl_count; - if (sgl_bidi && sgl_bidi_count) { - cmd->t_bidi_data_sg = sgl_bidi; - cmd->t_bidi_data_nents = sgl_bidi_count; - } - cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC; + if (sgl_bidi && sgl_bidi_count) { + cmd->t_bidi_data_sg = sgl_bidi; + cmd->t_bidi_data_nents = sgl_bidi_count; } - + cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC; return 0; } EXPORT_SYMBOL(transport_generic_map_mem_to_cmd); @@ -3453,7 +3413,7 @@ transport_generic_get_mem(struct se_cmd *cmd) cmd->t_data_nents = nents; sg_init_table(cmd->t_data_sg, nents); - zero_flag = cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB ? 0 : __GFP_ZERO; + zero_flag = cmd->se_cmd_flags & SCF_SCSI_DATA_CDB ? 0 : __GFP_ZERO; while (length) { u32 page_len = min_t(u32, length, PAGE_SIZE); @@ -3500,8 +3460,7 @@ int transport_generic_new_cmd(struct se_cmd *cmd) } /* Workaround for handling zero-length control CDBs */ - if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) && - !cmd->data_length) { + if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && !cmd->data_length) { spin_lock_irq(&cmd->t_state_lock); cmd->t_state = TRANSPORT_COMPLETE; cmd->transport_state |= CMD_T_ACTIVE; @@ -3519,7 +3478,7 @@ int transport_generic_new_cmd(struct se_cmd *cmd) return 0; } - if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) { + if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { struct se_dev_attrib *attr = &dev->se_sub_dev->se_dev_attrib; if (transport_cmd_get_valid_sectors(cmd) < 0) diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 5b65f33..4ad58ac 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -215,7 +215,7 @@ int ft_write_pending(struct se_cmd *se_cmd) */ if ((ep->xid <= lport->lro_xid) && (fh->fh_r_ctl == FC_RCTL_DD_DATA_DESC)) { - if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) && + if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && lport->tt.ddp_target(lport, ep->xid, se_cmd->t_data_sg, se_cmd->t_data_nents)) diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index dc35d86..abda19d 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -160,25 +160,22 @@ enum se_cmd_flags_table { SCF_SUPPORTED_SAM_OPCODE = 0x00000001, SCF_TRANSPORT_TASK_SENSE = 0x00000002, SCF_EMULATED_TASK_SENSE = 0x00000004, - SCF_SCSI_DATA_SG_IO_CDB = 0x00000008, - SCF_SCSI_CONTROL_SG_IO_CDB = 0x00000010, - SCF_SCSI_NON_DATA_CDB = 0x00000020, - SCF_SCSI_TMR_CDB = 0x00000040, - SCF_SCSI_CDB_EXCEPTION = 0x00000080, - SCF_SCSI_RESERVATION_CONFLICT = 0x00000100, - SCF_FUA = 0x00000200, - SCF_SE_LUN_CMD = 0x00000800, - SCF_SE_ALLOW_EOO = 0x00001000, - SCF_BIDI = 0x00002000, - SCF_SENT_CHECK_CONDITION = 0x00004000, - SCF_OVERFLOW_BIT = 0x00008000, - SCF_UNDERFLOW_BIT = 0x00010000, - SCF_SENT_DELAYED_TAS = 0x00020000, - SCF_ALUA_NON_OPTIMIZED = 0x00040000, - SCF_DELAYED_CMD_FROM_SAM_ATTR = 0x00080000, - SCF_UNUSED = 0x00100000, - SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00200000, - SCF_ACK_KREF = 0x00400000, + SCF_SCSI_DATA_CDB = 0x00000008, + SCF_SCSI_TMR_CDB = 0x00000010, + SCF_SCSI_CDB_EXCEPTION = 0x00000020, + SCF_SCSI_RESERVATION_CONFLICT = 0x00000040, + SCF_FUA = 0x00000080, + SCF_SE_LUN_CMD = 0x00000100, + SCF_SE_ALLOW_EOO = 0x00000200, + SCF_BIDI = 0x00000400, + SCF_SENT_CHECK_CONDITION = 0x00000800, + SCF_OVERFLOW_BIT = 0x00001000, + SCF_UNDERFLOW_BIT = 0x00002000, + SCF_SENT_DELAYED_TAS = 0x00004000, + SCF_ALUA_NON_OPTIMIZED = 0x00008000, + SCF_DELAYED_CMD_FROM_SAM_ATTR = 0x00010000, + SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000, + SCF_ACK_KREF = 0x00040000, }; /* struct se_dev_entry->lun_flags and struct se_lun->lun_access */ -- cgit v0.10.2 From 9b3b804101db067c3889948f57031f852186ea11 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 20 May 2012 11:59:12 -0400 Subject: target: split overflow and underflow checks into a helper Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index a181951..23657a0 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1345,6 +1345,55 @@ static inline void transport_generic_prepare_cdb( static int transport_generic_cmd_sequencer(struct se_cmd *, unsigned char *); +static int target_cmd_size_check(struct se_cmd *cmd, unsigned int size) +{ + struct se_device *dev = cmd->se_dev; + + if (cmd->unknown_data_length) { + cmd->data_length = size; + } else if (size != cmd->data_length) { + pr_warn("TARGET_CORE[%s]: Expected Transfer Length:" + " %u does not match SCSI CDB Length: %u for SAM Opcode:" + " 0x%02x\n", cmd->se_tfo->get_fabric_name(), + cmd->data_length, size, cmd->t_task_cdb[0]); + + cmd->cmd_spdtl = size; + + if (cmd->data_direction == DMA_TO_DEVICE) { + pr_err("Rejecting underflow/overflow" + " WRITE data\n"); + goto out_invalid_cdb_field; + } + /* + * Reject READ_* or WRITE_* with overflow/underflow for + * type SCF_SCSI_DATA_CDB. + */ + if (dev->se_sub_dev->se_dev_attrib.block_size != 512) { + pr_err("Failing OVERFLOW/UNDERFLOW for LBA op" + " CDB on non 512-byte sector setup subsystem" + " plugin: %s\n", dev->transport->name); + /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */ + goto out_invalid_cdb_field; + } + + if (size > cmd->data_length) { + cmd->se_cmd_flags |= SCF_OVERFLOW_BIT; + cmd->residual_count = (size - cmd->data_length); + } else { + cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; + cmd->residual_count = (cmd->data_length - size); + } + cmd->data_length = size; + } + + return 0; + +out_invalid_cdb_field: + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; +} + /* * Used by fabric modules containing a local struct se_cmd within their * fabric dependent per I/O descriptor. @@ -2431,6 +2480,7 @@ static int transport_generic_cmd_sequencer( int sector_ret = 0, passthrough; u32 sectors = 0, size = 0; u16 service_action; + int ret; /* * If we operate in passthrough mode we skip most CDB emulation and @@ -2929,43 +2979,9 @@ static int transport_generic_cmd_sequencer( goto out_unsupported_cdb; } - if (cmd->unknown_data_length) - cmd->data_length = size; - - if (size != cmd->data_length) { - pr_warn("TARGET_CORE[%s]: Expected Transfer Length:" - " %u does not match SCSI CDB Length: %u for SAM Opcode:" - " 0x%02x\n", cmd->se_tfo->get_fabric_name(), - cmd->data_length, size, cdb[0]); - - cmd->cmd_spdtl = size; - - if (cmd->data_direction == DMA_TO_DEVICE) { - pr_err("Rejecting underflow/overflow" - " WRITE data\n"); - goto out_invalid_cdb_field; - } - /* - * Reject READ_* or WRITE_* with overflow/underflow for - * type SCF_SCSI_DATA_CDB. - */ - if (dev->se_sub_dev->se_dev_attrib.block_size != 512) { - pr_err("Failing OVERFLOW/UNDERFLOW for LBA op" - " CDB on non 512-byte sector setup subsystem" - " plugin: %s\n", dev->transport->name); - /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */ - goto out_invalid_cdb_field; - } - - if (size > cmd->data_length) { - cmd->se_cmd_flags |= SCF_OVERFLOW_BIT; - cmd->residual_count = (size - cmd->data_length); - } else { - cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; - cmd->residual_count = (cmd->data_length - size); - } - cmd->data_length = size; - } + ret = target_cmd_size_check(cmd, size); + if (ret) + return ret; if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) { -- cgit v0.10.2 From 88455ec4be02c395820b1ff57656b0844ec03ac3 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 20 May 2012 11:59:13 -0400 Subject: target: split parsing of SPC commands into a separate helper (nab: Add EXPORT_SYMBOL usage for spc_parse_cdb) Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/Makefile b/drivers/target/Makefile index 61648d8..70cab2a 100644 --- a/drivers/target/Makefile +++ b/drivers/target/Makefile @@ -10,6 +10,7 @@ target_core_mod-y := target_core_configfs.o \ target_core_tpg.o \ target_core_transport.o \ target_core_cdb.o \ + target_core_spc.o \ target_core_ua.o \ target_core_rd.o \ target_core_stat.o diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 165e824..6bbf18d 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -96,6 +96,9 @@ int core_tpg_post_addlun(struct se_portal_group *, struct se_lun *, struct se_lun *core_tpg_pre_dellun(struct se_portal_group *, u32 unpacked_lun); int core_tpg_post_dellun(struct se_portal_group *, struct se_lun *); +/* target_core_spc.c */ +int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough); + /* target_core_transport.c */ extern struct kmem_cache *se_tmr_req_cache; diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c new file mode 100644 index 0000000..ec21086 --- /dev/null +++ b/drivers/target/target_core_spc.c @@ -0,0 +1,169 @@ +/* + * SCSI Primary Commands (SPC) parsing and emulation. + * + * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc. + * Copyright (c) 2005, 2006, 2007 SBE, Inc. + * Copyright (c) 2007-2010 Rising Tide Systems + * Copyright (c) 2008-2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "target_core_internal.h" +#include "target_core_pr.h" +#include "target_core_ua.h" + + +int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough) +{ + struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; + unsigned char *cdb = cmd->t_task_cdb; + + switch (cdb[0]) { + case MODE_SELECT: + *size = cdb[4]; + break; + case MODE_SELECT_10: + *size = (cdb[7] << 8) + cdb[8]; + break; + case MODE_SENSE: + *size = cdb[4]; + if (!passthrough) + cmd->execute_cmd = target_emulate_modesense; + break; + case MODE_SENSE_10: + *size = (cdb[7] << 8) + cdb[8]; + if (!passthrough) + cmd->execute_cmd = target_emulate_modesense; + break; + case LOG_SELECT: + case LOG_SENSE: + *size = (cdb[7] << 8) + cdb[8]; + break; + case PERSISTENT_RESERVE_IN: + if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) + cmd->execute_cmd = target_scsi3_emulate_pr_in; + *size = (cdb[7] << 8) + cdb[8]; + break; + case PERSISTENT_RESERVE_OUT: + if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) + cmd->execute_cmd = target_scsi3_emulate_pr_out; + *size = (cdb[7] << 8) + cdb[8]; + break; + case RELEASE: + case RELEASE_10: + if (cdb[0] == RELEASE_10) + *size = (cdb[7] << 8) | cdb[8]; + else + *size = cmd->data_length; + + if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) + cmd->execute_cmd = target_scsi2_reservation_release; + break; + case RESERVE: + case RESERVE_10: + /* + * The SPC-2 RESERVE does not contain a size in the SCSI CDB. + * Assume the passthrough or $FABRIC_MOD will tell us about it. + */ + if (cdb[0] == RESERVE_10) + *size = (cdb[7] << 8) | cdb[8]; + else + *size = cmd->data_length; + + /* + * Setup the legacy emulated handler for SPC-2 and + * >= SPC-3 compatible reservation handling (CRH=1) + * Otherwise, we assume the underlying SCSI logic is + * is running in SPC_PASSTHROUGH, and wants reservations + * emulation disabled. + */ + if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) + cmd->execute_cmd = target_scsi2_reservation_reserve; + break; + case REQUEST_SENSE: + *size = cdb[4]; + if (!passthrough) + cmd->execute_cmd = target_emulate_request_sense; + break; + case INQUIRY: + *size = (cdb[3] << 8) + cdb[4]; + + /* + * Do implict HEAD_OF_QUEUE processing for INQUIRY. + * See spc4r17 section 5.3 + */ + if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) + cmd->sam_task_attr = MSG_HEAD_TAG; + if (!passthrough) + cmd->execute_cmd = target_emulate_inquiry; + break; + case SECURITY_PROTOCOL_IN: + case SECURITY_PROTOCOL_OUT: + *size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + break; + case EXTENDED_COPY: + case READ_ATTRIBUTE: + case RECEIVE_COPY_RESULTS: + case WRITE_ATTRIBUTE: + *size = (cdb[10] << 24) | (cdb[11] << 16) | + (cdb[12] << 8) | cdb[13]; + break; + case RECEIVE_DIAGNOSTIC: + case SEND_DIAGNOSTIC: + *size = (cdb[3] << 8) | cdb[4]; + break; + case WRITE_BUFFER: + *size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; + break; + case REPORT_LUNS: + cmd->execute_cmd = target_report_luns; + *size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + /* + * Do implict HEAD_OF_QUEUE processing for REPORT_LUNS + * See spc4r17 section 5.3 + */ + if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) + cmd->sam_task_attr = MSG_HEAD_TAG; + break; + case TEST_UNIT_READY: + if (!passthrough) + cmd->execute_cmd = target_emulate_noop; + break; + default: + pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode" + " 0x%02x, sending CHECK_CONDITION.\n", + cmd->se_tfo->get_fabric_name(), cdb[0]); + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(spc_parse_cdb); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 23657a0..a8a3d15 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2658,26 +2658,8 @@ static int transport_generic_cmd_sequencer( size = (cdb[8] << 8) + cdb[9]; } break; - case MODE_SELECT: - size = cdb[4]; - break; - case MODE_SELECT_10: - size = (cdb[7] << 8) + cdb[8]; - break; - case MODE_SENSE: - size = cdb[4]; - if (!passthrough) - cmd->execute_cmd = target_emulate_modesense; - break; - case MODE_SENSE_10: - size = (cdb[7] << 8) + cdb[8]; - if (!passthrough) - cmd->execute_cmd = target_emulate_modesense; - break; case GPCMD_READ_BUFFER_CAPACITY: case GPCMD_SEND_OPC: - case LOG_SELECT: - case LOG_SENSE: size = (cdb[7] << 8) + cdb[8]; break; case READ_BLOCK_LIMITS: @@ -2689,16 +2671,6 @@ static int transport_generic_cmd_sequencer( case GPCMD_READ_TRACK_RZONE_INFO: size = (cdb[7] << 8) + cdb[8]; break; - case PERSISTENT_RESERVE_IN: - if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) - cmd->execute_cmd = target_scsi3_emulate_pr_in; - size = (cdb[7] << 8) + cdb[8]; - break; - case PERSISTENT_RESERVE_OUT: - if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) - cmd->execute_cmd = target_scsi3_emulate_pr_out; - size = (cdb[7] << 8) + cdb[8]; - break; case GPCMD_MECHANISM_STATUS: case GPCMD_READ_DVD_STRUCTURE: size = (cdb[8] << 8) + cdb[9]; @@ -2725,17 +2697,6 @@ static int transport_generic_cmd_sequencer( size = (cdb[8] << 8) + cdb[9]; } break; - case INQUIRY: - size = (cdb[3] << 8) + cdb[4]; - /* - * Do implict HEAD_OF_QUEUE processing for INQUIRY. - * See spc4r17 section 5.3 - */ - if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) - cmd->sam_task_attr = MSG_HEAD_TAG; - if (!passthrough) - cmd->execute_cmd = target_emulate_inquiry; - break; case READ_BUFFER: size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; break; @@ -2745,10 +2706,6 @@ static int transport_generic_cmd_sequencer( cmd->execute_cmd = target_emulate_readcapacity; break; case READ_MEDIA_SERIAL_NUMBER: - case SECURITY_PROTOCOL_IN: - case SECURITY_PROTOCOL_OUT: - size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - break; case SERVICE_ACTION_IN: switch (cmd->t_task_cdb[1] & 0x1f) { case SAI_READ_CAPACITY_16: @@ -2767,17 +2724,9 @@ static int transport_generic_cmd_sequencer( /*FALLTHROUGH*/ case ACCESS_CONTROL_IN: case ACCESS_CONTROL_OUT: - case EXTENDED_COPY: - case READ_ATTRIBUTE: - case RECEIVE_COPY_RESULTS: - case WRITE_ATTRIBUTE: size = (cdb[10] << 24) | (cdb[11] << 16) | (cdb[12] << 8) | cdb[13]; break; - case RECEIVE_DIAGNOSTIC: - case SEND_DIAGNOSTIC: - size = (cdb[3] << 8) | cdb[4]; - break; /* #warning FIXME: Figure out correct GPCMD_READ_CD blocksize. */ #if 0 case GPCMD_READ_CD: @@ -2788,52 +2737,9 @@ static int transport_generic_cmd_sequencer( case READ_TOC: size = cdb[8]; break; - case REQUEST_SENSE: - size = cdb[4]; - if (!passthrough) - cmd->execute_cmd = target_emulate_request_sense; - break; case READ_ELEMENT_STATUS: size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9]; break; - case WRITE_BUFFER: - size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; - break; - case RESERVE: - case RESERVE_10: - /* - * The SPC-2 RESERVE does not contain a size in the SCSI CDB. - * Assume the passthrough or $FABRIC_MOD will tell us about it. - */ - if (cdb[0] == RESERVE_10) - size = (cdb[7] << 8) | cdb[8]; - else - size = cmd->data_length; - - /* - * Setup the legacy emulated handler for SPC-2 and - * >= SPC-3 compatible reservation handling (CRH=1) - * Otherwise, we assume the underlying SCSI logic is - * is running in SPC_PASSTHROUGH, and wants reservations - * emulation disabled. - */ - if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) - cmd->execute_cmd = target_scsi2_reservation_reserve; - break; - case RELEASE: - case RELEASE_10: - /* - * The SPC-2 RELEASE does not contain a size in the SCSI CDB. - * Assume the passthrough or $FABRIC_MOD will tell us about it. - */ - if (cdb[0] == RELEASE_10) - size = (cdb[7] << 8) | cdb[8]; - else - size = cmd->data_length; - - if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) - cmd->execute_cmd = target_scsi2_reservation_release; - break; case SYNCHRONIZE_CACHE: case SYNCHRONIZE_CACHE_16: /* @@ -2916,7 +2822,6 @@ static int transport_generic_cmd_sequencer( case SEEK_10: case SPACE: case START_STOP: - case TEST_UNIT_READY: case VERIFY: case WRITE_FILEMARKS: if (!passthrough) @@ -2928,16 +2833,6 @@ static int transport_generic_cmd_sequencer( case GPCMD_SET_SPEED: case MOVE_MEDIUM: break; - case REPORT_LUNS: - cmd->execute_cmd = target_report_luns; - size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - /* - * Do implict HEAD_OF_QUEUE processing for REPORT_LUNS - * See spc4r17 section 5.3 - */ - if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) - cmd->sam_task_attr = MSG_HEAD_TAG; - break; case GET_EVENT_STATUS_NOTIFICATION: size = (cdb[7] << 8) | cdb[8]; break; @@ -2973,10 +2868,9 @@ static int transport_generic_cmd_sequencer( } break; default: - pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode" - " 0x%02x, sending CHECK_CONDITION.\n", - cmd->se_tfo->get_fabric_name(), cdb[0]); - goto out_unsupported_cdb; + ret = spc_parse_cdb(cmd, &size, passthrough); + if (ret) + return ret; } ret = target_cmd_size_check(cmd, size); -- cgit v0.10.2 From d6e0175cf3f9737a760482d185bb73566bcc9331 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 20 May 2012 11:59:14 -0400 Subject: target: add a parse_cdb method to the backend drivers Instead of trying to handle all SCSI command sets in one function (transport_generic_cmd_sequencer) call out to the backend driver to perform this functionality. For pSCSI a copy of the existing code is used, but for all virtual backends we can use a new parse_sbc_cdb helper is used to provide a simple SBC emulation. For now this setups means a fair amount of duplication between pSCSI and the SBC library, but patches later in this series will sort out that problem. (nab: Fix up build failure in target_core_pscsi.c) Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/Makefile b/drivers/target/Makefile index 70cab2a..50b887b 100644 --- a/drivers/target/Makefile +++ b/drivers/target/Makefile @@ -10,6 +10,7 @@ target_core_mod-y := target_core_configfs.o \ target_core_tpg.o \ target_core_transport.o \ target_core_cdb.o \ + target_core_sbc.o \ target_core_spc.o \ target_core_ua.o \ target_core_rd.o \ diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 9f99d04..e2df308 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -561,6 +561,7 @@ static struct se_subsystem_api fileio_template = { .allocate_virtdevice = fd_allocate_virtdevice, .create_virtdevice = fd_create_virtdevice, .free_device = fd_free_device, + .parse_cdb = sbc_parse_cdb, .execute_cmd = fd_execute_cmd, .do_sync_cache = fd_emulate_sync_cache, .check_configfs_dev_params = fd_check_configfs_dev_params, diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index fd47950..244fff4 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -653,6 +653,7 @@ static struct se_subsystem_api iblock_template = { .allocate_virtdevice = iblock_allocate_virtdevice, .create_virtdevice = iblock_create_virtdevice, .free_device = iblock_free_device, + .parse_cdb = sbc_parse_cdb, .execute_cmd = iblock_execute_cmd, .do_discard = iblock_do_discard, .do_sync_cache = iblock_emulate_sync_cache, diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 6bbf18d..165e824 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -96,9 +96,6 @@ int core_tpg_post_addlun(struct se_portal_group *, struct se_lun *, struct se_lun *core_tpg_pre_dellun(struct se_portal_group *, u32 unpacked_lun); int core_tpg_post_dellun(struct se_portal_group *, struct se_lun *); -/* target_core_spc.c */ -int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough); - /* target_core_transport.c */ extern struct kmem_cache *se_tmr_req_cache; diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index bfc7232..378da24 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -35,8 +35,10 @@ #include #include #include -#include +#include #include +#include + #include #include #include @@ -46,6 +48,7 @@ #include #include +#include "target_core_alua.h" #include "target_core_pscsi.h" #define ISPRINT(a) ((a >= ' ') && (a <= '~')) @@ -1019,6 +1022,470 @@ fail: return -ENOMEM; } +static inline u32 pscsi_get_sectors_6( + unsigned char *cdb, + struct se_cmd *cmd, + int *ret) +{ + struct se_device *dev = cmd->se_dev; + + /* + * Assume TYPE_DISK for non struct se_device objects. + * Use 8-bit sector value. + */ + if (!dev) + goto type_disk; + + /* + * Use 24-bit allocation length for TYPE_TAPE. + */ + if (dev->transport->get_device_type(dev) == TYPE_TAPE) + return (u32)(cdb[2] << 16) + (cdb[3] << 8) + cdb[4]; + + /* + * Everything else assume TYPE_DISK Sector CDB location. + * Use 8-bit sector value. SBC-3 says: + * + * A TRANSFER LENGTH field set to zero specifies that 256 + * logical blocks shall be written. Any other value + * specifies the number of logical blocks that shall be + * written. + */ +type_disk: + return cdb[4] ? : 256; +} + +static inline u32 pscsi_get_sectors_10( + unsigned char *cdb, + struct se_cmd *cmd, + int *ret) +{ + struct se_device *dev = cmd->se_dev; + + /* + * Assume TYPE_DISK for non struct se_device objects. + * Use 16-bit sector value. + */ + if (!dev) + goto type_disk; + + /* + * XXX_10 is not defined in SSC, throw an exception + */ + if (dev->transport->get_device_type(dev) == TYPE_TAPE) { + *ret = -EINVAL; + return 0; + } + + /* + * Everything else assume TYPE_DISK Sector CDB location. + * Use 16-bit sector value. + */ +type_disk: + return (u32)(cdb[7] << 8) + cdb[8]; +} + +static inline u32 pscsi_get_sectors_12( + unsigned char *cdb, + struct se_cmd *cmd, + int *ret) +{ + struct se_device *dev = cmd->se_dev; + + /* + * Assume TYPE_DISK for non struct se_device objects. + * Use 32-bit sector value. + */ + if (!dev) + goto type_disk; + + /* + * XXX_12 is not defined in SSC, throw an exception + */ + if (dev->transport->get_device_type(dev) == TYPE_TAPE) { + *ret = -EINVAL; + return 0; + } + + /* + * Everything else assume TYPE_DISK Sector CDB location. + * Use 32-bit sector value. + */ +type_disk: + return (u32)(cdb[6] << 24) + (cdb[7] << 16) + (cdb[8] << 8) + cdb[9]; +} + +static inline u32 pscsi_get_sectors_16( + unsigned char *cdb, + struct se_cmd *cmd, + int *ret) +{ + struct se_device *dev = cmd->se_dev; + + /* + * Assume TYPE_DISK for non struct se_device objects. + * Use 32-bit sector value. + */ + if (!dev) + goto type_disk; + + /* + * Use 24-bit allocation length for TYPE_TAPE. + */ + if (dev->transport->get_device_type(dev) == TYPE_TAPE) + return (u32)(cdb[12] << 16) + (cdb[13] << 8) + cdb[14]; + +type_disk: + return (u32)(cdb[10] << 24) + (cdb[11] << 16) + + (cdb[12] << 8) + cdb[13]; +} + +/* + * Used for VARIABLE_LENGTH_CDB WRITE_32 and READ_32 variants + */ +static inline u32 pscsi_get_sectors_32( + unsigned char *cdb, + struct se_cmd *cmd, + int *ret) +{ + /* + * Assume TYPE_DISK for non struct se_device objects. + * Use 32-bit sector value. + */ + return (u32)(cdb[28] << 24) + (cdb[29] << 16) + + (cdb[30] << 8) + cdb[31]; + +} + +static inline u32 pscsi_get_lba_21(unsigned char *cdb) +{ + return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3]; +} + +static inline u32 pscsi_get_lba_32(unsigned char *cdb) +{ + return (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; +} + +static inline unsigned long long pscsi_get_lba_64(unsigned char *cdb) +{ + unsigned int __v1, __v2; + + __v1 = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + __v2 = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + + return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; +} + +/* + * For VARIABLE_LENGTH_CDB w/ 32 byte extended CDBs + */ +static inline unsigned long long pscsi_get_lba_64_ext(unsigned char *cdb) +{ + unsigned int __v1, __v2; + + __v1 = (cdb[12] << 24) | (cdb[13] << 16) | (cdb[14] << 8) | cdb[15]; + __v2 = (cdb[16] << 24) | (cdb[17] << 16) | (cdb[18] << 8) | cdb[19]; + + return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; +} + + +static inline u32 pscsi_get_size( + u32 sectors, + unsigned char *cdb, + struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + + if (dev->transport->get_device_type(dev) == TYPE_TAPE) { + if (cdb[1] & 1) { /* sectors */ + return dev->se_sub_dev->se_dev_attrib.block_size * sectors; + } else /* bytes */ + return sectors; + } + + pr_debug("Returning block_size: %u, sectors: %u == %u for" + " %s object\n", dev->se_sub_dev->se_dev_attrib.block_size, + sectors, dev->se_sub_dev->se_dev_attrib.block_size * sectors, + dev->transport->name); + + return dev->se_sub_dev->se_dev_attrib.block_size * sectors; +} + +static int pscsi_parse_cdb(struct se_cmd *cmd, unsigned int *size) +{ + struct se_device *dev = cmd->se_dev; + struct se_subsystem_dev *su_dev = dev->se_sub_dev; + unsigned char *cdb = cmd->t_task_cdb; + int sector_ret = 0; + u32 sectors = 0; + u16 service_action; + int ret; + + if (cmd->se_cmd_flags & SCF_BIDI) + goto out_unsupported_cdb; + + switch (cdb[0]) { + case READ_6: + sectors = pscsi_get_sectors_6(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + *size = pscsi_get_size(sectors, cdb, cmd); + cmd->t_task_lba = pscsi_get_lba_21(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + break; + case READ_10: + sectors = pscsi_get_sectors_10(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + *size = pscsi_get_size(sectors, cdb, cmd); + cmd->t_task_lba = pscsi_get_lba_32(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + break; + case READ_12: + sectors = pscsi_get_sectors_12(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + *size = pscsi_get_size(sectors, cdb, cmd); + cmd->t_task_lba = pscsi_get_lba_32(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + break; + case READ_16: + sectors = pscsi_get_sectors_16(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + *size = pscsi_get_size(sectors, cdb, cmd); + cmd->t_task_lba = pscsi_get_lba_64(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + break; + case WRITE_6: + sectors = pscsi_get_sectors_6(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + *size = pscsi_get_size(sectors, cdb, cmd); + cmd->t_task_lba = pscsi_get_lba_21(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + break; + case WRITE_10: + case WRITE_VERIFY: + sectors = pscsi_get_sectors_10(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + *size = pscsi_get_size(sectors, cdb, cmd); + cmd->t_task_lba = pscsi_get_lba_32(cdb); + if (cdb[1] & 0x8) + cmd->se_cmd_flags |= SCF_FUA; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + break; + case WRITE_12: + sectors = pscsi_get_sectors_12(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + *size = pscsi_get_size(sectors, cdb, cmd); + cmd->t_task_lba = pscsi_get_lba_32(cdb); + if (cdb[1] & 0x8) + cmd->se_cmd_flags |= SCF_FUA; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + break; + case WRITE_16: + sectors = pscsi_get_sectors_16(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + *size = pscsi_get_size(sectors, cdb, cmd); + cmd->t_task_lba = pscsi_get_lba_64(cdb); + if (cdb[1] & 0x8) + cmd->se_cmd_flags |= SCF_FUA; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + break; + case VARIABLE_LENGTH_CMD: + service_action = get_unaligned_be16(&cdb[8]); + switch (service_action) { + case WRITE_SAME_32: + sectors = pscsi_get_sectors_32(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + + if (!sectors) { + pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not" + " supported\n"); + goto out_invalid_cdb_field; + } + + *size = pscsi_get_size(1, cdb, cmd); + cmd->t_task_lba = get_unaligned_be64(&cdb[12]); + break; + default: + pr_err("VARIABLE_LENGTH_CMD service action" + " 0x%04x not supported\n", service_action); + goto out_unsupported_cdb; + } + break; + case GPCMD_READ_BUFFER_CAPACITY: + case GPCMD_SEND_OPC: + *size = (cdb[7] << 8) + cdb[8]; + break; + case READ_BLOCK_LIMITS: + *size = READ_BLOCK_LEN; + break; + case GPCMD_GET_CONFIGURATION: + case GPCMD_READ_FORMAT_CAPACITIES: + case GPCMD_READ_DISC_INFO: + case GPCMD_READ_TRACK_RZONE_INFO: + *size = (cdb[7] << 8) + cdb[8]; + break; + case GPCMD_MECHANISM_STATUS: + case GPCMD_READ_DVD_STRUCTURE: + *size = (cdb[8] << 8) + cdb[9]; + break; + case READ_POSITION: + *size = READ_POSITION_LEN; + break; + case READ_BUFFER: + *size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; + break; + case READ_CAPACITY: + *size = READ_CAP_LEN; + break; + case READ_MEDIA_SERIAL_NUMBER: + case SERVICE_ACTION_IN: + case ACCESS_CONTROL_IN: + case ACCESS_CONTROL_OUT: + *size = (cdb[10] << 24) | (cdb[11] << 16) | + (cdb[12] << 8) | cdb[13]; + break; + case READ_TOC: + *size = cdb[8]; + break; + case READ_ELEMENT_STATUS: + *size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9]; + break; + case SYNCHRONIZE_CACHE: + case SYNCHRONIZE_CACHE_16: + /* + * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE + */ + if (cdb[0] == SYNCHRONIZE_CACHE) { + sectors = pscsi_get_sectors_10(cdb, cmd, §or_ret); + cmd->t_task_lba = pscsi_get_lba_32(cdb); + } else { + sectors = pscsi_get_sectors_16(cdb, cmd, §or_ret); + cmd->t_task_lba = pscsi_get_lba_64(cdb); + } + if (sector_ret) + goto out_unsupported_cdb; + + *size = pscsi_get_size(sectors, cdb, cmd); + break; + case UNMAP: + *size = get_unaligned_be16(&cdb[7]); + break; + case WRITE_SAME_16: + sectors = pscsi_get_sectors_16(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + + if (!sectors) { + pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); + goto out_invalid_cdb_field; + } + + *size = pscsi_get_size(1, cdb, cmd); + cmd->t_task_lba = get_unaligned_be64(&cdb[2]); + break; + case WRITE_SAME: + sectors = pscsi_get_sectors_10(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + + if (!sectors) { + pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); + goto out_invalid_cdb_field; + } + + *size = pscsi_get_size(1, cdb, cmd); + cmd->t_task_lba = get_unaligned_be32(&cdb[2]); + break; + case ALLOW_MEDIUM_REMOVAL: + case ERASE: + case REZERO_UNIT: + case SEEK_10: + case SPACE: + case START_STOP: + case VERIFY: + case WRITE_FILEMARKS: + case GPCMD_CLOSE_TRACK: + case INITIALIZE_ELEMENT_STATUS: + case GPCMD_LOAD_UNLOAD: + case GPCMD_SET_SPEED: + case MOVE_MEDIUM: + *size = 0; + break; + case GET_EVENT_STATUS_NOTIFICATION: + *size = (cdb[7] << 8) | cdb[8]; + break; + case ATA_16: + switch (cdb[2] & 0x3) { /* T_LENGTH */ + case 0x0: + sectors = 0; + break; + case 0x1: + sectors = (((cdb[1] & 0x1) ? cdb[3] : 0) << 8) | cdb[4]; + break; + case 0x2: + sectors = (((cdb[1] & 0x1) ? cdb[5] : 0) << 8) | cdb[6]; + break; + case 0x3: + pr_err("T_LENGTH=0x3 not supported for ATA_16\n"); + goto out_invalid_cdb_field; + } + + /* BYTE_BLOCK */ + if (cdb[2] & 0x4) { + /* BLOCK T_TYPE: 512 or sector */ + *size = sectors * ((cdb[2] & 0x10) ? + dev->se_sub_dev->se_dev_attrib.block_size : 512); + } else { + /* BYTE */ + *size = sectors; + } + break; + default: + ret = spc_parse_cdb(cmd, size, true); + if (ret) + return ret; + } + + if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { + if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) { + printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" + " big sectors %u exceeds fabric_max_sectors:" + " %u\n", cdb[0], sectors, + su_dev->se_dev_attrib.fabric_max_sectors); + goto out_invalid_cdb_field; + } + if (sectors > su_dev->se_dev_attrib.hw_max_sectors) { + printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" + " big sectors %u exceeds backend hw_max_sectors:" + " %u\n", cdb[0], sectors, + su_dev->se_dev_attrib.hw_max_sectors); + goto out_invalid_cdb_field; + } + } + + return 0; + +out_unsupported_cdb: + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + return -EINVAL; +out_invalid_cdb_field: + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; +} + + static int pscsi_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, enum dma_data_direction data_direction) { @@ -1188,6 +1655,7 @@ static struct se_subsystem_api pscsi_template = { .create_virtdevice = pscsi_create_virtdevice, .free_device = pscsi_free_device, .transport_complete = pscsi_transport_complete, + .parse_cdb = pscsi_parse_cdb, .execute_cmd = pscsi_execute_cmd, .check_configfs_dev_params = pscsi_check_configfs_dev_params, .set_configfs_dev_params = pscsi_set_configfs_dev_params, diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index d0ceb87..d7e8382 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -468,6 +468,7 @@ static struct se_subsystem_api rd_mcp_template = { .allocate_virtdevice = rd_allocate_virtdevice, .create_virtdevice = rd_create_virtdevice, .free_device = rd_free_device, + .parse_cdb = sbc_parse_cdb, .execute_cmd = rd_execute_cmd, .check_configfs_dev_params = rd_check_configfs_dev_params, .set_configfs_dev_params = rd_set_configfs_dev_params, diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c new file mode 100644 index 0000000..9d1ca38 --- /dev/null +++ b/drivers/target/target_core_sbc.c @@ -0,0 +1,450 @@ +/* + * SCSI Block Commands (SBC) parsing and emulation. + * + * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc. + * Copyright (c) 2005, 2006, 2007 SBE, Inc. + * Copyright (c) 2007-2010 Rising Tide Systems + * Copyright (c) 2008-2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "target_core_internal.h" +#include "target_core_ua.h" + + +static inline u32 sbc_get_size(struct se_cmd *cmd, u32 sectors) +{ + return cmd->se_dev->se_sub_dev->se_dev_attrib.block_size * sectors; +} + +static int sbc_check_valid_sectors(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + unsigned long long end_lba; + u32 sectors; + + sectors = cmd->data_length / dev->se_sub_dev->se_dev_attrib.block_size; + end_lba = dev->transport->get_blocks(dev) + 1; + + if (cmd->t_task_lba + sectors > end_lba) { + pr_err("target: lba %llu, sectors %u exceeds end lba %llu\n", + cmd->t_task_lba, sectors, end_lba); + return -EINVAL; + } + + return 0; +} + +static inline u32 transport_get_sectors_6(unsigned char *cdb) +{ + /* + * Use 8-bit sector value. SBC-3 says: + * + * A TRANSFER LENGTH field set to zero specifies that 256 + * logical blocks shall be written. Any other value + * specifies the number of logical blocks that shall be + * written. + */ + return cdb[4] ? : 256; +} + +static inline u32 transport_get_sectors_10(unsigned char *cdb) +{ + return (u32)(cdb[7] << 8) + cdb[8]; +} + +static inline u32 transport_get_sectors_12(unsigned char *cdb) +{ + return (u32)(cdb[6] << 24) + (cdb[7] << 16) + (cdb[8] << 8) + cdb[9]; +} + +static inline u32 transport_get_sectors_16(unsigned char *cdb) +{ + return (u32)(cdb[10] << 24) + (cdb[11] << 16) + + (cdb[12] << 8) + cdb[13]; +} + +/* + * Used for VARIABLE_LENGTH_CDB WRITE_32 and READ_32 variants + */ +static inline u32 transport_get_sectors_32(unsigned char *cdb) +{ + return (u32)(cdb[28] << 24) + (cdb[29] << 16) + + (cdb[30] << 8) + cdb[31]; + +} + +static inline u32 transport_lba_21(unsigned char *cdb) +{ + return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3]; +} + +static inline u32 transport_lba_32(unsigned char *cdb) +{ + return (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; +} + +static inline unsigned long long transport_lba_64(unsigned char *cdb) +{ + unsigned int __v1, __v2; + + __v1 = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + __v2 = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + + return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; +} + +/* + * For VARIABLE_LENGTH_CDB w/ 32 byte extended CDBs + */ +static inline unsigned long long transport_lba_64_ext(unsigned char *cdb) +{ + unsigned int __v1, __v2; + + __v1 = (cdb[12] << 24) | (cdb[13] << 16) | (cdb[14] << 8) | cdb[15]; + __v2 = (cdb[16] << 24) | (cdb[17] << 16) | (cdb[18] << 8) | cdb[19]; + + return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; +} + +static int sbc_write_same_supported(struct se_device *dev, + unsigned char *flags) +{ + if ((flags[0] & 0x04) || (flags[0] & 0x02)) { + pr_err("WRITE_SAME PBDATA and LBDATA" + " bits not supported for Block Discard" + " Emulation\n"); + return -ENOSYS; + } + + /* + * Currently for the emulated case we only accept + * tpws with the UNMAP=1 bit set. + */ + if (!(flags[0] & 0x08)) { + pr_err("WRITE_SAME w/o UNMAP bit not" + " supported for Block Discard Emulation\n"); + return -ENOSYS; + } + + return 0; +} + +static void xdreadwrite_callback(struct se_cmd *cmd) +{ + unsigned char *buf, *addr; + struct scatterlist *sg; + unsigned int offset; + int i; + int count; + /* + * From sbc3r22.pdf section 5.48 XDWRITEREAD (10) command + * + * 1) read the specified logical block(s); + * 2) transfer logical blocks from the data-out buffer; + * 3) XOR the logical blocks transferred from the data-out buffer with + * the logical blocks read, storing the resulting XOR data in a buffer; + * 4) if the DISABLE WRITE bit is set to zero, then write the logical + * blocks transferred from the data-out buffer; and + * 5) transfer the resulting XOR data to the data-in buffer. + */ + buf = kmalloc(cmd->data_length, GFP_KERNEL); + if (!buf) { + pr_err("Unable to allocate xor_callback buf\n"); + return; + } + /* + * Copy the scatterlist WRITE buffer located at cmd->t_data_sg + * into the locally allocated *buf + */ + sg_copy_to_buffer(cmd->t_data_sg, + cmd->t_data_nents, + buf, + cmd->data_length); + + /* + * Now perform the XOR against the BIDI read memory located at + * cmd->t_mem_bidi_list + */ + + offset = 0; + for_each_sg(cmd->t_bidi_data_sg, sg, cmd->t_bidi_data_nents, count) { + addr = kmap_atomic(sg_page(sg)); + if (!addr) + goto out; + + for (i = 0; i < sg->length; i++) + *(addr + sg->offset + i) ^= *(buf + offset + i); + + offset += sg->length; + kunmap_atomic(addr); + } + +out: + kfree(buf); +} + +int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size) +{ + struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; + struct se_device *dev = cmd->se_dev; + unsigned char *cdb = cmd->t_task_cdb; + u32 sectors = 0; + int ret; + + switch (cdb[0]) { + case READ_6: + sectors = transport_get_sectors_6(cdb); + cmd->t_task_lba = transport_lba_21(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + break; + case READ_10: + sectors = transport_get_sectors_10(cdb); + cmd->t_task_lba = transport_lba_32(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + break; + case READ_12: + sectors = transport_get_sectors_12(cdb); + cmd->t_task_lba = transport_lba_32(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + break; + case READ_16: + sectors = transport_get_sectors_16(cdb); + cmd->t_task_lba = transport_lba_64(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + break; + case WRITE_6: + sectors = transport_get_sectors_6(cdb); + cmd->t_task_lba = transport_lba_21(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + break; + case WRITE_10: + case WRITE_VERIFY: + sectors = transport_get_sectors_10(cdb); + cmd->t_task_lba = transport_lba_32(cdb); + if (cdb[1] & 0x8) + cmd->se_cmd_flags |= SCF_FUA; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + break; + case WRITE_12: + sectors = transport_get_sectors_12(cdb); + cmd->t_task_lba = transport_lba_32(cdb); + if (cdb[1] & 0x8) + cmd->se_cmd_flags |= SCF_FUA; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + break; + case WRITE_16: + sectors = transport_get_sectors_16(cdb); + cmd->t_task_lba = transport_lba_64(cdb); + if (cdb[1] & 0x8) + cmd->se_cmd_flags |= SCF_FUA; + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + break; + case XDWRITEREAD_10: + if ((cmd->data_direction != DMA_TO_DEVICE) || + !(cmd->se_cmd_flags & SCF_BIDI)) + goto out_invalid_cdb_field; + sectors = transport_get_sectors_10(cdb); + + cmd->t_task_lba = transport_lba_32(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + + /* + * Setup BIDI XOR callback to be run after I/O completion. + */ + cmd->transport_complete_callback = &xdreadwrite_callback; + if (cdb[1] & 0x8) + cmd->se_cmd_flags |= SCF_FUA; + break; + case VARIABLE_LENGTH_CMD: + { + u16 service_action = get_unaligned_be16(&cdb[8]); + switch (service_action) { + case XDWRITEREAD_32: + sectors = transport_get_sectors_32(cdb); + + /* + * Use WRITE_32 and READ_32 opcodes for the emulated + * XDWRITE_READ_32 logic. + */ + cmd->t_task_lba = transport_lba_64_ext(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + + /* + * Setup BIDI XOR callback to be run during after I/O + * completion. + */ + cmd->transport_complete_callback = &xdreadwrite_callback; + if (cdb[1] & 0x8) + cmd->se_cmd_flags |= SCF_FUA; + break; + case WRITE_SAME_32: + sectors = transport_get_sectors_32(cdb); + if (!sectors) { + pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not" + " supported\n"); + goto out_invalid_cdb_field; + } + + *size = sbc_get_size(cmd, 1); + cmd->t_task_lba = get_unaligned_be64(&cdb[12]); + + if (sbc_write_same_supported(dev, &cdb[10]) < 0) + goto out_unsupported_cdb; + cmd->execute_cmd = target_emulate_write_same; + break; + default: + pr_err("VARIABLE_LENGTH_CMD service action" + " 0x%04x not supported\n", service_action); + goto out_unsupported_cdb; + } + break; + } + case READ_CAPACITY: + *size = READ_CAP_LEN; + cmd->execute_cmd = target_emulate_readcapacity; + break; + case SERVICE_ACTION_IN: + switch (cmd->t_task_cdb[1] & 0x1f) { + case SAI_READ_CAPACITY_16: + cmd->execute_cmd = target_emulate_readcapacity_16; + break; + default: + pr_err("Unsupported SA: 0x%02x\n", + cmd->t_task_cdb[1] & 0x1f); + goto out_invalid_cdb_field; + } + *size = (cdb[10] << 24) | (cdb[11] << 16) | + (cdb[12] << 8) | cdb[13]; + break; + case SYNCHRONIZE_CACHE: + case SYNCHRONIZE_CACHE_16: + /* + * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE + */ + if (cdb[0] == SYNCHRONIZE_CACHE) { + sectors = transport_get_sectors_10(cdb); + cmd->t_task_lba = transport_lba_32(cdb); + } else { + sectors = transport_get_sectors_16(cdb); + cmd->t_task_lba = transport_lba_64(cdb); + } + + *size = sbc_get_size(cmd, sectors); + + /* + * Check to ensure that LBA + Range does not exceed past end of + * device for IBLOCK and FILEIO ->do_sync_cache() backend calls + */ + if (cmd->t_task_lba || sectors) { + if (sbc_check_valid_sectors(cmd) < 0) + goto out_invalid_cdb_field; + } + cmd->execute_cmd = target_emulate_synchronize_cache; + break; + case UNMAP: + *size = get_unaligned_be16(&cdb[7]); + cmd->execute_cmd = target_emulate_unmap; + break; + case WRITE_SAME_16: + sectors = transport_get_sectors_16(cdb); + if (!sectors) { + pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); + goto out_invalid_cdb_field; + } + + *size = sbc_get_size(cmd, 1); + cmd->t_task_lba = get_unaligned_be64(&cdb[2]); + + if (sbc_write_same_supported(dev, &cdb[1]) < 0) + goto out_unsupported_cdb; + cmd->execute_cmd = target_emulate_write_same; + break; + case WRITE_SAME: + sectors = transport_get_sectors_10(cdb); + if (!sectors) { + pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); + goto out_invalid_cdb_field; + } + + *size = sbc_get_size(cmd, 1); + cmd->t_task_lba = get_unaligned_be32(&cdb[2]); + + /* + * Follow sbcr26 with WRITE_SAME (10) and check for the existence + * of byte 1 bit 3 UNMAP instead of original reserved field + */ + if (sbc_write_same_supported(dev, &cdb[1]) < 0) + goto out_unsupported_cdb; + cmd->execute_cmd = target_emulate_write_same; + break; + case VERIFY: + *size = 0; + cmd->execute_cmd = target_emulate_noop; + break; + default: + ret = spc_parse_cdb(cmd, size, false); + if (ret) + return ret; + } + + /* reject any command that we don't have a handler for */ + if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && !cmd->execute_cmd) + goto out_unsupported_cdb; + + if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { + if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) { + printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" + " big sectors %u exceeds fabric_max_sectors:" + " %u\n", cdb[0], sectors, + su_dev->se_dev_attrib.fabric_max_sectors); + goto out_invalid_cdb_field; + } + if (sectors > su_dev->se_dev_attrib.hw_max_sectors) { + printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" + " big sectors %u exceeds backend hw_max_sectors:" + " %u\n", cdb[0], sectors, + su_dev->se_dev_attrib.hw_max_sectors); + goto out_invalid_cdb_field; + } + + *size = sbc_get_size(cmd, sectors); + } + + return 0; + +out_unsupported_cdb: + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + return -EINVAL; +out_invalid_cdb_field: + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; +} +EXPORT_SYMBOL(sbc_parse_cdb); diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index ec21086..156291f 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -152,6 +152,7 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough) cmd->sam_task_attr = MSG_HEAD_TAG; break; case TEST_UNIT_READY: + *size = 0; if (!passthrough) cmd->execute_cmd = target_emulate_noop; break; diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index a8a3d15..0adabd3 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1343,8 +1343,6 @@ static inline void transport_generic_prepare_cdb( } } -static int transport_generic_cmd_sequencer(struct se_cmd *, unsigned char *); - static int target_cmd_size_check(struct se_cmd *cmd, unsigned int size) { struct se_device *dev = cmd->se_dev; @@ -1471,6 +1469,7 @@ int target_setup_cmd_from_cdb( u32 pr_reg_type = 0; u8 alua_ascq = 0; unsigned long flags; + unsigned int size; int ret; transport_generic_prepare_cdb(cdb); @@ -1562,13 +1561,11 @@ int target_setup_cmd_from_cdb( */ } - /* - * Setup the received CDB based on SCSI defined opcodes and - * perform unit attention, persistent reservations and ALUA - * checks for virtual device backends. The cmd->t_task_cdb - * pointer is expected to be setup before we reach this point. - */ - ret = transport_generic_cmd_sequencer(cmd, cdb); + ret = cmd->se_dev->transport->parse_cdb(cmd, &size); + if (ret < 0) + return ret; + + ret = target_cmd_size_check(cmd, size); if (ret < 0) return ret; @@ -1694,10 +1691,7 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, target_put_sess_cmd(se_sess, se_cmd); return; } - /* - * Sanitize CDBs via transport_generic_cmd_sequencer() and - * allocate the necessary tasks to complete the received CDB+data - */ + rc = target_setup_cmd_from_cdb(se_cmd, cdb); if (rc != 0) { transport_generic_request_failure(se_cmd); @@ -1966,39 +1960,6 @@ queue_full: } EXPORT_SYMBOL(transport_generic_request_failure); -static inline u32 transport_lba_21(unsigned char *cdb) -{ - return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3]; -} - -static inline u32 transport_lba_32(unsigned char *cdb) -{ - return (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; -} - -static inline unsigned long long transport_lba_64(unsigned char *cdb) -{ - unsigned int __v1, __v2; - - __v1 = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - __v2 = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - - return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; -} - -/* - * For VARIABLE_LENGTH_CDB w/ 32 byte extended CDBs - */ -static inline unsigned long long transport_lba_64_ext(unsigned char *cdb) -{ - unsigned int __v1, __v2; - - __v1 = (cdb[12] << 24) | (cdb[13] << 16) | (cdb[14] << 8) | cdb[15]; - __v2 = (cdb[16] << 24) | (cdb[17] << 16) | (cdb[18] << 8) | cdb[19]; - - return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; -} - /* * Called from Fabric Module context from transport_execute_tasks() * @@ -2147,217 +2108,6 @@ check_depth: return 0; } -static inline u32 transport_get_sectors_6( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) -{ - struct se_device *dev = cmd->se_dev; - - /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 8-bit sector value. - */ - if (!dev) - goto type_disk; - - /* - * Use 24-bit allocation length for TYPE_TAPE. - */ - if (dev->transport->get_device_type(dev) == TYPE_TAPE) - return (u32)(cdb[2] << 16) + (cdb[3] << 8) + cdb[4]; - - /* - * Everything else assume TYPE_DISK Sector CDB location. - * Use 8-bit sector value. SBC-3 says: - * - * A TRANSFER LENGTH field set to zero specifies that 256 - * logical blocks shall be written. Any other value - * specifies the number of logical blocks that shall be - * written. - */ -type_disk: - return cdb[4] ? : 256; -} - -static inline u32 transport_get_sectors_10( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) -{ - struct se_device *dev = cmd->se_dev; - - /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 16-bit sector value. - */ - if (!dev) - goto type_disk; - - /* - * XXX_10 is not defined in SSC, throw an exception - */ - if (dev->transport->get_device_type(dev) == TYPE_TAPE) { - *ret = -EINVAL; - return 0; - } - - /* - * Everything else assume TYPE_DISK Sector CDB location. - * Use 16-bit sector value. - */ -type_disk: - return (u32)(cdb[7] << 8) + cdb[8]; -} - -static inline u32 transport_get_sectors_12( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) -{ - struct se_device *dev = cmd->se_dev; - - /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 32-bit sector value. - */ - if (!dev) - goto type_disk; - - /* - * XXX_12 is not defined in SSC, throw an exception - */ - if (dev->transport->get_device_type(dev) == TYPE_TAPE) { - *ret = -EINVAL; - return 0; - } - - /* - * Everything else assume TYPE_DISK Sector CDB location. - * Use 32-bit sector value. - */ -type_disk: - return (u32)(cdb[6] << 24) + (cdb[7] << 16) + (cdb[8] << 8) + cdb[9]; -} - -static inline u32 transport_get_sectors_16( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) -{ - struct se_device *dev = cmd->se_dev; - - /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 32-bit sector value. - */ - if (!dev) - goto type_disk; - - /* - * Use 24-bit allocation length for TYPE_TAPE. - */ - if (dev->transport->get_device_type(dev) == TYPE_TAPE) - return (u32)(cdb[12] << 16) + (cdb[13] << 8) + cdb[14]; - -type_disk: - return (u32)(cdb[10] << 24) + (cdb[11] << 16) + - (cdb[12] << 8) + cdb[13]; -} - -/* - * Used for VARIABLE_LENGTH_CDB WRITE_32 and READ_32 variants - */ -static inline u32 transport_get_sectors_32( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) -{ - /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 32-bit sector value. - */ - return (u32)(cdb[28] << 24) + (cdb[29] << 16) + - (cdb[30] << 8) + cdb[31]; - -} - -static inline u32 transport_get_size( - u32 sectors, - unsigned char *cdb, - struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - - if (dev->transport->get_device_type(dev) == TYPE_TAPE) { - if (cdb[1] & 1) { /* sectors */ - return dev->se_sub_dev->se_dev_attrib.block_size * sectors; - } else /* bytes */ - return sectors; - } - - pr_debug("Returning block_size: %u, sectors: %u == %u for" - " %s object\n", dev->se_sub_dev->se_dev_attrib.block_size, - sectors, dev->se_sub_dev->se_dev_attrib.block_size * sectors, - dev->transport->name); - - return dev->se_sub_dev->se_dev_attrib.block_size * sectors; -} - -static void transport_xor_callback(struct se_cmd *cmd) -{ - unsigned char *buf, *addr; - struct scatterlist *sg; - unsigned int offset; - int i; - int count; - /* - * From sbc3r22.pdf section 5.48 XDWRITEREAD (10) command - * - * 1) read the specified logical block(s); - * 2) transfer logical blocks from the data-out buffer; - * 3) XOR the logical blocks transferred from the data-out buffer with - * the logical blocks read, storing the resulting XOR data in a buffer; - * 4) if the DISABLE WRITE bit is set to zero, then write the logical - * blocks transferred from the data-out buffer; and - * 5) transfer the resulting XOR data to the data-in buffer. - */ - buf = kmalloc(cmd->data_length, GFP_KERNEL); - if (!buf) { - pr_err("Unable to allocate xor_callback buf\n"); - return; - } - /* - * Copy the scatterlist WRITE buffer located at cmd->t_data_sg - * into the locally allocated *buf - */ - sg_copy_to_buffer(cmd->t_data_sg, - cmd->t_data_nents, - buf, - cmd->data_length); - - /* - * Now perform the XOR against the BIDI read memory located at - * cmd->t_mem_bidi_list - */ - - offset = 0; - for_each_sg(cmd->t_bidi_data_sg, sg, cmd->t_bidi_data_nents, count) { - addr = kmap_atomic(sg_page(sg)); - if (!addr) - goto out; - - for (i = 0; i < sg->length; i++) - *(addr + sg->offset + i) ^= *(buf + offset + i); - - offset += sg->length; - kunmap_atomic(addr); - } - -out: - kfree(buf); -} - /* * Used to obtain Sense Data from underlying Linux/SCSI struct scsi_cmnd */ @@ -2439,478 +2189,6 @@ static int transport_cmd_get_valid_sectors(struct se_cmd *cmd) return 0; } -static int target_check_write_same_discard(unsigned char *flags, struct se_device *dev) -{ - /* - * Determine if the received WRITE_SAME is used to for direct - * passthrough into Linux/SCSI with struct request via TCM/pSCSI - * or we are signaling the use of internal WRITE_SAME + UNMAP=1 - * emulation for -> Linux/BLOCK disbard with TCM/IBLOCK code. - */ - int passthrough = (dev->transport->transport_type == - TRANSPORT_PLUGIN_PHBA_PDEV); - - if (!passthrough) { - if ((flags[0] & 0x04) || (flags[0] & 0x02)) { - pr_err("WRITE_SAME PBDATA and LBDATA" - " bits not supported for Block Discard" - " Emulation\n"); - return -ENOSYS; - } - /* - * Currently for the emulated case we only accept - * tpws with the UNMAP=1 bit set. - */ - if (!(flags[0] & 0x08)) { - pr_err("WRITE_SAME w/o UNMAP bit not" - " supported for Block Discard Emulation\n"); - return -ENOSYS; - } - } - - return 0; -} - -static int transport_generic_cmd_sequencer( - struct se_cmd *cmd, - unsigned char *cdb) -{ - struct se_device *dev = cmd->se_dev; - struct se_subsystem_dev *su_dev = dev->se_sub_dev; - int sector_ret = 0, passthrough; - u32 sectors = 0, size = 0; - u16 service_action; - int ret; - - /* - * If we operate in passthrough mode we skip most CDB emulation and - * instead hand the commands down to the physical SCSI device. - */ - passthrough = - (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV); - - switch (cdb[0]) { - case READ_6: - sectors = transport_get_sectors_6(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_21(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; - case READ_10: - sectors = transport_get_sectors_10(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_32(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; - case READ_12: - sectors = transport_get_sectors_12(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_32(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; - case READ_16: - sectors = transport_get_sectors_16(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_64(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; - case WRITE_6: - sectors = transport_get_sectors_6(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_21(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; - case WRITE_10: - case WRITE_VERIFY: - sectors = transport_get_sectors_10(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_32(cdb); - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; - case WRITE_12: - sectors = transport_get_sectors_12(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_32(cdb); - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; - case WRITE_16: - sectors = transport_get_sectors_16(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_64(cdb); - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; - case XDWRITEREAD_10: - if ((cmd->data_direction != DMA_TO_DEVICE) || - !(cmd->se_cmd_flags & SCF_BIDI)) - goto out_invalid_cdb_field; - sectors = transport_get_sectors_10(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - cmd->t_task_lba = transport_lba_32(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - - /* - * Do now allow BIDI commands for passthrough mode. - */ - if (passthrough) - goto out_unsupported_cdb; - - /* - * Setup BIDI XOR callback to be run after I/O completion. - */ - cmd->transport_complete_callback = &transport_xor_callback; - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; - break; - case VARIABLE_LENGTH_CMD: - service_action = get_unaligned_be16(&cdb[8]); - switch (service_action) { - case XDWRITEREAD_32: - sectors = transport_get_sectors_32(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - size = transport_get_size(sectors, cdb, cmd); - /* - * Use WRITE_32 and READ_32 opcodes for the emulated - * XDWRITE_READ_32 logic. - */ - cmd->t_task_lba = transport_lba_64_ext(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - - /* - * Do now allow BIDI commands for passthrough mode. - */ - if (passthrough) - goto out_unsupported_cdb; - - /* - * Setup BIDI XOR callback to be run during after I/O - * completion. - */ - cmd->transport_complete_callback = &transport_xor_callback; - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; - break; - case WRITE_SAME_32: - sectors = transport_get_sectors_32(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - - if (sectors) - size = transport_get_size(1, cdb, cmd); - else { - pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not" - " supported\n"); - goto out_invalid_cdb_field; - } - - cmd->t_task_lba = get_unaligned_be64(&cdb[12]); - - if (target_check_write_same_discard(&cdb[10], dev) < 0) - goto out_unsupported_cdb; - if (!passthrough) - cmd->execute_cmd = target_emulate_write_same; - break; - default: - pr_err("VARIABLE_LENGTH_CMD service action" - " 0x%04x not supported\n", service_action); - goto out_unsupported_cdb; - } - break; - case MAINTENANCE_IN: - if (dev->transport->get_device_type(dev) != TYPE_ROM) { - /* MAINTENANCE_IN from SCC-2 */ - /* - * Check for emulated MI_REPORT_TARGET_PGS. - */ - if ((cdb[1] & 0x1f) == MI_REPORT_TARGET_PGS && - su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { - cmd->execute_cmd = - target_emulate_report_target_port_groups; - } - size = (cdb[6] << 24) | (cdb[7] << 16) | - (cdb[8] << 8) | cdb[9]; - } else { - /* GPCMD_SEND_KEY from multi media commands */ - size = (cdb[8] << 8) + cdb[9]; - } - break; - case GPCMD_READ_BUFFER_CAPACITY: - case GPCMD_SEND_OPC: - size = (cdb[7] << 8) + cdb[8]; - break; - case READ_BLOCK_LIMITS: - size = READ_BLOCK_LEN; - break; - case GPCMD_GET_CONFIGURATION: - case GPCMD_READ_FORMAT_CAPACITIES: - case GPCMD_READ_DISC_INFO: - case GPCMD_READ_TRACK_RZONE_INFO: - size = (cdb[7] << 8) + cdb[8]; - break; - case GPCMD_MECHANISM_STATUS: - case GPCMD_READ_DVD_STRUCTURE: - size = (cdb[8] << 8) + cdb[9]; - break; - case READ_POSITION: - size = READ_POSITION_LEN; - break; - case MAINTENANCE_OUT: - if (dev->transport->get_device_type(dev) != TYPE_ROM) { - /* MAINTENANCE_OUT from SCC-2 - * - * Check for emulated MO_SET_TARGET_PGS. - */ - if (cdb[1] == MO_SET_TARGET_PGS && - su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { - cmd->execute_cmd = - target_emulate_set_target_port_groups; - } - - size = (cdb[6] << 24) | (cdb[7] << 16) | - (cdb[8] << 8) | cdb[9]; - } else { - /* GPCMD_REPORT_KEY from multi media commands */ - size = (cdb[8] << 8) + cdb[9]; - } - break; - case READ_BUFFER: - size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; - break; - case READ_CAPACITY: - size = READ_CAP_LEN; - if (!passthrough) - cmd->execute_cmd = target_emulate_readcapacity; - break; - case READ_MEDIA_SERIAL_NUMBER: - case SERVICE_ACTION_IN: - switch (cmd->t_task_cdb[1] & 0x1f) { - case SAI_READ_CAPACITY_16: - if (!passthrough) - cmd->execute_cmd = - target_emulate_readcapacity_16; - break; - default: - if (passthrough) - break; - - pr_err("Unsupported SA: 0x%02x\n", - cmd->t_task_cdb[1] & 0x1f); - goto out_invalid_cdb_field; - } - /*FALLTHROUGH*/ - case ACCESS_CONTROL_IN: - case ACCESS_CONTROL_OUT: - size = (cdb[10] << 24) | (cdb[11] << 16) | - (cdb[12] << 8) | cdb[13]; - break; -/* #warning FIXME: Figure out correct GPCMD_READ_CD blocksize. */ -#if 0 - case GPCMD_READ_CD: - sectors = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; - size = (2336 * sectors); - break; -#endif - case READ_TOC: - size = cdb[8]; - break; - case READ_ELEMENT_STATUS: - size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9]; - break; - case SYNCHRONIZE_CACHE: - case SYNCHRONIZE_CACHE_16: - /* - * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE - */ - if (cdb[0] == SYNCHRONIZE_CACHE) { - sectors = transport_get_sectors_10(cdb, cmd, §or_ret); - cmd->t_task_lba = transport_lba_32(cdb); - } else { - sectors = transport_get_sectors_16(cdb, cmd, §or_ret); - cmd->t_task_lba = transport_lba_64(cdb); - } - if (sector_ret) - goto out_unsupported_cdb; - - size = transport_get_size(sectors, cdb, cmd); - - if (passthrough) - break; - - /* - * Check to ensure that LBA + Range does not exceed past end of - * device for IBLOCK and FILEIO ->do_sync_cache() backend calls - */ - if ((cmd->t_task_lba != 0) || (sectors != 0)) { - if (transport_cmd_get_valid_sectors(cmd) < 0) - goto out_invalid_cdb_field; - } - cmd->execute_cmd = target_emulate_synchronize_cache; - break; - case UNMAP: - size = get_unaligned_be16(&cdb[7]); - if (!passthrough) - cmd->execute_cmd = target_emulate_unmap; - break; - case WRITE_SAME_16: - sectors = transport_get_sectors_16(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - - if (sectors) - size = transport_get_size(1, cdb, cmd); - else { - pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); - goto out_invalid_cdb_field; - } - - cmd->t_task_lba = get_unaligned_be64(&cdb[2]); - - if (target_check_write_same_discard(&cdb[1], dev) < 0) - goto out_unsupported_cdb; - if (!passthrough) - cmd->execute_cmd = target_emulate_write_same; - break; - case WRITE_SAME: - sectors = transport_get_sectors_10(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - - if (sectors) - size = transport_get_size(1, cdb, cmd); - else { - pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); - goto out_invalid_cdb_field; - } - - cmd->t_task_lba = get_unaligned_be32(&cdb[2]); - /* - * Follow sbcr26 with WRITE_SAME (10) and check for the existence - * of byte 1 bit 3 UNMAP instead of original reserved field - */ - if (target_check_write_same_discard(&cdb[1], dev) < 0) - goto out_unsupported_cdb; - if (!passthrough) - cmd->execute_cmd = target_emulate_write_same; - break; - case ALLOW_MEDIUM_REMOVAL: - case ERASE: - case REZERO_UNIT: - case SEEK_10: - case SPACE: - case START_STOP: - case VERIFY: - case WRITE_FILEMARKS: - if (!passthrough) - cmd->execute_cmd = target_emulate_noop; - break; - case GPCMD_CLOSE_TRACK: - case INITIALIZE_ELEMENT_STATUS: - case GPCMD_LOAD_UNLOAD: - case GPCMD_SET_SPEED: - case MOVE_MEDIUM: - break; - case GET_EVENT_STATUS_NOTIFICATION: - size = (cdb[7] << 8) | cdb[8]; - break; - case ATA_16: - /* Only support ATA passthrough to pSCSI backends.. */ - if (!passthrough) - goto out_unsupported_cdb; - - /* T_LENGTH */ - switch (cdb[2] & 0x3) { - case 0x0: - sectors = 0; - break; - case 0x1: - sectors = (((cdb[1] & 0x1) ? cdb[3] : 0) << 8) | cdb[4]; - break; - case 0x2: - sectors = (((cdb[1] & 0x1) ? cdb[5] : 0) << 8) | cdb[6]; - break; - case 0x3: - pr_err("T_LENGTH=0x3 not supported for ATA_16\n"); - goto out_invalid_cdb_field; - } - - /* BYTE_BLOCK */ - if (cdb[2] & 0x4) { - /* BLOCK T_TYPE: 512 or sector */ - size = sectors * ((cdb[2] & 0x10) ? - dev->se_sub_dev->se_dev_attrib.block_size : 512); - } else { - /* BYTE */ - size = sectors; - } - break; - default: - ret = spc_parse_cdb(cmd, &size, passthrough); - if (ret) - return ret; - } - - ret = target_cmd_size_check(cmd, size); - if (ret) - return ret; - - if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { - if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) { - printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" - " big sectors %u exceeds fabric_max_sectors:" - " %u\n", cdb[0], sectors, - su_dev->se_dev_attrib.fabric_max_sectors); - goto out_invalid_cdb_field; - } - if (sectors > su_dev->se_dev_attrib.hw_max_sectors) { - printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" - " big sectors %u exceeds backend hw_max_sectors:" - " %u\n", cdb[0], sectors, - su_dev->se_dev_attrib.hw_max_sectors); - goto out_invalid_cdb_field; - } - } - - /* reject any command that we don't have a handler for */ - if (!(passthrough || cmd->execute_cmd || - (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB))) - goto out_unsupported_cdb; - - return 0; - -out_unsupported_cdb: - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; - return -EINVAL; -out_invalid_cdb_field: - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -EINVAL; -} - /* * Called from I/O completion to determine which dormant/delayed * and ordered cmds need to have their tasks added to the execution queue. diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 2d7db85..f4f1eef 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -24,6 +24,8 @@ struct se_subsystem_api { struct se_subsystem_dev *, void *); void (*free_device)(void *); int (*transport_complete)(struct se_cmd *cmd, struct scatterlist *); + + int (*parse_cdb)(struct se_cmd *cmd, unsigned int *size); int (*execute_cmd)(struct se_cmd *, struct scatterlist *, u32, enum dma_data_direction); int (*do_discard)(struct se_device *, sector_t, u32); @@ -49,6 +51,9 @@ struct se_device *transport_add_device_to_core_hba(struct se_hba *, void target_complete_cmd(struct se_cmd *, u8); +int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size); +int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough); + void transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *); int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *); int transport_set_vpd_ident_type(struct t10_vpd *, unsigned char *); -- cgit v0.10.2 From 1fd032ee10d2816c947f5d5b9abda95e728f0a8f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 20 May 2012 11:59:15 -0400 Subject: target: move code for CDB emulation Move the existing code in target_core_cdb.c into the files for the command sets that the emulations implement. (roland + nab: Squash patch: Fix range calculation in WRITE SAME emulation when num blocks == 0s) Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/Makefile b/drivers/target/Makefile index 50b887b..9fdcb56 100644 --- a/drivers/target/Makefile +++ b/drivers/target/Makefile @@ -9,7 +9,6 @@ target_core_mod-y := target_core_configfs.o \ target_core_tmr.o \ target_core_tpg.o \ target_core_transport.o \ - target_core_cdb.o \ target_core_sbc.o \ target_core_spc.o \ target_core_ua.o \ diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c deleted file mode 100644 index 664f6e7..0000000 --- a/drivers/target/target_core_cdb.c +++ /dev/null @@ -1,1130 +0,0 @@ -/* - * CDB emulation for non-READ/WRITE commands. - * - * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc. - * Copyright (c) 2005, 2006, 2007 SBE, Inc. - * Copyright (c) 2007-2010 Rising Tide Systems - * Copyright (c) 2008-2010 Linux-iSCSI.org - * - * Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include "target_core_internal.h" -#include "target_core_ua.h" - -static void -target_fill_alua_data(struct se_port *port, unsigned char *buf) -{ - struct t10_alua_tg_pt_gp *tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; - - /* - * Set SCCS for MAINTENANCE_IN + REPORT_TARGET_PORT_GROUPS. - */ - buf[5] = 0x80; - - /* - * Set TPGS field for explict and/or implict ALUA access type - * and opteration. - * - * See spc4r17 section 6.4.2 Table 135 - */ - if (!port) - return; - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) - return; - - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; - if (tg_pt_gp) - buf[5] |= tg_pt_gp->tg_pt_gp_alua_access_type; - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); -} - -static int -target_emulate_inquiry_std(struct se_cmd *cmd, char *buf) -{ - struct se_lun *lun = cmd->se_lun; - struct se_device *dev = cmd->se_dev; - - /* Set RMB (removable media) for tape devices */ - if (dev->transport->get_device_type(dev) == TYPE_TAPE) - buf[1] = 0x80; - - buf[2] = dev->transport->get_device_rev(dev); - - /* - * NORMACA and HISUP = 0, RESPONSE DATA FORMAT = 2 - * - * SPC4 says: - * A RESPONSE DATA FORMAT field set to 2h indicates that the - * standard INQUIRY data is in the format defined in this - * standard. Response data format values less than 2h are - * obsolete. Response data format values greater than 2h are - * reserved. - */ - buf[3] = 2; - - /* - * Enable SCCS and TPGS fields for Emulated ALUA - */ - if (dev->se_sub_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) - target_fill_alua_data(lun->lun_sep, buf); - - buf[7] = 0x2; /* CmdQue=1 */ - - snprintf(&buf[8], 8, "LIO-ORG"); - snprintf(&buf[16], 16, "%s", dev->se_sub_dev->t10_wwn.model); - snprintf(&buf[32], 4, "%s", dev->se_sub_dev->t10_wwn.revision); - buf[4] = 31; /* Set additional length to 31 */ - - return 0; -} - -/* unit serial number */ -static int -target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) -{ - struct se_device *dev = cmd->se_dev; - u16 len = 0; - - if (dev->se_sub_dev->su_dev_flags & - SDF_EMULATED_VPD_UNIT_SERIAL) { - u32 unit_serial_len; - - unit_serial_len = strlen(dev->se_sub_dev->t10_wwn.unit_serial); - unit_serial_len++; /* For NULL Terminator */ - - len += sprintf(&buf[4], "%s", - dev->se_sub_dev->t10_wwn.unit_serial); - len++; /* Extra Byte for NULL Terminator */ - buf[3] = len; - } - return 0; -} - -static void -target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf) -{ - unsigned char *p = &dev->se_sub_dev->t10_wwn.unit_serial[0]; - int cnt; - bool next = true; - - /* - * Generate up to 36 bits of VENDOR SPECIFIC IDENTIFIER starting on - * byte 3 bit 3-0 for NAA IEEE Registered Extended DESIGNATOR field - * format, followed by 64 bits of VENDOR SPECIFIC IDENTIFIER EXTENSION - * to complete the payload. These are based from VPD=0x80 PRODUCT SERIAL - * NUMBER set via vpd_unit_serial in target_core_configfs.c to ensure - * per device uniqeness. - */ - for (cnt = 0; *p && cnt < 13; p++) { - int val = hex_to_bin(*p); - - if (val < 0) - continue; - - if (next) { - next = false; - buf[cnt++] |= val; - } else { - next = true; - buf[cnt] = val << 4; - } - } -} - -/* - * Device identification VPD, for a complete list of - * DESIGNATOR TYPEs see spc4r17 Table 459. - */ -static int -target_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) -{ - struct se_device *dev = cmd->se_dev; - struct se_lun *lun = cmd->se_lun; - struct se_port *port = NULL; - struct se_portal_group *tpg = NULL; - struct t10_alua_lu_gp_member *lu_gp_mem; - struct t10_alua_tg_pt_gp *tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; - unsigned char *prod = &dev->se_sub_dev->t10_wwn.model[0]; - u32 prod_len; - u32 unit_serial_len, off = 0; - u16 len = 0, id_len; - - off = 4; - - /* - * NAA IEEE Registered Extended Assigned designator format, see - * spc4r17 section 7.7.3.6.5 - * - * We depend upon a target_core_mod/ConfigFS provided - * /sys/kernel/config/target/core/$HBA/$DEV/wwn/vpd_unit_serial - * value in order to return the NAA id. - */ - if (!(dev->se_sub_dev->su_dev_flags & SDF_EMULATED_VPD_UNIT_SERIAL)) - goto check_t10_vend_desc; - - /* CODE SET == Binary */ - buf[off++] = 0x1; - - /* Set ASSOCIATION == addressed logical unit: 0)b */ - buf[off] = 0x00; - - /* Identifier/Designator type == NAA identifier */ - buf[off++] |= 0x3; - off++; - - /* Identifier/Designator length */ - buf[off++] = 0x10; - - /* - * Start NAA IEEE Registered Extended Identifier/Designator - */ - buf[off++] = (0x6 << 4); - - /* - * Use OpenFabrics IEEE Company ID: 00 14 05 - */ - buf[off++] = 0x01; - buf[off++] = 0x40; - buf[off] = (0x5 << 4); - - /* - * Return ConfigFS Unit Serial Number information for - * VENDOR_SPECIFIC_IDENTIFIER and - * VENDOR_SPECIFIC_IDENTIFIER_EXTENTION - */ - target_parse_naa_6h_vendor_specific(dev, &buf[off]); - - len = 20; - off = (len + 4); - -check_t10_vend_desc: - /* - * T10 Vendor Identifier Page, see spc4r17 section 7.7.3.4 - */ - id_len = 8; /* For Vendor field */ - prod_len = 4; /* For VPD Header */ - prod_len += 8; /* For Vendor field */ - prod_len += strlen(prod); - prod_len++; /* For : */ - - if (dev->se_sub_dev->su_dev_flags & - SDF_EMULATED_VPD_UNIT_SERIAL) { - unit_serial_len = - strlen(&dev->se_sub_dev->t10_wwn.unit_serial[0]); - unit_serial_len++; /* For NULL Terminator */ - - id_len += sprintf(&buf[off+12], "%s:%s", prod, - &dev->se_sub_dev->t10_wwn.unit_serial[0]); - } - buf[off] = 0x2; /* ASCII */ - buf[off+1] = 0x1; /* T10 Vendor ID */ - buf[off+2] = 0x0; - memcpy(&buf[off+4], "LIO-ORG", 8); - /* Extra Byte for NULL Terminator */ - id_len++; - /* Identifier Length */ - buf[off+3] = id_len; - /* Header size for Designation descriptor */ - len += (id_len + 4); - off += (id_len + 4); - /* - * struct se_port is only set for INQUIRY VPD=1 through $FABRIC_MOD - */ - port = lun->lun_sep; - if (port) { - struct t10_alua_lu_gp *lu_gp; - u32 padding, scsi_name_len; - u16 lu_gp_id = 0; - u16 tg_pt_gp_id = 0; - u16 tpgt; - - tpg = port->sep_tpg; - /* - * Relative target port identifer, see spc4r17 - * section 7.7.3.7 - * - * Get the PROTOCOL IDENTIFIER as defined by spc4r17 - * section 7.5.1 Table 362 - */ - buf[off] = - (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); - buf[off++] |= 0x1; /* CODE SET == Binary */ - buf[off] = 0x80; /* Set PIV=1 */ - /* Set ASSOCIATION == target port: 01b */ - buf[off] |= 0x10; - /* DESIGNATOR TYPE == Relative target port identifer */ - buf[off++] |= 0x4; - off++; /* Skip over Reserved */ - buf[off++] = 4; /* DESIGNATOR LENGTH */ - /* Skip over Obsolete field in RTPI payload - * in Table 472 */ - off += 2; - buf[off++] = ((port->sep_rtpi >> 8) & 0xff); - buf[off++] = (port->sep_rtpi & 0xff); - len += 8; /* Header size + Designation descriptor */ - /* - * Target port group identifier, see spc4r17 - * section 7.7.3.8 - * - * Get the PROTOCOL IDENTIFIER as defined by spc4r17 - * section 7.5.1 Table 362 - */ - if (dev->se_sub_dev->t10_alua.alua_type != - SPC3_ALUA_EMULATED) - goto check_scsi_name; - - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) - goto check_lu_gp; - - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; - if (!tg_pt_gp) { - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - goto check_lu_gp; - } - tg_pt_gp_id = tg_pt_gp->tg_pt_gp_id; - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - - buf[off] = - (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); - buf[off++] |= 0x1; /* CODE SET == Binary */ - buf[off] = 0x80; /* Set PIV=1 */ - /* Set ASSOCIATION == target port: 01b */ - buf[off] |= 0x10; - /* DESIGNATOR TYPE == Target port group identifier */ - buf[off++] |= 0x5; - off++; /* Skip over Reserved */ - buf[off++] = 4; /* DESIGNATOR LENGTH */ - off += 2; /* Skip over Reserved Field */ - buf[off++] = ((tg_pt_gp_id >> 8) & 0xff); - buf[off++] = (tg_pt_gp_id & 0xff); - len += 8; /* Header size + Designation descriptor */ - /* - * Logical Unit Group identifier, see spc4r17 - * section 7.7.3.8 - */ -check_lu_gp: - lu_gp_mem = dev->dev_alua_lu_gp_mem; - if (!lu_gp_mem) - goto check_scsi_name; - - spin_lock(&lu_gp_mem->lu_gp_mem_lock); - lu_gp = lu_gp_mem->lu_gp; - if (!lu_gp) { - spin_unlock(&lu_gp_mem->lu_gp_mem_lock); - goto check_scsi_name; - } - lu_gp_id = lu_gp->lu_gp_id; - spin_unlock(&lu_gp_mem->lu_gp_mem_lock); - - buf[off++] |= 0x1; /* CODE SET == Binary */ - /* DESIGNATOR TYPE == Logical Unit Group identifier */ - buf[off++] |= 0x6; - off++; /* Skip over Reserved */ - buf[off++] = 4; /* DESIGNATOR LENGTH */ - off += 2; /* Skip over Reserved Field */ - buf[off++] = ((lu_gp_id >> 8) & 0xff); - buf[off++] = (lu_gp_id & 0xff); - len += 8; /* Header size + Designation descriptor */ - /* - * SCSI name string designator, see spc4r17 - * section 7.7.3.11 - * - * Get the PROTOCOL IDENTIFIER as defined by spc4r17 - * section 7.5.1 Table 362 - */ -check_scsi_name: - scsi_name_len = strlen(tpg->se_tpg_tfo->tpg_get_wwn(tpg)); - /* UTF-8 ",t,0x<16-bit TPGT>" + NULL Terminator */ - scsi_name_len += 10; - /* Check for 4-byte padding */ - padding = ((-scsi_name_len) & 3); - if (padding != 0) - scsi_name_len += padding; - /* Header size + Designation descriptor */ - scsi_name_len += 4; - - buf[off] = - (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); - buf[off++] |= 0x3; /* CODE SET == UTF-8 */ - buf[off] = 0x80; /* Set PIV=1 */ - /* Set ASSOCIATION == target port: 01b */ - buf[off] |= 0x10; - /* DESIGNATOR TYPE == SCSI name string */ - buf[off++] |= 0x8; - off += 2; /* Skip over Reserved and length */ - /* - * SCSI name string identifer containing, $FABRIC_MOD - * dependent information. For LIO-Target and iSCSI - * Target Port, this means ",t,0x in - * UTF-8 encoding. - */ - tpgt = tpg->se_tpg_tfo->tpg_get_tag(tpg); - scsi_name_len = sprintf(&buf[off], "%s,t,0x%04x", - tpg->se_tpg_tfo->tpg_get_wwn(tpg), tpgt); - scsi_name_len += 1 /* Include NULL terminator */; - /* - * The null-terminated, null-padded (see 4.4.2) SCSI - * NAME STRING field contains a UTF-8 format string. - * The number of bytes in the SCSI NAME STRING field - * (i.e., the value in the DESIGNATOR LENGTH field) - * shall be no larger than 256 and shall be a multiple - * of four. - */ - if (padding) - scsi_name_len += padding; - - buf[off-1] = scsi_name_len; - off += scsi_name_len; - /* Header size + Designation descriptor */ - len += (scsi_name_len + 4); - } - buf[2] = ((len >> 8) & 0xff); - buf[3] = (len & 0xff); /* Page Length for VPD 0x83 */ - return 0; -} - -/* Extended INQUIRY Data VPD Page */ -static int -target_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) -{ - buf[3] = 0x3c; - /* Set HEADSUP, ORDSUP, SIMPSUP */ - buf[5] = 0x07; - - /* If WriteCache emulation is enabled, set V_SUP */ - if (cmd->se_dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) - buf[6] = 0x01; - return 0; -} - -/* Block Limits VPD page */ -static int -target_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) -{ - struct se_device *dev = cmd->se_dev; - u32 max_sectors; - int have_tp = 0; - - /* - * Following sbc3r22 section 6.5.3 Block Limits VPD page, when - * emulate_tpu=1 or emulate_tpws=1 we will be expect a - * different page length for Thin Provisioning. - */ - if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws) - have_tp = 1; - - buf[0] = dev->transport->get_device_type(dev); - buf[3] = have_tp ? 0x3c : 0x10; - - /* Set WSNZ to 1 */ - buf[4] = 0x01; - - /* - * Set OPTIMAL TRANSFER LENGTH GRANULARITY - */ - put_unaligned_be16(1, &buf[6]); - - /* - * Set MAXIMUM TRANSFER LENGTH - */ - max_sectors = min(dev->se_sub_dev->se_dev_attrib.fabric_max_sectors, - dev->se_sub_dev->se_dev_attrib.hw_max_sectors); - put_unaligned_be32(max_sectors, &buf[8]); - - /* - * Set OPTIMAL TRANSFER LENGTH - */ - put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.optimal_sectors, &buf[12]); - - /* - * Exit now if we don't support TP. - */ - if (!have_tp) - return 0; - - /* - * Set MAXIMUM UNMAP LBA COUNT - */ - put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count, &buf[20]); - - /* - * Set MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT - */ - put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count, - &buf[24]); - - /* - * Set OPTIMAL UNMAP GRANULARITY - */ - put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.unmap_granularity, &buf[28]); - - /* - * UNMAP GRANULARITY ALIGNMENT - */ - put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment, - &buf[32]); - if (dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment != 0) - buf[32] |= 0x80; /* Set the UGAVALID bit */ - - return 0; -} - -/* Block Device Characteristics VPD page */ -static int -target_emulate_evpd_b1(struct se_cmd *cmd, unsigned char *buf) -{ - struct se_device *dev = cmd->se_dev; - - buf[0] = dev->transport->get_device_type(dev); - buf[3] = 0x3c; - buf[5] = dev->se_sub_dev->se_dev_attrib.is_nonrot ? 1 : 0; - - return 0; -} - -/* Thin Provisioning VPD */ -static int -target_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf) -{ - struct se_device *dev = cmd->se_dev; - - /* - * From sbc3r22 section 6.5.4 Thin Provisioning VPD page: - * - * The PAGE LENGTH field is defined in SPC-4. If the DP bit is set to - * zero, then the page length shall be set to 0004h. If the DP bit - * is set to one, then the page length shall be set to the value - * defined in table 162. - */ - buf[0] = dev->transport->get_device_type(dev); - - /* - * Set Hardcoded length mentioned above for DP=0 - */ - put_unaligned_be16(0x0004, &buf[2]); - - /* - * The THRESHOLD EXPONENT field indicates the threshold set size in - * LBAs as a power of 2 (i.e., the threshold set size is equal to - * 2(threshold exponent)). - * - * Note that this is currently set to 0x00 as mkp says it will be - * changing again. We can enable this once it has settled in T10 - * and is actually used by Linux/SCSI ML code. - */ - buf[4] = 0x00; - - /* - * A TPU bit set to one indicates that the device server supports - * the UNMAP command (see 5.25). A TPU bit set to zero indicates - * that the device server does not support the UNMAP command. - */ - if (dev->se_sub_dev->se_dev_attrib.emulate_tpu != 0) - buf[5] = 0x80; - - /* - * A TPWS bit set to one indicates that the device server supports - * the use of the WRITE SAME (16) command (see 5.42) to unmap LBAs. - * A TPWS bit set to zero indicates that the device server does not - * support the use of the WRITE SAME (16) command to unmap LBAs. - */ - if (dev->se_sub_dev->se_dev_attrib.emulate_tpws != 0) - buf[5] |= 0x40; - - return 0; -} - -static int -target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf); - -static struct { - uint8_t page; - int (*emulate)(struct se_cmd *, unsigned char *); -} evpd_handlers[] = { - { .page = 0x00, .emulate = target_emulate_evpd_00 }, - { .page = 0x80, .emulate = target_emulate_evpd_80 }, - { .page = 0x83, .emulate = target_emulate_evpd_83 }, - { .page = 0x86, .emulate = target_emulate_evpd_86 }, - { .page = 0xb0, .emulate = target_emulate_evpd_b0 }, - { .page = 0xb1, .emulate = target_emulate_evpd_b1 }, - { .page = 0xb2, .emulate = target_emulate_evpd_b2 }, -}; - -/* supported vital product data pages */ -static int -target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) -{ - int p; - - /* - * Only report the INQUIRY EVPD=1 pages after a valid NAA - * Registered Extended LUN WWN has been set via ConfigFS - * during device creation/restart. - */ - if (cmd->se_dev->se_sub_dev->su_dev_flags & - SDF_EMULATED_VPD_UNIT_SERIAL) { - buf[3] = ARRAY_SIZE(evpd_handlers); - for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) - buf[p + 4] = evpd_handlers[p].page; - } - - return 0; -} - -int target_emulate_inquiry(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - struct se_portal_group *tpg = cmd->se_lun->lun_sep->sep_tpg; - unsigned char *buf, *map_buf; - unsigned char *cdb = cmd->t_task_cdb; - int p, ret; - - map_buf = transport_kmap_data_sg(cmd); - /* - * If SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is not set, then we - * know we actually allocated a full page. Otherwise, if the - * data buffer is too small, allocate a temporary buffer so we - * don't have to worry about overruns in all our INQUIRY - * emulation handling. - */ - if (cmd->data_length < SE_INQUIRY_BUF && - (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)) { - buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL); - if (!buf) { - transport_kunmap_data_sg(cmd); - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -ENOMEM; - } - } else { - buf = map_buf; - } - - if (dev == tpg->tpg_virt_lun0.lun_se_dev) - buf[0] = 0x3f; /* Not connected */ - else - buf[0] = dev->transport->get_device_type(dev); - - if (!(cdb[1] & 0x1)) { - if (cdb[2]) { - pr_err("INQUIRY with EVPD==0 but PAGE CODE=%02x\n", - cdb[2]); - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - ret = -EINVAL; - goto out; - } - - ret = target_emulate_inquiry_std(cmd, buf); - goto out; - } - - for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) { - if (cdb[2] == evpd_handlers[p].page) { - buf[1] = cdb[2]; - ret = evpd_handlers[p].emulate(cmd, buf); - goto out; - } - } - - pr_err("Unknown VPD Code: 0x%02x\n", cdb[2]); - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - ret = -EINVAL; - -out: - if (buf != map_buf) { - memcpy(map_buf, buf, cmd->data_length); - kfree(buf); - } - transport_kunmap_data_sg(cmd); - - if (!ret) - target_complete_cmd(cmd, GOOD); - return ret; -} - -int target_emulate_readcapacity(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - unsigned char *buf; - unsigned long long blocks_long = dev->transport->get_blocks(dev); - u32 blocks; - - if (blocks_long >= 0x00000000ffffffff) - blocks = 0xffffffff; - else - blocks = (u32)blocks_long; - - buf = transport_kmap_data_sg(cmd); - - buf[0] = (blocks >> 24) & 0xff; - buf[1] = (blocks >> 16) & 0xff; - buf[2] = (blocks >> 8) & 0xff; - buf[3] = blocks & 0xff; - buf[4] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff; - buf[5] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff; - buf[6] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff; - buf[7] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff; - - transport_kunmap_data_sg(cmd); - - target_complete_cmd(cmd, GOOD); - return 0; -} - -int target_emulate_readcapacity_16(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - unsigned char *buf; - unsigned long long blocks = dev->transport->get_blocks(dev); - - buf = transport_kmap_data_sg(cmd); - - buf[0] = (blocks >> 56) & 0xff; - buf[1] = (blocks >> 48) & 0xff; - buf[2] = (blocks >> 40) & 0xff; - buf[3] = (blocks >> 32) & 0xff; - buf[4] = (blocks >> 24) & 0xff; - buf[5] = (blocks >> 16) & 0xff; - buf[6] = (blocks >> 8) & 0xff; - buf[7] = blocks & 0xff; - buf[8] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff; - buf[9] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff; - buf[10] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff; - buf[11] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff; - /* - * Set Thin Provisioning Enable bit following sbc3r22 in section - * READ CAPACITY (16) byte 14 if emulate_tpu or emulate_tpws is enabled. - */ - if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws) - buf[14] = 0x80; - - transport_kunmap_data_sg(cmd); - - target_complete_cmd(cmd, GOOD); - return 0; -} - -static int -target_modesense_rwrecovery(unsigned char *p) -{ - p[0] = 0x01; - p[1] = 0x0a; - - return 12; -} - -static int -target_modesense_control(struct se_device *dev, unsigned char *p) -{ - p[0] = 0x0a; - p[1] = 0x0a; - p[2] = 2; - /* - * From spc4r23, 7.4.7 Control mode page - * - * The QUEUE ALGORITHM MODIFIER field (see table 368) specifies - * restrictions on the algorithm used for reordering commands - * having the SIMPLE task attribute (see SAM-4). - * - * Table 368 -- QUEUE ALGORITHM MODIFIER field - * Code Description - * 0h Restricted reordering - * 1h Unrestricted reordering allowed - * 2h to 7h Reserved - * 8h to Fh Vendor specific - * - * A value of zero in the QUEUE ALGORITHM MODIFIER field specifies that - * the device server shall order the processing sequence of commands - * having the SIMPLE task attribute such that data integrity is maintained - * for that I_T nexus (i.e., if the transmission of new SCSI transport protocol - * requests is halted at any time, the final value of all data observable - * on the medium shall be the same as if all the commands had been processed - * with the ORDERED task attribute). - * - * A value of one in the QUEUE ALGORITHM MODIFIER field specifies that the - * device server may reorder the processing sequence of commands having the - * SIMPLE task attribute in any manner. Any data integrity exposures related to - * command sequence order shall be explicitly handled by the application client - * through the selection of appropriate ommands and task attributes. - */ - p[3] = (dev->se_sub_dev->se_dev_attrib.emulate_rest_reord == 1) ? 0x00 : 0x10; - /* - * From spc4r17, section 7.4.6 Control mode Page - * - * Unit Attention interlocks control (UN_INTLCK_CTRL) to code 00b - * - * 00b: The logical unit shall clear any unit attention condition - * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION - * status and shall not establish a unit attention condition when a com- - * mand is completed with BUSY, TASK SET FULL, or RESERVATION CONFLICT - * status. - * - * 10b: The logical unit shall not clear any unit attention condition - * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION - * status and shall not establish a unit attention condition when - * a command is completed with BUSY, TASK SET FULL, or RESERVATION - * CONFLICT status. - * - * 11b a The logical unit shall not clear any unit attention condition - * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION - * status and shall establish a unit attention condition for the - * initiator port associated with the I_T nexus on which the BUSY, - * TASK SET FULL, or RESERVATION CONFLICT status is being returned. - * Depending on the status, the additional sense code shall be set to - * PREVIOUS BUSY STATUS, PREVIOUS TASK SET FULL STATUS, or PREVIOUS - * RESERVATION CONFLICT STATUS. Until it is cleared by a REQUEST SENSE - * command, a unit attention condition shall be established only once - * for a BUSY, TASK SET FULL, or RESERVATION CONFLICT status regardless - * to the number of commands completed with one of those status codes. - */ - p[4] = (dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl == 2) ? 0x30 : - (dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl == 1) ? 0x20 : 0x00; - /* - * From spc4r17, section 7.4.6 Control mode Page - * - * Task Aborted Status (TAS) bit set to zero. - * - * A task aborted status (TAS) bit set to zero specifies that aborted - * tasks shall be terminated by the device server without any response - * to the application client. A TAS bit set to one specifies that tasks - * aborted by the actions of an I_T nexus other than the I_T nexus on - * which the command was received shall be completed with TASK ABORTED - * status (see SAM-4). - */ - p[5] = (dev->se_sub_dev->se_dev_attrib.emulate_tas) ? 0x40 : 0x00; - p[8] = 0xff; - p[9] = 0xff; - p[11] = 30; - - return 12; -} - -static int -target_modesense_caching(struct se_device *dev, unsigned char *p) -{ - p[0] = 0x08; - p[1] = 0x12; - if (dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) - p[2] = 0x04; /* Write Cache Enable */ - p[12] = 0x20; /* Disabled Read Ahead */ - - return 20; -} - -static void -target_modesense_write_protect(unsigned char *buf, int type) -{ - /* - * I believe that the WP bit (bit 7) in the mode header is the same for - * all device types.. - */ - switch (type) { - case TYPE_DISK: - case TYPE_TAPE: - default: - buf[0] |= 0x80; /* WP bit */ - break; - } -} - -static void -target_modesense_dpofua(unsigned char *buf, int type) -{ - switch (type) { - case TYPE_DISK: - buf[0] |= 0x10; /* DPOFUA bit */ - break; - default: - break; - } -} - -int target_emulate_modesense(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - char *cdb = cmd->t_task_cdb; - unsigned char *rbuf; - int type = dev->transport->get_device_type(dev); - int ten = (cmd->t_task_cdb[0] == MODE_SENSE_10); - int offset = ten ? 8 : 4; - int length = 0; - unsigned char buf[SE_MODE_PAGE_BUF]; - - memset(buf, 0, SE_MODE_PAGE_BUF); - - switch (cdb[2] & 0x3f) { - case 0x01: - length = target_modesense_rwrecovery(&buf[offset]); - break; - case 0x08: - length = target_modesense_caching(dev, &buf[offset]); - break; - case 0x0a: - length = target_modesense_control(dev, &buf[offset]); - break; - case 0x3f: - length = target_modesense_rwrecovery(&buf[offset]); - length += target_modesense_caching(dev, &buf[offset+length]); - length += target_modesense_control(dev, &buf[offset+length]); - break; - default: - pr_err("MODE SENSE: unimplemented page/subpage: 0x%02x/0x%02x\n", - cdb[2] & 0x3f, cdb[3]); - cmd->scsi_sense_reason = TCM_UNKNOWN_MODE_PAGE; - return -EINVAL; - } - offset += length; - - if (ten) { - offset -= 2; - buf[0] = (offset >> 8) & 0xff; - buf[1] = offset & 0xff; - - if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) || - (cmd->se_deve && - (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) - target_modesense_write_protect(&buf[3], type); - - if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) && - (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0)) - target_modesense_dpofua(&buf[3], type); - - if ((offset + 2) > cmd->data_length) - offset = cmd->data_length; - - } else { - offset -= 1; - buf[0] = offset & 0xff; - - if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) || - (cmd->se_deve && - (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) - target_modesense_write_protect(&buf[2], type); - - if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) && - (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0)) - target_modesense_dpofua(&buf[2], type); - - if ((offset + 1) > cmd->data_length) - offset = cmd->data_length; - } - - rbuf = transport_kmap_data_sg(cmd); - memcpy(rbuf, buf, offset); - transport_kunmap_data_sg(cmd); - - target_complete_cmd(cmd, GOOD); - return 0; -} - -int target_emulate_request_sense(struct se_cmd *cmd) -{ - unsigned char *cdb = cmd->t_task_cdb; - unsigned char *buf; - u8 ua_asc = 0, ua_ascq = 0; - int err = 0; - - if (cdb[1] & 0x01) { - pr_err("REQUEST_SENSE description emulation not" - " supported\n"); - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -ENOSYS; - } - - buf = transport_kmap_data_sg(cmd); - - if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) { - /* - * CURRENT ERROR, UNIT ATTENTION - */ - buf[0] = 0x70; - buf[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION; - - if (cmd->data_length < 18) { - buf[7] = 0x00; - err = -EINVAL; - goto end; - } - /* - * The Additional Sense Code (ASC) from the UNIT ATTENTION - */ - buf[SPC_ASC_KEY_OFFSET] = ua_asc; - buf[SPC_ASCQ_KEY_OFFSET] = ua_ascq; - buf[7] = 0x0A; - } else { - /* - * CURRENT ERROR, NO SENSE - */ - buf[0] = 0x70; - buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE; - - if (cmd->data_length < 18) { - buf[7] = 0x00; - err = -EINVAL; - goto end; - } - /* - * NO ADDITIONAL SENSE INFORMATION - */ - buf[SPC_ASC_KEY_OFFSET] = 0x00; - buf[7] = 0x0A; - } - -end: - transport_kunmap_data_sg(cmd); - target_complete_cmd(cmd, GOOD); - return 0; -} - -/* - * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. - * Note this is not used for TCM/pSCSI passthrough - */ -int target_emulate_unmap(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - unsigned char *buf, *ptr = NULL; - unsigned char *cdb = &cmd->t_task_cdb[0]; - sector_t lba; - unsigned int size = cmd->data_length, range; - int ret = 0, offset; - unsigned short dl, bd_dl; - - if (!dev->transport->do_discard) { - pr_err("UNMAP emulation not supported for: %s\n", - dev->transport->name); - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; - return -ENOSYS; - } - - /* First UNMAP block descriptor starts at 8 byte offset */ - offset = 8; - size -= 8; - dl = get_unaligned_be16(&cdb[0]); - bd_dl = get_unaligned_be16(&cdb[2]); - - buf = transport_kmap_data_sg(cmd); - - ptr = &buf[offset]; - pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu" - " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr); - - while (size) { - lba = get_unaligned_be64(&ptr[0]); - range = get_unaligned_be32(&ptr[8]); - pr_debug("UNMAP: Using lba: %llu and range: %u\n", - (unsigned long long)lba, range); - - ret = dev->transport->do_discard(dev, lba, range); - if (ret < 0) { - pr_err("blkdev_issue_discard() failed: %d\n", - ret); - goto err; - } - - ptr += 16; - size -= 16; - } - -err: - transport_kunmap_data_sg(cmd); - if (!ret) - target_complete_cmd(cmd, GOOD); - return ret; -} - -/* - * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. - * Note this is not used for TCM/pSCSI passthrough - */ -int target_emulate_write_same(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - sector_t range; - sector_t lba = cmd->t_task_lba; - u32 num_blocks; - int ret; - - if (!dev->transport->do_discard) { - pr_err("WRITE_SAME emulation not supported" - " for: %s\n", dev->transport->name); - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; - return -ENOSYS; - } - - if (cmd->t_task_cdb[0] == WRITE_SAME) - num_blocks = get_unaligned_be16(&cmd->t_task_cdb[7]); - else if (cmd->t_task_cdb[0] == WRITE_SAME_16) - num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]); - else /* WRITE_SAME_32 via VARIABLE_LENGTH_CMD */ - num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]); - - /* - * Use the explicit range when non zero is supplied, otherwise calculate - * the remaining range based on ->get_blocks() - starting LBA. - */ - if (num_blocks != 0) - range = num_blocks; - else - range = (dev->transport->get_blocks(dev) - lba) + 1; - - pr_debug("WRITE_SAME UNMAP: LBA: %llu Range: %llu\n", - (unsigned long long)lba, (unsigned long long)range); - - ret = dev->transport->do_discard(dev, lba, range); - if (ret < 0) { - pr_debug("blkdev_issue_discard() failed for WRITE_SAME\n"); - return ret; - } - - target_complete_cmd(cmd, GOOD); - return 0; -} - -int target_emulate_synchronize_cache(struct se_cmd *cmd) -{ - if (!cmd->se_dev->transport->do_sync_cache) { - pr_err("SYNCHRONIZE_CACHE emulation not supported" - " for: %s\n", cmd->se_dev->transport->name); - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; - return -ENOSYS; - } - - cmd->se_dev->transport->do_sync_cache(cmd); - return 0; -} - -int target_emulate_noop(struct se_cmd *cmd) -{ - target_complete_cmd(cmd, GOOD); - return 0; -} diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 165e824..031c288 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -4,17 +4,6 @@ /* target_core_alua.c */ extern struct t10_alua_lu_gp *default_lu_gp; -/* target_core_cdb.c */ -int target_emulate_inquiry(struct se_cmd *cmd); -int target_emulate_readcapacity(struct se_cmd *cmd); -int target_emulate_readcapacity_16(struct se_cmd *cmd); -int target_emulate_modesense(struct se_cmd *cmd); -int target_emulate_request_sense(struct se_cmd *cmd); -int target_emulate_unmap(struct se_cmd *cmd); -int target_emulate_write_same(struct se_cmd *cmd); -int target_emulate_synchronize_cache(struct se_cmd *cmd); -int target_emulate_noop(struct se_cmd *cmd); - /* target_core_device.c */ struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16); int core_free_device_list_for_node(struct se_node_acl *, @@ -116,6 +105,7 @@ int transport_dump_vpd_ident(struct t10_vpd *, unsigned char *, int); bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags); int transport_clear_lun_from_sessions(struct se_lun *); void transport_send_task_abort(struct se_cmd *); +int target_cmd_size_check(struct se_cmd *cmd, unsigned int size); /* target_core_stat.c */ void target_stat_setup_dev_default_groups(struct se_subsystem_dev *); diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 378da24..099c59d 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -1022,470 +1022,53 @@ fail: return -ENOMEM; } -static inline u32 pscsi_get_sectors_6( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) +static int pscsi_parse_cdb(struct se_cmd *cmd) { - struct se_device *dev = cmd->se_dev; - - /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 8-bit sector value. - */ - if (!dev) - goto type_disk; - - /* - * Use 24-bit allocation length for TYPE_TAPE. - */ - if (dev->transport->get_device_type(dev) == TYPE_TAPE) - return (u32)(cdb[2] << 16) + (cdb[3] << 8) + cdb[4]; - - /* - * Everything else assume TYPE_DISK Sector CDB location. - * Use 8-bit sector value. SBC-3 says: - * - * A TRANSFER LENGTH field set to zero specifies that 256 - * logical blocks shall be written. Any other value - * specifies the number of logical blocks that shall be - * written. - */ -type_disk: - return cdb[4] ? : 256; -} - -static inline u32 pscsi_get_sectors_10( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) -{ - struct se_device *dev = cmd->se_dev; - - /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 16-bit sector value. - */ - if (!dev) - goto type_disk; - - /* - * XXX_10 is not defined in SSC, throw an exception - */ - if (dev->transport->get_device_type(dev) == TYPE_TAPE) { - *ret = -EINVAL; - return 0; - } - - /* - * Everything else assume TYPE_DISK Sector CDB location. - * Use 16-bit sector value. - */ -type_disk: - return (u32)(cdb[7] << 8) + cdb[8]; -} - -static inline u32 pscsi_get_sectors_12( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) -{ - struct se_device *dev = cmd->se_dev; - - /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 32-bit sector value. - */ - if (!dev) - goto type_disk; + unsigned char *cdb = cmd->t_task_cdb; + unsigned int dummy_size; + int ret; - /* - * XXX_12 is not defined in SSC, throw an exception - */ - if (dev->transport->get_device_type(dev) == TYPE_TAPE) { - *ret = -EINVAL; - return 0; + if (cmd->se_cmd_flags & SCF_BIDI) { + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + return -EINVAL; } /* - * Everything else assume TYPE_DISK Sector CDB location. - * Use 32-bit sector value. + * For REPORT LUNS we always need to emulate the respone, and for everything + * related to persistent reservations and ALUA we might optionally use our + * handlers before passing on the command to the physical hardware. */ -type_disk: - return (u32)(cdb[6] << 24) + (cdb[7] << 16) + (cdb[8] << 8) + cdb[9]; -} - -static inline u32 pscsi_get_sectors_16( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) -{ - struct se_device *dev = cmd->se_dev; - - /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 32-bit sector value. - */ - if (!dev) - goto type_disk; - - /* - * Use 24-bit allocation length for TYPE_TAPE. - */ - if (dev->transport->get_device_type(dev) == TYPE_TAPE) - return (u32)(cdb[12] << 16) + (cdb[13] << 8) + cdb[14]; - -type_disk: - return (u32)(cdb[10] << 24) + (cdb[11] << 16) + - (cdb[12] << 8) + cdb[13]; -} - -/* - * Used for VARIABLE_LENGTH_CDB WRITE_32 and READ_32 variants - */ -static inline u32 pscsi_get_sectors_32( - unsigned char *cdb, - struct se_cmd *cmd, - int *ret) -{ - /* - * Assume TYPE_DISK for non struct se_device objects. - * Use 32-bit sector value. - */ - return (u32)(cdb[28] << 24) + (cdb[29] << 16) + - (cdb[30] << 8) + cdb[31]; - -} - -static inline u32 pscsi_get_lba_21(unsigned char *cdb) -{ - return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3]; -} - -static inline u32 pscsi_get_lba_32(unsigned char *cdb) -{ - return (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; -} - -static inline unsigned long long pscsi_get_lba_64(unsigned char *cdb) -{ - unsigned int __v1, __v2; - - __v1 = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - __v2 = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - - return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; -} - -/* - * For VARIABLE_LENGTH_CDB w/ 32 byte extended CDBs - */ -static inline unsigned long long pscsi_get_lba_64_ext(unsigned char *cdb) -{ - unsigned int __v1, __v2; - - __v1 = (cdb[12] << 24) | (cdb[13] << 16) | (cdb[14] << 8) | cdb[15]; - __v2 = (cdb[16] << 24) | (cdb[17] << 16) | (cdb[18] << 8) | cdb[19]; - - return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; -} - - -static inline u32 pscsi_get_size( - u32 sectors, - unsigned char *cdb, - struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - - if (dev->transport->get_device_type(dev) == TYPE_TAPE) { - if (cdb[1] & 1) { /* sectors */ - return dev->se_sub_dev->se_dev_attrib.block_size * sectors; - } else /* bytes */ - return sectors; - } - - pr_debug("Returning block_size: %u, sectors: %u == %u for" - " %s object\n", dev->se_sub_dev->se_dev_attrib.block_size, - sectors, dev->se_sub_dev->se_dev_attrib.block_size * sectors, - dev->transport->name); - - return dev->se_sub_dev->se_dev_attrib.block_size * sectors; -} - -static int pscsi_parse_cdb(struct se_cmd *cmd, unsigned int *size) -{ - struct se_device *dev = cmd->se_dev; - struct se_subsystem_dev *su_dev = dev->se_sub_dev; - unsigned char *cdb = cmd->t_task_cdb; - int sector_ret = 0; - u32 sectors = 0; - u16 service_action; - int ret; - - if (cmd->se_cmd_flags & SCF_BIDI) - goto out_unsupported_cdb; - switch (cdb[0]) { - case READ_6: - sectors = pscsi_get_sectors_6(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - *size = pscsi_get_size(sectors, cdb, cmd); - cmd->t_task_lba = pscsi_get_lba_21(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + case REPORT_LUNS: + case PERSISTENT_RESERVE_IN: + case PERSISTENT_RESERVE_OUT: + case RELEASE: + case RELEASE_10: + case RESERVE: + case RESERVE_10: + ret = spc_parse_cdb(cmd, &dummy_size); + if (ret) + return ret; break; + case READ_6: case READ_10: - sectors = pscsi_get_sectors_10(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - *size = pscsi_get_size(sectors, cdb, cmd); - cmd->t_task_lba = pscsi_get_lba_32(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; case READ_12: - sectors = pscsi_get_sectors_12(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - *size = pscsi_get_size(sectors, cdb, cmd); - cmd->t_task_lba = pscsi_get_lba_32(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; case READ_16: - sectors = pscsi_get_sectors_16(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - *size = pscsi_get_size(sectors, cdb, cmd); - cmd->t_task_lba = pscsi_get_lba_64(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; case WRITE_6: - sectors = pscsi_get_sectors_6(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - *size = pscsi_get_size(sectors, cdb, cmd); - cmd->t_task_lba = pscsi_get_lba_21(cdb); - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; case WRITE_10: - case WRITE_VERIFY: - sectors = pscsi_get_sectors_10(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - *size = pscsi_get_size(sectors, cdb, cmd); - cmd->t_task_lba = pscsi_get_lba_32(cdb); - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; case WRITE_12: - sectors = pscsi_get_sectors_12(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - *size = pscsi_get_size(sectors, cdb, cmd); - cmd->t_task_lba = pscsi_get_lba_32(cdb); - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; case WRITE_16: - sectors = pscsi_get_sectors_16(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - *size = pscsi_get_size(sectors, cdb, cmd); - cmd->t_task_lba = pscsi_get_lba_64(cdb); - if (cdb[1] & 0x8) - cmd->se_cmd_flags |= SCF_FUA; + case WRITE_VERIFY: cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; break; - case VARIABLE_LENGTH_CMD: - service_action = get_unaligned_be16(&cdb[8]); - switch (service_action) { - case WRITE_SAME_32: - sectors = pscsi_get_sectors_32(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - - if (!sectors) { - pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not" - " supported\n"); - goto out_invalid_cdb_field; - } - - *size = pscsi_get_size(1, cdb, cmd); - cmd->t_task_lba = get_unaligned_be64(&cdb[12]); - break; - default: - pr_err("VARIABLE_LENGTH_CMD service action" - " 0x%04x not supported\n", service_action); - goto out_unsupported_cdb; - } - break; - case GPCMD_READ_BUFFER_CAPACITY: - case GPCMD_SEND_OPC: - *size = (cdb[7] << 8) + cdb[8]; - break; - case READ_BLOCK_LIMITS: - *size = READ_BLOCK_LEN; - break; - case GPCMD_GET_CONFIGURATION: - case GPCMD_READ_FORMAT_CAPACITIES: - case GPCMD_READ_DISC_INFO: - case GPCMD_READ_TRACK_RZONE_INFO: - *size = (cdb[7] << 8) + cdb[8]; - break; - case GPCMD_MECHANISM_STATUS: - case GPCMD_READ_DVD_STRUCTURE: - *size = (cdb[8] << 8) + cdb[9]; - break; - case READ_POSITION: - *size = READ_POSITION_LEN; - break; - case READ_BUFFER: - *size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; - break; - case READ_CAPACITY: - *size = READ_CAP_LEN; - break; - case READ_MEDIA_SERIAL_NUMBER: - case SERVICE_ACTION_IN: - case ACCESS_CONTROL_IN: - case ACCESS_CONTROL_OUT: - *size = (cdb[10] << 24) | (cdb[11] << 16) | - (cdb[12] << 8) | cdb[13]; - break; - case READ_TOC: - *size = cdb[8]; - break; - case READ_ELEMENT_STATUS: - *size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9]; - break; - case SYNCHRONIZE_CACHE: - case SYNCHRONIZE_CACHE_16: - /* - * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE - */ - if (cdb[0] == SYNCHRONIZE_CACHE) { - sectors = pscsi_get_sectors_10(cdb, cmd, §or_ret); - cmd->t_task_lba = pscsi_get_lba_32(cdb); - } else { - sectors = pscsi_get_sectors_16(cdb, cmd, §or_ret); - cmd->t_task_lba = pscsi_get_lba_64(cdb); - } - if (sector_ret) - goto out_unsupported_cdb; - - *size = pscsi_get_size(sectors, cdb, cmd); - break; - case UNMAP: - *size = get_unaligned_be16(&cdb[7]); - break; - case WRITE_SAME_16: - sectors = pscsi_get_sectors_16(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - - if (!sectors) { - pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); - goto out_invalid_cdb_field; - } - - *size = pscsi_get_size(1, cdb, cmd); - cmd->t_task_lba = get_unaligned_be64(&cdb[2]); - break; - case WRITE_SAME: - sectors = pscsi_get_sectors_10(cdb, cmd, §or_ret); - if (sector_ret) - goto out_unsupported_cdb; - - if (!sectors) { - pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); - goto out_invalid_cdb_field; - } - - *size = pscsi_get_size(1, cdb, cmd); - cmd->t_task_lba = get_unaligned_be32(&cdb[2]); - break; - case ALLOW_MEDIUM_REMOVAL: - case ERASE: - case REZERO_UNIT: - case SEEK_10: - case SPACE: - case START_STOP: - case VERIFY: - case WRITE_FILEMARKS: - case GPCMD_CLOSE_TRACK: - case INITIALIZE_ELEMENT_STATUS: - case GPCMD_LOAD_UNLOAD: - case GPCMD_SET_SPEED: - case MOVE_MEDIUM: - *size = 0; - break; - case GET_EVENT_STATUS_NOTIFICATION: - *size = (cdb[7] << 8) | cdb[8]; - break; - case ATA_16: - switch (cdb[2] & 0x3) { /* T_LENGTH */ - case 0x0: - sectors = 0; - break; - case 0x1: - sectors = (((cdb[1] & 0x1) ? cdb[3] : 0) << 8) | cdb[4]; - break; - case 0x2: - sectors = (((cdb[1] & 0x1) ? cdb[5] : 0) << 8) | cdb[6]; - break; - case 0x3: - pr_err("T_LENGTH=0x3 not supported for ATA_16\n"); - goto out_invalid_cdb_field; - } - - /* BYTE_BLOCK */ - if (cdb[2] & 0x4) { - /* BLOCK T_TYPE: 512 or sector */ - *size = sectors * ((cdb[2] & 0x10) ? - dev->se_sub_dev->se_dev_attrib.block_size : 512); - } else { - /* BYTE */ - *size = sectors; - } - break; default: - ret = spc_parse_cdb(cmd, size, true); - if (ret) - return ret; - } - - if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { - if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) { - printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" - " big sectors %u exceeds fabric_max_sectors:" - " %u\n", cdb[0], sectors, - su_dev->se_dev_attrib.fabric_max_sectors); - goto out_invalid_cdb_field; - } - if (sectors > su_dev->se_dev_attrib.hw_max_sectors) { - printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" - " big sectors %u exceeds backend hw_max_sectors:" - " %u\n", cdb[0], sectors, - su_dev->se_dev_attrib.hw_max_sectors); - goto out_invalid_cdb_field; - } + break; } return 0; - -out_unsupported_cdb: - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; - return -EINVAL; -out_invalid_cdb_field: - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -EINVAL; } - static int pscsi_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, enum dma_data_direction data_direction) { diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 9d1ca38..a5bd0c0 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -37,6 +37,192 @@ #include "target_core_ua.h" +static int sbc_emulate_readcapacity(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + unsigned char *buf; + unsigned long long blocks_long = dev->transport->get_blocks(dev); + u32 blocks; + + if (blocks_long >= 0x00000000ffffffff) + blocks = 0xffffffff; + else + blocks = (u32)blocks_long; + + buf = transport_kmap_data_sg(cmd); + + buf[0] = (blocks >> 24) & 0xff; + buf[1] = (blocks >> 16) & 0xff; + buf[2] = (blocks >> 8) & 0xff; + buf[3] = blocks & 0xff; + buf[4] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff; + buf[5] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff; + buf[6] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff; + buf[7] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff; + + transport_kunmap_data_sg(cmd); + + target_complete_cmd(cmd, GOOD); + return 0; +} + +static int sbc_emulate_readcapacity_16(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + unsigned char *buf; + unsigned long long blocks = dev->transport->get_blocks(dev); + + buf = transport_kmap_data_sg(cmd); + + buf[0] = (blocks >> 56) & 0xff; + buf[1] = (blocks >> 48) & 0xff; + buf[2] = (blocks >> 40) & 0xff; + buf[3] = (blocks >> 32) & 0xff; + buf[4] = (blocks >> 24) & 0xff; + buf[5] = (blocks >> 16) & 0xff; + buf[6] = (blocks >> 8) & 0xff; + buf[7] = blocks & 0xff; + buf[8] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff; + buf[9] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff; + buf[10] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff; + buf[11] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff; + /* + * Set Thin Provisioning Enable bit following sbc3r22 in section + * READ CAPACITY (16) byte 14 if emulate_tpu or emulate_tpws is enabled. + */ + if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws) + buf[14] = 0x80; + + transport_kunmap_data_sg(cmd); + + target_complete_cmd(cmd, GOOD); + return 0; +} + +/* + * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. + * Note this is not used for TCM/pSCSI passthrough + */ +static int sbc_emulate_unmap(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + unsigned char *buf, *ptr = NULL; + unsigned char *cdb = &cmd->t_task_cdb[0]; + sector_t lba; + unsigned int size = cmd->data_length, range; + int ret = 0, offset; + unsigned short dl, bd_dl; + + if (!dev->transport->do_discard) { + pr_err("UNMAP emulation not supported for: %s\n", + dev->transport->name); + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + return -ENOSYS; + } + + /* First UNMAP block descriptor starts at 8 byte offset */ + offset = 8; + size -= 8; + dl = get_unaligned_be16(&cdb[0]); + bd_dl = get_unaligned_be16(&cdb[2]); + + buf = transport_kmap_data_sg(cmd); + + ptr = &buf[offset]; + pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu" + " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr); + + while (size) { + lba = get_unaligned_be64(&ptr[0]); + range = get_unaligned_be32(&ptr[8]); + pr_debug("UNMAP: Using lba: %llu and range: %u\n", + (unsigned long long)lba, range); + + ret = dev->transport->do_discard(dev, lba, range); + if (ret < 0) { + pr_err("blkdev_issue_discard() failed: %d\n", + ret); + goto err; + } + + ptr += 16; + size -= 16; + } + +err: + transport_kunmap_data_sg(cmd); + if (!ret) + target_complete_cmd(cmd, GOOD); + return ret; +} + +/* + * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. + * Note this is not used for TCM/pSCSI passthrough + */ +static int sbc_emulate_write_same(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + sector_t range; + sector_t lba = cmd->t_task_lba; + u32 num_blocks; + int ret; + + if (!dev->transport->do_discard) { + pr_err("WRITE_SAME emulation not supported" + " for: %s\n", dev->transport->name); + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + return -ENOSYS; + } + + if (cmd->t_task_cdb[0] == WRITE_SAME) + num_blocks = get_unaligned_be16(&cmd->t_task_cdb[7]); + else if (cmd->t_task_cdb[0] == WRITE_SAME_16) + num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]); + else /* WRITE_SAME_32 via VARIABLE_LENGTH_CMD */ + num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]); + + /* + * Use the explicit range when non zero is supplied, otherwise calculate + * the remaining range based on ->get_blocks() - starting LBA. + */ + if (num_blocks != 0) + range = num_blocks; + else + range = (dev->transport->get_blocks(dev) - lba) + 1; + + pr_debug("WRITE_SAME UNMAP: LBA: %llu Range: %llu\n", + (unsigned long long)lba, (unsigned long long)range); + + ret = dev->transport->do_discard(dev, lba, range); + if (ret < 0) { + pr_debug("blkdev_issue_discard() failed for WRITE_SAME\n"); + return ret; + } + + target_complete_cmd(cmd, GOOD); + return 0; +} + +static int sbc_emulate_synchronize_cache(struct se_cmd *cmd) +{ + if (!cmd->se_dev->transport->do_sync_cache) { + pr_err("SYNCHRONIZE_CACHE emulation not supported" + " for: %s\n", cmd->se_dev->transport->name); + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + return -ENOSYS; + } + + cmd->se_dev->transport->do_sync_cache(cmd); + return 0; +} + +static int sbc_emulate_verify(struct se_cmd *cmd) +{ + target_complete_cmd(cmd, GOOD); + return 0; +} + static inline u32 sbc_get_size(struct se_cmd *cmd, u32 sectors) { return cmd->se_dev->se_sub_dev->se_dev_attrib.block_size * sectors; @@ -209,11 +395,12 @@ out: kfree(buf); } -int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size) +int sbc_parse_cdb(struct se_cmd *cmd) { struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; struct se_device *dev = cmd->se_dev; unsigned char *cdb = cmd->t_task_cdb; + unsigned int size; u32 sectors = 0; int ret; @@ -311,12 +498,12 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size) goto out_invalid_cdb_field; } - *size = sbc_get_size(cmd, 1); + size = sbc_get_size(cmd, 1); cmd->t_task_lba = get_unaligned_be64(&cdb[12]); if (sbc_write_same_supported(dev, &cdb[10]) < 0) goto out_unsupported_cdb; - cmd->execute_cmd = target_emulate_write_same; + cmd->execute_cmd = sbc_emulate_write_same; break; default: pr_err("VARIABLE_LENGTH_CMD service action" @@ -326,20 +513,20 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size) break; } case READ_CAPACITY: - *size = READ_CAP_LEN; - cmd->execute_cmd = target_emulate_readcapacity; + size = READ_CAP_LEN; + cmd->execute_cmd = sbc_emulate_readcapacity; break; case SERVICE_ACTION_IN: switch (cmd->t_task_cdb[1] & 0x1f) { case SAI_READ_CAPACITY_16: - cmd->execute_cmd = target_emulate_readcapacity_16; + cmd->execute_cmd = sbc_emulate_readcapacity_16; break; default: pr_err("Unsupported SA: 0x%02x\n", cmd->t_task_cdb[1] & 0x1f); goto out_invalid_cdb_field; } - *size = (cdb[10] << 24) | (cdb[11] << 16) | + size = (cdb[10] << 24) | (cdb[11] << 16) | (cdb[12] << 8) | cdb[13]; break; case SYNCHRONIZE_CACHE: @@ -355,7 +542,7 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size) cmd->t_task_lba = transport_lba_64(cdb); } - *size = sbc_get_size(cmd, sectors); + size = sbc_get_size(cmd, sectors); /* * Check to ensure that LBA + Range does not exceed past end of @@ -365,11 +552,11 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size) if (sbc_check_valid_sectors(cmd) < 0) goto out_invalid_cdb_field; } - cmd->execute_cmd = target_emulate_synchronize_cache; + cmd->execute_cmd = sbc_emulate_synchronize_cache; break; case UNMAP: - *size = get_unaligned_be16(&cdb[7]); - cmd->execute_cmd = target_emulate_unmap; + size = get_unaligned_be16(&cdb[7]); + cmd->execute_cmd = sbc_emulate_unmap; break; case WRITE_SAME_16: sectors = transport_get_sectors_16(cdb); @@ -378,12 +565,12 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size) goto out_invalid_cdb_field; } - *size = sbc_get_size(cmd, 1); + size = sbc_get_size(cmd, 1); cmd->t_task_lba = get_unaligned_be64(&cdb[2]); if (sbc_write_same_supported(dev, &cdb[1]) < 0) goto out_unsupported_cdb; - cmd->execute_cmd = target_emulate_write_same; + cmd->execute_cmd = sbc_emulate_write_same; break; case WRITE_SAME: sectors = transport_get_sectors_10(cdb); @@ -392,7 +579,7 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size) goto out_invalid_cdb_field; } - *size = sbc_get_size(cmd, 1); + size = sbc_get_size(cmd, 1); cmd->t_task_lba = get_unaligned_be32(&cdb[2]); /* @@ -401,14 +588,14 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size) */ if (sbc_write_same_supported(dev, &cdb[1]) < 0) goto out_unsupported_cdb; - cmd->execute_cmd = target_emulate_write_same; + cmd->execute_cmd = sbc_emulate_write_same; break; case VERIFY: - *size = 0; - cmd->execute_cmd = target_emulate_noop; + size = 0; + cmd->execute_cmd = sbc_emulate_verify; break; default: - ret = spc_parse_cdb(cmd, size, false); + ret = spc_parse_cdb(cmd, &size); if (ret) return ret; } @@ -418,6 +605,8 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size) goto out_unsupported_cdb; if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { + unsigned long long end_lba; + if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) { printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" " big sectors %u exceeds fabric_max_sectors:" @@ -433,9 +622,21 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size) goto out_invalid_cdb_field; } - *size = sbc_get_size(cmd, sectors); + end_lba = dev->transport->get_blocks(dev) + 1; + if (cmd->t_task_lba + sectors > end_lba) { + pr_err("cmd exceeds last lba %llu " + "(lba %llu, sectors %u)\n", + end_lba, cmd->t_task_lba, sectors); + goto out_invalid_cdb_field; + } + + size = sbc_get_size(cmd, sectors); } + ret = target_cmd_size_check(cmd, size); + if (ret < 0) + return ret; + return 0; out_unsupported_cdb: diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 156291f..96dcb57 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -39,7 +39,906 @@ #include "target_core_ua.h" -int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough) +static void spc_fill_alua_data(struct se_port *port, unsigned char *buf) +{ + struct t10_alua_tg_pt_gp *tg_pt_gp; + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; + + /* + * Set SCCS for MAINTENANCE_IN + REPORT_TARGET_PORT_GROUPS. + */ + buf[5] = 0x80; + + /* + * Set TPGS field for explict and/or implict ALUA access type + * and opteration. + * + * See spc4r17 section 6.4.2 Table 135 + */ + if (!port) + return; + tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; + if (!tg_pt_gp_mem) + return; + + spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + if (tg_pt_gp) + buf[5] |= tg_pt_gp->tg_pt_gp_alua_access_type; + spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); +} + +static int spc_emulate_inquiry_std(struct se_cmd *cmd, char *buf) +{ + struct se_lun *lun = cmd->se_lun; + struct se_device *dev = cmd->se_dev; + + /* Set RMB (removable media) for tape devices */ + if (dev->transport->get_device_type(dev) == TYPE_TAPE) + buf[1] = 0x80; + + buf[2] = dev->transport->get_device_rev(dev); + + /* + * NORMACA and HISUP = 0, RESPONSE DATA FORMAT = 2 + * + * SPC4 says: + * A RESPONSE DATA FORMAT field set to 2h indicates that the + * standard INQUIRY data is in the format defined in this + * standard. Response data format values less than 2h are + * obsolete. Response data format values greater than 2h are + * reserved. + */ + buf[3] = 2; + + /* + * Enable SCCS and TPGS fields for Emulated ALUA + */ + if (dev->se_sub_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) + spc_fill_alua_data(lun->lun_sep, buf); + + buf[7] = 0x2; /* CmdQue=1 */ + + snprintf(&buf[8], 8, "LIO-ORG"); + snprintf(&buf[16], 16, "%s", dev->se_sub_dev->t10_wwn.model); + snprintf(&buf[32], 4, "%s", dev->se_sub_dev->t10_wwn.revision); + buf[4] = 31; /* Set additional length to 31 */ + + return 0; +} + +/* unit serial number */ +static int spc_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) +{ + struct se_device *dev = cmd->se_dev; + u16 len = 0; + + if (dev->se_sub_dev->su_dev_flags & + SDF_EMULATED_VPD_UNIT_SERIAL) { + u32 unit_serial_len; + + unit_serial_len = strlen(dev->se_sub_dev->t10_wwn.unit_serial); + unit_serial_len++; /* For NULL Terminator */ + + len += sprintf(&buf[4], "%s", + dev->se_sub_dev->t10_wwn.unit_serial); + len++; /* Extra Byte for NULL Terminator */ + buf[3] = len; + } + return 0; +} + +static void spc_parse_naa_6h_vendor_specific(struct se_device *dev, + unsigned char *buf) +{ + unsigned char *p = &dev->se_sub_dev->t10_wwn.unit_serial[0]; + int cnt; + bool next = true; + + /* + * Generate up to 36 bits of VENDOR SPECIFIC IDENTIFIER starting on + * byte 3 bit 3-0 for NAA IEEE Registered Extended DESIGNATOR field + * format, followed by 64 bits of VENDOR SPECIFIC IDENTIFIER EXTENSION + * to complete the payload. These are based from VPD=0x80 PRODUCT SERIAL + * NUMBER set via vpd_unit_serial in target_core_configfs.c to ensure + * per device uniqeness. + */ + for (cnt = 0; *p && cnt < 13; p++) { + int val = hex_to_bin(*p); + + if (val < 0) + continue; + + if (next) { + next = false; + buf[cnt++] |= val; + } else { + next = true; + buf[cnt] = val << 4; + } + } +} + +/* + * Device identification VPD, for a complete list of + * DESIGNATOR TYPEs see spc4r17 Table 459. + */ +static int spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) +{ + struct se_device *dev = cmd->se_dev; + struct se_lun *lun = cmd->se_lun; + struct se_port *port = NULL; + struct se_portal_group *tpg = NULL; + struct t10_alua_lu_gp_member *lu_gp_mem; + struct t10_alua_tg_pt_gp *tg_pt_gp; + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; + unsigned char *prod = &dev->se_sub_dev->t10_wwn.model[0]; + u32 prod_len; + u32 unit_serial_len, off = 0; + u16 len = 0, id_len; + + off = 4; + + /* + * NAA IEEE Registered Extended Assigned designator format, see + * spc4r17 section 7.7.3.6.5 + * + * We depend upon a target_core_mod/ConfigFS provided + * /sys/kernel/config/target/core/$HBA/$DEV/wwn/vpd_unit_serial + * value in order to return the NAA id. + */ + if (!(dev->se_sub_dev->su_dev_flags & SDF_EMULATED_VPD_UNIT_SERIAL)) + goto check_t10_vend_desc; + + /* CODE SET == Binary */ + buf[off++] = 0x1; + + /* Set ASSOCIATION == addressed logical unit: 0)b */ + buf[off] = 0x00; + + /* Identifier/Designator type == NAA identifier */ + buf[off++] |= 0x3; + off++; + + /* Identifier/Designator length */ + buf[off++] = 0x10; + + /* + * Start NAA IEEE Registered Extended Identifier/Designator + */ + buf[off++] = (0x6 << 4); + + /* + * Use OpenFabrics IEEE Company ID: 00 14 05 + */ + buf[off++] = 0x01; + buf[off++] = 0x40; + buf[off] = (0x5 << 4); + + /* + * Return ConfigFS Unit Serial Number information for + * VENDOR_SPECIFIC_IDENTIFIER and + * VENDOR_SPECIFIC_IDENTIFIER_EXTENTION + */ + spc_parse_naa_6h_vendor_specific(dev, &buf[off]); + + len = 20; + off = (len + 4); + +check_t10_vend_desc: + /* + * T10 Vendor Identifier Page, see spc4r17 section 7.7.3.4 + */ + id_len = 8; /* For Vendor field */ + prod_len = 4; /* For VPD Header */ + prod_len += 8; /* For Vendor field */ + prod_len += strlen(prod); + prod_len++; /* For : */ + + if (dev->se_sub_dev->su_dev_flags & + SDF_EMULATED_VPD_UNIT_SERIAL) { + unit_serial_len = + strlen(&dev->se_sub_dev->t10_wwn.unit_serial[0]); + unit_serial_len++; /* For NULL Terminator */ + + id_len += sprintf(&buf[off+12], "%s:%s", prod, + &dev->se_sub_dev->t10_wwn.unit_serial[0]); + } + buf[off] = 0x2; /* ASCII */ + buf[off+1] = 0x1; /* T10 Vendor ID */ + buf[off+2] = 0x0; + memcpy(&buf[off+4], "LIO-ORG", 8); + /* Extra Byte for NULL Terminator */ + id_len++; + /* Identifier Length */ + buf[off+3] = id_len; + /* Header size for Designation descriptor */ + len += (id_len + 4); + off += (id_len + 4); + /* + * struct se_port is only set for INQUIRY VPD=1 through $FABRIC_MOD + */ + port = lun->lun_sep; + if (port) { + struct t10_alua_lu_gp *lu_gp; + u32 padding, scsi_name_len; + u16 lu_gp_id = 0; + u16 tg_pt_gp_id = 0; + u16 tpgt; + + tpg = port->sep_tpg; + /* + * Relative target port identifer, see spc4r17 + * section 7.7.3.7 + * + * Get the PROTOCOL IDENTIFIER as defined by spc4r17 + * section 7.5.1 Table 362 + */ + buf[off] = + (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); + buf[off++] |= 0x1; /* CODE SET == Binary */ + buf[off] = 0x80; /* Set PIV=1 */ + /* Set ASSOCIATION == target port: 01b */ + buf[off] |= 0x10; + /* DESIGNATOR TYPE == Relative target port identifer */ + buf[off++] |= 0x4; + off++; /* Skip over Reserved */ + buf[off++] = 4; /* DESIGNATOR LENGTH */ + /* Skip over Obsolete field in RTPI payload + * in Table 472 */ + off += 2; + buf[off++] = ((port->sep_rtpi >> 8) & 0xff); + buf[off++] = (port->sep_rtpi & 0xff); + len += 8; /* Header size + Designation descriptor */ + /* + * Target port group identifier, see spc4r17 + * section 7.7.3.8 + * + * Get the PROTOCOL IDENTIFIER as defined by spc4r17 + * section 7.5.1 Table 362 + */ + if (dev->se_sub_dev->t10_alua.alua_type != + SPC3_ALUA_EMULATED) + goto check_scsi_name; + + tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; + if (!tg_pt_gp_mem) + goto check_lu_gp; + + spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + if (!tg_pt_gp) { + spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + goto check_lu_gp; + } + tg_pt_gp_id = tg_pt_gp->tg_pt_gp_id; + spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + + buf[off] = + (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); + buf[off++] |= 0x1; /* CODE SET == Binary */ + buf[off] = 0x80; /* Set PIV=1 */ + /* Set ASSOCIATION == target port: 01b */ + buf[off] |= 0x10; + /* DESIGNATOR TYPE == Target port group identifier */ + buf[off++] |= 0x5; + off++; /* Skip over Reserved */ + buf[off++] = 4; /* DESIGNATOR LENGTH */ + off += 2; /* Skip over Reserved Field */ + buf[off++] = ((tg_pt_gp_id >> 8) & 0xff); + buf[off++] = (tg_pt_gp_id & 0xff); + len += 8; /* Header size + Designation descriptor */ + /* + * Logical Unit Group identifier, see spc4r17 + * section 7.7.3.8 + */ +check_lu_gp: + lu_gp_mem = dev->dev_alua_lu_gp_mem; + if (!lu_gp_mem) + goto check_scsi_name; + + spin_lock(&lu_gp_mem->lu_gp_mem_lock); + lu_gp = lu_gp_mem->lu_gp; + if (!lu_gp) { + spin_unlock(&lu_gp_mem->lu_gp_mem_lock); + goto check_scsi_name; + } + lu_gp_id = lu_gp->lu_gp_id; + spin_unlock(&lu_gp_mem->lu_gp_mem_lock); + + buf[off++] |= 0x1; /* CODE SET == Binary */ + /* DESIGNATOR TYPE == Logical Unit Group identifier */ + buf[off++] |= 0x6; + off++; /* Skip over Reserved */ + buf[off++] = 4; /* DESIGNATOR LENGTH */ + off += 2; /* Skip over Reserved Field */ + buf[off++] = ((lu_gp_id >> 8) & 0xff); + buf[off++] = (lu_gp_id & 0xff); + len += 8; /* Header size + Designation descriptor */ + /* + * SCSI name string designator, see spc4r17 + * section 7.7.3.11 + * + * Get the PROTOCOL IDENTIFIER as defined by spc4r17 + * section 7.5.1 Table 362 + */ +check_scsi_name: + scsi_name_len = strlen(tpg->se_tpg_tfo->tpg_get_wwn(tpg)); + /* UTF-8 ",t,0x<16-bit TPGT>" + NULL Terminator */ + scsi_name_len += 10; + /* Check for 4-byte padding */ + padding = ((-scsi_name_len) & 3); + if (padding != 0) + scsi_name_len += padding; + /* Header size + Designation descriptor */ + scsi_name_len += 4; + + buf[off] = + (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); + buf[off++] |= 0x3; /* CODE SET == UTF-8 */ + buf[off] = 0x80; /* Set PIV=1 */ + /* Set ASSOCIATION == target port: 01b */ + buf[off] |= 0x10; + /* DESIGNATOR TYPE == SCSI name string */ + buf[off++] |= 0x8; + off += 2; /* Skip over Reserved and length */ + /* + * SCSI name string identifer containing, $FABRIC_MOD + * dependent information. For LIO-Target and iSCSI + * Target Port, this means ",t,0x in + * UTF-8 encoding. + */ + tpgt = tpg->se_tpg_tfo->tpg_get_tag(tpg); + scsi_name_len = sprintf(&buf[off], "%s,t,0x%04x", + tpg->se_tpg_tfo->tpg_get_wwn(tpg), tpgt); + scsi_name_len += 1 /* Include NULL terminator */; + /* + * The null-terminated, null-padded (see 4.4.2) SCSI + * NAME STRING field contains a UTF-8 format string. + * The number of bytes in the SCSI NAME STRING field + * (i.e., the value in the DESIGNATOR LENGTH field) + * shall be no larger than 256 and shall be a multiple + * of four. + */ + if (padding) + scsi_name_len += padding; + + buf[off-1] = scsi_name_len; + off += scsi_name_len; + /* Header size + Designation descriptor */ + len += (scsi_name_len + 4); + } + buf[2] = ((len >> 8) & 0xff); + buf[3] = (len & 0xff); /* Page Length for VPD 0x83 */ + return 0; +} + +/* Extended INQUIRY Data VPD Page */ +static int spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) +{ + buf[3] = 0x3c; + /* Set HEADSUP, ORDSUP, SIMPSUP */ + buf[5] = 0x07; + + /* If WriteCache emulation is enabled, set V_SUP */ + if (cmd->se_dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) + buf[6] = 0x01; + return 0; +} + +/* Block Limits VPD page */ +static int spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) +{ + struct se_device *dev = cmd->se_dev; + u32 max_sectors; + int have_tp = 0; + + /* + * Following spc3r22 section 6.5.3 Block Limits VPD page, when + * emulate_tpu=1 or emulate_tpws=1 we will be expect a + * different page length for Thin Provisioning. + */ + if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws) + have_tp = 1; + + buf[0] = dev->transport->get_device_type(dev); + buf[3] = have_tp ? 0x3c : 0x10; + + /* Set WSNZ to 1 */ + buf[4] = 0x01; + + /* + * Set OPTIMAL TRANSFER LENGTH GRANULARITY + */ + put_unaligned_be16(1, &buf[6]); + + /* + * Set MAXIMUM TRANSFER LENGTH + */ + max_sectors = min(dev->se_sub_dev->se_dev_attrib.fabric_max_sectors, + dev->se_sub_dev->se_dev_attrib.hw_max_sectors); + put_unaligned_be32(max_sectors, &buf[8]); + + /* + * Set OPTIMAL TRANSFER LENGTH + */ + put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.optimal_sectors, &buf[12]); + + /* + * Exit now if we don't support TP. + */ + if (!have_tp) + return 0; + + /* + * Set MAXIMUM UNMAP LBA COUNT + */ + put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count, &buf[20]); + + /* + * Set MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT + */ + put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count, + &buf[24]); + + /* + * Set OPTIMAL UNMAP GRANULARITY + */ + put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.unmap_granularity, &buf[28]); + + /* + * UNMAP GRANULARITY ALIGNMENT + */ + put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment, + &buf[32]); + if (dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment != 0) + buf[32] |= 0x80; /* Set the UGAVALID bit */ + + return 0; +} + +/* Block Device Characteristics VPD page */ +static int spc_emulate_evpd_b1(struct se_cmd *cmd, unsigned char *buf) +{ + struct se_device *dev = cmd->se_dev; + + buf[0] = dev->transport->get_device_type(dev); + buf[3] = 0x3c; + buf[5] = dev->se_sub_dev->se_dev_attrib.is_nonrot ? 1 : 0; + + return 0; +} + +/* Thin Provisioning VPD */ +static int spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf) +{ + struct se_device *dev = cmd->se_dev; + + /* + * From spc3r22 section 6.5.4 Thin Provisioning VPD page: + * + * The PAGE LENGTH field is defined in SPC-4. If the DP bit is set to + * zero, then the page length shall be set to 0004h. If the DP bit + * is set to one, then the page length shall be set to the value + * defined in table 162. + */ + buf[0] = dev->transport->get_device_type(dev); + + /* + * Set Hardcoded length mentioned above for DP=0 + */ + put_unaligned_be16(0x0004, &buf[2]); + + /* + * The THRESHOLD EXPONENT field indicates the threshold set size in + * LBAs as a power of 2 (i.e., the threshold set size is equal to + * 2(threshold exponent)). + * + * Note that this is currently set to 0x00 as mkp says it will be + * changing again. We can enable this once it has settled in T10 + * and is actually used by Linux/SCSI ML code. + */ + buf[4] = 0x00; + + /* + * A TPU bit set to one indicates that the device server supports + * the UNMAP command (see 5.25). A TPU bit set to zero indicates + * that the device server does not support the UNMAP command. + */ + if (dev->se_sub_dev->se_dev_attrib.emulate_tpu != 0) + buf[5] = 0x80; + + /* + * A TPWS bit set to one indicates that the device server supports + * the use of the WRITE SAME (16) command (see 5.42) to unmap LBAs. + * A TPWS bit set to zero indicates that the device server does not + * support the use of the WRITE SAME (16) command to unmap LBAs. + */ + if (dev->se_sub_dev->se_dev_attrib.emulate_tpws != 0) + buf[5] |= 0x40; + + return 0; +} + +static int spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf); + +static struct { + uint8_t page; + int (*emulate)(struct se_cmd *, unsigned char *); +} evpd_handlers[] = { + { .page = 0x00, .emulate = spc_emulate_evpd_00 }, + { .page = 0x80, .emulate = spc_emulate_evpd_80 }, + { .page = 0x83, .emulate = spc_emulate_evpd_83 }, + { .page = 0x86, .emulate = spc_emulate_evpd_86 }, + { .page = 0xb0, .emulate = spc_emulate_evpd_b0 }, + { .page = 0xb1, .emulate = spc_emulate_evpd_b1 }, + { .page = 0xb2, .emulate = spc_emulate_evpd_b2 }, +}; + +/* supported vital product data pages */ +static int spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) +{ + int p; + + /* + * Only report the INQUIRY EVPD=1 pages after a valid NAA + * Registered Extended LUN WWN has been set via ConfigFS + * during device creation/restart. + */ + if (cmd->se_dev->se_sub_dev->su_dev_flags & + SDF_EMULATED_VPD_UNIT_SERIAL) { + buf[3] = ARRAY_SIZE(evpd_handlers); + for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) + buf[p + 4] = evpd_handlers[p].page; + } + + return 0; +} + +static int spc_emulate_inquiry(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + struct se_portal_group *tpg = cmd->se_lun->lun_sep->sep_tpg; + unsigned char *buf, *map_buf; + unsigned char *cdb = cmd->t_task_cdb; + int p, ret; + + map_buf = transport_kmap_data_sg(cmd); + /* + * If SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is not set, then we + * know we actually allocated a full page. Otherwise, if the + * data buffer is too small, allocate a temporary buffer so we + * don't have to worry about overruns in all our INQUIRY + * emulation handling. + */ + if (cmd->data_length < SE_INQUIRY_BUF && + (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)) { + buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL); + if (!buf) { + transport_kunmap_data_sg(cmd); + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -ENOMEM; + } + } else { + buf = map_buf; + } + + if (dev == tpg->tpg_virt_lun0.lun_se_dev) + buf[0] = 0x3f; /* Not connected */ + else + buf[0] = dev->transport->get_device_type(dev); + + if (!(cdb[1] & 0x1)) { + if (cdb[2]) { + pr_err("INQUIRY with EVPD==0 but PAGE CODE=%02x\n", + cdb[2]); + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + ret = -EINVAL; + goto out; + } + + ret = spc_emulate_inquiry_std(cmd, buf); + goto out; + } + + for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) { + if (cdb[2] == evpd_handlers[p].page) { + buf[1] = cdb[2]; + ret = evpd_handlers[p].emulate(cmd, buf); + goto out; + } + } + + pr_err("Unknown VPD Code: 0x%02x\n", cdb[2]); + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + ret = -EINVAL; + +out: + if (buf != map_buf) { + memcpy(map_buf, buf, cmd->data_length); + kfree(buf); + } + transport_kunmap_data_sg(cmd); + + if (!ret) + target_complete_cmd(cmd, GOOD); + return ret; +} + +static int spc_modesense_rwrecovery(unsigned char *p) +{ + p[0] = 0x01; + p[1] = 0x0a; + + return 12; +} + +static int spc_modesense_control(struct se_device *dev, unsigned char *p) +{ + p[0] = 0x0a; + p[1] = 0x0a; + p[2] = 2; + /* + * From spc4r23, 7.4.7 Control mode page + * + * The QUEUE ALGORITHM MODIFIER field (see table 368) specifies + * restrictions on the algorithm used for reordering commands + * having the SIMPLE task attribute (see SAM-4). + * + * Table 368 -- QUEUE ALGORITHM MODIFIER field + * Code Description + * 0h Restricted reordering + * 1h Unrestricted reordering allowed + * 2h to 7h Reserved + * 8h to Fh Vendor specific + * + * A value of zero in the QUEUE ALGORITHM MODIFIER field specifies that + * the device server shall order the processing sequence of commands + * having the SIMPLE task attribute such that data integrity is maintained + * for that I_T nexus (i.e., if the transmission of new SCSI transport protocol + * requests is halted at any time, the final value of all data observable + * on the medium shall be the same as if all the commands had been processed + * with the ORDERED task attribute). + * + * A value of one in the QUEUE ALGORITHM MODIFIER field specifies that the + * device server may reorder the processing sequence of commands having the + * SIMPLE task attribute in any manner. Any data integrity exposures related to + * command sequence order shall be explicitly handled by the application client + * through the selection of appropriate ommands and task attributes. + */ + p[3] = (dev->se_sub_dev->se_dev_attrib.emulate_rest_reord == 1) ? 0x00 : 0x10; + /* + * From spc4r17, section 7.4.6 Control mode Page + * + * Unit Attention interlocks control (UN_INTLCK_CTRL) to code 00b + * + * 00b: The logical unit shall clear any unit attention condition + * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION + * status and shall not establish a unit attention condition when a com- + * mand is completed with BUSY, TASK SET FULL, or RESERVATION CONFLICT + * status. + * + * 10b: The logical unit shall not clear any unit attention condition + * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION + * status and shall not establish a unit attention condition when + * a command is completed with BUSY, TASK SET FULL, or RESERVATION + * CONFLICT status. + * + * 11b a The logical unit shall not clear any unit attention condition + * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION + * status and shall establish a unit attention condition for the + * initiator port associated with the I_T nexus on which the BUSY, + * TASK SET FULL, or RESERVATION CONFLICT status is being returned. + * Depending on the status, the additional sense code shall be set to + * PREVIOUS BUSY STATUS, PREVIOUS TASK SET FULL STATUS, or PREVIOUS + * RESERVATION CONFLICT STATUS. Until it is cleared by a REQUEST SENSE + * command, a unit attention condition shall be established only once + * for a BUSY, TASK SET FULL, or RESERVATION CONFLICT status regardless + * to the number of commands completed with one of those status codes. + */ + p[4] = (dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl == 2) ? 0x30 : + (dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl == 1) ? 0x20 : 0x00; + /* + * From spc4r17, section 7.4.6 Control mode Page + * + * Task Aborted Status (TAS) bit set to zero. + * + * A task aborted status (TAS) bit set to zero specifies that aborted + * tasks shall be terminated by the device server without any response + * to the application client. A TAS bit set to one specifies that tasks + * aborted by the actions of an I_T nexus other than the I_T nexus on + * which the command was received shall be completed with TASK ABORTED + * status (see SAM-4). + */ + p[5] = (dev->se_sub_dev->se_dev_attrib.emulate_tas) ? 0x40 : 0x00; + p[8] = 0xff; + p[9] = 0xff; + p[11] = 30; + + return 12; +} + +static int spc_modesense_caching(struct se_device *dev, unsigned char *p) +{ + p[0] = 0x08; + p[1] = 0x12; + if (dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) + p[2] = 0x04; /* Write Cache Enable */ + p[12] = 0x20; /* Disabled Read Ahead */ + + return 20; +} + +static void spc_modesense_write_protect(unsigned char *buf, int type) +{ + /* + * I believe that the WP bit (bit 7) in the mode header is the same for + * all device types.. + */ + switch (type) { + case TYPE_DISK: + case TYPE_TAPE: + default: + buf[0] |= 0x80; /* WP bit */ + break; + } +} + +static void spc_modesense_dpofua(unsigned char *buf, int type) +{ + switch (type) { + case TYPE_DISK: + buf[0] |= 0x10; /* DPOFUA bit */ + break; + default: + break; + } +} + +static int spc_emulate_modesense(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + char *cdb = cmd->t_task_cdb; + unsigned char *rbuf; + int type = dev->transport->get_device_type(dev); + int ten = (cmd->t_task_cdb[0] == MODE_SENSE_10); + int offset = ten ? 8 : 4; + int length = 0; + unsigned char buf[SE_MODE_PAGE_BUF]; + + memset(buf, 0, SE_MODE_PAGE_BUF); + + switch (cdb[2] & 0x3f) { + case 0x01: + length = spc_modesense_rwrecovery(&buf[offset]); + break; + case 0x08: + length = spc_modesense_caching(dev, &buf[offset]); + break; + case 0x0a: + length = spc_modesense_control(dev, &buf[offset]); + break; + case 0x3f: + length = spc_modesense_rwrecovery(&buf[offset]); + length += spc_modesense_caching(dev, &buf[offset+length]); + length += spc_modesense_control(dev, &buf[offset+length]); + break; + default: + pr_err("MODE SENSE: unimplemented page/subpage: 0x%02x/0x%02x\n", + cdb[2] & 0x3f, cdb[3]); + cmd->scsi_sense_reason = TCM_UNKNOWN_MODE_PAGE; + return -EINVAL; + } + offset += length; + + if (ten) { + offset -= 2; + buf[0] = (offset >> 8) & 0xff; + buf[1] = offset & 0xff; + + if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) || + (cmd->se_deve && + (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) + spc_modesense_write_protect(&buf[3], type); + + if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) && + (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0)) + spc_modesense_dpofua(&buf[3], type); + + if ((offset + 2) > cmd->data_length) + offset = cmd->data_length; + + } else { + offset -= 1; + buf[0] = offset & 0xff; + + if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) || + (cmd->se_deve && + (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) + spc_modesense_write_protect(&buf[2], type); + + if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) && + (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0)) + spc_modesense_dpofua(&buf[2], type); + + if ((offset + 1) > cmd->data_length) + offset = cmd->data_length; + } + + rbuf = transport_kmap_data_sg(cmd); + memcpy(rbuf, buf, offset); + transport_kunmap_data_sg(cmd); + + target_complete_cmd(cmd, GOOD); + return 0; +} + +static int spc_emulate_request_sense(struct se_cmd *cmd) +{ + unsigned char *cdb = cmd->t_task_cdb; + unsigned char *buf; + u8 ua_asc = 0, ua_ascq = 0; + int err = 0; + + if (cdb[1] & 0x01) { + pr_err("REQUEST_SENSE description emulation not" + " supported\n"); + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -ENOSYS; + } + + buf = transport_kmap_data_sg(cmd); + + if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) { + /* + * CURRENT ERROR, UNIT ATTENTION + */ + buf[0] = 0x70; + buf[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION; + + if (cmd->data_length < 18) { + buf[7] = 0x00; + err = -EINVAL; + goto end; + } + /* + * The Additional Sense Code (ASC) from the UNIT ATTENTION + */ + buf[SPC_ASC_KEY_OFFSET] = ua_asc; + buf[SPC_ASCQ_KEY_OFFSET] = ua_ascq; + buf[7] = 0x0A; + } else { + /* + * CURRENT ERROR, NO SENSE + */ + buf[0] = 0x70; + buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE; + + if (cmd->data_length < 18) { + buf[7] = 0x00; + err = -EINVAL; + goto end; + } + /* + * NO ADDITIONAL SENSE INFORMATION + */ + buf[SPC_ASC_KEY_OFFSET] = 0x00; + buf[7] = 0x0A; + } + +end: + transport_kunmap_data_sg(cmd); + target_complete_cmd(cmd, GOOD); + return 0; +} + +static int spc_emulate_testunitready(struct se_cmd *cmd) +{ + target_complete_cmd(cmd, GOOD); + return 0; +} + +int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) { struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; unsigned char *cdb = cmd->t_task_cdb; @@ -53,13 +952,11 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough) break; case MODE_SENSE: *size = cdb[4]; - if (!passthrough) - cmd->execute_cmd = target_emulate_modesense; + cmd->execute_cmd = spc_emulate_modesense; break; case MODE_SENSE_10: *size = (cdb[7] << 8) + cdb[8]; - if (!passthrough) - cmd->execute_cmd = target_emulate_modesense; + cmd->execute_cmd = spc_emulate_modesense; break; case LOG_SELECT: case LOG_SENSE: @@ -108,8 +1005,7 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough) break; case REQUEST_SENSE: *size = cdb[4]; - if (!passthrough) - cmd->execute_cmd = target_emulate_request_sense; + cmd->execute_cmd = spc_emulate_request_sense; break; case INQUIRY: *size = (cdb[3] << 8) + cdb[4]; @@ -120,8 +1016,7 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough) */ if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) cmd->sam_task_attr = MSG_HEAD_TAG; - if (!passthrough) - cmd->execute_cmd = target_emulate_inquiry; + cmd->execute_cmd = spc_emulate_inquiry; break; case SECURITY_PROTOCOL_IN: case SECURITY_PROTOCOL_OUT: @@ -152,9 +1047,8 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough) cmd->sam_task_attr = MSG_HEAD_TAG; break; case TEST_UNIT_READY: + cmd->execute_cmd = spc_emulate_testunitready; *size = 0; - if (!passthrough) - cmd->execute_cmd = target_emulate_noop; break; default: pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode" diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 0adabd3..3a7fe21 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1343,7 +1343,7 @@ static inline void transport_generic_prepare_cdb( } } -static int target_cmd_size_check(struct se_cmd *cmd, unsigned int size) +int target_cmd_size_check(struct se_cmd *cmd, unsigned int size) { struct se_device *dev = cmd->se_dev; @@ -1469,7 +1469,6 @@ int target_setup_cmd_from_cdb( u32 pr_reg_type = 0; u8 alua_ascq = 0; unsigned long flags; - unsigned int size; int ret; transport_generic_prepare_cdb(cdb); @@ -1561,11 +1560,7 @@ int target_setup_cmd_from_cdb( */ } - ret = cmd->se_dev->transport->parse_cdb(cmd, &size); - if (ret < 0) - return ret; - - ret = target_cmd_size_check(cmd, size); + ret = cmd->se_dev->transport->parse_cdb(cmd); if (ret < 0) return ret; @@ -2163,32 +2158,6 @@ out: return -1; } -static inline long long transport_dev_end_lba(struct se_device *dev) -{ - return dev->transport->get_blocks(dev) + 1; -} - -static int transport_cmd_get_valid_sectors(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - u32 sectors; - - if (dev->transport->get_device_type(dev) != TYPE_DISK) - return 0; - - sectors = (cmd->data_length / dev->se_sub_dev->se_dev_attrib.block_size); - - if ((cmd->t_task_lba + sectors) > transport_dev_end_lba(dev)) { - pr_err("LBA: %llu Sectors: %u exceeds" - " transport_dev_end_lba(): %llu\n", - cmd->t_task_lba, sectors, - transport_dev_end_lba(dev)); - return -EINVAL; - } - - return 0; -} - /* * Called from I/O completion to determine which dormant/delayed * and ordered cmds need to have their tasks added to the execution queue. @@ -2632,7 +2601,6 @@ out: */ int transport_generic_new_cmd(struct se_cmd *cmd) { - struct se_device *dev = cmd->se_dev; int ret = 0; /* @@ -2666,17 +2634,6 @@ int transport_generic_new_cmd(struct se_cmd *cmd) return 0; } - if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { - struct se_dev_attrib *attr = &dev->se_sub_dev->se_dev_attrib; - - if (transport_cmd_get_valid_sectors(cmd) < 0) - return -EINVAL; - - BUG_ON(cmd->data_length % attr->block_size); - BUG_ON(DIV_ROUND_UP(cmd->data_length, attr->block_size) > - attr->hw_max_sectors); - } - atomic_inc(&cmd->t_fe_count); /* diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index f4f1eef..24d2004 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -25,7 +25,7 @@ struct se_subsystem_api { void (*free_device)(void *); int (*transport_complete)(struct se_cmd *cmd, struct scatterlist *); - int (*parse_cdb)(struct se_cmd *cmd, unsigned int *size); + int (*parse_cdb)(struct se_cmd *cmd); int (*execute_cmd)(struct se_cmd *, struct scatterlist *, u32, enum dma_data_direction); int (*do_discard)(struct se_device *, sector_t, u32); @@ -51,8 +51,8 @@ struct se_device *transport_add_device_to_core_hba(struct se_hba *, void target_complete_cmd(struct se_cmd *, u8); -int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size); -int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough); +int sbc_parse_cdb(struct se_cmd *cmd); +int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size); void transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *); int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *); -- cgit v0.10.2 From 3d6d72014f16967ca92765040be30f022c5952e6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 20 May 2012 11:59:17 -0400 Subject: target: move transport_generic_prepare_cdb into pscsi The virtual drivers don't need to clear cdb fields they never look at, so move this code into the pscsi backend. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 099c59d..9a776cc 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -1022,6 +1022,30 @@ fail: return -ENOMEM; } +/* + * Clear a lun set in the cdb if the initiator talking to use spoke + * and old standards version, as we can't assume the underlying device + * won't choke up on it. + */ +static inline void pscsi_clear_cdb_lun(unsigned char *cdb) +{ + switch (cdb[0]) { + case READ_10: /* SBC - RDProtect */ + case READ_12: /* SBC - RDProtect */ + case READ_16: /* SBC - RDProtect */ + case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */ + case VERIFY: /* SBC - VRProtect */ + case VERIFY_16: /* SBC - VRProtect */ + case WRITE_VERIFY: /* SBC - VRProtect */ + case WRITE_VERIFY_12: /* SBC - VRProtect */ + case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */ + break; + default: + cdb[1] &= 0x1f; /* clear logical unit number */ + break; + } +} + static int pscsi_parse_cdb(struct se_cmd *cmd) { unsigned char *cdb = cmd->t_task_cdb; @@ -1034,6 +1058,8 @@ static int pscsi_parse_cdb(struct se_cmd *cmd) return -EINVAL; } + pscsi_clear_cdb_lun(cdb); + /* * For REPORT LUNS we always need to emulate the respone, and for everything * related to persistent reservations and ALUA we might optionally use our diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 3a7fe21..7cfb519 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1315,34 +1315,6 @@ out: } EXPORT_SYMBOL(transport_add_device_to_core_hba); -/* transport_generic_prepare_cdb(): - * - * Since the Initiator sees iSCSI devices as LUNs, the SCSI CDB will - * contain the iSCSI LUN in bits 7-5 of byte 1 as per SAM-2. - * The point of this is since we are mapping iSCSI LUNs to - * SCSI Target IDs having a non-zero LUN in the CDB will throw the - * devices and HBAs for a loop. - */ -static inline void transport_generic_prepare_cdb( - unsigned char *cdb) -{ - switch (cdb[0]) { - case READ_10: /* SBC - RDProtect */ - case READ_12: /* SBC - RDProtect */ - case READ_16: /* SBC - RDProtect */ - case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */ - case VERIFY: /* SBC - VRProtect */ - case VERIFY_16: /* SBC - VRProtect */ - case WRITE_VERIFY: /* SBC - VRProtect */ - case WRITE_VERIFY_12: /* SBC - VRProtect */ - case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */ - break; - default: - cdb[1] &= 0x1f; /* clear logical unit number */ - break; - } -} - int target_cmd_size_check(struct se_cmd *cmd, unsigned int size) { struct se_device *dev = cmd->se_dev; @@ -1471,7 +1443,6 @@ int target_setup_cmd_from_cdb( unsigned long flags; int ret; - transport_generic_prepare_cdb(cdb); /* * Ensure that the received CDB is less than the max (252 + 8) bytes * for VARIABLE_LENGTH_CMD -- cgit v0.10.2 From eba2ca450526c1aaf2bfd363dffd63b024e80ea7 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Wed, 30 May 2012 14:09:10 -0700 Subject: target: Move MAINTENANCE_[IN,OUT] from pscsi_parse_cdb -> spc_parse_cdb The MAINTENANCE_[IN,OUT] CDB parsing required for generic ALUA emulation needs to be in spc_parse_cdb() to function for virtual TYPE_DISK exports, instead of in backend pscsi_parse_cdb() code used only for passthrough ops. Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 96dcb57..4c861de 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -35,6 +35,7 @@ #include #include "target_core_internal.h" +#include "target_core_alua.h" #include "target_core_pr.h" #include "target_core_ua.h" @@ -940,7 +941,8 @@ static int spc_emulate_testunitready(struct se_cmd *cmd) int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) { - struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; + struct se_device *dev = cmd->se_dev; + struct se_subsystem_dev *su_dev = dev->se_sub_dev; unsigned char *cdb = cmd->t_task_cdb; switch (cdb[0]) { @@ -1050,6 +1052,44 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) cmd->execute_cmd = spc_emulate_testunitready; *size = 0; break; + case MAINTENANCE_IN: + if (dev->transport->get_device_type(dev) != TYPE_ROM) { + /* + * MAINTENANCE_IN from SCC-2 + * Check for emulated MI_REPORT_TARGET_PGS + */ + if ((cdb[1] & 0x1f) == MI_REPORT_TARGET_PGS && + su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { + cmd->execute_cmd = + target_emulate_report_target_port_groups; + } + *size = get_unaligned_be32(&cdb[6]); + } else { + /* + * GPCMD_SEND_KEY from multi media commands + */ + *size = get_unaligned_be16(&cdb[8]); + } + break; + case MAINTENANCE_OUT: + if (dev->transport->get_device_type(dev) != TYPE_ROM) { + /* + * MAINTENANCE_OUT from SCC-2 + * Check for emulated MO_SET_TARGET_PGS. + */ + if (cdb[1] == MO_SET_TARGET_PGS && + su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { + cmd->execute_cmd = + target_emulate_set_target_port_groups; + } + *size = get_unaligned_be32(&cdb[6]); + } else { + /* + * GPCMD_SEND_KEY from multi media commands + */ + *size = get_unaligned_be16(&cdb[8]); + } + break; default: pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode" " 0x%02x, sending CHECK_CONDITION.\n", -- cgit v0.10.2 From a3785c8740c5b56b49ec336b59be996393d83332 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Wed, 30 May 2012 14:47:18 -0700 Subject: target/pscsi: Only emulate REPORT_LUNS for passthrough This patch changes back the pSCSI backend to follow pre 3.6-queue code to passthrough SPC-3 persistent reservations + SPC-2 legacy reservation handling to the underlying LLD / physical hardware. For folks who really need this for their own SPC-3 emulation logic, avoid changing the functionality of this beyond what is exported for REPORT_LUNS for existing code, and to avoid problems with SPC-3 PR/ALUA as INQUIRY EVPD=0x83 emulation needs to be in place in order for this to work as expected with spc_parse_cdb() code.. Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 9a776cc..cb4c6b1 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -1061,18 +1061,12 @@ static int pscsi_parse_cdb(struct se_cmd *cmd) pscsi_clear_cdb_lun(cdb); /* - * For REPORT LUNS we always need to emulate the respone, and for everything - * related to persistent reservations and ALUA we might optionally use our - * handlers before passing on the command to the physical hardware. + * For REPORT LUNS we always need to emulate the response, for everything + * else the default for pSCSI is to pass the command to the underlying + * LLD / physical hardware. */ switch (cdb[0]) { case REPORT_LUNS: - case PERSISTENT_RESERVE_IN: - case PERSISTENT_RESERVE_OUT: - case RELEASE: - case RELEASE_10: - case RESERVE: - case RESERVE_10: ret = spc_parse_cdb(cmd, &dummy_size); if (ret) return ret; -- cgit v0.10.2 From 5f41a31d0a49a014adb1588edd0cc7f7e30cc55b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 20 May 2012 14:34:44 -0400 Subject: target: remove the execute list Since "target: Drop se_device TCQ queue_depth usage from I/O path" we always submit all commands (or back then, tasks) from __transport_execute_tasks. That means the the execute list has lots its purpose, as we can simply submit the commands that are restarted in transport_complete_task_attr directly while we walk the list. In fact doing so also solves a race in the way it currently walks to delayed_cmd_list as well. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 031c288..88f69e0 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -93,7 +93,6 @@ void release_se_kmem_caches(void); u32 scsi_get_new_index(scsi_index_t); void transport_subsystem_check_init(void); void transport_cmd_finish_abort(struct se_cmd *, int); -void __target_remove_from_execute_list(struct se_cmd *); unsigned char *transport_dump_cmd_direction(struct se_cmd *); void transport_dump_dev_state(struct se_device *, char *, int *); void transport_dump_dev_info(struct se_device *, struct se_lun *, diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 84caf1b..4185db1 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -295,9 +295,6 @@ static void core_tmr_drain_state_list( list_move_tail(&cmd->state_list, &drain_task_list); cmd->state_active = false; - - if (!list_empty(&cmd->execute_list)) - __target_remove_from_execute_list(cmd); } spin_unlock_irqrestore(&dev->execute_task_lock, flags); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 7cfb519..1c53fce 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -68,7 +68,6 @@ struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; static int transport_generic_write_pending(struct se_cmd *); static int transport_processing_thread(void *param); -static int __transport_execute_tasks(struct se_device *dev, struct se_cmd *); static void transport_complete_task_attr(struct se_cmd *cmd); static void transport_handle_queue_full(struct se_cmd *cmd, struct se_device *dev); @@ -742,65 +741,6 @@ static void target_add_to_state_list(struct se_cmd *cmd) spin_unlock_irqrestore(&dev->execute_task_lock, flags); } -static void __target_add_to_execute_list(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - bool head_of_queue = false; - - if (!list_empty(&cmd->execute_list)) - return; - - if (dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED && - cmd->sam_task_attr == MSG_HEAD_TAG) - head_of_queue = true; - - if (head_of_queue) - list_add(&cmd->execute_list, &dev->execute_list); - else - list_add_tail(&cmd->execute_list, &dev->execute_list); - - atomic_inc(&dev->execute_tasks); - - if (cmd->state_active) - return; - - if (head_of_queue) - list_add(&cmd->state_list, &dev->state_list); - else - list_add_tail(&cmd->state_list, &dev->state_list); - - cmd->state_active = true; -} - -static void target_add_to_execute_list(struct se_cmd *cmd) -{ - unsigned long flags; - struct se_device *dev = cmd->se_dev; - - spin_lock_irqsave(&dev->execute_task_lock, flags); - __target_add_to_execute_list(cmd); - spin_unlock_irqrestore(&dev->execute_task_lock, flags); -} - -void __target_remove_from_execute_list(struct se_cmd *cmd) -{ - list_del_init(&cmd->execute_list); - atomic_dec(&cmd->se_dev->execute_tasks); -} - -static void target_remove_from_execute_list(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - unsigned long flags; - - if (WARN_ON(list_empty(&cmd->execute_list))) - return; - - spin_lock_irqsave(&dev->execute_task_lock, flags); - __target_remove_from_execute_list(cmd); - spin_unlock_irqrestore(&dev->execute_task_lock, flags); -} - /* * Handle QUEUE_FULL / -EAGAIN and -ENOMEM status */ @@ -874,8 +814,7 @@ void transport_dump_dev_state( break; } - *bl += sprintf(b + *bl, " Execute/Max Queue Depth: %d/%d", - atomic_read(&dev->execute_tasks), dev->queue_depth); + *bl += sprintf(b + *bl, " Max Queue Depth: %d", dev->queue_depth); *bl += sprintf(b + *bl, " SectorSize: %u HwMaxSectors: %u\n", dev->se_sub_dev->se_dev_attrib.block_size, dev->se_sub_dev->se_dev_attrib.hw_max_sectors); @@ -1222,7 +1161,6 @@ struct se_device *transport_add_device_to_core_hba( INIT_LIST_HEAD(&dev->dev_list); INIT_LIST_HEAD(&dev->dev_sep_list); INIT_LIST_HEAD(&dev->dev_tmr_list); - INIT_LIST_HEAD(&dev->execute_list); INIT_LIST_HEAD(&dev->delayed_cmd_list); INIT_LIST_HEAD(&dev->state_list); INIT_LIST_HEAD(&dev->qf_cmd_list); @@ -1382,7 +1320,6 @@ void transport_init_se_cmd( INIT_LIST_HEAD(&cmd->se_qf_node); INIT_LIST_HEAD(&cmd->se_queue_node); INIT_LIST_HEAD(&cmd->se_cmd_list); - INIT_LIST_HEAD(&cmd->execute_list); INIT_LIST_HEAD(&cmd->state_list); init_completion(&cmd->transport_lun_fe_stop_comp); init_completion(&cmd->transport_lun_stop_comp); @@ -1926,152 +1863,92 @@ queue_full: } EXPORT_SYMBOL(transport_generic_request_failure); -/* - * Called from Fabric Module context from transport_execute_tasks() - * - * The return of this function determins if the tasks from struct se_cmd - * get added to the execution queue in transport_execute_tasks(), - * or are added to the delayed or ordered lists here. - */ -static inline int transport_execute_task_attr(struct se_cmd *cmd) +static void __target_execute_cmd(struct se_cmd *cmd) { - if (cmd->se_dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED) - return 1; + int error; + + spin_lock_irq(&cmd->t_state_lock); + cmd->transport_state |= (CMD_T_BUSY|CMD_T_SENT); + spin_unlock_irq(&cmd->t_state_lock); + + if (cmd->execute_cmd) + error = cmd->execute_cmd(cmd); + else { + error = cmd->se_dev->transport->execute_cmd(cmd, cmd->t_data_sg, + cmd->t_data_nents, cmd->data_direction); + } + + if (error) { + spin_lock_irq(&cmd->t_state_lock); + cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT); + spin_unlock_irq(&cmd->t_state_lock); + + transport_generic_request_failure(cmd); + } +} + +static void target_execute_cmd(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + + if (transport_cmd_check_stop(cmd, 0, TRANSPORT_PROCESSING)) + return; + + if (dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED) + goto execute; + /* * Check for the existence of HEAD_OF_QUEUE, and if true return 1 * to allow the passed struct se_cmd list of tasks to the front of the list. */ - if (cmd->sam_task_attr == MSG_HEAD_TAG) { - pr_debug("Added HEAD_OF_QUEUE for CDB:" - " 0x%02x, se_ordered_id: %u\n", - cmd->t_task_cdb[0], - cmd->se_ordered_id); - return 1; - } else if (cmd->sam_task_attr == MSG_ORDERED_TAG) { - atomic_inc(&cmd->se_dev->dev_ordered_sync); + switch (cmd->sam_task_attr) { + case MSG_HEAD_TAG: + pr_debug("Added HEAD_OF_QUEUE for CDB: 0x%02x, " + "se_ordered_id: %u\n", + cmd->t_task_cdb[0], cmd->se_ordered_id); + goto execute; + case MSG_ORDERED_TAG: + atomic_inc(&dev->dev_ordered_sync); smp_mb__after_atomic_inc(); - pr_debug("Added ORDERED for CDB: 0x%02x to ordered" - " list, se_ordered_id: %u\n", - cmd->t_task_cdb[0], - cmd->se_ordered_id); + pr_debug("Added ORDERED for CDB: 0x%02x to ordered list, " + " se_ordered_id: %u\n", + cmd->t_task_cdb[0], cmd->se_ordered_id); + /* - * Add ORDERED command to tail of execution queue if - * no other older commands exist that need to be - * completed first. + * Execute an ORDERED command if no other older commands + * exist that need to be completed first. */ - if (!atomic_read(&cmd->se_dev->simple_cmds)) - return 1; - } else { + if (!atomic_read(&dev->simple_cmds)) + goto execute; + break; + default: /* * For SIMPLE and UNTAGGED Task Attribute commands */ - atomic_inc(&cmd->se_dev->simple_cmds); + atomic_inc(&dev->simple_cmds); smp_mb__after_atomic_inc(); + break; } - /* - * Otherwise if one or more outstanding ORDERED task attribute exist, - * add the dormant task(s) built for the passed struct se_cmd to the - * execution queue and become in Active state for this struct se_device. - */ - if (atomic_read(&cmd->se_dev->dev_ordered_sync) != 0) { - /* - * Otherwise, add cmd w/ tasks to delayed cmd queue that - * will be drained upon completion of HEAD_OF_QUEUE task. - */ - spin_lock(&cmd->se_dev->delayed_cmd_lock); + + if (atomic_read(&dev->dev_ordered_sync) != 0) { + spin_lock(&dev->delayed_cmd_lock); cmd->se_cmd_flags |= SCF_DELAYED_CMD_FROM_SAM_ATTR; - list_add_tail(&cmd->se_delayed_node, - &cmd->se_dev->delayed_cmd_list); - spin_unlock(&cmd->se_dev->delayed_cmd_lock); + list_add_tail(&cmd->se_delayed_node, &dev->delayed_cmd_list); + spin_unlock(&dev->delayed_cmd_lock); pr_debug("Added CDB: 0x%02x Task Attr: 0x%02x to" " delayed CMD list, se_ordered_id: %u\n", cmd->t_task_cdb[0], cmd->sam_task_attr, cmd->se_ordered_id); - /* - * Return zero to let transport_execute_tasks() know - * not to add the delayed tasks to the execution list. - */ - return 0; + return; } - /* - * Otherwise, no ORDERED task attributes exist.. - */ - return 1; -} -/* - * Called from fabric module context in transport_generic_new_cmd() and - * transport_generic_process_write() - */ -static void transport_execute_tasks(struct se_cmd *cmd) -{ - int add_tasks; - struct se_device *se_dev = cmd->se_dev; +execute: /* - * Call transport_cmd_check_stop() to see if a fabric exception - * has occurred that prevents execution. + * Otherwise, no ORDERED task attributes exist.. */ - if (!transport_cmd_check_stop(cmd, 0, TRANSPORT_PROCESSING)) { - /* - * Check for SAM Task Attribute emulation and HEAD_OF_QUEUE - * attribute for the tasks of the received struct se_cmd CDB - */ - add_tasks = transport_execute_task_attr(cmd); - if (add_tasks) { - __transport_execute_tasks(se_dev, cmd); - return; - } - } - __transport_execute_tasks(se_dev, NULL); -} - -static int __transport_execute_tasks(struct se_device *dev, struct se_cmd *new_cmd) -{ - int error; - struct se_cmd *cmd = NULL; - unsigned long flags; - -check_depth: - spin_lock_irq(&dev->execute_task_lock); - if (new_cmd != NULL) - __target_add_to_execute_list(new_cmd); - - if (list_empty(&dev->execute_list)) { - spin_unlock_irq(&dev->execute_task_lock); - return 0; - } - cmd = list_first_entry(&dev->execute_list, struct se_cmd, execute_list); - __target_remove_from_execute_list(cmd); - spin_unlock_irq(&dev->execute_task_lock); - - spin_lock_irqsave(&cmd->t_state_lock, flags); - cmd->transport_state |= CMD_T_BUSY; - cmd->transport_state |= CMD_T_SENT; - - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - - if (cmd->execute_cmd) - error = cmd->execute_cmd(cmd); - else { - error = dev->transport->execute_cmd(cmd, cmd->t_data_sg, - cmd->t_data_nents, cmd->data_direction); - } - - if (error != 0) { - spin_lock_irqsave(&cmd->t_state_lock, flags); - cmd->transport_state &= ~CMD_T_BUSY; - cmd->transport_state &= ~CMD_T_SENT; - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - - transport_generic_request_failure(cmd); - } - - new_cmd = NULL; - goto check_depth; - - return 0; + __target_execute_cmd(cmd); } /* @@ -2130,14 +2007,39 @@ out: } /* + * Process all commands up to the last received ORDERED task attribute which + * requires another blocking boundary + */ +static void target_restart_delayed_cmds(struct se_device *dev) +{ + for (;;) { + struct se_cmd *cmd; + + spin_lock(&dev->delayed_cmd_lock); + if (list_empty(&dev->delayed_cmd_list)) { + spin_unlock(&dev->delayed_cmd_lock); + break; + } + + cmd = list_entry(dev->delayed_cmd_list.next, + struct se_cmd, se_delayed_node); + list_del(&cmd->se_delayed_node); + spin_unlock(&dev->delayed_cmd_lock); + + __target_execute_cmd(cmd); + + if (cmd->sam_task_attr == MSG_ORDERED_TAG) + break; + } +} + +/* * Called from I/O completion to determine which dormant/delayed * and ordered cmds need to have their tasks added to the execution queue. */ static void transport_complete_task_attr(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - struct se_cmd *cmd_p, *cmd_tmp; - int new_active_tasks = 0; if (cmd->sam_task_attr == MSG_SIMPLE_TAG) { atomic_dec(&dev->simple_cmds); @@ -2159,38 +2061,8 @@ static void transport_complete_task_attr(struct se_cmd *cmd) pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED:" " %u\n", dev->dev_cur_ordered_id, cmd->se_ordered_id); } - /* - * Process all commands up to the last received - * ORDERED task attribute which requires another blocking - * boundary - */ - spin_lock(&dev->delayed_cmd_lock); - list_for_each_entry_safe(cmd_p, cmd_tmp, - &dev->delayed_cmd_list, se_delayed_node) { - - list_del(&cmd_p->se_delayed_node); - spin_unlock(&dev->delayed_cmd_lock); - - pr_debug("Calling add_tasks() for" - " cmd_p: 0x%02x Task Attr: 0x%02x" - " Dormant -> Active, se_ordered_id: %u\n", - cmd_p->t_task_cdb[0], - cmd_p->sam_task_attr, cmd_p->se_ordered_id); - - target_add_to_execute_list(cmd_p); - new_active_tasks++; - spin_lock(&dev->delayed_cmd_lock); - if (cmd_p->sam_task_attr == MSG_ORDERED_TAG) - break; - } - spin_unlock(&dev->delayed_cmd_lock); - /* - * If new tasks have become active, wake up the transport thread - * to do the processing of the Active tasks. - */ - if (new_active_tasks != 0) - wake_up_interruptible(&dev->dev_queue_obj.thread_wq); + target_restart_delayed_cmds(dev); } static void transport_complete_qf(struct se_cmd *cmd) @@ -2612,15 +2484,13 @@ int transport_generic_new_cmd(struct se_cmd *cmd) * * The command will be added to the execution queue after its write * data has arrived. - */ - if (cmd->data_direction == DMA_TO_DEVICE) { - target_add_to_state_list(cmd); - return transport_generic_write_pending(cmd); - } - /* + * * Everything else but a WRITE, add the command to the execution queue. */ - transport_execute_tasks(cmd); + target_add_to_state_list(cmd); + if (cmd->data_direction == DMA_TO_DEVICE) + return transport_generic_write_pending(cmd); + target_execute_cmd(cmd); return 0; out_fail: @@ -2636,7 +2506,7 @@ EXPORT_SYMBOL(transport_generic_new_cmd); */ void transport_generic_process_write(struct se_cmd *cmd) { - transport_execute_tasks(cmd); + target_execute_cmd(cmd); } EXPORT_SYMBOL(transport_generic_process_write); @@ -2872,12 +2742,8 @@ static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun) (cmd->transport_state & CMD_T_SENT)) { if (!target_stop_cmd(cmd, &flags)) ret++; - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - } else { - spin_unlock_irqrestore(&cmd->t_state_lock, - flags); - target_remove_from_execute_list(cmd); } + spin_unlock_irqrestore(&cmd->t_state_lock, flags); pr_debug("ConfigFS: cmd: %p stop tasks ret:" " %d\n", cmd, ret); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index abda19d..6e99dc5 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -572,7 +572,6 @@ struct se_cmd { struct scatterlist *t_bidi_data_sg; unsigned int t_bidi_data_nents; - struct list_head execute_list; struct list_head state_list; bool state_active; @@ -777,7 +776,6 @@ struct se_device { /* Active commands on this virtual SE device */ atomic_t simple_cmds; atomic_t dev_ordered_id; - atomic_t execute_tasks; atomic_t dev_ordered_sync; atomic_t dev_qf_count; struct se_obj dev_obj; @@ -803,7 +801,6 @@ struct se_device { struct task_struct *process_thread; struct work_struct qf_work_queue; struct list_head delayed_cmd_list; - struct list_head execute_list; struct list_head state_list; struct list_head qf_cmd_list; /* Pointer to associated SE HBA */ -- cgit v0.10.2 From 9f3eb93eaf5bd49051458fcb098af3fcf111d3d0 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 20 May 2012 14:35:02 -0400 Subject: target: move ref_cmd from the generic se_tmr_req into iscsi code Also remove the unused ref_task_lun field in struct se_tmr_req. (nab: Add missing TASK_REASSIGN ref_lun vs. ref_cmd orig_fe_lun checks in iscsit_tmr_task_reassign) Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index 1c70144..63a8ed2 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h @@ -481,6 +481,7 @@ struct iscsi_tmr_req { bool task_reassign:1; u32 ref_cmd_sn; u32 exp_data_sn; + struct iscsi_cmd *ref_cmd; struct iscsi_conn_recovery *conn_recovery; struct se_tmr_req *se_tmr_req; }; diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c index f4e640b..1f75529 100644 --- a/drivers/target/iscsi/iscsi_target_tmr.c +++ b/drivers/target/iscsi/iscsi_target_tmr.c @@ -19,6 +19,7 @@ ******************************************************************************/ #include +#include #include #include #include @@ -61,7 +62,7 @@ u8 iscsit_tmr_abort_task( } se_tmr->ref_task_tag = hdr->rtt; - se_tmr->ref_cmd = &ref_cmd->se_cmd; + tmr_req->ref_cmd = ref_cmd; tmr_req->ref_cmd_sn = hdr->refcmdsn; tmr_req->exp_data_sn = hdr->exp_datasn; @@ -121,7 +122,7 @@ u8 iscsit_tmr_task_reassign( struct iscsi_tmr_req *tmr_req = cmd->tmr_req; struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req; struct iscsi_tm *hdr = (struct iscsi_tm *) buf; - int ret; + int ret, ref_lun; pr_debug("Got TASK_REASSIGN TMR ITT: 0x%08x," " RefTaskTag: 0x%08x, ExpDataSN: 0x%08x, CID: %hu\n", @@ -155,9 +156,16 @@ u8 iscsit_tmr_task_reassign( return ISCSI_TMF_RSP_REJECTED; } + ref_lun = scsilun_to_int(&hdr->lun); + if (ref_lun != ref_cmd->se_cmd.orig_fe_lun) { + pr_err("Unable to perform connection recovery for" + " differing ref_lun: %d ref_cmd orig_fe_lun: %u\n", + ref_lun, ref_cmd->se_cmd.orig_fe_lun); + return ISCSI_TMF_RSP_REJECTED; + } + se_tmr->ref_task_tag = hdr->rtt; - se_tmr->ref_cmd = &ref_cmd->se_cmd; - se_tmr->ref_task_lun = get_unaligned_le64(&hdr->lun); + tmr_req->ref_cmd = ref_cmd; tmr_req->ref_cmd_sn = hdr->refcmdsn; tmr_req->exp_data_sn = hdr->exp_datasn; tmr_req->conn_recovery = cr; @@ -191,9 +199,7 @@ static int iscsit_task_reassign_complete_nop_out( struct iscsi_tmr_req *tmr_req, struct iscsi_conn *conn) { - struct se_tmr_req *se_tmr = tmr_req->se_tmr_req; - struct se_cmd *se_cmd = se_tmr->ref_cmd; - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); + struct iscsi_cmd *cmd = tmr_req->ref_cmd; struct iscsi_conn_recovery *cr; if (!cmd->cr) { @@ -360,9 +366,7 @@ static int iscsit_task_reassign_complete_scsi_cmnd( struct iscsi_tmr_req *tmr_req, struct iscsi_conn *conn) { - struct se_tmr_req *se_tmr = tmr_req->se_tmr_req; - struct se_cmd *se_cmd = se_tmr->ref_cmd; - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); + struct iscsi_cmd *cmd = tmr_req->ref_cmd; struct iscsi_conn_recovery *cr; if (!cmd->cr) { @@ -385,7 +389,7 @@ static int iscsit_task_reassign_complete_scsi_cmnd( list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); spin_unlock_bh(&conn->cmd_lock); - if (se_cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) { + if (cmd->se_cmd.se_cmd_flags & SCF_SENT_CHECK_CONDITION) { cmd->i_state = ISTATE_SEND_STATUS; iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); return 0; @@ -411,17 +415,14 @@ static int iscsit_task_reassign_complete( struct iscsi_tmr_req *tmr_req, struct iscsi_conn *conn) { - struct se_tmr_req *se_tmr = tmr_req->se_tmr_req; - struct se_cmd *se_cmd; struct iscsi_cmd *cmd; int ret = 0; - if (!se_tmr->ref_cmd) { + if (!tmr_req->ref_cmd) { pr_err("TMR Request is missing a RefCmd struct iscsi_cmd.\n"); return -1; } - se_cmd = se_tmr->ref_cmd; - cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); + cmd = tmr_req->ref_cmd; cmd->conn = conn; @@ -547,9 +548,7 @@ int iscsit_task_reassign_prepare_write( struct iscsi_tmr_req *tmr_req, struct iscsi_conn *conn) { - struct se_tmr_req *se_tmr = tmr_req->se_tmr_req; - struct se_cmd *se_cmd = se_tmr->ref_cmd; - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); + struct iscsi_cmd *cmd = tmr_req->ref_cmd; struct iscsi_pdu *pdu = NULL; struct iscsi_r2t *r2t = NULL, *r2t_tmp; int first_incomplete_r2t = 1, i = 0; @@ -782,14 +781,12 @@ int iscsit_check_task_reassign_expdatasn( struct iscsi_tmr_req *tmr_req, struct iscsi_conn *conn) { - struct se_tmr_req *se_tmr = tmr_req->se_tmr_req; - struct se_cmd *se_cmd = se_tmr->ref_cmd; - struct iscsi_cmd *ref_cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); + struct iscsi_cmd *ref_cmd = tmr_req->ref_cmd; if (ref_cmd->iscsi_opcode != ISCSI_OP_SCSI_CMD) return 0; - if (se_cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) + if (ref_cmd->se_cmd.se_cmd_flags & SCF_SENT_CHECK_CONDITION) return 0; if (ref_cmd->data_direction == DMA_NONE) diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 6e99dc5..15039dd 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -483,11 +483,8 @@ struct se_tmr_req { int call_transport; /* Reference to ITT that Task Mgmt should be performed */ u32 ref_task_tag; - /* 64-bit encoded SAM LUN from $FABRIC_MOD TMR header */ - u64 ref_task_lun; void *fabric_tmr_ptr; struct se_cmd *task_cmd; - struct se_cmd *ref_cmd; struct se_device *tmr_dev; struct se_lun *tmr_lun; struct list_head tmr_list; -- cgit v0.10.2 From 7acd57070649da4ac3923f1d2075c084d83da1f4 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 7 Jun 2012 10:38:50 -0700 Subject: target: Do not special-case loop and iscsi fabric module loads These modules, along with other fabrics, should be loaded as-needed by the LIO userspace tools. Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 801efa8..37c4bf3 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -122,47 +122,9 @@ static struct config_group *target_core_register_fabric( const char *name) { struct target_fabric_configfs *tf; - int ret; pr_debug("Target_Core_ConfigFS: REGISTER -> group: %p name:" " %s\n", group, name); - /* - * Below are some hardcoded request_module() calls to automatically - * local fabric modules when the following is called: - * - * mkdir -p /sys/kernel/config/target/$MODULE_NAME - * - * Note that this does not limit which TCM fabric module can be - * registered, but simply provids auto loading logic for modules with - * mkdir(2) system calls with known TCM fabric modules. - */ - if (!strncmp(name, "iscsi", 5)) { - /* - * Automatically load the LIO Target fabric module when the - * following is called: - * - * mkdir -p $CONFIGFS/target/iscsi - */ - ret = request_module("iscsi_target_mod"); - if (ret < 0) { - pr_err("request_module() failed for" - " iscsi_target_mod.ko: %d\n", ret); - return ERR_PTR(-EINVAL); - } - } else if (!strncmp(name, "loopback", 8)) { - /* - * Automatically load the tcm_loop fabric module when the - * following is called: - * - * mkdir -p $CONFIGFS/target/loopback - */ - ret = request_module("tcm_loop"); - if (ret < 0) { - pr_err("request_module() failed for" - " tcm_loop.ko: %d\n", ret); - return ERR_PTR(-EINVAL); - } - } tf = target_core_get_fabric(name); if (!tf) { -- cgit v0.10.2 From 44bfd0185043c9a92b2f20a4508dd6cd3bb84ded Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 7 Jun 2012 10:38:51 -0700 Subject: target/iblock: Add parameter to specify read-only devices see https://bugzilla.redhat.com/show_bug.cgi?id=818855 Adds a parameter so read-only block devices may be registered as LIO backstores. Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 244fff4..c2d4ccb 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -96,6 +96,7 @@ static struct se_device *iblock_create_virtdevice( struct request_queue *q; struct queue_limits *limits; u32 dev_flags = 0; + fmode_t mode; int ret = -EINVAL; if (!ib_dev) { @@ -117,8 +118,11 @@ static struct se_device *iblock_create_virtdevice( pr_debug( "IBLOCK: Claiming struct block_device: %s\n", ib_dev->ibd_udev_path); - bd = blkdev_get_by_path(ib_dev->ibd_udev_path, - FMODE_WRITE|FMODE_READ|FMODE_EXCL, ib_dev); + mode = FMODE_READ|FMODE_EXCL; + if (!ib_dev->ibd_readonly) + mode |= FMODE_WRITE; + + bd = blkdev_get_by_path(ib_dev->ibd_udev_path, mode, ib_dev); if (IS_ERR(bd)) { ret = PTR_ERR(bd); goto failed; @@ -323,11 +327,12 @@ static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range) } enum { - Opt_udev_path, Opt_force, Opt_err + Opt_udev_path, Opt_readonly, Opt_force, Opt_err }; static match_table_t tokens = { {Opt_udev_path, "udev_path=%s"}, + {Opt_readonly, "readonly=%d"}, {Opt_force, "force=%d"}, {Opt_err, NULL} }; @@ -340,6 +345,7 @@ static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba, char *orig, *ptr, *arg_p, *opts; substring_t args[MAX_OPT_ARGS]; int ret = 0, token; + unsigned long tmp_readonly; opts = kstrdup(page, GFP_KERNEL); if (!opts) @@ -372,6 +378,22 @@ static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba, ib_dev->ibd_udev_path); ib_dev->ibd_flags |= IBDF_HAS_UDEV_PATH; break; + case Opt_readonly: + arg_p = match_strdup(&args[0]); + if (!arg_p) { + ret = -ENOMEM; + break; + } + ret = strict_strtoul(arg_p, 0, &tmp_readonly); + kfree(arg_p); + if (ret < 0) { + pr_err("strict_strtoul() failed for" + " readonly=\n"); + goto out; + } + ib_dev->ibd_readonly = tmp_readonly; + pr_debug("IBLOCK: readonly: %d\n", ib_dev->ibd_readonly); + break; case Opt_force: break; default: @@ -411,11 +433,10 @@ static ssize_t iblock_show_configfs_dev_params( if (bd) bl += sprintf(b + bl, "iBlock device: %s", bdevname(bd, buf)); - if (ibd->ibd_flags & IBDF_HAS_UDEV_PATH) { - bl += sprintf(b + bl, " UDEV PATH: %s\n", + if (ibd->ibd_flags & IBDF_HAS_UDEV_PATH) + bl += sprintf(b + bl, " UDEV PATH: %s", ibd->ibd_udev_path); - } else - bl += sprintf(b + bl, "\n"); + bl += sprintf(b + bl, " readonly: %d\n", ibd->ibd_readonly); bl += sprintf(b + bl, " "); if (bd) { diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h index 66cf7b9..533627a 100644 --- a/drivers/target/target_core_iblock.h +++ b/drivers/target/target_core_iblock.h @@ -18,6 +18,7 @@ struct iblock_dev { u32 ibd_flags; struct bio_set *ibd_bio_set; struct block_device *ibd_bd; + bool ibd_readonly; } ____cacheline_aligned; #endif /* TARGET_CORE_IBLOCK_H */ -- cgit v0.10.2 From c75660c5e42c1a3edc4df0d062b2bd73e69dadb7 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 11 Jun 2012 09:49:13 -0700 Subject: target/iscsi: Remove dead code in lio_get_tpg_from_tpg_item() It's got no callers... Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 69dc8e3..a7b25e7 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -47,28 +47,6 @@ struct lio_target_configfs_attribute { ssize_t (*store)(void *, const char *, size_t); }; -struct iscsi_portal_group *lio_get_tpg_from_tpg_item( - struct config_item *item, - struct iscsi_tiqn **tiqn_out) -{ - struct se_portal_group *se_tpg = container_of(to_config_group(item), - struct se_portal_group, tpg_group); - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; - int ret; - - if (!tpg) { - pr_err("Unable to locate struct iscsi_portal_group " - "pointer\n"); - return NULL; - } - ret = iscsit_get_tpg(tpg); - if (ret < 0) - return NULL; - - *tiqn_out = tpg->tpg_tiqn; - return tpg; -} - /* Start items for lio_target_portal_cit */ static ssize_t lio_target_np_show_sctp( -- cgit v0.10.2 From e1306bdab3af8bef620990a99e613f99eb30065c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 17 Jun 2012 18:40:51 -0400 Subject: target: remove dead SCF_ flags Remove the dead SCF_SE_ALLOW_EOO and SCF_DELAYED_CMD_FROM_SAM_ATTR from se_cmd_flags_table. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 1c53fce..8294696 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1933,7 +1933,6 @@ static void target_execute_cmd(struct se_cmd *cmd) if (atomic_read(&dev->dev_ordered_sync) != 0) { spin_lock(&dev->delayed_cmd_lock); - cmd->se_cmd_flags |= SCF_DELAYED_CMD_FROM_SAM_ATTR; list_add_tail(&cmd->se_delayed_node, &dev->delayed_cmd_list); spin_unlock(&dev->delayed_cmd_lock); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 15039dd..1ae97fe 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -166,14 +166,12 @@ enum se_cmd_flags_table { SCF_SCSI_RESERVATION_CONFLICT = 0x00000040, SCF_FUA = 0x00000080, SCF_SE_LUN_CMD = 0x00000100, - SCF_SE_ALLOW_EOO = 0x00000200, SCF_BIDI = 0x00000400, SCF_SENT_CHECK_CONDITION = 0x00000800, SCF_OVERFLOW_BIT = 0x00001000, SCF_UNDERFLOW_BIT = 0x00002000, SCF_SENT_DELAYED_TAS = 0x00004000, SCF_ALUA_NON_OPTIMIZED = 0x00008000, - SCF_DELAYED_CMD_FROM_SAM_ATTR = 0x00010000, SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000, SCF_ACK_KREF = 0x00040000, }; -- cgit v0.10.2 From 0c2ad7d1132d8b089b1d37875917858e03610019 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 17 Jun 2012 18:40:52 -0400 Subject: target: add struct spc_ops + initial ->execute_rw pointer usage Remove the execute_cmd method in struct se_subsystem_api, and always use the one directly in struct se_cmd. To make life simpler for SBC virtual backends a struct spc_ops that is passed to sbc_parse_cmd is added. For now it only contains an execute_rw member, but more will follow with the subsequent commits. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index e2df308..720ed59 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -375,9 +375,11 @@ static void fd_emulate_sync_cache(struct se_cmd *cmd) } } -static int fd_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, - u32 sgl_nents, enum dma_data_direction data_direction) +static int fd_execute_rw(struct se_cmd *cmd) { + struct scatterlist *sgl = cmd->t_data_sg; + u32 sgl_nents = cmd->t_data_nents; + enum dma_data_direction data_direction = cmd->data_direction; struct se_device *dev = cmd->se_dev; int ret = 0; @@ -550,6 +552,15 @@ static sector_t fd_get_blocks(struct se_device *dev) return div_u64(dev_size, dev->se_sub_dev->se_dev_attrib.block_size); } +static struct spc_ops fd_spc_ops = { + .execute_rw = fd_execute_rw, +}; + +static int fd_parse_cdb(struct se_cmd *cmd) +{ + return sbc_parse_cdb(cmd, &fd_spc_ops); +} + static struct se_subsystem_api fileio_template = { .name = "fileio", .owner = THIS_MODULE, @@ -561,8 +572,7 @@ static struct se_subsystem_api fileio_template = { .allocate_virtdevice = fd_allocate_virtdevice, .create_virtdevice = fd_create_virtdevice, .free_device = fd_free_device, - .parse_cdb = sbc_parse_cdb, - .execute_cmd = fd_execute_cmd, + .parse_cdb = fd_parse_cdb, .do_sync_cache = fd_emulate_sync_cache, .check_configfs_dev_params = fd_check_configfs_dev_params, .set_configfs_dev_params = fd_set_configfs_dev_params, diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index c2d4ccb..eb94367 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -514,9 +514,11 @@ static void iblock_submit_bios(struct bio_list *list, int rw) blk_finish_plug(&plug); } -static int iblock_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, - u32 sgl_nents, enum dma_data_direction data_direction) +static int iblock_execute_rw(struct se_cmd *cmd) { + struct scatterlist *sgl = cmd->t_data_sg; + u32 sgl_nents = cmd->t_data_nents; + enum dma_data_direction data_direction = cmd->data_direction; struct se_device *dev = cmd->se_dev; struct iblock_req *ibr; struct bio *bio; @@ -663,6 +665,15 @@ static void iblock_bio_done(struct bio *bio, int err) iblock_complete_cmd(cmd); } +static struct spc_ops iblock_spc_ops = { + .execute_rw = iblock_execute_rw, +}; + +static int iblock_parse_cdb(struct se_cmd *cmd) +{ + return sbc_parse_cdb(cmd, &iblock_spc_ops); +} + static struct se_subsystem_api iblock_template = { .name = "iblock", .owner = THIS_MODULE, @@ -674,8 +685,7 @@ static struct se_subsystem_api iblock_template = { .allocate_virtdevice = iblock_allocate_virtdevice, .create_virtdevice = iblock_create_virtdevice, .free_device = iblock_free_device, - .parse_cdb = sbc_parse_cdb, - .execute_cmd = iblock_execute_cmd, + .parse_cdb = iblock_parse_cdb, .do_discard = iblock_do_discard, .do_sync_cache = iblock_emulate_sync_cache, .check_configfs_dev_params = iblock_check_configfs_dev_params, diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index cb4c6b1..6e32ff6 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -55,6 +55,7 @@ static struct se_subsystem_api pscsi_template; +static int pscsi_execute_cmd(struct se_cmd *cmd); static void pscsi_req_done(struct request *, int); /* pscsi_attach_hba(): @@ -1081,17 +1082,20 @@ static int pscsi_parse_cdb(struct se_cmd *cmd) case WRITE_16: case WRITE_VERIFY: cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; + /* FALLTHROUGH*/ default: + cmd->execute_cmd = pscsi_execute_cmd; break; } return 0; } -static int pscsi_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, - u32 sgl_nents, enum dma_data_direction data_direction) +static int pscsi_execute_cmd(struct se_cmd *cmd) { + struct scatterlist *sgl = cmd->t_data_sg; + u32 sgl_nents = cmd->t_data_nents; + enum dma_data_direction data_direction = cmd->data_direction; struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr; struct pscsi_plugin_task *pt; struct request *req; @@ -1259,7 +1263,6 @@ static struct se_subsystem_api pscsi_template = { .free_device = pscsi_free_device, .transport_complete = pscsi_transport_complete, .parse_cdb = pscsi_parse_cdb, - .execute_cmd = pscsi_execute_cmd, .check_configfs_dev_params = pscsi_check_configfs_dev_params, .set_configfs_dev_params = pscsi_set_configfs_dev_params, .show_configfs_dev_params = pscsi_show_configfs_dev_params, diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index d7e8382..d00bbe3 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -284,9 +284,11 @@ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page) return NULL; } -static int rd_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, - u32 sgl_nents, enum dma_data_direction data_direction) +static int rd_execute_rw(struct se_cmd *cmd) { + struct scatterlist *sgl = cmd->t_data_sg; + u32 sgl_nents = cmd->t_data_nents; + enum dma_data_direction data_direction = cmd->data_direction; struct se_device *se_dev = cmd->se_dev; struct rd_dev *dev = se_dev->dev_ptr; struct rd_dev_sg_table *table; @@ -460,6 +462,15 @@ static sector_t rd_get_blocks(struct se_device *dev) return blocks_long; } +static struct spc_ops rd_spc_ops = { + .execute_rw = rd_execute_rw, +}; + +static int rd_parse_cdb(struct se_cmd *cmd) +{ + return sbc_parse_cdb(cmd, &rd_spc_ops); +} + static struct se_subsystem_api rd_mcp_template = { .name = "rd_mcp", .transport_type = TRANSPORT_PLUGIN_VHBA_VDEV, @@ -468,8 +479,7 @@ static struct se_subsystem_api rd_mcp_template = { .allocate_virtdevice = rd_allocate_virtdevice, .create_virtdevice = rd_create_virtdevice, .free_device = rd_free_device, - .parse_cdb = sbc_parse_cdb, - .execute_cmd = rd_execute_cmd, + .parse_cdb = rd_parse_cdb, .check_configfs_dev_params = rd_check_configfs_dev_params, .set_configfs_dev_params = rd_set_configfs_dev_params, .show_configfs_dev_params = rd_show_configfs_dev_params, diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index a5bd0c0..da441b2 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -395,7 +395,7 @@ out: kfree(buf); } -int sbc_parse_cdb(struct se_cmd *cmd) +int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) { struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; struct se_device *dev = cmd->se_dev; @@ -409,26 +409,31 @@ int sbc_parse_cdb(struct se_cmd *cmd) sectors = transport_get_sectors_6(cdb); cmd->t_task_lba = transport_lba_21(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + cmd->execute_cmd = ops->execute_rw; break; case READ_10: sectors = transport_get_sectors_10(cdb); cmd->t_task_lba = transport_lba_32(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + cmd->execute_cmd = ops->execute_rw; break; case READ_12: sectors = transport_get_sectors_12(cdb); cmd->t_task_lba = transport_lba_32(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + cmd->execute_cmd = ops->execute_rw; break; case READ_16: sectors = transport_get_sectors_16(cdb); cmd->t_task_lba = transport_lba_64(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + cmd->execute_cmd = ops->execute_rw; break; case WRITE_6: sectors = transport_get_sectors_6(cdb); cmd->t_task_lba = transport_lba_21(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + cmd->execute_cmd = ops->execute_rw; break; case WRITE_10: case WRITE_VERIFY: @@ -437,6 +442,7 @@ int sbc_parse_cdb(struct se_cmd *cmd) if (cdb[1] & 0x8) cmd->se_cmd_flags |= SCF_FUA; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + cmd->execute_cmd = ops->execute_rw; break; case WRITE_12: sectors = transport_get_sectors_12(cdb); @@ -444,6 +450,7 @@ int sbc_parse_cdb(struct se_cmd *cmd) if (cdb[1] & 0x8) cmd->se_cmd_flags |= SCF_FUA; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + cmd->execute_cmd = ops->execute_rw; break; case WRITE_16: sectors = transport_get_sectors_16(cdb); @@ -451,6 +458,7 @@ int sbc_parse_cdb(struct se_cmd *cmd) if (cdb[1] & 0x8) cmd->se_cmd_flags |= SCF_FUA; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + cmd->execute_cmd = ops->execute_rw; break; case XDWRITEREAD_10: if ((cmd->data_direction != DMA_TO_DEVICE) || @@ -464,6 +472,7 @@ int sbc_parse_cdb(struct se_cmd *cmd) /* * Setup BIDI XOR callback to be run after I/O completion. */ + cmd->execute_cmd = ops->execute_rw; cmd->transport_complete_callback = &xdreadwrite_callback; if (cdb[1] & 0x8) cmd->se_cmd_flags |= SCF_FUA; @@ -486,6 +495,7 @@ int sbc_parse_cdb(struct se_cmd *cmd) * Setup BIDI XOR callback to be run during after I/O * completion. */ + cmd->execute_cmd = ops->execute_rw; cmd->transport_complete_callback = &xdreadwrite_callback; if (cdb[1] & 0x8) cmd->se_cmd_flags |= SCF_FUA; diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 8294696..803ac52 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1865,7 +1865,7 @@ EXPORT_SYMBOL(transport_generic_request_failure); static void __target_execute_cmd(struct se_cmd *cmd) { - int error; + int error = 0; spin_lock_irq(&cmd->t_state_lock); cmd->transport_state |= (CMD_T_BUSY|CMD_T_SENT); @@ -1873,10 +1873,6 @@ static void __target_execute_cmd(struct se_cmd *cmd) if (cmd->execute_cmd) error = cmd->execute_cmd(cmd); - else { - error = cmd->se_dev->transport->execute_cmd(cmd, cmd->t_data_sg, - cmd->t_data_nents, cmd->data_direction); - } if (error) { spin_lock_irq(&cmd->t_state_lock); diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 24d2004..9b4f2c9 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -26,8 +26,6 @@ struct se_subsystem_api { int (*transport_complete)(struct se_cmd *cmd, struct scatterlist *); int (*parse_cdb)(struct se_cmd *cmd); - int (*execute_cmd)(struct se_cmd *, struct scatterlist *, u32, - enum dma_data_direction); int (*do_discard)(struct se_device *, sector_t, u32); void (*do_sync_cache)(struct se_cmd *); ssize_t (*check_configfs_dev_params)(struct se_hba *, @@ -42,6 +40,10 @@ struct se_subsystem_api { unsigned char *(*get_sense_buffer)(struct se_cmd *); }; +struct spc_ops { + int (*execute_rw)(struct se_cmd *cmd); +}; + int transport_subsystem_register(struct se_subsystem_api *); void transport_subsystem_release(struct se_subsystem_api *); @@ -51,7 +53,7 @@ struct se_device *transport_add_device_to_core_hba(struct se_hba *, void target_complete_cmd(struct se_cmd *, u8); -int sbc_parse_cdb(struct se_cmd *cmd); +int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops); int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size); void transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *); -- cgit v0.10.2 From ad67f0d9e63ca94661e06a145f05a9302368a826 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 17 Jun 2012 18:40:53 -0400 Subject: target: move sync_cache to struct spc_ops Add spc_ops->execute_sync_cache() caller for ->execute_cmd() setup, and update IBLOCK + FILEIO backends to use it. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 720ed59..9e21005 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -331,7 +331,7 @@ static int fd_do_writev(struct se_cmd *cmd, struct scatterlist *sgl, return 1; } -static void fd_emulate_sync_cache(struct se_cmd *cmd) +static int fd_execute_sync_cache(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; struct fd_dev *fd_dev = dev->dev_ptr; @@ -365,7 +365,7 @@ static void fd_emulate_sync_cache(struct se_cmd *cmd) pr_err("FILEIO: vfs_fsync_range() failed: %d\n", ret); if (immed) - return; + return 0; if (ret) { cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; @@ -373,6 +373,8 @@ static void fd_emulate_sync_cache(struct se_cmd *cmd) } else { target_complete_cmd(cmd, SAM_STAT_GOOD); } + + return 0; } static int fd_execute_rw(struct se_cmd *cmd) @@ -554,6 +556,7 @@ static sector_t fd_get_blocks(struct se_device *dev) static struct spc_ops fd_spc_ops = { .execute_rw = fd_execute_rw, + .execute_sync_cache = fd_execute_sync_cache, }; static int fd_parse_cdb(struct se_cmd *cmd) @@ -573,7 +576,6 @@ static struct se_subsystem_api fileio_template = { .create_virtdevice = fd_create_virtdevice, .free_device = fd_free_device, .parse_cdb = fd_parse_cdb, - .do_sync_cache = fd_emulate_sync_cache, .check_configfs_dev_params = fd_check_configfs_dev_params, .set_configfs_dev_params = fd_set_configfs_dev_params, .show_configfs_dev_params = fd_show_configfs_dev_params, diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index eb94367..863c962 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -296,7 +296,7 @@ static void iblock_end_io_flush(struct bio *bio, int err) * Implement SYCHRONIZE CACHE. Note that we can't handle lba ranges and must * always flush the whole cache. */ -static void iblock_emulate_sync_cache(struct se_cmd *cmd) +static int iblock_execute_sync_cache(struct se_cmd *cmd) { struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr; int immed = (cmd->t_task_cdb[1] & 0x2); @@ -315,6 +315,7 @@ static void iblock_emulate_sync_cache(struct se_cmd *cmd) if (!immed) bio->bi_private = cmd; submit_bio(WRITE_FLUSH, bio); + return 0; } static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range) @@ -667,6 +668,7 @@ static void iblock_bio_done(struct bio *bio, int err) static struct spc_ops iblock_spc_ops = { .execute_rw = iblock_execute_rw, + .execute_sync_cache = iblock_execute_sync_cache, }; static int iblock_parse_cdb(struct se_cmd *cmd) @@ -687,7 +689,6 @@ static struct se_subsystem_api iblock_template = { .free_device = iblock_free_device, .parse_cdb = iblock_parse_cdb, .do_discard = iblock_do_discard, - .do_sync_cache = iblock_emulate_sync_cache, .check_configfs_dev_params = iblock_check_configfs_dev_params, .set_configfs_dev_params = iblock_set_configfs_dev_params, .show_configfs_dev_params = iblock_show_configfs_dev_params, diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index da441b2..377c510 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -204,19 +204,6 @@ static int sbc_emulate_write_same(struct se_cmd *cmd) return 0; } -static int sbc_emulate_synchronize_cache(struct se_cmd *cmd) -{ - if (!cmd->se_dev->transport->do_sync_cache) { - pr_err("SYNCHRONIZE_CACHE emulation not supported" - " for: %s\n", cmd->se_dev->transport->name); - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; - return -ENOSYS; - } - - cmd->se_dev->transport->do_sync_cache(cmd); - return 0; -} - static int sbc_emulate_verify(struct se_cmd *cmd) { target_complete_cmd(cmd, GOOD); @@ -541,6 +528,9 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) break; case SYNCHRONIZE_CACHE: case SYNCHRONIZE_CACHE_16: + if (!ops->execute_sync_cache) + goto out_unsupported_cdb; + /* * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE */ @@ -562,7 +552,7 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) if (sbc_check_valid_sectors(cmd) < 0) goto out_invalid_cdb_field; } - cmd->execute_cmd = sbc_emulate_synchronize_cache; + cmd->execute_cmd = ops->execute_sync_cache; break; case UNMAP: size = get_unaligned_be16(&cdb[7]); diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 9b4f2c9..5797b11 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -27,7 +27,6 @@ struct se_subsystem_api { int (*parse_cdb)(struct se_cmd *cmd); int (*do_discard)(struct se_device *, sector_t, u32); - void (*do_sync_cache)(struct se_cmd *); ssize_t (*check_configfs_dev_params)(struct se_hba *, struct se_subsystem_dev *); ssize_t (*set_configfs_dev_params)(struct se_hba *, @@ -42,6 +41,7 @@ struct se_subsystem_api { struct spc_ops { int (*execute_rw)(struct se_cmd *cmd); + int (*execute_sync_cache)(struct se_cmd *cmd); }; int transport_subsystem_register(struct se_subsystem_api *); -- cgit v0.10.2 From 6f974e8ce7b3f661910a49c7c2ba095631f341e9 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 17 Jun 2012 18:40:54 -0400 Subject: target: move write_same to struct spc_ops Add spc_ops->execute_write_same() caller for ->execute_cmd() setup, and update IBLOCK backends to use it. (nab: add export of spc_get_write_same_sectors symbol) (roland: Carry forward: Fix range calculation in WRITE SAME emulation when num blocks == 0) Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 863c962..ee70cc9 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -327,6 +327,23 @@ static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range) return blkdev_issue_discard(bd, lba, range, GFP_KERNEL, barrier); } +static int iblock_execute_write_same(struct se_cmd *cmd) +{ + struct iblock_dev *ibd = cmd->se_dev->dev_ptr; + int ret; + + ret = blkdev_issue_discard(ibd->ibd_bd, cmd->t_task_lba, + spc_get_write_same_sectors(cmd), GFP_KERNEL, + 0); + if (ret < 0) { + pr_debug("blkdev_issue_discard() failed for WRITE_SAME\n"); + return ret; + } + + target_complete_cmd(cmd, GOOD); + return 0; +} + enum { Opt_udev_path, Opt_readonly, Opt_force, Opt_err }; @@ -669,6 +686,7 @@ static void iblock_bio_done(struct bio *bio, int err) static struct spc_ops iblock_spc_ops = { .execute_rw = iblock_execute_rw, .execute_sync_cache = iblock_execute_sync_cache, + .execute_write_same = iblock_execute_write_same, }; static int iblock_parse_cdb(struct se_cmd *cmd) diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 377c510..146ca37 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -156,24 +156,9 @@ err: return ret; } -/* - * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. - * Note this is not used for TCM/pSCSI passthrough - */ -static int sbc_emulate_write_same(struct se_cmd *cmd) +int spc_get_write_same_sectors(struct se_cmd *cmd) { - struct se_device *dev = cmd->se_dev; - sector_t range; - sector_t lba = cmd->t_task_lba; u32 num_blocks; - int ret; - - if (!dev->transport->do_discard) { - pr_err("WRITE_SAME emulation not supported" - " for: %s\n", dev->transport->name); - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; - return -ENOSYS; - } if (cmd->t_task_cdb[0] == WRITE_SAME) num_blocks = get_unaligned_be16(&cmd->t_task_cdb[7]); @@ -186,23 +171,13 @@ static int sbc_emulate_write_same(struct se_cmd *cmd) * Use the explicit range when non zero is supplied, otherwise calculate * the remaining range based on ->get_blocks() - starting LBA. */ - if (num_blocks != 0) - range = num_blocks; - else - range = (dev->transport->get_blocks(dev) - lba) + 1; + if (num_blocks) + return num_blocks; - pr_debug("WRITE_SAME UNMAP: LBA: %llu Range: %llu\n", - (unsigned long long)lba, (unsigned long long)range); - - ret = dev->transport->do_discard(dev, lba, range); - if (ret < 0) { - pr_debug("blkdev_issue_discard() failed for WRITE_SAME\n"); - return ret; - } - - target_complete_cmd(cmd, GOOD); - return 0; + return cmd->se_dev->transport->get_blocks(cmd->se_dev) - + cmd->t_task_lba + 1; } +EXPORT_SYMBOL(spc_get_write_same_sectors); static int sbc_emulate_verify(struct se_cmd *cmd) { @@ -488,6 +463,9 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) cmd->se_cmd_flags |= SCF_FUA; break; case WRITE_SAME_32: + if (!ops->execute_write_same) + goto out_unsupported_cdb; + sectors = transport_get_sectors_32(cdb); if (!sectors) { pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not" @@ -500,7 +478,7 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) if (sbc_write_same_supported(dev, &cdb[10]) < 0) goto out_unsupported_cdb; - cmd->execute_cmd = sbc_emulate_write_same; + cmd->execute_cmd = ops->execute_write_same; break; default: pr_err("VARIABLE_LENGTH_CMD service action" @@ -559,6 +537,9 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) cmd->execute_cmd = sbc_emulate_unmap; break; case WRITE_SAME_16: + if (!ops->execute_write_same) + goto out_unsupported_cdb; + sectors = transport_get_sectors_16(cdb); if (!sectors) { pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); @@ -570,9 +551,12 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) if (sbc_write_same_supported(dev, &cdb[1]) < 0) goto out_unsupported_cdb; - cmd->execute_cmd = sbc_emulate_write_same; + cmd->execute_cmd = ops->execute_write_same; break; case WRITE_SAME: + if (!ops->execute_write_same) + goto out_unsupported_cdb; + sectors = transport_get_sectors_10(cdb); if (!sectors) { pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); @@ -588,7 +572,7 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) */ if (sbc_write_same_supported(dev, &cdb[1]) < 0) goto out_unsupported_cdb; - cmd->execute_cmd = sbc_emulate_write_same; + cmd->execute_cmd = ops->execute_write_same; break; case VERIFY: size = 0; diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 5797b11..fbc6a1b 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -42,6 +42,7 @@ struct se_subsystem_api { struct spc_ops { int (*execute_rw)(struct se_cmd *cmd); int (*execute_sync_cache)(struct se_cmd *cmd); + int (*execute_write_same)(struct se_cmd *cmd); }; int transport_subsystem_register(struct se_subsystem_api *); @@ -55,6 +56,7 @@ void target_complete_cmd(struct se_cmd *, u8); int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops); int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size); +int spc_get_write_same_sectors(struct se_cmd *cmd); void transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *); int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *); -- cgit v0.10.2 From 14150a6bbe9e15ce8e7a4f79047c2b4284a51b3d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 17 Jun 2012 18:40:55 -0400 Subject: target: move unmap to struct spc_ops Having all the unmap payload parsing in the backed is a bit ugly, but until more drivers support it and we can find a good interface for all of them that seems the way to go. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index ee70cc9..8a12e29 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -318,13 +319,52 @@ static int iblock_execute_sync_cache(struct se_cmd *cmd) return 0; } -static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range) +static int iblock_execute_unmap(struct se_cmd *cmd) { + struct se_device *dev = cmd->se_dev; struct iblock_dev *ibd = dev->dev_ptr; - struct block_device *bd = ibd->ibd_bd; - int barrier = 0; + unsigned char *buf, *ptr = NULL; + unsigned char *cdb = &cmd->t_task_cdb[0]; + sector_t lba; + unsigned int size = cmd->data_length, range; + int ret = 0, offset; + unsigned short dl, bd_dl; + + /* First UNMAP block descriptor starts at 8 byte offset */ + offset = 8; + size -= 8; + dl = get_unaligned_be16(&cdb[0]); + bd_dl = get_unaligned_be16(&cdb[2]); + + buf = transport_kmap_data_sg(cmd); + + ptr = &buf[offset]; + pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu" + " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr); + + while (size) { + lba = get_unaligned_be64(&ptr[0]); + range = get_unaligned_be32(&ptr[8]); + pr_debug("UNMAP: Using lba: %llu and range: %u\n", + (unsigned long long)lba, range); + + ret = blkdev_issue_discard(ibd->ibd_bd, lba, range, + GFP_KERNEL, 0); + if (ret < 0) { + pr_err("blkdev_issue_discard() failed: %d\n", + ret); + goto err; + } + + ptr += 16; + size -= 16; + } - return blkdev_issue_discard(bd, lba, range, GFP_KERNEL, barrier); +err: + transport_kunmap_data_sg(cmd); + if (!ret) + target_complete_cmd(cmd, GOOD); + return ret; } static int iblock_execute_write_same(struct se_cmd *cmd) @@ -687,6 +727,7 @@ static struct spc_ops iblock_spc_ops = { .execute_rw = iblock_execute_rw, .execute_sync_cache = iblock_execute_sync_cache, .execute_write_same = iblock_execute_write_same, + .execute_unmap = iblock_execute_unmap, }; static int iblock_parse_cdb(struct se_cmd *cmd) @@ -706,7 +747,6 @@ static struct se_subsystem_api iblock_template = { .create_virtdevice = iblock_create_virtdevice, .free_device = iblock_free_device, .parse_cdb = iblock_parse_cdb, - .do_discard = iblock_do_discard, .check_configfs_dev_params = iblock_check_configfs_dev_params, .set_configfs_dev_params = iblock_set_configfs_dev_params, .show_configfs_dev_params = iblock_show_configfs_dev_params, diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 146ca37..a9dd946 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -99,63 +99,6 @@ static int sbc_emulate_readcapacity_16(struct se_cmd *cmd) return 0; } -/* - * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. - * Note this is not used for TCM/pSCSI passthrough - */ -static int sbc_emulate_unmap(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - unsigned char *buf, *ptr = NULL; - unsigned char *cdb = &cmd->t_task_cdb[0]; - sector_t lba; - unsigned int size = cmd->data_length, range; - int ret = 0, offset; - unsigned short dl, bd_dl; - - if (!dev->transport->do_discard) { - pr_err("UNMAP emulation not supported for: %s\n", - dev->transport->name); - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; - return -ENOSYS; - } - - /* First UNMAP block descriptor starts at 8 byte offset */ - offset = 8; - size -= 8; - dl = get_unaligned_be16(&cdb[0]); - bd_dl = get_unaligned_be16(&cdb[2]); - - buf = transport_kmap_data_sg(cmd); - - ptr = &buf[offset]; - pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu" - " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr); - - while (size) { - lba = get_unaligned_be64(&ptr[0]); - range = get_unaligned_be32(&ptr[8]); - pr_debug("UNMAP: Using lba: %llu and range: %u\n", - (unsigned long long)lba, range); - - ret = dev->transport->do_discard(dev, lba, range); - if (ret < 0) { - pr_err("blkdev_issue_discard() failed: %d\n", - ret); - goto err; - } - - ptr += 16; - size -= 16; - } - -err: - transport_kunmap_data_sg(cmd); - if (!ret) - target_complete_cmd(cmd, GOOD); - return ret; -} - int spc_get_write_same_sectors(struct se_cmd *cmd) { u32 num_blocks; @@ -533,8 +476,11 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) cmd->execute_cmd = ops->execute_sync_cache; break; case UNMAP: + if (!ops->execute_unmap) + goto out_unsupported_cdb; + size = get_unaligned_be16(&cdb[7]); - cmd->execute_cmd = sbc_emulate_unmap; + cmd->execute_cmd = ops->execute_unmap; break; case WRITE_SAME_16: if (!ops->execute_write_same) diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index fbc6a1b..f1405d33 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -26,7 +26,6 @@ struct se_subsystem_api { int (*transport_complete)(struct se_cmd *cmd, struct scatterlist *); int (*parse_cdb)(struct se_cmd *cmd); - int (*do_discard)(struct se_device *, sector_t, u32); ssize_t (*check_configfs_dev_params)(struct se_hba *, struct se_subsystem_dev *); ssize_t (*set_configfs_dev_params)(struct se_hba *, @@ -43,6 +42,7 @@ struct spc_ops { int (*execute_rw)(struct se_cmd *cmd); int (*execute_sync_cache)(struct se_cmd *cmd); int (*execute_write_same)(struct se_cmd *cmd); + int (*execute_unmap)(struct se_cmd *cmd); }; int transport_subsystem_register(struct se_subsystem_api *); -- cgit v0.10.2 From 182a9e2cef7bb7017f95bd1b9f27fb81b97f07de Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Wed, 11 Jul 2012 13:29:47 -0700 Subject: Revert "target: Do not special-case loop and iscsi fabric module loads" Existing lio_dump.py code expects this to be in place for /iscsi. Revert for now to avoid userspace breakage in lio-utils This reverts commit fd88a785f9ac5d6be437c528571ccd85cdf2d493. Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 37c4bf3..801efa8 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -122,9 +122,47 @@ static struct config_group *target_core_register_fabric( const char *name) { struct target_fabric_configfs *tf; + int ret; pr_debug("Target_Core_ConfigFS: REGISTER -> group: %p name:" " %s\n", group, name); + /* + * Below are some hardcoded request_module() calls to automatically + * local fabric modules when the following is called: + * + * mkdir -p /sys/kernel/config/target/$MODULE_NAME + * + * Note that this does not limit which TCM fabric module can be + * registered, but simply provids auto loading logic for modules with + * mkdir(2) system calls with known TCM fabric modules. + */ + if (!strncmp(name, "iscsi", 5)) { + /* + * Automatically load the LIO Target fabric module when the + * following is called: + * + * mkdir -p $CONFIGFS/target/iscsi + */ + ret = request_module("iscsi_target_mod"); + if (ret < 0) { + pr_err("request_module() failed for" + " iscsi_target_mod.ko: %d\n", ret); + return ERR_PTR(-EINVAL); + } + } else if (!strncmp(name, "loopback", 8)) { + /* + * Automatically load the tcm_loop fabric module when the + * following is called: + * + * mkdir -p $CONFIGFS/target/loopback + */ + ret = request_module("tcm_loop"); + if (ret < 0) { + pr_err("request_module() failed for" + " tcm_loop.ko: %d\n", ret); + return ERR_PTR(-EINVAL); + } + } tf = target_core_get_fabric(name); if (!tf) { -- cgit v0.10.2 From e85276871978614723830684096f7e44903963b3 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 22 Jun 2012 17:23:58 +0530 Subject: tcm_qla2xxx: Remove duplicate header file inclusion ctype.h and string.h header files were included more than once. Signed-off-by: Sachin Kamat Signed-off-by: Nicholas Bellinger diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 6e64314..dd0a0df 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -38,8 +38,6 @@ #include #include #include -#include -#include #include #include #include -- cgit v0.10.2 From f7113a47e2c3880ed5f8a05ff9c54ead4ee7351c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 8 Jul 2012 15:58:38 -0400 Subject: target: split transport_cmd_check_stop Inline the transport_off == 0 case into target_execute_cmd to simplify the function for the remaining cases. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 803ac52..3f20fbd 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -467,18 +467,7 @@ static void target_remove_from_state_list(struct se_cmd *cmd) spin_unlock_irqrestore(&dev->execute_task_lock, flags); } -/* transport_cmd_check_stop(): - * - * 'transport_off = 1' determines if CMD_T_ACTIVE should be cleared. - * 'transport_off = 2' determines if task_dev_state should be removed. - * - * A non-zero u8 t_state sets cmd->t_state. - * Returns 1 when command is stopped, else 0. - */ -static int transport_cmd_check_stop( - struct se_cmd *cmd, - int transport_off, - u8 t_state) +static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists) { unsigned long flags; @@ -492,13 +481,23 @@ static int transport_cmd_check_stop( __func__, __LINE__, cmd->se_tfo->get_task_tag(cmd)); cmd->transport_state &= ~CMD_T_ACTIVE; - if (transport_off == 2) + if (remove_from_lists) target_remove_from_state_list(cmd); spin_unlock_irqrestore(&cmd->t_state_lock, flags); complete(&cmd->transport_lun_stop_comp); return 1; } + + if (remove_from_lists) { + target_remove_from_state_list(cmd); + + /* + * Clear struct se_cmd->se_lun before the handoff to FE. + */ + cmd->se_lun = NULL; + } + /* * Determine if frontend context caller is requesting the stopping of * this command for frontend exceptions. @@ -508,58 +507,36 @@ static int transport_cmd_check_stop( __func__, __LINE__, cmd->se_tfo->get_task_tag(cmd)); - if (transport_off == 2) - target_remove_from_state_list(cmd); - - /* - * Clear struct se_cmd->se_lun before the transport_off == 2 handoff - * to FE. - */ - if (transport_off == 2) - cmd->se_lun = NULL; spin_unlock_irqrestore(&cmd->t_state_lock, flags); complete(&cmd->t_transport_stop_comp); return 1; } - if (transport_off) { - cmd->transport_state &= ~CMD_T_ACTIVE; - if (transport_off == 2) { - target_remove_from_state_list(cmd); - /* - * Clear struct se_cmd->se_lun before the transport_off == 2 - * handoff to fabric module. - */ - cmd->se_lun = NULL; - /* - * Some fabric modules like tcm_loop can release - * their internally allocated I/O reference now and - * struct se_cmd now. - * - * Fabric modules are expected to return '1' here if the - * se_cmd being passed is released at this point, - * or zero if not being released. - */ - if (cmd->se_tfo->check_stop_free != NULL) { - spin_unlock_irqrestore( - &cmd->t_state_lock, flags); - - return cmd->se_tfo->check_stop_free(cmd); - } + + cmd->transport_state &= ~CMD_T_ACTIVE; + if (remove_from_lists) { + /* + * Some fabric modules like tcm_loop can release + * their internally allocated I/O reference now and + * struct se_cmd now. + * + * Fabric modules are expected to return '1' here if the + * se_cmd being passed is released at this point, + * or zero if not being released. + */ + if (cmd->se_tfo->check_stop_free != NULL) { + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + return cmd->se_tfo->check_stop_free(cmd); } - spin_unlock_irqrestore(&cmd->t_state_lock, flags); + } - return 0; - } else if (t_state) - cmd->t_state = t_state; spin_unlock_irqrestore(&cmd->t_state_lock, flags); - return 0; } static int transport_cmd_check_stop_to_fabric(struct se_cmd *cmd) { - return transport_cmd_check_stop(cmd, 2, 0); + return transport_cmd_check_stop(cmd, true); } static void transport_lun_remove_cmd(struct se_cmd *cmd) @@ -1887,8 +1864,36 @@ static void target_execute_cmd(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - if (transport_cmd_check_stop(cmd, 0, TRANSPORT_PROCESSING)) + /* + * Determine if IOCTL context caller in requesting the stopping of this + * command for LUN shutdown purposes. + */ + spin_lock_irq(&cmd->t_state_lock); + if (cmd->transport_state & CMD_T_LUN_STOP) { + pr_debug("%s:%d CMD_T_LUN_STOP for ITT: 0x%08x\n", + __func__, __LINE__, cmd->se_tfo->get_task_tag(cmd)); + + cmd->transport_state &= ~CMD_T_ACTIVE; + spin_unlock_irq(&cmd->t_state_lock); + complete(&cmd->transport_lun_stop_comp); + return; + } + /* + * Determine if frontend context caller is requesting the stopping of + * this command for frontend exceptions. + */ + if (cmd->transport_state & CMD_T_STOP) { + pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08x\n", + __func__, __LINE__, + cmd->se_tfo->get_task_tag(cmd)); + + spin_unlock_irq(&cmd->t_state_lock); + complete(&cmd->t_transport_stop_comp); return; + } + + cmd->t_state = TRANSPORT_PROCESSING; + spin_unlock_irq(&cmd->t_state_lock); if (dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED) goto execute; @@ -2530,10 +2535,10 @@ static int transport_generic_write_pending(struct se_cmd *cmd) * Clear the se_cmd for WRITE_PENDING status in order to set * CMD_T_ACTIVE so that transport_generic_handle_data can be called * from HW target mode interrupt code. This is safe to be called - * with transport_off=1 before the cmd->se_tfo->write_pending + * with remove_from_lists false before the cmd->se_tfo->write_pending * because the se_cmd->se_lun pointer is not being cleared. */ - transport_cmd_check_stop(cmd, 1, 0); + transport_cmd_check_stop(cmd, false); /* * Call the fabric write_pending function here to let the @@ -2723,7 +2728,7 @@ static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun) pr_debug("ConfigFS ITT[0x%08x] - CMD_T_STOP, skipping\n", cmd->se_tfo->get_task_tag(cmd)); spin_unlock_irqrestore(&cmd->t_state_lock, flags); - transport_cmd_check_stop(cmd, 1, 0); + transport_cmd_check_stop(cmd, false); return -EPERM; } cmd->transport_state |= CMD_T_LUN_FE_STOP; @@ -2768,11 +2773,6 @@ static void __transport_clear_lun_from_sessions(struct se_lun *lun) struct se_cmd, se_lun_node); list_del_init(&cmd->se_lun_node); - /* - * This will notify iscsi_target_transport.c: - * transport_cmd_check_stop() that a LUN shutdown is in - * progress for the iscsi_cmd_t. - */ spin_lock(&cmd->t_state_lock); pr_debug("SE_LUN[%d] - Setting cmd->transport" "_lun_stop for ITT: 0x%08x\n", @@ -2839,7 +2839,7 @@ check_cond: spin_unlock_irqrestore(&cmd->t_state_lock, cmd_flags); - transport_cmd_check_stop(cmd, 1, 0); + transport_cmd_check_stop(cmd, false); complete(&cmd->transport_lun_fe_stop_comp); spin_lock_irqsave(&lun->lun_cmd_lock, lun_flags); continue; -- cgit v0.10.2 From 70baf0ab3b2608727515086bee4c484a93e22880 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 8 Jul 2012 15:58:39 -0400 Subject: target: remove transport_generic_process_write Just call target_execute_cmd directly. Also, convert loopback, sbp, usb-gadget to use the newly exported target_execute_cmd(). Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index f65dc9d..5491c63 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -778,7 +778,7 @@ static int tcm_loop_write_pending(struct se_cmd *se_cmd) * We now tell TCM to add this WRITE CDB directly into the TCM storage * object execution queue. */ - transport_generic_process_write(se_cmd); + target_execute_cmd(se_cmd); return 0; } diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 7e6136e..0848c4c 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1784,8 +1784,7 @@ static int sbp_write_pending(struct se_cmd *se_cmd) return ret; } - transport_generic_process_write(se_cmd); - + target_execute_cmd(se_cmd); return 0; } diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 3f20fbd..aeb2d57 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1860,7 +1860,7 @@ static void __target_execute_cmd(struct se_cmd *cmd) } } -static void target_execute_cmd(struct se_cmd *cmd) +void target_execute_cmd(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; @@ -1950,6 +1950,7 @@ execute: */ __target_execute_cmd(cmd); } +EXPORT_SYMBOL(target_execute_cmd); /* * Used to obtain Sense Data from underlying Linux/SCSI struct scsi_cmnd @@ -2500,16 +2501,6 @@ out_fail: } EXPORT_SYMBOL(transport_generic_new_cmd); -/* transport_generic_process_write(): - * - * - */ -void transport_generic_process_write(struct se_cmd *cmd) -{ - target_execute_cmd(cmd); -} -EXPORT_SYMBOL(transport_generic_process_write); - static void transport_write_pending_qf(struct se_cmd *cmd) { int ret; @@ -3321,7 +3312,7 @@ get_cmd: } break; case TRANSPORT_PROCESS_WRITE: - transport_generic_process_write(cmd); + target_execute_cmd(cmd); break; case TRANSPORT_PROCESS_TMR: transport_generic_do_tmr(cmd); diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index c46439c..031d44e 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c @@ -294,7 +294,7 @@ static int bot_send_write_request(struct usbg_cmd *cmd) pr_err("%s(%d)\n", __func__, __LINE__); wait_for_completion(&cmd->write_complete); - transport_generic_process_write(se_cmd); + target_execute_cmd(se_cmd); cleanup: return ret; } @@ -725,7 +725,7 @@ static int uasp_send_write_request(struct usbg_cmd *cmd) } wait_for_completion(&cmd->write_complete); - transport_generic_process_write(se_cmd); + target_execute_cmd(se_cmd); cleanup: return ret; } diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index c78a233..59b4afb 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -121,7 +121,7 @@ int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32, struct scatterlist *, u32); int transport_generic_new_cmd(struct se_cmd *); -void transport_generic_process_write(struct se_cmd *); +void target_execute_cmd(struct se_cmd *cmd); void transport_generic_free_cmd(struct se_cmd *, int); -- cgit v0.10.2 From d59a02b4ebe6fe5ac42b702f1ced6368ced78d76 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 8 Jul 2012 15:58:40 -0400 Subject: target: call transport_check_aborted_status from target_execute_cmd When we call target_execute_cmd for write commands the command has been on the state list before an abort might have come in before target_execute_cmd. Call transport_check_aborted_status to deal with this case. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index aeb2d57..dd9c87f 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1865,6 +1865,12 @@ void target_execute_cmd(struct se_cmd *cmd) struct se_device *dev = cmd->se_dev; /* + * If the received CDB has aleady been aborted stop processing it here. + */ + if (transport_check_aborted_status(cmd, 1)) + return; + + /* * Determine if IOCTL context caller in requesting the stopping of this * command for LUN shutdown purposes. */ -- cgit v0.10.2 From c3196f0cf0061ae62660b3d9a6ce736bef817aba Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 8 Jul 2012 15:58:41 -0400 Subject: target: merge transport_generic_write_pending into transport_generic_new_cmd Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index dd9c87f..db13913 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -66,7 +66,6 @@ struct kmem_cache *t10_alua_lu_gp_mem_cache; struct kmem_cache *t10_alua_tg_pt_gp_cache; struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; -static int transport_generic_write_pending(struct se_cmd *); static int transport_processing_thread(void *param); static void transport_complete_task_attr(struct se_cmd *cmd); static void transport_handle_queue_full(struct se_cmd *cmd, @@ -2487,23 +2486,39 @@ int transport_generic_new_cmd(struct se_cmd *cmd) atomic_inc(&cmd->t_fe_count); /* - * For WRITEs, let the fabric know its buffer is ready. - * - * The command will be added to the execution queue after its write - * data has arrived. - * - * Everything else but a WRITE, add the command to the execution queue. + * If this command is not a write we can execute it right here, + * for write buffers we need to notify the fabric driver first + * and let it call back once the write buffers are ready. */ target_add_to_state_list(cmd); - if (cmd->data_direction == DMA_TO_DEVICE) - return transport_generic_write_pending(cmd); - target_execute_cmd(cmd); - return 0; + if (cmd->data_direction != DMA_TO_DEVICE) { + target_execute_cmd(cmd); + return 0; + } + + spin_lock_irq(&cmd->t_state_lock); + cmd->t_state = TRANSPORT_WRITE_PENDING; + spin_unlock_irq(&cmd->t_state_lock); + + transport_cmd_check_stop(cmd, false); + + ret = cmd->se_tfo->write_pending(cmd); + if (ret == -EAGAIN || ret == -ENOMEM) + goto queue_full; + + if (ret < 0) + return ret; + return 1; out_fail: cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; return -EINVAL; +queue_full: + pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n", cmd); + cmd->t_state = TRANSPORT_COMPLETE_QF_WP; + transport_handle_queue_full(cmd, cmd->se_dev); + return 0; } EXPORT_SYMBOL(transport_generic_new_cmd); @@ -2519,43 +2534,6 @@ static void transport_write_pending_qf(struct se_cmd *cmd) } } -static int transport_generic_write_pending(struct se_cmd *cmd) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&cmd->t_state_lock, flags); - cmd->t_state = TRANSPORT_WRITE_PENDING; - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - - /* - * Clear the se_cmd for WRITE_PENDING status in order to set - * CMD_T_ACTIVE so that transport_generic_handle_data can be called - * from HW target mode interrupt code. This is safe to be called - * with remove_from_lists false before the cmd->se_tfo->write_pending - * because the se_cmd->se_lun pointer is not being cleared. - */ - transport_cmd_check_stop(cmd, false); - - /* - * Call the fabric write_pending function here to let the - * frontend know that WRITE buffers are ready. - */ - ret = cmd->se_tfo->write_pending(cmd); - if (ret == -EAGAIN || ret == -ENOMEM) - goto queue_full; - else if (ret < 0) - return ret; - - return 1; - -queue_full: - pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n", cmd); - cmd->t_state = TRANSPORT_COMPLETE_QF_WP; - transport_handle_queue_full(cmd, cmd->se_dev); - return 0; -} - void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) { if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) { -- cgit v0.10.2 From 67441b68fa73af1c578ccc1d85671b163a7adc13 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 8 Jul 2012 15:58:42 -0400 Subject: iscsit: use target_execute_cmd for WRITEs All three callers of transport_generic_handle_data are from user context and can use target_execute_cmd directly to handle the backend I/O submission of WRITE I/O. Signed-off-by: Christoph Hellwig Cc: Andy Grover Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index d57d10c..0aa04a0 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -1413,8 +1413,10 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf) spin_unlock_bh(&cmd->istate_lock); iscsit_stop_dataout_timer(cmd); - return (!ooo_cmdsn) ? transport_generic_handle_data( - &cmd->se_cmd) : 0; + if (ooo_cmdsn) + return 0; + target_execute_cmd(&cmd->se_cmd); + return 0; } else /* DATAOUT_CANNOT_RECOVER */ return -1; diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index ecdd46d..3df8a2c 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c @@ -965,8 +965,8 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo) if (cmd->immediate_data) { if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) { spin_unlock_bh(&cmd->istate_lock); - return transport_generic_handle_data( - &cmd->se_cmd); + target_execute_cmd(&cmd->se_cmd); + return 0; } spin_unlock_bh(&cmd->istate_lock); diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c index 1f75529..f62fe12 100644 --- a/drivers/target/iscsi/iscsi_target_tmr.c +++ b/drivers/target/iscsi/iscsi_target_tmr.c @@ -257,7 +257,8 @@ static int iscsit_task_reassign_complete_write( pr_debug("WRITE ITT: 0x%08x: t_state: %d" " never sent to transport\n", cmd->init_task_tag, cmd->se_cmd.t_state); - return transport_generic_handle_data(se_cmd); + target_execute_cmd(se_cmd); + return 0; } cmd->i_state = ISTATE_SEND_STATUS; -- cgit v0.10.2 From e672a47fd99b47589dfe2f85759e4c8de526196b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 8 Jul 2012 15:58:43 -0400 Subject: srpt: use target_execute_cmd for WRITEs in srpt_handle_rdma_comp srpt_handle_rdma_comp is called from kthread context and thus can execute target_execute_cmd directly. srpt_abort_cmd sets the CMD_T_LUN_STOP flag directly, and thus the abuse of transport_generic_handle_data can be replaced with an opencoded variant of that code path. I'm still not happy about a fabric driver poking into target core internals like this, but let's defer the bigger architecture changes for now. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 5f6b7f6..7a0ce8d 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1377,10 +1377,14 @@ static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx) break; case SRPT_STATE_NEED_DATA: /* DMA_TO_DEVICE (write) - RDMA read error. */ + + /* XXX(hch): this is a horrible layering violation.. */ spin_lock_irqsave(&ioctx->cmd.t_state_lock, flags); ioctx->cmd.transport_state |= CMD_T_LUN_STOP; + ioctx->cmd.transport_state &= ~CMD_T_ACTIVE; spin_unlock_irqrestore(&ioctx->cmd.t_state_lock, flags); - transport_generic_handle_data(&ioctx->cmd); + + complete(&ioctx->cmd.transport_lun_stop_comp); break; case SRPT_STATE_CMD_RSP_SENT: /* @@ -1463,9 +1467,10 @@ static void srpt_handle_send_comp(struct srpt_rdma_ch *ch, /** * srpt_handle_rdma_comp() - Process an IB RDMA completion notification. * - * Note: transport_generic_handle_data() is asynchronous so unmapping the - * data that has been transferred via IB RDMA must be postponed until the - * check_stop_free() callback. + * XXX: what is now target_execute_cmd used to be asynchronous, and unmapping + * the data that has been transferred via IB RDMA had to be postponed until the + * check_stop_free() callback. None of this is nessecary anymore and needs to + * be cleaned up. */ static void srpt_handle_rdma_comp(struct srpt_rdma_ch *ch, struct srpt_send_ioctx *ioctx, @@ -1477,7 +1482,7 @@ static void srpt_handle_rdma_comp(struct srpt_rdma_ch *ch, if (opcode == SRPT_RDMA_READ_LAST) { if (srpt_test_and_set_cmd_state(ioctx, SRPT_STATE_NEED_DATA, SRPT_STATE_DATA_IN)) - transport_generic_handle_data(&ioctx->cmd); + target_execute_cmd(&ioctx->cmd); else printk(KERN_ERR "%s[%d]: wrong state = %d\n", __func__, __LINE__, srpt_get_cmd_state(ioctx)); -- cgit v0.10.2 From 43381ce8bb14d2536102fe700b43e97da1410169 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 8 Jul 2012 15:58:44 -0400 Subject: tcm_qla2xxx: Offload WRITE I/O backend submission to tcm_qla2xxx wq Defer the whole tcm_qla2xxx_handle_data call instead of just the error path to the qla2xxx-internal workqueue. Also remove the useless lock around the CMD_T_ABORTED check. Signed-off-by: Christoph Hellwig Cc: Roland Dreier Cc: Giridhar Malavali Cc: tcm-qla2xxx@qlogic.com Signed-off-by: Nicholas Bellinger diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 9f9ef16..2953db8 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -639,7 +639,7 @@ struct qla_tgt_func_tmpl { int (*handle_cmd)(struct scsi_qla_host *, struct qla_tgt_cmd *, unsigned char *, uint32_t, int, int, int); - int (*handle_data)(struct qla_tgt_cmd *); + void (*handle_data)(struct qla_tgt_cmd *); int (*handle_tmr)(struct qla_tgt_mgmt_cmd *, uint32_t, uint8_t, uint32_t); void (*free_cmd)(struct qla_tgt_cmd *); diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index dd0a0df..977cb8b 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -604,22 +604,10 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd, return 0; } -static void tcm_qla2xxx_do_rsp(struct work_struct *work) +static void tcm_qla2xxx_handle_data_work(struct work_struct *work) { struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); - /* - * Dispatch ->queue_status from workqueue process context - */ - transport_generic_request_failure(&cmd->se_cmd); -} -/* - * Called from qla_target.c:qlt_do_ctio_completion() - */ -static int tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd) -{ - struct se_cmd *se_cmd = &cmd->se_cmd; - unsigned long flags; /* * Ensure that the complete FCP WRITE payload has been received. * Otherwise return an exception via CHECK_CONDITION status. @@ -629,24 +617,26 @@ static int tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd) * Check if se_cmd has already been aborted via LUN_RESET, and * waiting upon completion in tcm_qla2xxx_write_pending_status() */ - spin_lock_irqsave(&se_cmd->t_state_lock, flags); - if (se_cmd->transport_state & CMD_T_ABORTED) { - spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); - complete(&se_cmd->t_transport_stop_comp); - return 0; + if (cmd->se_cmd.transport_state & CMD_T_ABORTED) { + complete(&cmd->se_cmd.t_transport_stop_comp); + return; } - spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); - se_cmd->scsi_sense_reason = TCM_CHECK_CONDITION_ABORT_CMD; - INIT_WORK(&cmd->work, tcm_qla2xxx_do_rsp); - queue_work(tcm_qla2xxx_free_wq, &cmd->work); - return 0; + cmd->se_cmd.scsi_sense_reason = TCM_CHECK_CONDITION_ABORT_CMD; + transport_generic_request_failure(&cmd->se_cmd); + return; } - /* - * We now tell TCM to queue this WRITE CDB with TRANSPORT_PROCESS_WRITE - * status to the backstore processing thread. - */ - return transport_generic_handle_data(&cmd->se_cmd); + + return target_execute_cmd(&cmd->se_cmd); +} + +/* + * Called from qla_target.c:qlt_do_ctio_completion() + */ +static void tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd) +{ + INIT_WORK(&cmd->work, tcm_qla2xxx_handle_data_work); + queue_work(tcm_qla2xxx_free_wq, &cmd->work); } /* -- cgit v0.10.2 From b8b22533fed12dbb9e5a63d414cb1c768d1c28dd Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 8 Jul 2012 15:58:45 -0400 Subject: tcm_fc: Offload WRITE I/O backend submission to tpg workqueue Defer the write processing to the internal to be able to use target_execute_cmd. I'm not even entirely sure the calling code requires this due to the convoluted structure in libfc, but let's be safe for now. Signed-off-by: Christoph Hellwig Cc: Mark Rustad Cc: Kiran Patil Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index 071a505..ad36ede1 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c @@ -183,6 +183,13 @@ int ft_queue_data_in(struct se_cmd *se_cmd) return ft_queue_status(se_cmd); } +static void ft_execute_work(struct work_struct *work) +{ + struct ft_cmd *cmd = container_of(work, struct ft_cmd, work); + + target_execute_cmd(&cmd->se_cmd); +} + /* * Receive write data frame. */ @@ -307,8 +314,10 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) cmd->write_data_len += tlen; } last_frame: - if (cmd->write_data_len == se_cmd->data_length) - transport_generic_handle_data(se_cmd); + if (cmd->write_data_len == se_cmd->data_length) { + INIT_WORK(&cmd->work, ft_execute_work); + queue_work(cmd->sess->tport->tpg->workqueue, &cmd->work); + } drop: fc_frame_free(fp); } -- cgit v0.10.2 From 1389533ef944823a6ebc170345ad8743e48bc404 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 8 Jul 2012 15:58:46 -0400 Subject: target: remove transport_generic_handle_data Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index db13913..1f28d18 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1583,12 +1583,6 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, */ core_alua_check_nonop_delay(se_cmd); - /* - * Dispatch se_cmd descriptor to se_lun->lun_se_dev backend - * for immediate execution of READs, otherwise wait for - * transport_generic_handle_data() to be called for WRITEs - * when fabric has filled the incoming buffer. - */ transport_handle_cdb_direct(se_cmd); return; } @@ -1681,36 +1675,6 @@ int transport_generic_handle_cdb_map( } EXPORT_SYMBOL(transport_generic_handle_cdb_map); -/* transport_generic_handle_data(): - * - * - */ -int transport_generic_handle_data( - struct se_cmd *cmd) -{ - /* - * For the software fabric case, then we assume the nexus is being - * failed/shutdown when signals are pending from the kthread context - * caller, so we return a failure. For the HW target mode case running - * in interrupt code, the signal_pending() check is skipped. - */ - if (!in_interrupt() && signal_pending(current)) - return -EPERM; - /* - * If the received CDB has aleady been ABORTED by the generic - * target engine, we now call transport_check_aborted_status() - * to queue any delated TASK_ABORTED status for the received CDB to the - * fabric module as we are expecting no further incoming DATA OUT - * sequences at this point. - */ - if (transport_check_aborted_status(cmd, 1) != 0) - return 0; - - transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_WRITE, false); - return 0; -} -EXPORT_SYMBOL(transport_generic_handle_data); - /* transport_generic_handle_tmr(): * * @@ -3295,9 +3259,6 @@ get_cmd: break; } break; - case TRANSPORT_PROCESS_WRITE: - target_execute_cmd(cmd); - break; case TRANSPORT_PROCESS_TMR: transport_generic_do_tmr(cmd); break; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 1ae97fe..72a41dd 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -145,7 +145,6 @@ enum transport_state_table { TRANSPORT_NO_STATE = 0, TRANSPORT_NEW_CMD = 1, TRANSPORT_WRITE_PENDING = 3, - TRANSPORT_PROCESS_WRITE = 4, TRANSPORT_PROCESSING = 5, TRANSPORT_COMPLETE = 6, TRANSPORT_PROCESS_TMR = 9, diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 59b4afb..69321bc 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -116,7 +116,6 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, gfp_t, unsigned int, int); int transport_handle_cdb_direct(struct se_cmd *); int transport_generic_handle_cdb_map(struct se_cmd *); -int transport_generic_handle_data(struct se_cmd *); int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32, struct scatterlist *, u32); int transport_generic_new_cmd(struct se_cmd *); -- cgit v0.10.2 From 7a6f0a1ea5f5ac9b67211071d558c5b09580695d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 8 Jul 2012 15:58:47 -0400 Subject: target: simply fabric driver queue full processing There is no need to schedule the delayed processing in a workqueue that offloads it to the target processing thread. Instead execute it directly from the workqueue. There will be a lot of future work in this area, which I'd likfe to defer for now as it is not nessecary for getting rid of the target processing thread. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 1f28d18..68f0c8d 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -720,6 +720,8 @@ static void target_add_to_state_list(struct se_cmd *cmd) /* * Handle QUEUE_FULL / -EAGAIN and -ENOMEM status */ +static void transport_write_pending_qf(struct se_cmd *cmd); +static void transport_complete_qf(struct se_cmd *cmd); static void target_qf_do_work(struct work_struct *work) { @@ -743,7 +745,10 @@ static void target_qf_do_work(struct work_struct *work) (cmd->t_state == TRANSPORT_COMPLETE_QF_WP) ? "WRITE_PENDING" : "UNKNOWN"); - transport_add_cmd_to_queue(cmd, cmd->t_state, true); + if (cmd->t_state == TRANSPORT_COMPLETE_QF_WP) + transport_write_pending_qf(cmd); + else if (cmd->t_state == TRANSPORT_COMPLETE_QF_OK) + transport_complete_qf(cmd); } } @@ -3262,12 +3267,6 @@ get_cmd: case TRANSPORT_PROCESS_TMR: transport_generic_do_tmr(cmd); break; - case TRANSPORT_COMPLETE_QF_WP: - transport_write_pending_qf(cmd); - break; - case TRANSPORT_COMPLETE_QF_OK: - transport_complete_qf(cmd); - break; default: pr_err("Unknown t_state: %d for ITT: 0x%08x " "i_state: %d on SE LUN: %u\n", -- cgit v0.10.2 From f314643751450a582c1ca40a54558240ef7cd4bf Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 8 Jul 2012 15:58:48 -0400 Subject: target: remove transport_generic_handle_cdb_map Remove this command submission path which is not used by any in-tree driver. This also removes the now unused new_cmd_map fabtric method, which a few drivers implemented despite never calling transport_generic_handle_cdb_map. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 977cb8b..d85a817 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -1678,7 +1678,6 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = { .tpg_alloc_fabric_acl = tcm_qla2xxx_alloc_fabric_acl, .tpg_release_fabric_acl = tcm_qla2xxx_release_fabric_acl, .tpg_get_inst_index = tcm_qla2xxx_tpg_get_inst_index, - .new_cmd_map = NULL, .check_stop_free = tcm_qla2xxx_check_stop_free, .release_cmd = tcm_qla2xxx_release_cmd, .put_session = tcm_qla2xxx_put_session, diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 68f0c8d..9b7bbbe 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1661,25 +1661,6 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, } EXPORT_SYMBOL(target_submit_tmr); -/* - * Used by fabric module frontends defining a TFO->new_cmd_map() caller - * to queue up a newly setup se_cmd w/ TRANSPORT_NEW_CMD_MAP in order to - * complete setup in TCM process context w/ TFO->new_cmd_map(). - */ -int transport_generic_handle_cdb_map( - struct se_cmd *cmd) -{ - if (!cmd->se_lun) { - dump_stack(); - pr_err("cmd->se_lun is NULL\n"); - return -EINVAL; - } - - transport_add_cmd_to_queue(cmd, TRANSPORT_NEW_CMD_MAP, false); - return 0; -} -EXPORT_SYMBOL(transport_generic_handle_cdb_map); - /* transport_generic_handle_tmr(): * * @@ -1784,13 +1765,7 @@ void transport_generic_request_failure(struct se_cmd *cmd) cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; break; } - /* - * If a fabric does not define a cmd->se_tfo->new_cmd_map caller, - * make the call to transport_send_check_condition_and_sense() - * directly. Otherwise expect the fabric to make the call to - * transport_send_check_condition_and_sense() after handling - * possible unsoliticied write data payloads. - */ + ret = transport_send_check_condition_and_sense(cmd, cmd->scsi_sense_reason, 0); if (ret == -EAGAIN || ret == -ENOMEM) @@ -3247,23 +3222,6 @@ get_cmd: case TRANSPORT_NEW_CMD: BUG(); break; - case TRANSPORT_NEW_CMD_MAP: - if (!cmd->se_tfo->new_cmd_map) { - pr_err("cmd->se_tfo->new_cmd_map is" - " NULL for TRANSPORT_NEW_CMD_MAP\n"); - BUG(); - } - ret = cmd->se_tfo->new_cmd_map(cmd); - if (ret < 0) { - transport_generic_request_failure(cmd); - break; - } - ret = transport_generic_new_cmd(cmd); - if (ret < 0) { - transport_generic_request_failure(cmd); - break; - } - break; case TRANSPORT_PROCESS_TMR: transport_generic_do_tmr(cmd); break; diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index 031d44e..02ace18 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c @@ -1400,19 +1400,6 @@ static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg) return 1; } -static int usbg_new_cmd(struct se_cmd *se_cmd) -{ - struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, - se_cmd); - int ret; - - ret = target_setup_cmd_from_cdb(se_cmd, cmd->cmd_buf); - if (ret) - return ret; - - return transport_generic_map_mem_to_cmd(se_cmd, NULL, 0, NULL, 0); -} - static void usbg_cmd_release(struct kref *ref) { struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd, @@ -1902,7 +1889,6 @@ static struct target_core_fabric_ops usbg_ops = { .tpg_alloc_fabric_acl = usbg_alloc_fabric_acl, .tpg_release_fabric_acl = usbg_release_fabric_acl, .tpg_get_inst_index = usbg_tpg_get_inst_index, - .new_cmd_map = usbg_new_cmd, .release_cmd = usbg_release_cmd, .shutdown_session = usbg_shutdown_session, .close_session = usbg_close_session, diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 72a41dd..11052b2 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -149,7 +149,6 @@ enum transport_state_table { TRANSPORT_COMPLETE = 6, TRANSPORT_PROCESS_TMR = 9, TRANSPORT_ISTATE_PROCESSING = 11, - TRANSPORT_NEW_CMD_MAP = 16, TRANSPORT_COMPLETE_QF_WP = 18, TRANSPORT_COMPLETE_QF_OK = 19, }; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 69321bc..c3ad1ec 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -33,12 +33,6 @@ struct target_core_fabric_ops { struct se_node_acl *); u32 (*tpg_get_inst_index)(struct se_portal_group *); /* - * Optional function pointer for TCM to perform command map - * from TCM processing thread context, for those struct se_cmd - * initially allocated in interrupt context. - */ - int (*new_cmd_map)(struct se_cmd *); - /* * Optional to release struct se_cmd and fabric dependent allocated * I/O descriptor in transport_cmd_check_stop(). * @@ -115,7 +109,6 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, void *fabric_tmr_ptr, unsigned char tm_type, gfp_t, unsigned int, int); int transport_handle_cdb_direct(struct se_cmd *); -int transport_generic_handle_cdb_map(struct se_cmd *); int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32, struct scatterlist *, u32); int transport_generic_new_cmd(struct se_cmd *); -- cgit v0.10.2 From af8772926f019b7bddd7477b8de5f3b0f12bad21 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 8 Jul 2012 15:58:49 -0400 Subject: target: replace the processing thread with a TMR work queue The last functionality of the target processing thread is offloading possibly long running task management requests from the submitter context. To keep TMR semantics the same we need a single threaded ordered queue, which can be provided by a per-device workqueue with the right flags. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 5ad9728..bcef677 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -715,7 +715,7 @@ void se_release_device_for_hba(struct se_device *dev) se_dev_stop(dev); if (dev->dev_ptr) { - kthread_stop(dev->process_thread); + destroy_workqueue(dev->tmr_wq); if (dev->transport->free_device) dev->transport->free_device(dev->dev_ptr); } diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 4185db1..1c59a3c 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -351,57 +351,6 @@ static void core_tmr_drain_state_list( } } -static void core_tmr_drain_cmd_list( - struct se_device *dev, - struct se_cmd *prout_cmd, - struct se_node_acl *tmr_nacl, - int tas, - struct list_head *preempt_and_abort_list) -{ - LIST_HEAD(drain_cmd_list); - struct se_queue_obj *qobj = &dev->dev_queue_obj; - struct se_cmd *cmd, *tcmd; - unsigned long flags; - - /* - * Release all commands remaining in the per-device command queue. - * - * This follows the same logic as above for the state list. - */ - spin_lock_irqsave(&qobj->cmd_queue_lock, flags); - list_for_each_entry_safe(cmd, tcmd, &qobj->qobj_list, se_queue_node) { - /* - * For PREEMPT_AND_ABORT usage, only process commands - * with a matching reservation key. - */ - if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd)) - continue; - /* - * Not aborting PROUT PREEMPT_AND_ABORT CDB.. - */ - if (prout_cmd == cmd) - continue; - - cmd->transport_state &= ~CMD_T_QUEUED; - atomic_dec(&qobj->queue_cnt); - list_move_tail(&cmd->se_queue_node, &drain_cmd_list); - } - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - - while (!list_empty(&drain_cmd_list)) { - cmd = list_entry(drain_cmd_list.next, struct se_cmd, se_queue_node); - list_del_init(&cmd->se_queue_node); - - pr_debug("LUN_RESET: %s from Device Queue: cmd: %p t_state:" - " %d t_fe_count: %d\n", (preempt_and_abort_list) ? - "Preempt" : "", cmd, cmd->t_state, - atomic_read(&cmd->t_fe_count)); - - core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, - atomic_read(&cmd->t_fe_count)); - } -} - int core_tmr_lun_reset( struct se_device *dev, struct se_tmr_req *tmr, @@ -444,8 +393,7 @@ int core_tmr_lun_reset( core_tmr_drain_tmr_list(dev, tmr, preempt_and_abort_list); core_tmr_drain_state_list(dev, prout_cmd, tmr_nacl, tas, preempt_and_abort_list); - core_tmr_drain_cmd_list(dev, prout_cmd, tmr_nacl, tas, - preempt_and_abort_list); + /* * Clear any legacy SPC-2 reservation when called during * LOGICAL UNIT RESET diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 9b7bbbe..45ed170 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -66,13 +66,11 @@ struct kmem_cache *t10_alua_lu_gp_mem_cache; struct kmem_cache *t10_alua_tg_pt_gp_cache; struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; -static int transport_processing_thread(void *param); static void transport_complete_task_attr(struct se_cmd *cmd); static void transport_handle_queue_full(struct se_cmd *cmd, struct se_device *dev); static int transport_generic_get_mem(struct se_cmd *cmd); static void transport_put_cmd(struct se_cmd *cmd); -static void transport_remove_cmd_from_queue(struct se_cmd *cmd); static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); static void target_complete_ok_work(struct work_struct *work); @@ -193,14 +191,6 @@ u32 scsi_get_new_index(scsi_index_t type) return new_index; } -static void transport_init_queue_obj(struct se_queue_obj *qobj) -{ - atomic_set(&qobj->queue_cnt, 0); - INIT_LIST_HEAD(&qobj->qobj_list); - init_waitqueue_head(&qobj->thread_wq); - spin_lock_init(&qobj->cmd_queue_lock); -} - void transport_subsystem_check_init(void) { int ret; @@ -566,79 +556,8 @@ void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) if (transport_cmd_check_stop_to_fabric(cmd)) return; - if (remove) { - transport_remove_cmd_from_queue(cmd); + if (remove) transport_put_cmd(cmd); - } -} - -static void transport_add_cmd_to_queue(struct se_cmd *cmd, int t_state, - bool at_head) -{ - struct se_device *dev = cmd->se_dev; - struct se_queue_obj *qobj = &dev->dev_queue_obj; - unsigned long flags; - - if (t_state) { - spin_lock_irqsave(&cmd->t_state_lock, flags); - cmd->t_state = t_state; - cmd->transport_state |= CMD_T_ACTIVE; - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - } - - spin_lock_irqsave(&qobj->cmd_queue_lock, flags); - - /* If the cmd is already on the list, remove it before we add it */ - if (!list_empty(&cmd->se_queue_node)) - list_del(&cmd->se_queue_node); - else - atomic_inc(&qobj->queue_cnt); - - if (at_head) - list_add(&cmd->se_queue_node, &qobj->qobj_list); - else - list_add_tail(&cmd->se_queue_node, &qobj->qobj_list); - cmd->transport_state |= CMD_T_QUEUED; - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - - wake_up_interruptible(&qobj->thread_wq); -} - -static struct se_cmd * -transport_get_cmd_from_queue(struct se_queue_obj *qobj) -{ - struct se_cmd *cmd; - unsigned long flags; - - spin_lock_irqsave(&qobj->cmd_queue_lock, flags); - if (list_empty(&qobj->qobj_list)) { - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - return NULL; - } - cmd = list_first_entry(&qobj->qobj_list, struct se_cmd, se_queue_node); - - cmd->transport_state &= ~CMD_T_QUEUED; - list_del_init(&cmd->se_queue_node); - atomic_dec(&qobj->queue_cnt); - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - - return cmd; -} - -static void transport_remove_cmd_from_queue(struct se_cmd *cmd) -{ - struct se_queue_obj *qobj = &cmd->se_dev->dev_queue_obj; - unsigned long flags; - - spin_lock_irqsave(&qobj->cmd_queue_lock, flags); - if (!(cmd->transport_state & CMD_T_QUEUED)) { - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - return; - } - cmd->transport_state &= ~CMD_T_QUEUED; - atomic_dec(&qobj->queue_cnt); - list_del_init(&cmd->se_queue_node); - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); } static void target_complete_failure_work(struct work_struct *work) @@ -1132,7 +1051,6 @@ struct se_device *transport_add_device_to_core_hba( return NULL; } - transport_init_queue_obj(&dev->dev_queue_obj); dev->dev_flags = device_flags; dev->dev_status |= TRANSPORT_DEVICE_DEACTIVATED; dev->dev_ptr = transport_dev; @@ -1185,10 +1103,10 @@ struct se_device *transport_add_device_to_core_hba( /* * Startup the struct se_device processing thread */ - dev->process_thread = kthread_run(transport_processing_thread, dev, - "LIO_%s", dev->transport->name); - if (IS_ERR(dev->process_thread)) { - pr_err("Unable to create kthread: LIO_%s\n", + dev->tmr_wq = alloc_workqueue("tmr-%s", WQ_MEM_RECLAIM | WQ_UNBOUND, 1, + dev->transport->name); + if (!dev->tmr_wq) { + pr_err("Unable to create tmr workqueue for %s\n", dev->transport->name); goto out; } @@ -1219,7 +1137,7 @@ struct se_device *transport_add_device_to_core_hba( return dev; out: - kthread_stop(dev->process_thread); + destroy_workqueue(dev->tmr_wq); spin_lock(&hba->device_lock); list_del(&dev->dev_list); @@ -1299,7 +1217,6 @@ void transport_init_se_cmd( INIT_LIST_HEAD(&cmd->se_lun_node); INIT_LIST_HEAD(&cmd->se_delayed_node); INIT_LIST_HEAD(&cmd->se_qf_node); - INIT_LIST_HEAD(&cmd->se_queue_node); INIT_LIST_HEAD(&cmd->se_cmd_list); INIT_LIST_HEAD(&cmd->state_list); init_completion(&cmd->transport_lun_fe_stop_comp); @@ -1494,10 +1411,9 @@ int transport_handle_cdb_direct( return -EINVAL; } /* - * Set TRANSPORT_NEW_CMD state and CMD_T_ACTIVE following - * transport_generic_handle_cdb*() -> transport_add_cmd_to_queue() - * in existing usage to ensure that outstanding descriptors are handled - * correctly during shutdown via transport_wait_for_tasks() + * Set TRANSPORT_NEW_CMD state and CMD_T_ACTIVE to ensure that + * outstanding descriptors are handled correctly during shutdown via + * transport_wait_for_tasks() * * Also, we don't take cmd->t_state_lock here as we only expect * this to be called for initial descriptor submission. @@ -1661,18 +1577,6 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, } EXPORT_SYMBOL(target_submit_tmr); -/* transport_generic_handle_tmr(): - * - * - */ -int transport_generic_handle_tmr( - struct se_cmd *cmd) -{ - transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_TMR, false); - return 0; -} -EXPORT_SYMBOL(transport_generic_handle_tmr); - /* * If the cmd is active, request it to be stopped and sleep until it * has completed. @@ -2653,8 +2557,6 @@ static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun) cmd->transport_state |= CMD_T_LUN_FE_STOP; spin_unlock_irqrestore(&cmd->t_state_lock, flags); - wake_up_interruptible(&cmd->se_dev->dev_queue_obj.thread_wq); - // XXX: audit task_flags checks. spin_lock_irqsave(&cmd->t_state_lock, flags); if ((cmd->transport_state & CMD_T_BUSY) && @@ -2673,7 +2575,6 @@ static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun) pr_debug("ConfigFS: ITT[0x%08x] - stopped cmd....\n", cmd->se_tfo->get_task_tag(cmd)); } - transport_remove_cmd_from_queue(cmd); return 0; } @@ -2872,8 +2773,6 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) spin_unlock_irqrestore(&cmd->t_state_lock, flags); - wake_up_interruptible(&cmd->se_dev->dev_queue_obj.thread_wq); - wait_for_completion(&cmd->t_transport_stop_comp); spin_lock_irqsave(&cmd->t_state_lock, flags); @@ -3156,8 +3055,9 @@ void transport_send_task_abort(struct se_cmd *cmd) cmd->se_tfo->queue_status(cmd); } -static int transport_generic_do_tmr(struct se_cmd *cmd) +static void target_tmr_work(struct work_struct *work) { + struct se_cmd *cmd = container_of(work, struct se_cmd, work); struct se_device *dev = cmd->se_dev; struct se_tmr_req *tmr = cmd->se_tmr_req; int ret; @@ -3193,54 +3093,13 @@ static int transport_generic_do_tmr(struct se_cmd *cmd) cmd->se_tfo->queue_tm_rsp(cmd); transport_cmd_check_stop_to_fabric(cmd); - return 0; } -/* transport_processing_thread(): - * - * - */ -static int transport_processing_thread(void *param) +int transport_generic_handle_tmr( + struct se_cmd *cmd) { - int ret; - struct se_cmd *cmd; - struct se_device *dev = param; - - while (!kthread_should_stop()) { - ret = wait_event_interruptible(dev->dev_queue_obj.thread_wq, - atomic_read(&dev->dev_queue_obj.queue_cnt) || - kthread_should_stop()); - if (ret < 0) - goto out; - -get_cmd: - cmd = transport_get_cmd_from_queue(&dev->dev_queue_obj); - if (!cmd) - continue; - - switch (cmd->t_state) { - case TRANSPORT_NEW_CMD: - BUG(); - break; - case TRANSPORT_PROCESS_TMR: - transport_generic_do_tmr(cmd); - break; - default: - pr_err("Unknown t_state: %d for ITT: 0x%08x " - "i_state: %d on SE LUN: %u\n", - cmd->t_state, - cmd->se_tfo->get_task_tag(cmd), - cmd->se_tfo->get_cmd_state(cmd), - cmd->se_lun->unpacked_lun); - BUG(); - } - - goto get_cmd; - } - -out: - WARN_ON(!list_empty(&dev->state_list)); - WARN_ON(!list_empty(&dev->dev_queue_obj.qobj_list)); - dev->process_thread = NULL; + INIT_WORK(&cmd->work, target_tmr_work); + queue_work(cmd->se_dev->tmr_wq, &cmd->work); return 0; } +EXPORT_SYMBOL(transport_generic_handle_tmr); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 11052b2..4f4f042 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -147,7 +147,6 @@ enum transport_state_table { TRANSPORT_WRITE_PENDING = 3, TRANSPORT_PROCESSING = 5, TRANSPORT_COMPLETE = 6, - TRANSPORT_PROCESS_TMR = 9, TRANSPORT_ISTATE_PROCESSING = 11, TRANSPORT_COMPLETE_QF_WP = 18, TRANSPORT_COMPLETE_QF_OK = 19, @@ -464,13 +463,6 @@ struct t10_reservation { struct t10_reservation_ops pr_ops; }; -struct se_queue_obj { - atomic_t queue_cnt; - spinlock_t cmd_queue_lock; - struct list_head qobj_list; - wait_queue_head_t thread_wq; -}; - struct se_tmr_req { /* Task Management function to be performed */ u8 function; @@ -527,7 +519,6 @@ struct se_cmd { /* Only used for internal passthrough and legacy TCM fabric modules */ struct se_session *se_sess; struct se_tmr_req *se_tmr_req; - struct list_head se_queue_node; struct list_head se_cmd_list; struct completion cmd_wait_comp; struct kref cmd_kref; @@ -774,7 +765,6 @@ struct se_device { struct se_obj dev_obj; struct se_obj dev_access_obj; struct se_obj dev_export_obj; - struct se_queue_obj dev_queue_obj; spinlock_t delayed_cmd_lock; spinlock_t execute_task_lock; spinlock_t dev_reservation_lock; @@ -790,8 +780,7 @@ struct se_device { struct t10_pr_registration *dev_pr_res_holder; struct list_head dev_sep_list; struct list_head dev_tmr_list; - /* Pointer to descriptor for processing thread */ - struct task_struct *process_thread; + struct workqueue_struct *tmr_wq; struct work_struct qf_work_queue; struct list_head delayed_cmd_list; struct list_head state_list; -- cgit v0.10.2 From ee1b1b9c3db29643eb82a6b52694555c91af2f97 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 12 Jul 2012 17:34:54 -0700 Subject: target: Remove unneeded double parentheses Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 0aa04a0..5d56ce4 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -2685,7 +2685,7 @@ static int iscsit_send_logout_response( */ logout_conn = iscsit_get_conn_from_cid_rcfr(sess, cmd->logout_cid); - if ((logout_conn)) { + if (logout_conn) { iscsit_connection_reinstatement_rcfr(logout_conn); iscsit_dec_conn_usage_count(logout_conn); } diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index a3656c9..1434110 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -518,7 +518,7 @@ int iscsi_login_post_auth_non_zero_tsih( * initiator and release the new connection. */ conn_ptr = iscsit_get_conn_from_cid_rcfr(sess, cid); - if ((conn_ptr)) { + if (conn_ptr) { pr_err("Connection exists with CID %hu for %s," " performing connection reinstatement.\n", conn_ptr->cid, sess->sess_ops->InitiatorName); @@ -539,7 +539,7 @@ int iscsi_login_post_auth_non_zero_tsih( if (sess->sess_ops->ErrorRecoveryLevel == 2) { cr = iscsit_get_inactive_connection_recovery_entry( sess, cid); - if ((cr)) { + if (cr) { pr_debug("Performing implicit logout" " for connection recovery on CID: %hu\n", conn->cid); @@ -1081,7 +1081,7 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) goto new_sess_out; zero_tsih = (pdu->tsih == 0x0000); - if ((zero_tsih)) { + if (zero_tsih) { /* * This is the leading connection of a new session. * We wait until after authentication to check for diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 879d8d0..1429895 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -593,7 +593,7 @@ int iscsit_ta_authentication(struct iscsi_portal_group *tpg, u32 authentication) } else { snprintf(buf1, sizeof(buf1), "%s", param->value); none = strstr(buf1, NONE); - if ((none)) + if (none) goto out; strncat(buf1, ",", strlen(",")); strncat(buf1, NONE, strlen(NONE)); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index a1bcd927..1e94650 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -507,7 +507,7 @@ static int core_scsi3_pr_seq_non_holder( * Check if write exclusive initiator ports *NOT* holding the * WRITE_EXCLUSIVE_* reservation. */ - if ((we) && !(registered_nexus)) { + if (we && !registered_nexus) { if (cmd->data_direction == DMA_TO_DEVICE) { /* * Conflict for write exclusive @@ -2486,7 +2486,7 @@ static int core_scsi3_pro_reserve( */ spin_lock(&dev->dev_reservation_lock); pr_res_holder = dev->dev_pr_res_holder; - if ((pr_res_holder)) { + if (pr_res_holder) { /* * From spc4r17 Section 5.7.9: Reserving: * @@ -4030,7 +4030,7 @@ static int core_scsi3_pri_read_reservation(struct se_cmd *cmd) spin_lock(&se_dev->dev_reservation_lock); pr_reg = se_dev->dev_pr_res_holder; - if ((pr_reg)) { + if (pr_reg) { /* * Set the hardcoded Additional Length */ -- cgit v0.10.2 From 2dca673b46c586d8e5dd0c8e3a582b51a1d7907d Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 12 Jul 2012 17:34:55 -0700 Subject: target: Remove hba param from core_dev_add_lun Only used in a debugprint, and function signature is cleaner now. Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index bcef677..415c71e 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1273,7 +1273,6 @@ int se_dev_set_block_size(struct se_device *dev, u32 block_size) struct se_lun *core_dev_add_lun( struct se_portal_group *tpg, - struct se_hba *hba, struct se_device *dev, u32 lun) { @@ -1298,7 +1297,7 @@ struct se_lun *core_dev_add_lun( pr_debug("%s_TPG[%u]_LUN[%u] - Activated %s Logical Unit from" " CORE HBA: %u\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), lun_p->unpacked_lun, - tpg->se_tpg_tfo->get_fabric_name(), hba->hba_id); + tpg->se_tpg_tfo->get_fabric_name(), dev->se_hba->hba_id); /* * Update LUN maps for dynamically added initiators when * generate_node_acl is enabled. diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 405cc98..ea479e5 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -764,8 +764,7 @@ static int target_fabric_port_link( goto out; } - lun_p = core_dev_add_lun(se_tpg, dev->se_hba, dev, - lun->unpacked_lun); + lun_p = core_dev_add_lun(se_tpg, dev, lun->unpacked_lun); if (IS_ERR(lun_p)) { pr_err("core_dev_add_lun() failed\n"); ret = PTR_ERR(lun_p); diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 88f69e0..d41a9bb 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -45,8 +45,7 @@ int se_dev_set_max_sectors(struct se_device *, u32); int se_dev_set_fabric_max_sectors(struct se_device *, u32); int se_dev_set_optimal_sectors(struct se_device *, u32); int se_dev_set_block_size(struct se_device *, u32); -struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_hba *, - struct se_device *, u32); +struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_device *, u32); int core_dev_del_lun(struct se_portal_group *, u32); struct se_lun *core_get_lun_from_tpg(struct se_portal_group *, u32); struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *, -- cgit v0.10.2 From 617a0c2eb316c4d3c8a67255f85c7cf676ab59a9 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 12 Jul 2012 17:34:56 -0700 Subject: target: Misc retval cleanups Bubble-up retval from iscsi_update_param_value() and iscsit_ta_authentication(). Other very small retval cleanups. Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index ed5241e..0c4760f 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c @@ -681,7 +681,7 @@ int iscsi_update_param_value(struct iscsi_param *param, char *value) param->value = kzalloc(strlen(value) + 1, GFP_KERNEL); if (!param->value) { pr_err("Unable to allocate memory for value.\n"); - return -1; + return -ENOMEM; } memcpy(param->value, value, strlen(value)); diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 1429895..a38a3f8 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -303,6 +303,7 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg) { struct iscsi_param *param; struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; + int ret; spin_lock(&tpg->tpg_state_lock); if (tpg->tpg_state == TPG_STATE_ACTIVE) { @@ -319,19 +320,19 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg) param = iscsi_find_param_from_key(AUTHMETHOD, tpg->param_list); if (!param) { spin_unlock(&tpg->tpg_state_lock); - return -ENOMEM; + return -EINVAL; } if (ISCSI_TPG_ATTRIB(tpg)->authentication) { - if (!strcmp(param->value, NONE)) - if (iscsi_update_param_value(param, CHAP) < 0) { - spin_unlock(&tpg->tpg_state_lock); - return -ENOMEM; - } - if (iscsit_ta_authentication(tpg, 1) < 0) { - spin_unlock(&tpg->tpg_state_lock); - return -ENOMEM; + if (!strcmp(param->value, NONE)) { + ret = iscsi_update_param_value(param, CHAP); + if (ret) + goto err; } + + ret = iscsit_ta_authentication(tpg, 1); + if (ret < 0) + goto err; } tpg->tpg_state = TPG_STATE_ACTIVE; @@ -344,6 +345,10 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg) spin_unlock(&tiqn->tiqn_tpg_lock); return 0; + +err: + spin_unlock(&tpg->tpg_state_lock); + return ret; } int iscsit_tpg_disable_portal_group(struct iscsi_portal_group *tpg, int force) @@ -558,7 +563,7 @@ int iscsit_ta_authentication(struct iscsi_portal_group *tpg, u32 authentication) if ((authentication != 1) && (authentication != 0)) { pr_err("Illegal value for authentication parameter:" " %u, ignoring request.\n", authentication); - return -1; + return -EINVAL; } memset(buf1, 0, sizeof(buf1)); -- cgit v0.10.2 From cdf88a2fe3825458c584cd751aa843ab3af6a42c Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 12 Jul 2012 17:34:57 -0700 Subject: target: Eliminate else using boolean logic Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 8bd58e2..5ca340c 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -306,10 +306,8 @@ struct se_node_acl *core_tpg_check_initiator_node_acl( * TPG LUNs if the fabric is not explictly asking for * tpg_check_demo_mode_login_only() == 1. */ - if ((tpg->se_tpg_tfo->tpg_check_demo_mode_login_only != NULL) && - (tpg->se_tpg_tfo->tpg_check_demo_mode_login_only(tpg) == 1)) - do { ; } while (0); - else + if ((tpg->se_tpg_tfo->tpg_check_demo_mode_login_only == NULL) || + (tpg->se_tpg_tfo->tpg_check_demo_mode_login_only(tpg) != 1)) core_tpg_add_node_to_devs(acl, tpg); spin_lock_irq(&tpg->acl_node_lock); -- cgit v0.10.2 From e80ac6c4cc073d54daef8ba4ced88347d130d314 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 12 Jul 2012 17:34:58 -0700 Subject: target: refactor core_update_device_list_for_node() Code was almost entirely divided based on value of bool param "enable". Split it into two functions. Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 415c71e..0a1c907 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -300,8 +300,8 @@ int core_free_device_list_for_node( lun = deve->se_lun; spin_unlock_irq(&nacl->device_list_lock); - core_update_device_list_for_node(lun, NULL, deve->mapped_lun, - TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg, 0); + core_disable_device_list_for_node(lun, NULL, deve->mapped_lun, + TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg); spin_lock_irq(&nacl->device_list_lock); } spin_unlock_irq(&nacl->device_list_lock); @@ -342,72 +342,46 @@ void core_update_device_list_access( spin_unlock_irq(&nacl->device_list_lock); } -/* core_update_device_list_for_node(): +/* core_enable_device_list_for_node(): * * */ -int core_update_device_list_for_node( +int core_enable_device_list_for_node( struct se_lun *lun, struct se_lun_acl *lun_acl, u32 mapped_lun, u32 lun_access, struct se_node_acl *nacl, - struct se_portal_group *tpg, - int enable) + struct se_portal_group *tpg) { struct se_port *port = lun->lun_sep; - struct se_dev_entry *deve = nacl->device_list[mapped_lun]; - int trans = 0; - /* - * If the MappedLUN entry is being disabled, the entry in - * port->sep_alua_list must be removed now before clearing the - * struct se_dev_entry pointers below as logic in - * core_alua_do_transition_tg_pt() depends on these being present. - */ - if (!enable) { - /* - * deve->se_lun_acl will be NULL for demo-mode created LUNs - * that have not been explicitly concerted to MappedLUNs -> - * struct se_lun_acl, but we remove deve->alua_port_list from - * port->sep_alua_list. This also means that active UAs and - * NodeACL context specific PR metadata for demo-mode - * MappedLUN *deve will be released below.. - */ - spin_lock_bh(&port->sep_alua_lock); - list_del(&deve->alua_port_list); - spin_unlock_bh(&port->sep_alua_lock); - } + struct se_dev_entry *deve; spin_lock_irq(&nacl->device_list_lock); - if (enable) { - /* - * Check if the call is handling demo mode -> explict LUN ACL - * transition. This transition must be for the same struct se_lun - * + mapped_lun that was setup in demo mode.. - */ - if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) { - if (deve->se_lun_acl != NULL) { - pr_err("struct se_dev_entry->se_lun_acl" - " already set for demo mode -> explict" - " LUN ACL transition\n"); - spin_unlock_irq(&nacl->device_list_lock); - return -EINVAL; - } - if (deve->se_lun != lun) { - pr_err("struct se_dev_entry->se_lun does" - " match passed struct se_lun for demo mode" - " -> explict LUN ACL transition\n"); - spin_unlock_irq(&nacl->device_list_lock); - return -EINVAL; - } - deve->se_lun_acl = lun_acl; - trans = 1; - } else { - deve->se_lun = lun; - deve->se_lun_acl = lun_acl; - deve->mapped_lun = mapped_lun; - deve->lun_flags |= TRANSPORT_LUNFLAGS_INITIATOR_ACCESS; + + deve = nacl->device_list[mapped_lun]; + + /* + * Check if the call is handling demo mode -> explict LUN ACL + * transition. This transition must be for the same struct se_lun + * + mapped_lun that was setup in demo mode.. + */ + if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) { + if (deve->se_lun_acl != NULL) { + pr_err("struct se_dev_entry->se_lun_acl" + " already set for demo mode -> explict" + " LUN ACL transition\n"); + spin_unlock_irq(&nacl->device_list_lock); + return -EINVAL; + } + if (deve->se_lun != lun) { + pr_err("struct se_dev_entry->se_lun does" + " match passed struct se_lun for demo mode" + " -> explict LUN ACL transition\n"); + spin_unlock_irq(&nacl->device_list_lock); + return -EINVAL; } + deve->se_lun_acl = lun_acl; if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) { deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY; @@ -417,20 +391,70 @@ int core_update_device_list_for_node( deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY; } - if (trans) { - spin_unlock_irq(&nacl->device_list_lock); - return 0; - } - deve->creation_time = get_jiffies_64(); - deve->attach_count++; spin_unlock_irq(&nacl->device_list_lock); + return 0; + } - spin_lock_bh(&port->sep_alua_lock); - list_add_tail(&deve->alua_port_list, &port->sep_alua_list); - spin_unlock_bh(&port->sep_alua_lock); + deve->se_lun = lun; + deve->se_lun_acl = lun_acl; + deve->mapped_lun = mapped_lun; + deve->lun_flags |= TRANSPORT_LUNFLAGS_INITIATOR_ACCESS; - return 0; + if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) { + deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY; + deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE; + } else { + deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_WRITE; + deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY; } + + deve->creation_time = get_jiffies_64(); + deve->attach_count++; + spin_unlock_irq(&nacl->device_list_lock); + + spin_lock_bh(&port->sep_alua_lock); + list_add_tail(&deve->alua_port_list, &port->sep_alua_list); + spin_unlock_bh(&port->sep_alua_lock); + + return 0; +} + +/* core_disable_device_list_for_node(): + * + * + */ +int core_disable_device_list_for_node( + struct se_lun *lun, + struct se_lun_acl *lun_acl, + u32 mapped_lun, + u32 lun_access, + struct se_node_acl *nacl, + struct se_portal_group *tpg) +{ + struct se_port *port = lun->lun_sep; + struct se_dev_entry *deve; + + spin_lock_irq(&nacl->device_list_lock); + + deve = nacl->device_list[mapped_lun]; + + /* + * If the MappedLUN entry is being disabled, the entry in + * port->sep_alua_list must be removed now before clearing the + * struct se_dev_entry pointers below as logic in + * core_alua_do_transition_tg_pt() depends on these being present. + * + * deve->se_lun_acl will be NULL for demo-mode created LUNs + * that have not been explicitly converted to MappedLUNs -> + * struct se_lun_acl, but we remove deve->alua_port_list from + * port->sep_alua_list. This also means that active UAs and + * NodeACL context specific PR metadata for demo-mode + * MappedLUN *deve will be released below.. + */ + spin_lock_bh(&port->sep_alua_lock); + list_del(&deve->alua_port_list); + spin_unlock_bh(&port->sep_alua_lock); + /* * Wait for any in process SPEC_I_PT=1 or REGISTER_AND_MOVE * PR operation to complete. @@ -475,9 +499,9 @@ void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg) continue; spin_unlock_irq(&nacl->device_list_lock); - core_update_device_list_for_node(lun, NULL, + core_disable_device_list_for_node(lun, NULL, deve->mapped_lun, TRANSPORT_LUNFLAGS_NO_ACCESS, - nacl, tpg, 0); + nacl, tpg); spin_lock_irq(&nacl->device_list_lock); } @@ -1469,8 +1493,8 @@ int core_dev_add_initiator_node_lun_acl( lacl->se_lun = lun; - if (core_update_device_list_for_node(lun, lacl, lacl->mapped_lun, - lun_access, nacl, tpg, 1) < 0) + if (core_enable_device_list_for_node(lun, lacl, lacl->mapped_lun, + lun_access, nacl, tpg) < 0) return -EINVAL; spin_lock(&lun->lun_acl_lock); @@ -1513,8 +1537,8 @@ int core_dev_del_initiator_node_lun_acl( smp_mb__after_atomic_dec(); spin_unlock(&lun->lun_acl_lock); - core_update_device_list_for_node(lun, NULL, lacl->mapped_lun, - TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg, 0); + core_disable_device_list_for_node(lun, NULL, lacl->mapped_lun, + TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg); lacl->se_lun = NULL; diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index d41a9bb..0fd4282 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -10,8 +10,10 @@ int core_free_device_list_for_node(struct se_node_acl *, struct se_portal_group *); void core_dec_lacl_count(struct se_node_acl *, struct se_cmd *); void core_update_device_list_access(u32, u32, struct se_node_acl *); -int core_update_device_list_for_node(struct se_lun *, struct se_lun_acl *, - u32, u32, struct se_node_acl *, struct se_portal_group *, int); +int core_enable_device_list_for_node(struct se_lun *, struct se_lun_acl *, + u32, u32, struct se_node_acl *, struct se_portal_group *); +int core_disable_device_list_for_node(struct se_lun *, struct se_lun_acl *, + u32, u32, struct se_node_acl *, struct se_portal_group *); void core_clear_lun_from_tpg(struct se_lun *, struct se_portal_group *); int core_dev_export(struct se_device *, struct se_portal_group *, struct se_lun *); diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 5ca340c..b8628a5 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -77,8 +77,8 @@ static void core_clear_initiator_node_from_tpg( lun = deve->se_lun; spin_unlock_irq(&nacl->device_list_lock); - core_update_device_list_for_node(lun, NULL, deve->mapped_lun, - TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg, 0); + core_disable_device_list_for_node(lun, NULL, deve->mapped_lun, + TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg); spin_lock_irq(&nacl->device_list_lock); } @@ -172,8 +172,8 @@ void core_tpg_add_node_to_devs( (lun_access == TRANSPORT_LUNFLAGS_READ_WRITE) ? "READ-WRITE" : "READ-ONLY"); - core_update_device_list_for_node(lun, NULL, lun->unpacked_lun, - lun_access, acl, tpg, 1); + core_enable_device_list_for_node(lun, NULL, lun->unpacked_lun, + lun_access, acl, tpg); spin_lock(&tpg->tpg_lun_lock); } spin_unlock(&tpg->tpg_lun_lock); -- cgit v0.10.2 From 77d4c7450646e6bcba3ff6de17aa4b98c34fe849 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sat, 14 Jul 2012 15:11:41 -0700 Subject: target: Make core_disable_device_list_for_node use pre-refactoring lock ordering So after kicking around commit 547ac4c9c90 around a bit more, a tcm_qla2xxx LUN unlink OP has generated the following warning: [ 50.386625] qla2xxx [0000:07:00.0]-00af:0: Performing ISP error recovery - ha=ffff880263774000. [ 70.572988] qla2xxx [0000:07:00.0]-8038:0: Cable is unplugged... [ 126.527531] ------------[ cut here ]------------ [ 126.532677] WARNING: at kernel/softirq.c:159 local_bh_enable_ip+0x41/0x8c() [ 126.540433] Hardware name: S5520HC [ 126.544248] Modules linked in: tcm_vhost ib_srpt ib_cm ib_sa ib_mad ib_core tcm_qla2xxx tcm_loop tcm_fc libfc iscsi_target_mod target_core_pscsi target_core_file target_core_iblock target_core_mod configfs ipv6 iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi dm_round_robin dm_multipath scsi_dh loop i2c_i801 kvm_intel kvm crc32c_intel i2c_core microcode joydev button iomemory_vsl(O) pcspkr ext3 jbd uhci_hcd lpfc ata_piix libata ehci_hcd qla2xxx mlx4_core scsi_transport_fc scsi_tgt igb [last unloaded: scsi_wait_scan] [ 126.595567] Pid: 3283, comm: unlink Tainted: G O 3.5.0-rc2+ #33 [ 126.603128] Call Trace: [ 126.605853] [] ? warn_slowpath_common+0x78/0x8c [ 126.612737] [] ? local_bh_enable_ip+0x41/0x8c [ 126.619433] [] ? core_disable_device_list_for_node+0x70/0xe3 [target_core_mod] [ 126.629323] [] ? core_clear_lun_from_tpg+0x88/0xeb [target_core_mod] [ 126.638244] [] ? core_tpg_post_dellun+0x17/0x48 [target_core_mod] [ 126.646873] [] ? core_dev_del_lun+0x26/0x8c [target_core_mod] [ 126.655114] [] ? dput+0x27/0x154 [ 126.660549] [] ? target_fabric_port_unlink+0x3b/0x41 [target_core_mod] [ 126.669661] [] ? configfs_unlink+0xfc/0x14a [configfs] [ 126.677224] [] ? vfs_unlink+0x58/0xb7 [ 126.683141] [] ? do_unlinkat+0xbb/0x142 [ 126.689253] [] ? page_fault+0x25/0x30 [ 126.695170] [] ? system_call_fastpath+0x16/0x1b [ 126.702053] ---[ end trace 2f8e5b0a9ec797ef ]--- [ 126.756336] qla2xxx [0000:07:00.0]-00af:0: Performing ISP error recovery - ha=ffff880263774000. [ 146.942414] qla2xxx [0000:07:00.0]-8038:0: Cable is unplugged... So this warning triggered because device_list disable logic is now holding nacl->device_list_lock w/ spin_lock_irqsave before obtaining port->sep_alua_lock with only spin_lock_bh.. The original disable logic obtains *deve ahead of dropping the entry from deve->alua_port_list and then obtains ->device_list_lock to do the remaining work. Also, I'm pretty sure this particular warning is being generated by a demo-mode session in tcm_qla2xxx, and not by explicit NodeACL MappedLUNs. The Initiator MappedLUNs are already protected by a seperate configfs symlink reference back se_lun->lun_group, and the demo-mode se_node_acl (and associated ->device_list[]) is released during se_portal_group->tpg_group shutdown. The following patch drops the extra functional change to disable logic in commit 547ac4c9c90 Cc: Andy Grover Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 0a1c907..0048d0a 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -432,11 +432,7 @@ int core_disable_device_list_for_node( struct se_portal_group *tpg) { struct se_port *port = lun->lun_sep; - struct se_dev_entry *deve; - - spin_lock_irq(&nacl->device_list_lock); - - deve = nacl->device_list[mapped_lun]; + struct se_dev_entry *deve = nacl->device_list[mapped_lun]; /* * If the MappedLUN entry is being disabled, the entry in @@ -454,14 +450,13 @@ int core_disable_device_list_for_node( spin_lock_bh(&port->sep_alua_lock); list_del(&deve->alua_port_list); spin_unlock_bh(&port->sep_alua_lock); - /* * Wait for any in process SPEC_I_PT=1 or REGISTER_AND_MOVE * PR operation to complete. */ - spin_unlock_irq(&nacl->device_list_lock); while (atomic_read(&deve->pr_ref_count) != 0) cpu_relax(); + spin_lock_irq(&nacl->device_list_lock); /* * Disable struct se_dev_entry LUN ACL mapping -- cgit v0.10.2 From b46e34a6721cb057702f19ebe27cfc7877e500e5 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 11:04:36 -0700 Subject: qla2xxx: Get rid of redundant qla_tgt_sess.tearing_down The only place that sets qla_tgt_sess.tearing_down calls target_splice_sess_cmd_list() immediately afterwards, without dropping the lock it holds. That function sets se_session.sess_tearing_down, so we can get rid of the qla_target-specific flag, and in the one place that looks at the qla_tgt_sess.tearing_down flag just test se_session.sess_tearing_down instead. Cc: Chad Dupuis Cc: Arun Easi Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 77759c7..87b5a330 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -2644,7 +2644,7 @@ static void qlt_do_work(struct work_struct *work) sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, atio->u.isp24.fcp_hdr.s_id); if (sess) { - if (unlikely(sess->tearing_down)) { + if (unlikely(sess->se_sess->sess_tearing_down)) { sess = NULL; spin_unlock_irqrestore(&ha->hardware_lock, flags); goto out_term; diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 2953db8..170af15 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -813,7 +813,6 @@ struct qla_tgt_sess { unsigned int conf_compl_supported:1; unsigned int deleted:1; unsigned int local:1; - unsigned int tearing_down:1; struct se_session *se_sess; struct scsi_qla_host *vha; diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index d85a817..e131d68 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -464,7 +464,6 @@ static int tcm_qla2xxx_shutdown_session(struct se_session *se_sess) vha = sess->vha; spin_lock_irqsave(&vha->hw->hardware_lock, flags); - sess->tearing_down = 1; target_splice_sess_cmd_list(se_sess); spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); -- cgit v0.10.2 From 669ab62c9d045bd2ff647f39e9e7a088e7e8706a Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 11:04:37 -0700 Subject: target: Un-export target_get_sess_cmd() There are no in-tree users of target_get_sess_cmd() outside of target_core_transport.c. Any new code should use the higher-level target_submit_cmd() interface. So let's un-export target_get_sess_cmd() and make it static to the one file where it's actually used. (nab: Fix up minor fuzz to for-next) Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 45ed170..7b85434 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -70,6 +70,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd); static void transport_handle_queue_full(struct se_cmd *cmd, struct se_device *dev); static int transport_generic_get_mem(struct se_cmd *cmd); +static void target_get_sess_cmd(struct se_session *, struct se_cmd *, bool); static void transport_put_cmd(struct se_cmd *cmd); static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); static void target_complete_ok_work(struct work_struct *work); @@ -2408,8 +2409,8 @@ EXPORT_SYMBOL(transport_generic_free_cmd); * @se_cmd: command descriptor to add * @ack_kref: Signal that fabric will perform an ack target_put_sess_cmd() */ -void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, - bool ack_kref) +static void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, + bool ack_kref) { unsigned long flags; @@ -2429,7 +2430,6 @@ void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, se_cmd->check_release = 1; spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); } -EXPORT_SYMBOL(target_get_sess_cmd); static void target_release_cmd_kref(struct kref *kref) { diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index c3ad1ec..2eba240 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -121,7 +121,6 @@ bool transport_wait_for_tasks(struct se_cmd *); int transport_check_aborted_status(struct se_cmd *, int); int transport_send_check_condition_and_sense(struct se_cmd *, u8, int); -void target_get_sess_cmd(struct se_session *, struct se_cmd *, bool); int target_put_sess_cmd(struct se_session *, struct se_cmd *); void target_splice_sess_cmd_list(struct se_session *); void target_wait_for_sess_cmds(struct se_session *, int); -- cgit v0.10.2 From 7c78b8de267cc4bc63c4f95bda694be606c3644d Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 11:04:38 -0700 Subject: sbp-target: Consolidate duplicated error path code in sbp_handle_command() Cc: Chris Boot Cc: Stefan Richter Signed-off-by: Roland Dreier diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 0848c4c..e10e622 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1219,28 +1219,14 @@ static void sbp_handle_command(struct sbp_target_request *req) ret = sbp_fetch_command(req); if (ret) { pr_debug("sbp_handle_command: fetch command failed: %d\n", ret); - req->status.status |= cpu_to_be32( - STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) | - STATUS_BLOCK_DEAD(0) | - STATUS_BLOCK_LEN(1) | - STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR)); - sbp_send_status(req); - sbp_free_request(req); - return; + goto err; } ret = sbp_fetch_page_table(req); if (ret) { pr_debug("sbp_handle_command: fetch page table failed: %d\n", ret); - req->status.status |= cpu_to_be32( - STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) | - STATUS_BLOCK_DEAD(0) | - STATUS_BLOCK_LEN(1) | - STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR)); - sbp_send_status(req); - sbp_free_request(req); - return; + goto err; } unpacked_lun = req->login->lun->unpacked_lun; @@ -1252,6 +1238,16 @@ static void sbp_handle_command(struct sbp_target_request *req) target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf, req->sense_buf, unpacked_lun, data_length, MSG_SIMPLE_TAG, data_dir, 0); + return; + +err: + req->status.status |= cpu_to_be32( + STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) | + STATUS_BLOCK_DEAD(0) | + STATUS_BLOCK_LEN(1) | + STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR)); + sbp_send_status(req); + sbp_free_request(req); } /* -- cgit v0.10.2 From bc187ea6c3b3d20bd190f3ee90c954aee0ce8aad Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 11:04:40 -0700 Subject: target: Check sess_tearing_down in target_get_sess_cmd() Target core code assumes that target_splice_sess_cmd_list() has set sess_tearing_down and moved the list of pending commands to sess_wait_list, no more commands will be added to the session; if any are added, nothing keeps the se_session from being freed while the command is still in flight, which e.g. leads to use-after-free of se_cmd->se_sess in target_release_cmd_kref(). To enforce this invariant, put a check of sess_tearing_down inside of sess_cmd_lock in target_get_sess_cmd(); any checks before this are racy and can lead to the use-after-free described above. For example, the qla_target check in qlt_do_work() checks sess_tearing_down from work thread context but then drops all locks before calling target_submit_cmd() (as it must, since that is a sleeping function). However, since no locks are held, anything can happen with respect to the session it has looked up -- although it does correctly get sess_kref within its lock, so the memory won't be freed while target_submit_cmd() is actually running, nothing stops eg an ACL from being dropped and calling ->shutdown_session() (which calls into target_splice_sess_cmd_list()) before we get to target_get_sess_cmd(). Once this happens, the se_session memory can be freed as soon as target_submit_cmd() returns and qlt_do_work() drops its reference, even though we've just added a command to sess_cmd_list. To prevent this use-after-free, check sess_tearing_down inside of sess_cmd_lock right before target_get_sess_cmd() adds a command to sess_cmd_list; this is synchronized with target_splice_sess_cmd_list() so that every command is either waited for or not added to the queue. (nab: Keep target_submit_cmd() returning void for now..) Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 7b85434..a979514 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -70,7 +70,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd); static void transport_handle_queue_full(struct se_cmd *cmd, struct se_device *dev); static int transport_generic_get_mem(struct se_cmd *cmd); -static void target_get_sess_cmd(struct se_session *, struct se_cmd *, bool); +static int target_get_sess_cmd(struct se_session *, struct se_cmd *, bool); static void transport_put_cmd(struct se_cmd *cmd); static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); static void target_complete_ok_work(struct work_struct *work); @@ -1477,7 +1477,9 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, * for fabrics using TARGET_SCF_ACK_KREF that expect a second * kref_put() to happen during fabric packet acknowledgement. */ - target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + rc = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + if (rc) + return; /* * Signal bidirectional data payloads to target-core */ @@ -1561,7 +1563,11 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, se_cmd->se_tmr_req->ref_task_tag = tag; /* See target_submit_cmd for commentary */ - target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + ret = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + if (ret) { + core_tmr_release_req(se_cmd->se_tmr_req); + return ret; + } ret = transport_lookup_tmr_lun(se_cmd, unpacked_lun); if (ret) { @@ -2409,10 +2415,11 @@ EXPORT_SYMBOL(transport_generic_free_cmd); * @se_cmd: command descriptor to add * @ack_kref: Signal that fabric will perform an ack target_put_sess_cmd() */ -static void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, - bool ack_kref) +static int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, + bool ack_kref) { unsigned long flags; + int ret = 0; kref_init(&se_cmd->cmd_kref); /* @@ -2426,9 +2433,16 @@ static void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cm } spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); + if (se_sess->sess_tearing_down) { + ret = -ESHUTDOWN; + goto out; + } list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list); se_cmd->check_release = 1; + +out: spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + return ret; } static void target_release_cmd_kref(struct kref *kref) -- cgit v0.10.2 From e1013f14376f3121e73917f5455b9b7a22bdfb41 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 11:04:41 -0700 Subject: qla2xxx: Remove racy, now-redundant check of sess_tearing_down Now that target_submit_cmd() / target_get_sess_cmd() check sess_tearing_down before adding commands to the list, we no longer need the check in qlt_do_work(). In fact this check is racy anyway (and that race is what inspired the change to add the check of sess_tearing_down to the target core). Cc: Chad Dupuis Cc: Arun Easi Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 87b5a330..5b30132 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -2643,19 +2643,9 @@ static void qlt_do_work(struct work_struct *work) spin_lock_irqsave(&ha->hardware_lock, flags); sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, atio->u.isp24.fcp_hdr.s_id); - if (sess) { - if (unlikely(sess->se_sess->sess_tearing_down)) { - sess = NULL; - spin_unlock_irqrestore(&ha->hardware_lock, flags); - goto out_term; - } else { - /* - * Do the extra kref_get() before dropping - * qla_hw_data->hardware_lock. - */ - kref_get(&sess->se_sess->sess_kref); - } - } + /* Do kref_get() before dropping qla_hw_data->hardware_lock. */ + if (sess) + kref_get(&sess->se_sess->sess_kref); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (unlikely(!sess)) { -- cgit v0.10.2 From 1c7b13fe65269960f63082eafccede547191ab02 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 11:04:42 -0700 Subject: target: Remove se_session.sess_wait_list Since we set se_session.sess_tearing_down and stop new commands from being added to se_session.sess_cmd_list before we wait for commands to finish when freeing a session, there's no need for a separate sess_wait_list -- if we let new commands be added to sess_cmd_list after setting sess_tearing_down, that would be a bug that breaks the logic of waiting in-flight commands. Also rename target_splice_sess_cmd_list() to target_sess_cmd_list_set_waiting(), since we are no longer splicing onto a separate list. Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index e131d68..65a7ed9 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -464,7 +464,7 @@ static int tcm_qla2xxx_shutdown_session(struct se_session *se_sess) vha = sess->vha; spin_lock_irqsave(&vha->hw->hardware_lock, flags); - target_splice_sess_cmd_list(se_sess); + target_sess_cmd_list_set_waiting(se_sess); spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); return 1; diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index a979514..357bb24 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -232,7 +232,6 @@ struct se_session *transport_init_session(void) INIT_LIST_HEAD(&se_sess->sess_list); INIT_LIST_HEAD(&se_sess->sess_acl_list); INIT_LIST_HEAD(&se_sess->sess_cmd_list); - INIT_LIST_HEAD(&se_sess->sess_wait_list); spin_lock_init(&se_sess->sess_cmd_lock); kref_init(&se_sess->sess_kref); @@ -2478,28 +2477,27 @@ int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) } EXPORT_SYMBOL(target_put_sess_cmd); -/* target_splice_sess_cmd_list - Split active cmds into sess_wait_list - * @se_sess: session to split +/* target_sess_cmd_list_set_waiting - Flag all commands in + * sess_cmd_list to complete cmd_wait_comp. Set + * sess_tearing_down so no more commands are queued. + * @se_sess: session to flag */ -void target_splice_sess_cmd_list(struct se_session *se_sess) +void target_sess_cmd_list_set_waiting(struct se_session *se_sess) { struct se_cmd *se_cmd; unsigned long flags; - WARN_ON(!list_empty(&se_sess->sess_wait_list)); - INIT_LIST_HEAD(&se_sess->sess_wait_list); - spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); - se_sess->sess_tearing_down = 1; - list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list); + WARN_ON(se_sess->sess_tearing_down); + se_sess->sess_tearing_down = 1; - list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) + list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) se_cmd->cmd_wait_set = 1; spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); } -EXPORT_SYMBOL(target_splice_sess_cmd_list); +EXPORT_SYMBOL(target_sess_cmd_list_set_waiting); /* target_wait_for_sess_cmds - Wait for outstanding descriptors * @se_sess: session to wait for active I/O @@ -2513,7 +2511,7 @@ void target_wait_for_sess_cmds( bool rc = false; list_for_each_entry_safe(se_cmd, tmp_cmd, - &se_sess->sess_wait_list, se_cmd_list) { + &se_sess->sess_cmd_list, se_cmd_list) { list_del(&se_cmd->se_cmd_list); pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:" diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 4f4f042..fa83ea1 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -613,7 +613,6 @@ struct se_session { struct list_head sess_list; struct list_head sess_acl_list; struct list_head sess_cmd_list; - struct list_head sess_wait_list; spinlock_t sess_cmd_lock; struct kref sess_kref; }; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 2eba240..815e064 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -122,7 +122,7 @@ int transport_check_aborted_status(struct se_cmd *, int); int transport_send_check_condition_and_sense(struct se_cmd *, u8, int); int target_put_sess_cmd(struct se_session *, struct se_cmd *); -void target_splice_sess_cmd_list(struct se_session *); +void target_sess_cmd_list_set_waiting(struct se_session *); void target_wait_for_sess_cmds(struct se_session *, int); int core_alua_check_nonop_delay(struct se_cmd *); -- cgit v0.10.2 From c8045372dd2d4784bc4cb32ddc27f4b88ff2140c Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 15:17:12 -0700 Subject: target: Make unnecessarily global se_dev_align_max_sectors() static Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 0048d0a..cf2c66f 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -841,7 +841,7 @@ int se_dev_check_shutdown(struct se_device *dev) return ret; } -u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size) +static u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size) { u32 tmp, aligned_max_sectors; /* -- cgit v0.10.2 From e2397c704429025bc6b331a970f699e52f34283e Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 15:34:21 -0700 Subject: target: Add generation of LOGICAL BLOCK ADDRESS OUT OF RANGE Many SCSI commands are defined to return a CHECK CONDITION / ILLEGAL REQUEST with ASC set to LOGICAL BLOCK ADDRESS OUT OF RANGE if the initiator sends a command that accesses a too-big LBA. Add an enum value and case entries so that target code can return this status. Signed-off-by: Roland Dreier Cc: stable@vger.kernel.org Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 357bb24..14e54b4 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1640,6 +1640,7 @@ void transport_generic_request_failure(struct se_cmd *cmd) case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE: case TCM_UNKNOWN_MODE_PAGE: case TCM_WRITE_PROTECTED: + case TCM_ADDRESS_OUT_OF_RANGE: case TCM_CHECK_CONDITION_ABORT_CMD: case TCM_CHECK_CONDITION_UNIT_ATTENTION: case TCM_CHECK_CONDITION_NOT_READY: @@ -2967,6 +2968,15 @@ int transport_send_check_condition_and_sense( /* WRITE PROTECTED */ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x27; break; + case TCM_ADDRESS_OUT_OF_RANGE: + /* CURRENT ERROR */ + buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; + /* ILLEGAL REQUEST */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; + /* LOGICAL BLOCK ADDRESS OUT OF RANGE */ + buffer[offset+SPC_ASC_KEY_OFFSET] = 0x21; + break; case TCM_CHECK_CONDITION_UNIT_ATTENTION: /* CURRENT ERROR */ buffer[offset] = 0x70; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index fa83ea1..128ce46 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -212,6 +212,7 @@ enum tcm_sense_reason_table { TCM_CHECK_CONDITION_UNIT_ATTENTION = 0x0e, TCM_CHECK_CONDITION_NOT_READY = 0x0f, TCM_RESERVATION_CONFLICT = 0x10, + TCM_ADDRESS_OUT_OF_RANGE = 0x11, }; enum target_sc_flags_table { -- cgit v0.10.2 From 2594e29865c291db162313187612cd9f14538f33 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 15:34:22 -0700 Subject: target: Add range checking to UNMAP emulation When processing an UNMAP command, we need to make sure that the number of blocks we're asked to UNMAP does not exceed our reported maximum number of blocks per UNMAP, and that the range of blocks we're unmapping doesn't go past the end of the device. Signed-off-by: Roland Dreier Cc: stable@vger.kernel.org Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 8a12e29..8fb3822 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -348,6 +348,18 @@ static int iblock_execute_unmap(struct se_cmd *cmd) pr_debug("UNMAP: Using lba: %llu and range: %u\n", (unsigned long long)lba, range); + if (range > dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count) { + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; + goto err; + } + + if (lba + range > dev->transport->get_blocks(dev) + 1) { + cmd->scsi_sense_reason = TCM_ADDRESS_OUT_OF_RANGE; + ret = -EINVAL; + goto err; + } + ret = blkdev_issue_discard(ibd->ibd_bd, lba, range, GFP_KERNEL, 0); if (ret < 0) { -- cgit v0.10.2 From 1a5fa4576ec8a462313c7516b31d7453481ddbe8 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 15:34:23 -0700 Subject: target: Fix reading of data length fields for UNMAP commands The UNMAP DATA LENGTH and UNMAP BLOCK DESCRIPTOR DATA LENGTH fields are in the unmap descriptor (the payload transferred to our data out buffer), not in the CDB itself. Read them from the correct place in target_emulated_unmap. Signed-off-by: Roland Dreier Cc: stable@vger.kernel.org Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 8fb3822..e6d08ee 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -324,7 +324,6 @@ static int iblock_execute_unmap(struct se_cmd *cmd) struct se_device *dev = cmd->se_dev; struct iblock_dev *ibd = dev->dev_ptr; unsigned char *buf, *ptr = NULL; - unsigned char *cdb = &cmd->t_task_cdb[0]; sector_t lba; unsigned int size = cmd->data_length, range; int ret = 0, offset; @@ -333,11 +332,12 @@ static int iblock_execute_unmap(struct se_cmd *cmd) /* First UNMAP block descriptor starts at 8 byte offset */ offset = 8; size -= 8; - dl = get_unaligned_be16(&cdb[0]); - bd_dl = get_unaligned_be16(&cdb[2]); buf = transport_kmap_data_sg(cmd); + dl = get_unaligned_be16(&buf[0]); + bd_dl = get_unaligned_be16(&buf[2]); + ptr = &buf[offset]; pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu" " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr); -- cgit v0.10.2 From b7fc7f3777582dea85156a821d78a522a0c083aa Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 15:34:24 -0700 Subject: target: Fix possible integer underflow in UNMAP emulation It's possible for an initiator to send us an UNMAP command with a descriptor that is less than 8 bytes; in that case it's really bad for us to set an unsigned int to that value, subtract 8 from it, and then use that as a limit for our loop (since the value will wrap around to a huge positive value). Fix this by making size be signed and only looping if size >= 16 (ie if we have at least a full descriptor available). Also remove offset as an obfuscated name for the constant 8. Signed-off-by: Roland Dreier Cc: stable@vger.kernel.org Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index e6d08ee..2efd70c 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -325,24 +325,24 @@ static int iblock_execute_unmap(struct se_cmd *cmd) struct iblock_dev *ibd = dev->dev_ptr; unsigned char *buf, *ptr = NULL; sector_t lba; - unsigned int size = cmd->data_length, range; - int ret = 0, offset; - unsigned short dl, bd_dl; - - /* First UNMAP block descriptor starts at 8 byte offset */ - offset = 8; - size -= 8; + int size = cmd->data_length; + u32 range; + int ret = 0; + int dl, bd_dl; buf = transport_kmap_data_sg(cmd); dl = get_unaligned_be16(&buf[0]); bd_dl = get_unaligned_be16(&buf[2]); - ptr = &buf[offset]; - pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu" + size = min(size - 8, bd_dl); + + /* First UNMAP block descriptor starts at 8 byte offset */ + ptr = &buf[8]; + pr_debug("UNMAP: Sub: %s Using dl: %u bd_dl: %u size: %u" " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr); - while (size) { + while (size >= 16) { lba = get_unaligned_be64(&ptr[0]); range = get_unaligned_be32(&ptr[8]); pr_debug("UNMAP: Using lba: %llu and range: %u\n", -- cgit v0.10.2 From 7409a6657aebf8be74c21d0eded80709b27275cb Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 15:34:25 -0700 Subject: target: Check number of unmap descriptors against our limit Fail UNMAP commands that have more than our reported limit on unmap descriptors. Signed-off-by: Roland Dreier Cc: stable@vger.kernel.org Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 2efd70c..76db75e 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -336,6 +336,11 @@ static int iblock_execute_unmap(struct se_cmd *cmd) bd_dl = get_unaligned_be16(&buf[2]); size = min(size - 8, bd_dl); + if (size / 16 > dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) { + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; + goto err; + } /* First UNMAP block descriptor starts at 8 byte offset */ ptr = &buf[8]; -- cgit v0.10.2 From d6dfc868bcf329392abd1ecfa7357eb51ebf8c30 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 16 Jul 2012 11:04:39 -0700 Subject: target: Allow for target_submit_cmd() returning errors We want it to be possible for target_submit_cmd() to return errors up to its fabric module callers. For now just update the prototype to return an int, and update all callers to handle non-zero return values as an error. This is immediately useful for tcm_qla2xxx to fix a long-standing active I/O session shutdown race, but tcm_fc, usb-gadget, and sbp-target the fabric maintainers need to check + ACK that handling a target_submit_cmd() failure due to session shutdown does not introduce regressions (nab: Respin against for-next after initial NACK + update docbook comment + fix double se_cmd init in exception path for usb-gadget) Cc: Chad Dupuis Cc: Arun Easi Cc: Chris Boot Cc: Stefan Richter Cc: Mark Rustad Cc: Sebastian Andrzej Siewior Cc: Felipe Balbi Cc: Andy Grover Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 65a7ed9..4752f65 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -597,10 +597,9 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd, return -EINVAL; } - target_submit_cmd(se_cmd, se_sess, cdb, &cmd->sense_buffer[0], + return target_submit_cmd(se_cmd, se_sess, cdb, &cmd->sense_buffer[0], cmd->unpacked_lun, data_length, fcp_task_attr, data_dir, flags); - return 0; } static void tcm_qla2xxx_handle_data_work(struct work_struct *work) diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index e10e622..39ddba5 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1235,9 +1235,11 @@ static void sbp_handle_command(struct sbp_target_request *req) pr_debug("sbp_handle_command ORB:0x%llx unpacked_lun:%d data_len:%d data_dir:%d\n", req->orb_pointer, unpacked_lun, data_length, data_dir); - target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf, - req->sense_buf, unpacked_lun, data_length, - MSG_SIMPLE_TAG, data_dir, 0); + if (target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf, + req->sense_buf, unpacked_lun, data_length, + MSG_SIMPLE_TAG, data_dir, 0)) + goto err; + return; err: diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 14e54b4..7647eca 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1447,10 +1447,14 @@ EXPORT_SYMBOL(transport_handle_cdb_direct); * @data_dir: DMA data direction * @flags: flags for command submission from target_sc_flags_tables * + * Returns non zero to signal active I/O shutdown failure. All other + * setup exceptions will be returned as a SCSI CHECK_CONDITION response, + * but still return zero here. + * * This may only be called from process context, and also currently * assumes internal allocation of fabric payload buffer by target-core. **/ -void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, +int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, unsigned char *cdb, unsigned char *sense, u32 unpacked_lun, u32 data_length, int task_attr, int data_dir, int flags) { @@ -1478,7 +1482,7 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, */ rc = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); if (rc) - return; + return rc; /* * Signal bidirectional data payloads to target-core */ @@ -1491,13 +1495,13 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, transport_send_check_condition_and_sense(se_cmd, se_cmd->scsi_sense_reason, 0); target_put_sess_cmd(se_sess, se_cmd); - return; + return 0; } rc = target_setup_cmd_from_cdb(se_cmd, cdb); if (rc != 0) { transport_generic_request_failure(se_cmd); - return; + return 0; } /* @@ -1507,7 +1511,7 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, core_alua_check_nonop_delay(se_cmd); transport_handle_cdb_direct(se_cmd); - return; + return 0; } EXPORT_SYMBOL(target_submit_cmd); diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 4ad58ac..b9cb500 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -543,9 +543,11 @@ static void ft_send_work(struct work_struct *work) * Use a single se_cmd->cmd_kref as we expect to release se_cmd * directly from ft_check_stop_free callback in response path. */ - target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb, - &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), - ntohl(fcp->fc_dl), task_attr, data_dir, 0); + if (target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb, + &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), + ntohl(fcp->fc_dl), task_attr, data_dir, 0)) + goto err; + pr_debug("r_ctl %x alloc target_submit_cmd\n", fh->fh_r_ctl); return; diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index 02ace18..5444866 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c @@ -1065,16 +1065,20 @@ static void usbg_cmd_work(struct work_struct *work) tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo, tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE, cmd->prio_attr, cmd->sense_iu.sense); - - transport_send_check_condition_and_sense(se_cmd, - TCM_UNSUPPORTED_SCSI_OPCODE, 1); - usbg_cleanup_cmd(cmd); - return; + goto out; } - target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, + if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, - 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE); + 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE) < 0) + goto out; + + return; + +out: + transport_send_check_condition_and_sense(se_cmd, + TCM_UNSUPPORTED_SCSI_OPCODE, 1); + usbg_cleanup_cmd(cmd); } static int usbg_submit_command(struct f_uas *fu, @@ -1177,16 +1181,20 @@ static void bot_cmd_work(struct work_struct *work) tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo, tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE, cmd->prio_attr, cmd->sense_iu.sense); - - transport_send_check_condition_and_sense(se_cmd, - TCM_UNSUPPORTED_SCSI_OPCODE, 1); - usbg_cleanup_cmd(cmd); - return; + goto out; } - target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, + if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, - cmd->data_len, cmd->prio_attr, dir, 0); + cmd->data_len, cmd->prio_attr, dir, 0) < 0) + goto out; + + return; + +out: + transport_send_check_condition_and_sense(se_cmd, + TCM_UNSUPPORTED_SCSI_OPCODE, 1); + usbg_cleanup_cmd(cmd); } static int bot_submit_command(struct f_uas *fu, diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 815e064..69fb3cf 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -102,7 +102,7 @@ void transport_init_se_cmd(struct se_cmd *, struct target_core_fabric_ops *, struct se_session *, u32, int, int, unsigned char *); int transport_lookup_cmd_lun(struct se_cmd *, u32); int target_setup_cmd_from_cdb(struct se_cmd *, unsigned char *); -void target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *, +int target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *, unsigned char *, u32, u32, int, int, int); int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, unsigned char *sense, u32 unpacked_lun, -- cgit v0.10.2 From 2962846d14769e526b5d266f4af998b5a027b1d7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 20 Jul 2012 10:07:34 +0300 Subject: target: NULL dereference on error path During a failure in transport_add_device_to_core_hba() code, we called destroy_workqueue(dev->tmr_wq) before ->tmr_wq was allocated which leads to an oops. This fixes a regression introduced in with: commit af8772926f019b7bddd7477b8de5f3b0f12bad21 Author: Christoph Hellwig Date: Sun Jul 8 15:58:49 2012 -0400 target: replace the processing thread with a TMR work queue Signed-off-by: Dan Carpenter Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 7647eca..0eaae23 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1098,7 +1098,7 @@ struct se_device *transport_add_device_to_core_hba( * Setup the Asymmetric Logical Unit Assignment for struct se_device */ if (core_setup_alua(dev, force_pt) < 0) - goto out; + goto err_dev_list; /* * Startup the struct se_device processing thread @@ -1108,7 +1108,7 @@ struct se_device *transport_add_device_to_core_hba( if (!dev->tmr_wq) { pr_err("Unable to create tmr workqueue for %s\n", dev->transport->name); - goto out; + goto err_dev_list; } /* * Setup work_queue for QUEUE_FULL @@ -1126,7 +1126,7 @@ struct se_device *transport_add_device_to_core_hba( if (!inquiry_prod || !inquiry_rev) { pr_err("All non TCM/pSCSI plugins require" " INQUIRY consts\n"); - goto out; + goto err_wq; } strncpy(&dev->se_sub_dev->t10_wwn.vendor[0], "LIO-ORG", 8); @@ -1136,9 +1136,10 @@ struct se_device *transport_add_device_to_core_hba( scsi_dump_inquiry(dev); return dev; -out: - destroy_workqueue(dev->tmr_wq); +err_wq: + destroy_workqueue(dev->tmr_wq); +err_dev_list: spin_lock(&hba->device_lock); list_del(&dev->dev_list); hba->dev_count--; -- cgit v0.10.2 From bf6932f44a7b3fa7e2246a8b18a44670e5eab6c2 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 21 Jul 2012 08:55:18 +0100 Subject: iscsi-target: Drop bogus struct file usage for iSCSI/SCTP From Al Viro: BTW, speaking of struct file treatment related to sockets - there's this piece of code in iscsi: /* * The SCTP stack needs struct socket->file. */ if ((np->np_network_transport == ISCSI_SCTP_TCP) || (np->np_network_transport == ISCSI_SCTP_UDP)) { if (!new_sock->file) { new_sock->file = kzalloc( sizeof(struct file), GFP_KERNEL); For one thing, as far as I can see it'not true - sctp does *not* depend on socket->file being non-NULL; it does, in one place, check socket->file->f_flags for O_NONBLOCK, but there it treats NULL socket->file as "flag not set". Which is the case here anyway - the fake struct file created in __iscsi_target_login_thread() (and in iscsi_target_setup_login_socket(), with the same excuse) do *not* get that flag set. Moreover, it's a bloody serious violation of a bunch of asserts in VFS; all struct file instances should come from filp_cachep, via get_empty_filp() (or alloc_file(), which is a wrapper for it). FWIW, I'm very tempted to do this and be done with the entire mess: Signed-off-by: Al Viro Cc: Andy Grover Cc: Hannes Reinecke Cc: Christoph Hellwig Cc: stable@vger.kernel.org Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 5d56ce4..97c0f78 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -429,19 +429,8 @@ int iscsit_reset_np_thread( int iscsit_del_np_comm(struct iscsi_np *np) { - if (!np->np_socket) - return 0; - - /* - * Some network transports allocate their own struct sock->file, - * see if we need to free any additional allocated resources. - */ - if (np->np_flags & NPF_SCTP_STRUCT_FILE) { - kfree(np->np_socket->file); - np->np_socket->file = NULL; - } - - sock_release(np->np_socket); + if (np->np_socket) + sock_release(np->np_socket); return 0; } @@ -4079,13 +4068,8 @@ int iscsit_close_connection( kfree(conn->conn_ops); conn->conn_ops = NULL; - if (conn->sock) { - if (conn->conn_flags & CONNFLAG_SCTP_STRUCT_FILE) { - kfree(conn->sock->file); - conn->sock->file = NULL; - } + if (conn->sock) sock_release(conn->sock); - } conn->thread_set = NULL; pr_debug("Moving to TARG_CONN_STATE_FREE.\n"); diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index 63a8ed2..8a908b2 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h @@ -224,7 +224,6 @@ enum iscsi_timer_flags_table { /* Used for struct iscsi_np->np_flags */ enum np_flags_table { NPF_IP_NETWORK = 0x00, - NPF_SCTP_STRUCT_FILE = 0x01 /* Bugfix */ }; /* Used for struct iscsi_np->np_thread_state */ @@ -504,7 +503,6 @@ struct iscsi_conn { u16 local_port; int net_size; u32 auth_id; -#define CONNFLAG_SCTP_STRUCT_FILE 0x01 u32 conn_flags; /* Used for iscsi_tx_login_rsp() */ u32 login_itt; diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 1434110..0694d9b 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -795,22 +795,6 @@ int iscsi_target_setup_login_socket( } np->np_socket = sock; /* - * The SCTP stack needs struct socket->file. - */ - if ((np->np_network_transport == ISCSI_SCTP_TCP) || - (np->np_network_transport == ISCSI_SCTP_UDP)) { - if (!sock->file) { - sock->file = kzalloc(sizeof(struct file), GFP_KERNEL); - if (!sock->file) { - pr_err("Unable to allocate struct" - " file for SCTP\n"); - ret = -ENOMEM; - goto fail; - } - np->np_flags |= NPF_SCTP_STRUCT_FILE; - } - } - /* * Setup the np->np_sockaddr from the passed sockaddr setup * in iscsi_target_configfs.c code.. */ @@ -869,21 +853,15 @@ int iscsi_target_setup_login_socket( fail: np->np_socket = NULL; - if (sock) { - if (np->np_flags & NPF_SCTP_STRUCT_FILE) { - kfree(sock->file); - sock->file = NULL; - } - + if (sock) sock_release(sock); - } return ret; } static int __iscsi_target_login_thread(struct iscsi_np *np) { u8 buffer[ISCSI_HDR_LEN], iscsi_opcode, zero_tsih = 0; - int err, ret = 0, set_sctp_conn_flag, stop; + int err, ret = 0, stop; struct iscsi_conn *conn = NULL; struct iscsi_login *login; struct iscsi_portal_group *tpg = NULL; @@ -894,7 +872,6 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) struct sockaddr_in6 sock_in6; flush_signals(current); - set_sctp_conn_flag = 0; sock = np->np_socket; spin_lock_bh(&np->np_thread_lock); @@ -917,35 +894,12 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) spin_unlock_bh(&np->np_thread_lock); goto out; } - /* - * The SCTP stack needs struct socket->file. - */ - if ((np->np_network_transport == ISCSI_SCTP_TCP) || - (np->np_network_transport == ISCSI_SCTP_UDP)) { - if (!new_sock->file) { - new_sock->file = kzalloc( - sizeof(struct file), GFP_KERNEL); - if (!new_sock->file) { - pr_err("Unable to allocate struct" - " file for SCTP\n"); - sock_release(new_sock); - /* Get another socket */ - return 1; - } - set_sctp_conn_flag = 1; - } - } - iscsi_start_login_thread_timer(np); conn = kzalloc(sizeof(struct iscsi_conn), GFP_KERNEL); if (!conn) { pr_err("Could not allocate memory for" " new connection\n"); - if (set_sctp_conn_flag) { - kfree(new_sock->file); - new_sock->file = NULL; - } sock_release(new_sock); /* Get another socket */ return 1; @@ -955,9 +909,6 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) conn->conn_state = TARG_CONN_STATE_FREE; conn->sock = new_sock; - if (set_sctp_conn_flag) - conn->conn_flags |= CONNFLAG_SCTP_STRUCT_FILE; - pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n"); conn->conn_state = TARG_CONN_STATE_XPT_UP; @@ -1205,13 +1156,8 @@ old_sess_out: iscsi_release_param_list(conn->param_list); conn->param_list = NULL; } - if (conn->sock) { - if (conn->conn_flags & CONNFLAG_SCTP_STRUCT_FILE) { - kfree(conn->sock->file); - conn->sock->file = NULL; - } + if (conn->sock) sock_release(conn->sock); - } kfree(conn); if (tpg) { -- cgit v0.10.2