diff options
Diffstat (limited to 'drivers/target/target_core_transport.c')
-rw-r--r-- | drivers/target/target_core_transport.c | 269 |
1 files changed, 153 insertions, 116 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 269f544..9097155 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -55,8 +55,6 @@ #include "target_core_pr.h" #include "target_core_ua.h" -static int sub_api_initialized; - static struct workqueue_struct *target_completion_wq; static struct kmem_cache *se_sess_cache; struct kmem_cache *se_ua_cache; @@ -195,6 +193,7 @@ u32 scsi_get_new_index(scsi_index_t type) void transport_subsystem_check_init(void) { int ret; + static int sub_api_initialized; if (sub_api_initialized) return; @@ -211,12 +210,7 @@ void transport_subsystem_check_init(void) if (ret != 0) pr_err("Unable to load target_core_pscsi\n"); - ret = request_module("target_core_stgt"); - if (ret != 0) - pr_err("Unable to load target_core_stgt\n"); - sub_api_initialized = 1; - return; } struct se_session *transport_init_session(void) @@ -573,9 +567,7 @@ static void target_complete_failure_work(struct work_struct *work) */ static unsigned char *transport_get_sense_buffer(struct se_cmd *cmd) { - unsigned char *buffer = cmd->sense_buffer; struct se_device *dev = cmd->se_dev; - u32 offset = 0; WARN_ON(!cmd->se_lun); @@ -585,14 +577,11 @@ static unsigned char *transport_get_sense_buffer(struct se_cmd *cmd) if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) return NULL; - offset = cmd->se_tfo->set_fabric_sense_len(cmd, TRANSPORT_SENSE_BUFFER); - - /* Automatically padded */ - cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset; + cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER; pr_debug("HBA_[%u]_PLUG[%s]: Requesting sense for SAM STATUS: 0x%02x\n", dev->se_hba->hba_id, dev->transport->name, cmd->scsi_status); - return &buffer[offset]; + return cmd->sense_buffer; } void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) @@ -969,7 +958,7 @@ int transport_set_vpd_ident(struct t10_vpd *vpd, unsigned char *page_83) { static const char hex_str[] = "0123456789abcdef"; - int j = 0, i = 4; /* offset to start of the identifer */ + int j = 0, i = 4; /* offset to start of the identifier */ /* * The VPD Code Set (encoding) @@ -1466,8 +1455,9 @@ int transport_handle_cdb_direct( } EXPORT_SYMBOL(transport_handle_cdb_direct); -/** - * target_submit_cmd - lookup unpacked lun and submit uninitialized se_cmd +/* + * target_submit_cmd_map_sgls - lookup unpacked lun and submit uninitialized + * se_cmd + use pre-allocated SGL memory. * * @se_cmd: command descriptor to submit * @se_sess: associated se_sess for endpoint @@ -1478,6 +1468,10 @@ EXPORT_SYMBOL(transport_handle_cdb_direct); * @task_addr: SAM task attribute * @data_dir: DMA data direction * @flags: flags for command submission from target_sc_flags_tables + * @sgl: struct scatterlist memory for unidirectional mapping + * @sgl_count: scatterlist count for unidirectional mapping + * @sgl_bidi: struct scatterlist memory for bidirectional READ mapping + * @sgl_bidi_count: scatterlist count for bidirectional READ mapping * * Returns non zero to signal active I/O shutdown failure. All other * setup exceptions will be returned as a SCSI CHECK_CONDITION response, @@ -1485,10 +1479,12 @@ EXPORT_SYMBOL(transport_handle_cdb_direct); * * This may only be called from process context, and also currently * assumes internal allocation of fabric payload buffer by target-core. - **/ -int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, + */ +int target_submit_cmd_map_sgls(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) + u32 data_length, int task_attr, int data_dir, int flags, + struct scatterlist *sgl, u32 sgl_count, + struct scatterlist *sgl_bidi, u32 sgl_bidi_count) { struct se_portal_group *se_tpg; int rc; @@ -1535,7 +1531,42 @@ int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, transport_generic_request_failure(se_cmd); return 0; } + /* + * When a non zero sgl_count has been passed perform SGL passthrough + * mapping for pre-allocated fabric memory instead of having target + * core perform an internal SGL allocation.. + */ + if (sgl_count != 0) { + BUG_ON(!sgl); + + /* + * A work-around for tcm_loop as some userspace code via + * scsi-generic do not memset their associated read buffers, + * so go ahead and do that here for type 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_DATA_CDB) && + se_cmd->data_direction == DMA_FROM_DEVICE) { + unsigned char *buf = NULL; + + if (sgl) + buf = kmap(sg_page(sgl)) + sgl->offset; + + if (buf) { + memset(buf, 0, sgl->length); + kunmap(sg_page(sgl)); + } + } + rc = transport_generic_map_mem_to_cmd(se_cmd, sgl, sgl_count, + sgl_bidi, sgl_bidi_count); + if (rc != 0) { + transport_generic_request_failure(se_cmd); + return 0; + } + } /* * Check if we need to delay processing because of ALUA * Active/NonOptimized primary access state.. @@ -1545,6 +1576,38 @@ int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, transport_handle_cdb_direct(se_cmd); return 0; } +EXPORT_SYMBOL(target_submit_cmd_map_sgls); + +/* + * target_submit_cmd - lookup unpacked lun and submit uninitialized se_cmd + * + * @se_cmd: command descriptor to submit + * @se_sess: associated se_sess for endpoint + * @cdb: pointer to SCSI CDB + * @sense: pointer to SCSI sense buffer + * @unpacked_lun: unpacked LUN to reference for struct se_lun + * @data_length: fabric expected data transfer length + * @task_addr: SAM task attribute + * @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. + * + * It also assumes interal target core SGL memory allocation. + */ +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) +{ + return target_submit_cmd_map_sgls(se_cmd, se_sess, cdb, sense, + unpacked_lun, data_length, task_attr, data_dir, + flags, NULL, 0, NULL, 0); +} EXPORT_SYMBOL(target_submit_cmd); static void target_complete_tmr_failure(struct work_struct *work) @@ -1553,7 +1616,6 @@ static void target_complete_tmr_failure(struct work_struct *work) se_cmd->se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST; se_cmd->se_tfo->queue_tm_rsp(se_cmd); - transport_generic_free_cmd(se_cmd, 0); } /** @@ -2300,23 +2362,6 @@ int transport_generic_new_cmd(struct se_cmd *cmd) if (ret < 0) goto out_fail; } - /* - * If this command doesn't have any payload and we don't have to call - * into the fabric for data transfers, go ahead and complete it right - * away. - */ - if (!cmd->data_length && - cmd->t_task_cdb[0] != REQUEST_SENSE && - cmd->se_dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) { - spin_lock_irq(&cmd->t_state_lock); - cmd->t_state = TRANSPORT_COMPLETE; - cmd->transport_state |= CMD_T_ACTIVE; - spin_unlock_irq(&cmd->t_state_lock); - - INIT_WORK(&cmd->work, target_complete_ok_work); - queue_work(target_completion_wq, &cmd->work); - return 0; - } atomic_inc(&cmd->t_fe_count); @@ -2771,7 +2816,7 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) spin_lock_irqsave(&cmd->t_state_lock, flags); cmd->transport_state &= ~(CMD_T_ACTIVE | CMD_T_STOP); - pr_debug("wait_for_tasks: Stopped wait_for_compltion(" + pr_debug("wait_for_tasks: Stopped wait_for_completion(" "&cmd->t_transport_stop_comp) for ITT: 0x%08x\n", cmd->se_tfo->get_task_tag(cmd)); @@ -2810,7 +2855,6 @@ int transport_send_check_condition_and_sense( { unsigned char *buffer = cmd->sense_buffer; unsigned long flags; - int offset; u8 asc = 0, ascq = 0; spin_lock_irqsave(&cmd->t_state_lock, flags); @@ -2826,14 +2870,7 @@ int transport_send_check_condition_and_sense( if (!from_transport) cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE; - /* - * Data Segment and SenseLength of the fabric response PDU. - * - * TRANSPORT_SENSE_BUFFER is now set to SCSI_SENSE_BUFFERSIZE - * from include/scsi/scsi_cmnd.h - */ - offset = cmd->se_tfo->set_fabric_sense_len(cmd, - TRANSPORT_SENSE_BUFFER); + /* * Actual SENSE DATA, see SPC-3 7.23.2 SPC_SENSE_KEY_OFFSET uses * SENSE KEY values from include/scsi/scsi.h @@ -2841,151 +2878,151 @@ int transport_send_check_condition_and_sense( switch (reason) { case TCM_NON_EXISTENT_LUN: /* CURRENT ERROR */ - buffer[offset] = 0x70; - buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; + buffer[0] = 0x70; + buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ILLEGAL REQUEST */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; + buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* LOGICAL UNIT NOT SUPPORTED */ - buffer[offset+SPC_ASC_KEY_OFFSET] = 0x25; + buffer[SPC_ASC_KEY_OFFSET] = 0x25; break; case TCM_UNSUPPORTED_SCSI_OPCODE: case TCM_SECTOR_COUNT_TOO_MANY: /* CURRENT ERROR */ - buffer[offset] = 0x70; - buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; + buffer[0] = 0x70; + buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ILLEGAL REQUEST */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; + buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* INVALID COMMAND OPERATION CODE */ - buffer[offset+SPC_ASC_KEY_OFFSET] = 0x20; + buffer[SPC_ASC_KEY_OFFSET] = 0x20; break; case TCM_UNKNOWN_MODE_PAGE: /* CURRENT ERROR */ - buffer[offset] = 0x70; - buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; + buffer[0] = 0x70; + buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ILLEGAL REQUEST */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; + buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* INVALID FIELD IN CDB */ - buffer[offset+SPC_ASC_KEY_OFFSET] = 0x24; + buffer[SPC_ASC_KEY_OFFSET] = 0x24; break; case TCM_CHECK_CONDITION_ABORT_CMD: /* CURRENT ERROR */ - buffer[offset] = 0x70; - buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; + buffer[0] = 0x70; + buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; + buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* BUS DEVICE RESET FUNCTION OCCURRED */ - buffer[offset+SPC_ASC_KEY_OFFSET] = 0x29; - buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x03; + buffer[SPC_ASC_KEY_OFFSET] = 0x29; + buffer[SPC_ASCQ_KEY_OFFSET] = 0x03; break; case TCM_INCORRECT_AMOUNT_OF_DATA: /* CURRENT ERROR */ - buffer[offset] = 0x70; - buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; + buffer[0] = 0x70; + buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; + buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* WRITE ERROR */ - buffer[offset+SPC_ASC_KEY_OFFSET] = 0x0c; + buffer[SPC_ASC_KEY_OFFSET] = 0x0c; /* NOT ENOUGH UNSOLICITED DATA */ - buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x0d; + buffer[SPC_ASCQ_KEY_OFFSET] = 0x0d; break; case TCM_INVALID_CDB_FIELD: /* CURRENT ERROR */ - buffer[offset] = 0x70; - buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; + buffer[0] = 0x70; + buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ILLEGAL REQUEST */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; + buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* INVALID FIELD IN CDB */ - buffer[offset+SPC_ASC_KEY_OFFSET] = 0x24; + buffer[SPC_ASC_KEY_OFFSET] = 0x24; break; case TCM_INVALID_PARAMETER_LIST: /* CURRENT ERROR */ - buffer[offset] = 0x70; - buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; + buffer[0] = 0x70; + buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ILLEGAL REQUEST */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; + buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* INVALID FIELD IN PARAMETER LIST */ - buffer[offset+SPC_ASC_KEY_OFFSET] = 0x26; + buffer[SPC_ASC_KEY_OFFSET] = 0x26; break; case TCM_UNEXPECTED_UNSOLICITED_DATA: /* CURRENT ERROR */ - buffer[offset] = 0x70; - buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; + buffer[0] = 0x70; + buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; + buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* WRITE ERROR */ - buffer[offset+SPC_ASC_KEY_OFFSET] = 0x0c; + buffer[SPC_ASC_KEY_OFFSET] = 0x0c; /* UNEXPECTED_UNSOLICITED_DATA */ - buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x0c; + buffer[SPC_ASCQ_KEY_OFFSET] = 0x0c; break; case TCM_SERVICE_CRC_ERROR: /* CURRENT ERROR */ - buffer[offset] = 0x70; - buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; + buffer[0] = 0x70; + buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; + buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* PROTOCOL SERVICE CRC ERROR */ - buffer[offset+SPC_ASC_KEY_OFFSET] = 0x47; + buffer[SPC_ASC_KEY_OFFSET] = 0x47; /* N/A */ - buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x05; + buffer[SPC_ASCQ_KEY_OFFSET] = 0x05; break; case TCM_SNACK_REJECTED: /* CURRENT ERROR */ - buffer[offset] = 0x70; - buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; + buffer[0] = 0x70; + buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; + buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* READ ERROR */ - buffer[offset+SPC_ASC_KEY_OFFSET] = 0x11; + buffer[SPC_ASC_KEY_OFFSET] = 0x11; /* FAILED RETRANSMISSION REQUEST */ - buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x13; + buffer[SPC_ASCQ_KEY_OFFSET] = 0x13; break; case TCM_WRITE_PROTECTED: /* CURRENT ERROR */ - buffer[offset] = 0x70; - buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; + buffer[0] = 0x70; + buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; /* DATA PROTECT */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = DATA_PROTECT; + buffer[SPC_SENSE_KEY_OFFSET] = DATA_PROTECT; /* WRITE PROTECTED */ - buffer[offset+SPC_ASC_KEY_OFFSET] = 0x27; + buffer[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; + buffer[0] = 0x70; + buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ILLEGAL REQUEST */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; + buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* LOGICAL BLOCK ADDRESS OUT OF RANGE */ - buffer[offset+SPC_ASC_KEY_OFFSET] = 0x21; + buffer[SPC_ASC_KEY_OFFSET] = 0x21; break; case TCM_CHECK_CONDITION_UNIT_ATTENTION: /* CURRENT ERROR */ - buffer[offset] = 0x70; - buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; + buffer[0] = 0x70; + buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; /* UNIT ATTENTION */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION; + buffer[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION; core_scsi3_ua_for_check_condition(cmd, &asc, &ascq); - buffer[offset+SPC_ASC_KEY_OFFSET] = asc; - buffer[offset+SPC_ASCQ_KEY_OFFSET] = ascq; + buffer[SPC_ASC_KEY_OFFSET] = asc; + buffer[SPC_ASCQ_KEY_OFFSET] = ascq; break; case TCM_CHECK_CONDITION_NOT_READY: /* CURRENT ERROR */ - buffer[offset] = 0x70; - buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; + buffer[0] = 0x70; + buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; /* Not Ready */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = NOT_READY; + buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY; transport_get_sense_codes(cmd, &asc, &ascq); - buffer[offset+SPC_ASC_KEY_OFFSET] = asc; - buffer[offset+SPC_ASCQ_KEY_OFFSET] = ascq; + buffer[SPC_ASC_KEY_OFFSET] = asc; + buffer[SPC_ASCQ_KEY_OFFSET] = ascq; break; case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE: default: /* CURRENT ERROR */ - buffer[offset] = 0x70; - buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; + buffer[0] = 0x70; + buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ILLEGAL REQUEST */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; + buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* LOGICAL UNIT COMMUNICATION FAILURE */ - buffer[offset+SPC_ASC_KEY_OFFSET] = 0x80; + buffer[SPC_ASC_KEY_OFFSET] = 0x80; break; } /* @@ -2996,7 +3033,7 @@ int transport_send_check_condition_and_sense( * Automatically padded, this value is encoded in the fabric's * data_length response PDU containing the SCSI defined sense data. */ - cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset; + cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER; after_reason: return cmd->se_tfo->queue_status(cmd); |