diff options
author | Jiri Kosina <jkosina@suse.cz> | 2013-01-29 10:48:30 +0100 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2013-01-29 10:48:30 +0100 |
commit | 617677295b53a40d0e54aac4cbbc216ffbc755dd (patch) | |
tree | 51b9e87213243ed5efff252c8e8d8fec4eebc588 /drivers/target | |
parent | time: x86: report_lost_ticks doesn't exist any more (diff) | |
parent | Merge tag 'regulator-3.8-rc5' of git://git.kernel.org/pub/scm/linux/kernel/gi... (diff) | |
download | linux-617677295b53a40d0e54aac4cbbc216ffbc755dd.tar.xz linux-617677295b53a40d0e54aac4cbbc216ffbc755dd.zip |
Merge branch 'master' into for-next
Conflicts:
drivers/devfreq/exynos4_bus.c
Sync with Linus' tree to be able to apply patches that are
against newer code (mvneta).
Diffstat (limited to 'drivers/target')
42 files changed, 2733 insertions, 3712 deletions
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index d6ce2182e672..339f97f7085b 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -735,7 +735,7 @@ static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn) list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) { spin_lock(&cmd->istate_lock); if ((cmd->i_state == ISTATE_SENT_STATUS) && - (cmd->stat_sn < exp_statsn)) { + iscsi_sna_lt(cmd->stat_sn, exp_statsn)) { cmd->i_state = ISTATE_REMOVE; spin_unlock(&cmd->istate_lock); iscsit_add_cmd_to_immediate_queue(cmd, conn, @@ -767,9 +767,8 @@ static int iscsit_handle_scsi_cmd( struct iscsi_conn *conn, unsigned char *buf) { - int data_direction, cmdsn_ret = 0, immed_ret, ret, transport_ret; - int dump_immediate_data = 0, send_check_condition = 0, payload_length; - struct iscsi_cmd *cmd = NULL; + int data_direction, payload_length, cmdsn_ret = 0, immed_ret; + struct iscsi_cmd *cmd = NULL; struct iscsi_scsi_req *hdr; int iscsi_task_attr; int sam_task_attr; @@ -956,38 +955,26 @@ done: " ExpXferLen: %u, Length: %u, CID: %hu\n", hdr->itt, hdr->cmdsn, hdr->data_length, payload_length, conn->cid); - /* - * The CDB is going to an se_device_t. - */ - ret = transport_lookup_cmd_lun(&cmd->se_cmd, - scsilun_to_int(&hdr->lun)); - if (ret < 0) { - if (cmd->se_cmd.scsi_sense_reason == TCM_NON_EXISTENT_LUN) { - pr_debug("Responding to non-acl'ed," - " non-existent or non-exported iSCSI LUN:" - " 0x%016Lx\n", get_unaligned_le64(&hdr->lun)); + cmd->sense_reason = transport_lookup_cmd_lun(&cmd->se_cmd, + scsilun_to_int(&hdr->lun)); + if (cmd->sense_reason) + goto attach_cmd; + + cmd->sense_reason = target_setup_cmd_from_cdb(&cmd->se_cmd, hdr->cdb); + if (cmd->sense_reason) { + if (cmd->sense_reason == TCM_OUT_OF_RESOURCES) { + return iscsit_add_reject_from_cmd( + ISCSI_REASON_BOOKMARK_NO_RESOURCES, + 1, 1, buf, cmd); } - send_check_condition = 1; + goto attach_cmd; } - transport_ret = target_setup_cmd_from_cdb(&cmd->se_cmd, hdr->cdb); - if (transport_ret == -ENOMEM) { + if (iscsit_build_pdu_and_seq_lists(cmd, payload_length) < 0) { return iscsit_add_reject_from_cmd( - ISCSI_REASON_BOOKMARK_NO_RESOURCES, - 1, 1, buf, cmd); - } else if (transport_ret < 0) { - /* - * Unsupported SAM Opcode. CHECK_CONDITION will be sent - * in iscsit_execute_cmd() during the CmdSN OOO Execution - * Mechinism. - */ - send_check_condition = 1; - } else { - if (iscsit_build_pdu_and_seq_lists(cmd, payload_length) < 0) - return iscsit_add_reject_from_cmd( - ISCSI_REASON_BOOKMARK_NO_RESOURCES, - 1, 1, buf, cmd); + ISCSI_REASON_BOOKMARK_NO_RESOURCES, + 1, 1, buf, cmd); } attach_cmd: @@ -1000,11 +987,12 @@ attach_cmd: */ core_alua_check_nonop_delay(&cmd->se_cmd); - ret = iscsit_allocate_iovecs(cmd); - if (ret < 0) + if (iscsit_allocate_iovecs(cmd) < 0) { return iscsit_add_reject_from_cmd( ISCSI_REASON_BOOKMARK_NO_RESOURCES, 1, 0, buf, cmd); + } + /* * Check the CmdSN against ExpCmdSN/MaxCmdSN here if * the Immediate Bit is not set, and no Immediate @@ -1031,10 +1019,7 @@ attach_cmd: * If no Immediate Data is attached, it's OK to return now. */ if (!cmd->immediate_data) { - if (send_check_condition) - return 0; - - if (cmd->unsolicited_data) { + if (!cmd->sense_reason && cmd->unsolicited_data) { iscsit_set_dataout_sequence_values(cmd); spin_lock_bh(&cmd->dataout_timeout_lock); @@ -1050,19 +1035,17 @@ attach_cmd: * thread. They are processed in CmdSN order by * iscsit_check_received_cmdsn() below. */ - if (send_check_condition) { + if (cmd->sense_reason) { immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION; - dump_immediate_data = 1; goto after_immediate_data; } /* * Call directly into transport_generic_new_cmd() to perform * the backend memory allocation. */ - ret = transport_generic_new_cmd(&cmd->se_cmd); - if (ret < 0) { + cmd->sense_reason = transport_generic_new_cmd(&cmd->se_cmd); + if (cmd->sense_reason) { immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION; - dump_immediate_data = 1; goto after_immediate_data; } @@ -1079,7 +1062,7 @@ after_immediate_data: * Special case for Unsupported SAM WRITE Opcodes * and ImmediateData=Yes. */ - if (dump_immediate_data) { + if (cmd->sense_reason) { if (iscsit_dump_data_payload(conn, payload_length, 1) < 0) return -1; } else if (cmd->unsolicited_data) { @@ -1272,8 +1255,7 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf) spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); spin_lock_irqsave(&se_cmd->t_state_lock, flags); - if (!(se_cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) || - (se_cmd->se_cmd_flags & SCF_SCSI_CDB_EXCEPTION)) + if (!(se_cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE)) dump_unsolicited_data = 1; spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); @@ -1742,7 +1724,6 @@ static int iscsit_handle_task_mgt_cmd( ret = transport_lookup_tmr_lun(&cmd->se_cmd, scsilun_to_int(&hdr->lun)); if (ret < 0) { - cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; se_tmr->response = ISCSI_TMF_RSP_NO_LUN; goto attach; } @@ -1751,10 +1732,8 @@ static int iscsit_handle_task_mgt_cmd( switch (function) { case ISCSI_TM_FUNC_ABORT_TASK: se_tmr->response = iscsit_tmr_abort_task(cmd, buf); - if (se_tmr->response != ISCSI_TMF_RSP_COMPLETE) { - cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + if (se_tmr->response) goto attach; - } break; case ISCSI_TM_FUNC_ABORT_TASK_SET: case ISCSI_TM_FUNC_CLEAR_ACA: @@ -1763,14 +1742,12 @@ static int iscsit_handle_task_mgt_cmd( break; case ISCSI_TM_FUNC_TARGET_WARM_RESET: if (iscsit_tmr_task_warm_reset(conn, tmr_req, buf) < 0) { - cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; se_tmr->response = ISCSI_TMF_RSP_AUTH_FAILED; goto attach; } break; case ISCSI_TM_FUNC_TARGET_COLD_RESET: if (iscsit_tmr_task_cold_reset(conn, tmr_req, buf) < 0) { - cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; se_tmr->response = ISCSI_TMF_RSP_AUTH_FAILED; goto attach; } @@ -1781,7 +1758,7 @@ static int iscsit_handle_task_mgt_cmd( * Perform sanity checks on the ExpDataSN only if the * TASK_REASSIGN was successful. */ - if (se_tmr->response != ISCSI_TMF_RSP_COMPLETE) + if (se_tmr->response) break; if (iscsit_check_task_reassign_expdatasn(tmr_req, conn) < 0) @@ -1792,7 +1769,6 @@ static int iscsit_handle_task_mgt_cmd( default: pr_err("Unknown TMR function: 0x%02x, protocol" " error.\n", function); - cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; se_tmr->response = ISCSI_TMF_RSP_NOT_SUPPORTED; goto attach; } @@ -2360,7 +2336,7 @@ static void iscsit_build_conn_drop_async_message(struct iscsi_conn *conn) if (!conn_p) return; - cmd = iscsit_allocate_cmd(conn_p, GFP_KERNEL); + cmd = iscsit_allocate_cmd(conn_p, GFP_ATOMIC); if (!cmd) { iscsit_dec_conn_usage_count(conn_p); return; @@ -3719,7 +3695,9 @@ restart: */ iscsit_thread_check_cpumask(conn, current, 1); - schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT); + wait_event_interruptible(conn->queues_wq, + !iscsit_conn_all_queues_empty(conn) || + ts->status == ISCSI_THREAD_SET_RESET); if ((ts->status == ISCSI_THREAD_SET_RESET) || signal_pending(current)) diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 0f03b7919d7c..78d75c8567d0 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -754,9 +754,33 @@ static ssize_t lio_target_nacl_store_cmdsn_depth( TF_NACL_BASE_ATTR(lio_target, cmdsn_depth, S_IRUGO | S_IWUSR); +static ssize_t lio_target_nacl_show_tag( + struct se_node_acl *se_nacl, + char *page) +{ + return snprintf(page, PAGE_SIZE, "%s", se_nacl->acl_tag); +} + +static ssize_t lio_target_nacl_store_tag( + struct se_node_acl *se_nacl, + const char *page, + size_t count) +{ + int ret; + + ret = core_tpg_set_initiator_node_tag(se_nacl->se_tpg, se_nacl, page); + + if (ret < 0) + return ret; + return count; +} + +TF_NACL_BASE_ATTR(lio_target, tag, S_IRUGO | S_IWUSR); + static struct configfs_attribute *lio_target_initiator_attrs[] = { &lio_target_nacl_info.attr, &lio_target_nacl_cmdsn_depth.attr, + &lio_target_nacl_tag.attr, NULL, }; @@ -803,7 +827,7 @@ static struct se_node_acl *lio_target_make_nodeacl( acl = container_of(se_nacl, struct iscsi_node_acl, se_node_acl); stats_cg = &se_nacl->acl_fabric_stat_group; - stats_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, + stats_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, GFP_KERNEL); if (!stats_cg->default_groups) { pr_err("Unable to allocate memory for" @@ -1268,7 +1292,7 @@ static struct se_wwn *lio_target_call_coreaddtiqn( */ stats_cg = &tiqn->tiqn_wwn.fabric_stat_group; - stats_cg->default_groups = kzalloc(sizeof(struct config_group) * 6, + stats_cg->default_groups = kmalloc(sizeof(struct config_group *) * 6, GFP_KERNEL); if (!stats_cg->default_groups) { pr_err("Unable to allocate memory for" diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index 2ba9f9b9435c..7a333d28d9a2 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h @@ -474,7 +474,7 @@ struct iscsi_cmd { struct scatterlist *first_data_sg; u32 first_data_sg_off; u32 kmapped_nents; - + sense_reason_t sense_reason; } ____cacheline_aligned; struct iscsi_tmr_req { @@ -486,6 +486,7 @@ struct iscsi_tmr_req { }; struct iscsi_conn { + wait_queue_head_t queues_wq; /* Authentication Successful for this connection */ u8 auth_complete; /* State connection is currently in */ diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index 21f29d91a8cb..0b52a2371305 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c @@ -929,11 +929,10 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo) case ISCSI_OP_SCSI_CMD: /* * Go ahead and send the CHECK_CONDITION status for - * any SCSI CDB exceptions that may have occurred, also - * handle the SCF_SCSI_RESERVATION_CONFLICT case here as well. + * any SCSI CDB exceptions that may have occurred. */ - if (se_cmd->se_cmd_flags & SCF_SCSI_CDB_EXCEPTION) { - if (se_cmd->scsi_sense_reason == TCM_RESERVATION_CONFLICT) { + if (cmd->sense_reason) { + if (cmd->sense_reason == TCM_RESERVATION_CONFLICT) { cmd->i_state = ISTATE_SEND_STATUS; spin_unlock_bh(&cmd->istate_lock); iscsit_add_cmd_to_response_queue(cmd, cmd->conn, @@ -956,7 +955,7 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo) * exception */ return transport_send_check_condition_and_sense(se_cmd, - se_cmd->scsi_sense_reason, 0); + cmd->sense_reason, 0); } /* * Special case for delayed CmdSN with Immediate @@ -1013,7 +1012,7 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo) iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state); break; case ISCSI_OP_SCSI_TMFUNC: - if (se_cmd->se_cmd_flags & SCF_SCSI_CDB_EXCEPTION) { + if (cmd->se_cmd.se_tmr_req->response) { spin_unlock_bh(&cmd->istate_lock); iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state); diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c index 17d8c20094fd..ba6091bf93fc 100644 --- a/drivers/target/iscsi/iscsi_target_erl2.c +++ b/drivers/target/iscsi/iscsi_target_erl2.c @@ -372,7 +372,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn) * made generic here. */ if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd && - (cmd->cmd_sn >= conn->sess->exp_cmd_sn)) { + iscsi_sna_gte(cmd->cmd_sn, conn->sess->exp_cmd_sn)) { list_del(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); iscsit_free_cmd(cmd); diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index cdc8a10939c3..fdb632f0ab85 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -41,6 +41,7 @@ static int iscsi_login_init_conn(struct iscsi_conn *conn) { + init_waitqueue_head(&conn->queues_wq); INIT_LIST_HEAD(&conn->conn_list); INIT_LIST_HEAD(&conn->conn_cmd_list); INIT_LIST_HEAD(&conn->immed_queue_list); @@ -126,13 +127,13 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn) initiatorname_param = iscsi_find_param_from_key( INITIATORNAME, conn->param_list); - if (!initiatorname_param) - return -1; - sessiontype_param = iscsi_find_param_from_key( SESSIONTYPE, conn->param_list); - if (!sessiontype_param) + if (!initiatorname_param || !sessiontype_param) { + iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, + ISCSI_LOGIN_STATUS_MISSING_FIELDS); return -1; + } sessiontype = (strncmp(sessiontype_param->value, NORMAL, 6)) ? 1 : 0; @@ -253,9 +254,9 @@ static int iscsi_login_zero_tsih_s1( kfree(sess); return -ENOMEM; } - spin_lock(&sess_idr_lock); + spin_lock_bh(&sess_idr_lock); ret = idr_get_new(&sess_idr, NULL, &sess->session_index); - spin_unlock(&sess_idr_lock); + spin_unlock_bh(&sess_idr_lock); if (ret < 0) { pr_err("idr_get_new() for sess_idr failed\n"); @@ -1117,10 +1118,8 @@ new_sess_out: idr_remove(&sess_idr, conn->sess->session_index); spin_unlock_bh(&sess_idr_lock); } - if (conn->sess->sess_ops) - kfree(conn->sess->sess_ops); - if (conn->sess) - kfree(conn->sess); + kfree(conn->sess->sess_ops); + kfree(conn->sess); old_sess_out: iscsi_stop_login_thread_timer(np); /* diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index e9053a04f24c..9d902aefe01a 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -620,8 +620,11 @@ static int iscsi_target_handle_csg_one(struct iscsi_conn *conn, struct iscsi_log login->req_buf, payload_length, conn); - if (ret < 0) + if (ret < 0) { + iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, + ISCSI_LOGIN_STATUS_INIT_ERR); return -1; + } if (login->first_request) if (iscsi_target_check_first_request(conn, login) < 0) @@ -636,8 +639,11 @@ static int iscsi_target_handle_csg_one(struct iscsi_conn *conn, struct iscsi_log login->rsp_buf, &login->rsp_length, conn->param_list); - if (ret < 0) + if (ret < 0) { + iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, + ISCSI_LOGIN_STATUS_INIT_ERR); return -1; + } if (!login->auth_complete && ISCSI_TPG_ATTRIB(ISCSI_TPG_C(conn))->authentication) { diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index 1bf7432bfcbc..d89164287d00 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c @@ -154,22 +154,18 @@ static struct iscsi_param *iscsi_set_default_param(struct iscsi_param_list *para } INIT_LIST_HEAD(¶m->p_list); - param->name = kzalloc(strlen(name) + 1, GFP_KERNEL); + param->name = kstrdup(name, GFP_KERNEL); if (!param->name) { pr_err("Unable to allocate memory for parameter name.\n"); goto out; } - param->value = kzalloc(strlen(value) + 1, GFP_KERNEL); + param->value = kstrdup(value, GFP_KERNEL); if (!param->value) { pr_err("Unable to allocate memory for parameter value.\n"); goto out; } - memcpy(param->name, name, strlen(name)); - param->name[strlen(name)] = '\0'; - memcpy(param->value, value, strlen(value)); - param->value[strlen(value)] = '\0'; param->phase = phase; param->scope = scope; param->sender = sender; @@ -635,11 +631,8 @@ void iscsi_release_param_list(struct iscsi_param_list *param_list) list_del(¶m->p_list); kfree(param->name); - param->name = NULL; kfree(param->value); - param->value = NULL; kfree(param); - param = NULL; } iscsi_release_extra_responses(param_list); @@ -687,15 +680,12 @@ int iscsi_update_param_value(struct iscsi_param *param, char *value) { kfree(param->value); - param->value = kzalloc(strlen(value) + 1, GFP_KERNEL); + param->value = kstrdup(value, GFP_KERNEL); if (!param->value) { pr_err("Unable to allocate memory for value.\n"); return -ENOMEM; } - memcpy(param->value, value, strlen(value)); - param->value[strlen(value)] = '\0'; - pr_debug("iSCSI Parameter updated to %s=%s\n", param->name, param->value); return 0; diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c index 4a99820d063b..9d4417aae921 100644 --- a/drivers/target/iscsi/iscsi_target_tmr.c +++ b/drivers/target/iscsi/iscsi_target_tmr.c @@ -50,8 +50,8 @@ u8 iscsit_tmr_abort_task( if (!ref_cmd) { pr_err("Unable to locate RefTaskTag: 0x%08x on CID:" " %hu.\n", hdr->rtt, conn->cid); - return (be32_to_cpu(hdr->refcmdsn) >= conn->sess->exp_cmd_sn && - be32_to_cpu(hdr->refcmdsn) <= conn->sess->max_cmd_sn) ? + return (iscsi_sna_gte(be32_to_cpu(hdr->refcmdsn), conn->sess->exp_cmd_sn) && + iscsi_sna_lte(be32_to_cpu(hdr->refcmdsn), conn->sess->max_cmd_sn)) ? ISCSI_TMF_RSP_COMPLETE : ISCSI_TMF_RSP_NO_TASK; } if (ref_cmd->cmd_sn != be32_to_cpu(hdr->refcmdsn)) { diff --git a/drivers/target/iscsi/iscsi_target_tq.c b/drivers/target/iscsi/iscsi_target_tq.c index 9d881a000e42..81289520f96b 100644 --- a/drivers/target/iscsi/iscsi_target_tq.c +++ b/drivers/target/iscsi/iscsi_target_tq.c @@ -66,8 +66,7 @@ static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void) return NULL; } - list_for_each_entry(ts, &inactive_ts_list, ts_list) - break; + ts = list_first_entry(&inactive_ts_list, struct iscsi_thread_set, ts_list); list_del(&ts->ts_list); iscsit_global->inactive_ts--; diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index c8dab6c7b5dc..7ce350578c82 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -488,7 +488,7 @@ void iscsit_add_cmd_to_immediate_queue( atomic_set(&conn->check_immediate_queue, 1); spin_unlock_bh(&conn->immed_queue_lock); - wake_up_process(conn->thread_set->tx_thread); + wake_up(&conn->queues_wq); } struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *conn) @@ -500,8 +500,8 @@ struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *c spin_unlock_bh(&conn->immed_queue_lock); return NULL; } - list_for_each_entry(qr, &conn->immed_queue_list, qr_list) - break; + qr = list_first_entry(&conn->immed_queue_list, + struct iscsi_queue_req, qr_list); list_del(&qr->qr_list); if (qr->cmd) @@ -562,7 +562,7 @@ void iscsit_add_cmd_to_response_queue( atomic_inc(&cmd->response_queue_count); spin_unlock_bh(&conn->response_queue_lock); - wake_up_process(conn->thread_set->tx_thread); + wake_up(&conn->queues_wq); } struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *conn) @@ -575,8 +575,8 @@ struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *co return NULL; } - list_for_each_entry(qr, &conn->response_queue_list, qr_list) - break; + qr = list_first_entry(&conn->response_queue_list, + struct iscsi_queue_req, qr_list); list_del(&qr->qr_list); if (qr->cmd) @@ -616,6 +616,24 @@ static void iscsit_remove_cmd_from_response_queue( } } +bool iscsit_conn_all_queues_empty(struct iscsi_conn *conn) +{ + bool empty; + + spin_lock_bh(&conn->immed_queue_lock); + empty = list_empty(&conn->immed_queue_list); + spin_unlock_bh(&conn->immed_queue_lock); + + if (!empty) + return empty; + + spin_lock_bh(&conn->response_queue_lock); + empty = list_empty(&conn->response_queue_list); + spin_unlock_bh(&conn->response_queue_lock); + + return empty; +} + void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn) { struct iscsi_queue_req *qr, *qr_tmp; diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h index 44054bd35437..894d0f837924 100644 --- a/drivers/target/iscsi/iscsi_target_util.h +++ b/drivers/target/iscsi/iscsi_target_util.h @@ -25,6 +25,7 @@ extern struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_ extern void iscsit_add_cmd_to_response_queue(struct iscsi_cmd *, struct iscsi_conn *, u8); extern struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *); extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_conn *); +extern bool iscsit_conn_all_queues_empty(struct iscsi_conn *); extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *); extern void iscsit_release_cmd(struct iscsi_cmd *); extern void iscsit_free_cmd(struct iscsi_cmd *); diff --git a/drivers/target/loopback/tcm_loop.h b/drivers/target/loopback/tcm_loop.h index 7b54893db665..dd7a84ee78e1 100644 --- a/drivers/target/loopback/tcm_loop.h +++ b/drivers/target/loopback/tcm_loop.h @@ -53,7 +53,6 @@ struct tcm_loop_hba { struct se_hba_s *se_hba; struct se_lun *tl_hba_lun; struct se_port *tl_hba_lun_sep; - struct se_device_s *se_dev_hba_ptr; struct tcm_loop_nexus *tl_nexus; struct device dev; struct Scsi_Host *sh; diff --git a/drivers/target/sbp/Kconfig b/drivers/target/sbp/Kconfig index 132da544eafc..1614bc710d4e 100644 --- a/drivers/target/sbp/Kconfig +++ b/drivers/target/sbp/Kconfig @@ -1,6 +1,6 @@ config SBP_TARGET tristate "FireWire SBP-2 fabric module" - depends on FIREWIRE && EXPERIMENTAL + depends on FIREWIRE help Say Y or M here to enable SCSI target functionality over FireWire. This enables you to expose SCSI devices to other nodes on the FireWire diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index be793883413d..6917a9e938e7 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -704,16 +704,17 @@ static void session_maintenance_work(struct work_struct *work) static int tgt_agent_rw_agent_state(struct fw_card *card, int tcode, void *data, struct sbp_target_agent *agent) { - __be32 state; + int state; switch (tcode) { case TCODE_READ_QUADLET_REQUEST: pr_debug("tgt_agent AGENT_STATE READ\n"); spin_lock_bh(&agent->lock); - state = cpu_to_be32(agent->state); + state = agent->state; spin_unlock_bh(&agent->lock); - memcpy(data, &state, sizeof(state)); + + *(__be32 *)data = cpu_to_be32(state); return RCODE_COMPLETE; @@ -2207,20 +2208,23 @@ static struct se_portal_group *sbp_make_tpg( tport->mgt_agt = sbp_management_agent_register(tport); if (IS_ERR(tport->mgt_agt)) { ret = PTR_ERR(tport->mgt_agt); - kfree(tpg); - return ERR_PTR(ret); + goto out_free_tpg; } ret = core_tpg_register(&sbp_fabric_configfs->tf_ops, wwn, &tpg->se_tpg, (void *)tpg, TRANSPORT_TPG_TYPE_NORMAL); - if (ret < 0) { - sbp_management_agent_unregister(tport->mgt_agt); - kfree(tpg); - return ERR_PTR(ret); - } + if (ret < 0) + goto out_unreg_mgt_agt; return &tpg->se_tpg; + +out_unreg_mgt_agt: + sbp_management_agent_unregister(tport->mgt_agt); +out_free_tpg: + tport->tpg = NULL; + kfree(tpg); + return ERR_PTR(ret); } static void sbp_drop_tpg(struct se_portal_group *se_tpg) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 9a5f9a7aecd2..7d4ec02e29a9 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -3,8 +3,7 @@ * * This file contains SPC-3 compliant asymmetric logical unit assigntment (ALUA) * - * Copyright (c) 2009-2010 Rising Tide Systems - * Copyright (c) 2009-2010 Linux-iSCSI.org + * (c) Copyright 2009-2012 RisingTide Systems LLC. * * Nicholas A. Bellinger <nab@kernel.org> * @@ -41,7 +40,7 @@ #include "target_core_alua.h" #include "target_core_ua.h" -static int core_alua_check_transition(int state, int *primary); +static sense_reason_t core_alua_check_transition(int state, int *primary); static int core_alua_set_tg_pt_secondary_state( struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, struct se_port *port, int explict, int offline); @@ -59,15 +58,17 @@ struct t10_alua_lu_gp *default_lu_gp; * * See spc4r17 section 6.27 */ -int target_emulate_report_target_port_groups(struct se_cmd *cmd) +sense_reason_t +target_emulate_report_target_port_groups(struct se_cmd *cmd) { - struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; + struct se_device *dev = cmd->se_dev; struct se_port *port; struct t10_alua_tg_pt_gp *tg_pt_gp; struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; unsigned char *buf; u32 rd_len = 0, off; int ext_hdr = (cmd->t_task_cdb[1] & 0x20); + /* * Skip over RESERVED area to first Target port group descriptor * depending on the PARAMETER DATA FORMAT type.. @@ -81,13 +82,14 @@ int target_emulate_report_target_port_groups(struct se_cmd *cmd) pr_warn("REPORT TARGET PORT GROUPS allocation length %u too" " small for %s header\n", cmd->data_length, (ext_hdr) ? "extended" : "normal"); - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -EINVAL; + return TCM_INVALID_CDB_FIELD; } buf = transport_kmap_data_sg(cmd); + if (!buf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); - list_for_each_entry(tg_pt_gp, &su_dev->t10_alua.tg_pt_gps_list, + spin_lock(&dev->t10_alua.tg_pt_gps_lock); + list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list, tg_pt_gp_list) { /* * Check if the Target port group and Target port descriptor list @@ -160,7 +162,7 @@ int target_emulate_report_target_port_groups(struct se_cmd *cmd) } spin_unlock(&tg_pt_gp->tg_pt_gp_lock); } - spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); + spin_unlock(&dev->t10_alua.tg_pt_gps_lock); /* * Set the RETURN DATA LENGTH set in the header of the DataIN Payload */ @@ -200,32 +202,33 @@ int target_emulate_report_target_port_groups(struct se_cmd *cmd) * * See spc4r17 section 6.35 */ -int target_emulate_set_target_port_groups(struct se_cmd *cmd) +sense_reason_t +target_emulate_set_target_port_groups(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - struct se_subsystem_dev *su_dev = dev->se_sub_dev; struct se_port *port, *l_port = cmd->se_lun->lun_sep; struct se_node_acl *nacl = cmd->se_sess->se_node_acl; struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *l_tg_pt_gp; struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *l_tg_pt_gp_mem; unsigned char *buf; unsigned char *ptr; + sense_reason_t rc = TCM_NO_SENSE; u32 len = 4; /* Skip over RESERVED area in header */ - int alua_access_state, primary = 0, rc; + int alua_access_state, primary = 0; u16 tg_pt_id, rtpi; - if (!l_port) { - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -EINVAL; - } + if (!l_port) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + if (cmd->data_length < 4) { pr_warn("SET TARGET PORT GROUPS parameter list length %u too" " small\n", cmd->data_length); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - return -EINVAL; + return TCM_INVALID_PARAMETER_LIST; } buf = transport_kmap_data_sg(cmd); + if (!buf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; /* * Determine if explict ALUA via SET_TARGET_PORT_GROUPS is allowed @@ -234,8 +237,7 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd) l_tg_pt_gp_mem = l_port->sep_alua_tg_pt_gp_mem; if (!l_tg_pt_gp_mem) { pr_err("Unable to access l_port->sep_alua_tg_pt_gp_mem\n"); - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; - rc = -EINVAL; + rc = TCM_UNSUPPORTED_SCSI_OPCODE; goto out; } spin_lock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); @@ -243,24 +245,22 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd) if (!l_tg_pt_gp) { spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); pr_err("Unable to access *l_tg_pt_gp_mem->tg_pt_gp\n"); - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; - rc = -EINVAL; + rc = TCM_UNSUPPORTED_SCSI_OPCODE; goto out; } - rc = (l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICT_ALUA); spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); - if (!rc) { + if (!(l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICT_ALUA)) { pr_debug("Unable to process SET_TARGET_PORT_GROUPS" " while TPGS_EXPLICT_ALUA is disabled\n"); - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; - rc = -EINVAL; + rc = TCM_UNSUPPORTED_SCSI_OPCODE; goto out; } ptr = &buf[4]; /* Skip over RESERVED area in header */ while (len < cmd->data_length) { + bool found = false; alua_access_state = (ptr[0] & 0x0f); /* * Check the received ALUA access state, and determine if @@ -268,7 +268,7 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd) * access state. */ rc = core_alua_check_transition(alua_access_state, &primary); - if (rc != 0) { + if (rc) { /* * If the SET TARGET PORT GROUPS attempts to establish * an invalid combination of target port asymmetric @@ -279,11 +279,9 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd) * REQUEST, and the additional sense code set to INVALID * FIELD IN PARAMETER LIST. */ - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - rc = -EINVAL; goto out; } - rc = -1; + /* * If the ASYMMETRIC ACCESS STATE field (see table 267) * specifies a primary target port asymmetric access state, @@ -303,9 +301,9 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd) * Locate the matching target port group ID from * the global tg_pt_gp list */ - spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); + spin_lock(&dev->t10_alua.tg_pt_gps_lock); list_for_each_entry(tg_pt_gp, - &su_dev->t10_alua.tg_pt_gps_list, + &dev->t10_alua.tg_pt_gps_list, tg_pt_gp_list) { if (!tg_pt_gp->tg_pt_gp_valid_id) continue; @@ -315,27 +313,20 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd) atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt); smp_mb__after_atomic_inc(); - spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); - rc = core_alua_do_port_transition(tg_pt_gp, + spin_unlock(&dev->t10_alua.tg_pt_gps_lock); + + if (!core_alua_do_port_transition(tg_pt_gp, dev, l_port, nacl, - alua_access_state, 1); + alua_access_state, 1)) + found = true; - spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); + spin_lock(&dev->t10_alua.tg_pt_gps_lock); atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt); smp_mb__after_atomic_dec(); break; } - spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); - /* - * If not matching target port group ID can be located - * throw an exception with ASCQ: INVALID_PARAMETER_LIST - */ - if (rc != 0) { - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - rc = -EINVAL; - goto out; - } + spin_unlock(&dev->t10_alua.tg_pt_gps_lock); } else { /* * Extact the RELATIVE TARGET PORT IDENTIFIER to identify @@ -354,25 +345,22 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd) continue; tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; + spin_unlock(&dev->se_port_lock); - rc = core_alua_set_tg_pt_secondary_state( - tg_pt_gp_mem, port, 1, 1); + if (!core_alua_set_tg_pt_secondary_state( + tg_pt_gp_mem, port, 1, 1)) + found = true; spin_lock(&dev->se_port_lock); break; } spin_unlock(&dev->se_port_lock); - /* - * If not matching relative target port identifier can - * be located, throw an exception with ASCQ: - * INVALID_PARAMETER_LIST - */ - if (rc != 0) { - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - rc = -EINVAL; - goto out; - } + } + + if (!found) { + rc = TCM_INVALID_PARAMETER_LIST; + goto out; } ptr += 4; @@ -523,40 +511,27 @@ static inline int core_alua_state_transition( } /* - * Used for alua_type SPC_ALUA_PASSTHROUGH and SPC2_ALUA_DISABLED - * in transport_cmd_sequencer(). This function is assigned to - * struct t10_alua *->state_check() in core_setup_alua() - */ -static int core_alua_state_check_nop( - struct se_cmd *cmd, - unsigned char *cdb, - u8 *alua_ascq) -{ - return 0; -} - -/* - * Used for alua_type SPC3_ALUA_EMULATED in transport_cmd_sequencer(). - * This function is assigned to struct t10_alua *->state_check() in - * core_setup_alua() - * - * Also, this function can return three different return codes to - * signal transport_generic_cmd_sequencer() - * * return 1: Is used to signal LUN not accecsable, and check condition/not ready * return 0: Used to signal success * reutrn -1: Used to signal failure, and invalid cdb field */ -static int core_alua_state_check( - struct se_cmd *cmd, - unsigned char *cdb, - u8 *alua_ascq) +sense_reason_t +target_alua_state_check(struct se_cmd *cmd) { + struct se_device *dev = cmd->se_dev; + unsigned char *cdb = cmd->t_task_cdb; struct se_lun *lun = cmd->se_lun; struct se_port *port = lun->lun_sep; struct t10_alua_tg_pt_gp *tg_pt_gp; struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; int out_alua_state, nonop_delay_msecs; + u8 alua_ascq; + int ret; + + if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE) + return 0; + if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + return 0; if (!port) return 0; @@ -565,11 +540,11 @@ static int core_alua_state_check( * access state: OFFLINE */ if (atomic_read(&port->sep_tg_pt_secondary_offline)) { - *alua_ascq = ASCQ_04H_ALUA_OFFLINE; pr_debug("ALUA: Got secondary offline status for local" " target port\n"); - *alua_ascq = ASCQ_04H_ALUA_OFFLINE; - return 1; + alua_ascq = ASCQ_04H_ALUA_OFFLINE; + ret = 1; + goto out; } /* * Second, obtain the struct t10_alua_tg_pt_gp_member pointer to the @@ -594,14 +569,18 @@ static int core_alua_state_check( switch (out_alua_state) { case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: - return core_alua_state_nonoptimized(cmd, cdb, - nonop_delay_msecs, alua_ascq); + ret = core_alua_state_nonoptimized(cmd, cdb, + nonop_delay_msecs, &alua_ascq); + break; case ALUA_ACCESS_STATE_STANDBY: - return core_alua_state_standby(cmd, cdb, alua_ascq); + ret = core_alua_state_standby(cmd, cdb, &alua_ascq); + break; case ALUA_ACCESS_STATE_UNAVAILABLE: - return core_alua_state_unavailable(cmd, cdb, alua_ascq); + ret = core_alua_state_unavailable(cmd, cdb, &alua_ascq); + break; case ALUA_ACCESS_STATE_TRANSITION: - return core_alua_state_transition(cmd, cdb, alua_ascq); + ret = core_alua_state_transition(cmd, cdb, &alua_ascq); + break; /* * OFFLINE is a secondary ALUA target port group access state, that is * handled above with struct se_port->sep_tg_pt_secondary_offline=1 @@ -610,7 +589,24 @@ static int core_alua_state_check( default: pr_err("Unknown ALUA access state: 0x%02x\n", out_alua_state); - return -EINVAL; + return TCM_INVALID_CDB_FIELD; + } + +out: + 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.. + */ + 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); + + cmd->scsi_asc = 0x04; + cmd->scsi_ascq = alua_ascq; + return TCM_CHECK_CONDITION_NOT_READY; } return 0; @@ -619,7 +615,8 @@ static int core_alua_state_check( /* * Check implict and explict ALUA state change request. */ -static int core_alua_check_transition(int state, int *primary) +static sense_reason_t +core_alua_check_transition(int state, int *primary) { switch (state) { case ALUA_ACCESS_STATE_ACTIVE_OPTMIZED: @@ -641,7 +638,7 @@ static int core_alua_check_transition(int state, int *primary) break; default: pr_err("Unknown ALUA access state: 0x%02x\n", state); - return -EINVAL; + return TCM_INVALID_PARAMETER_LIST; } return 0; @@ -758,8 +755,7 @@ static int core_alua_update_tpg_primary_metadata( int primary_state, unsigned char *md_buf) { - struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev; - struct t10_wwn *wwn = &su_dev->t10_wwn; + struct t10_wwn *wwn = &tg_pt_gp->tg_pt_gp_dev->t10_wwn; char path[ALUA_METADATA_PATH_LEN]; int len; @@ -899,7 +895,6 @@ int core_alua_do_port_transition( { struct se_device *dev; struct se_port *port; - struct se_subsystem_dev *su_dev; struct se_node_acl *nacl; struct t10_alua_lu_gp *lu_gp; struct t10_alua_lu_gp_member *lu_gp_mem, *local_lu_gp_mem; @@ -949,14 +944,13 @@ int core_alua_do_port_transition( lu_gp_mem_list) { dev = lu_gp_mem->lu_gp_mem_dev; - su_dev = dev->se_sub_dev; atomic_inc(&lu_gp_mem->lu_gp_mem_ref_cnt); smp_mb__after_atomic_inc(); spin_unlock(&lu_gp->lu_gp_lock); - spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); + spin_lock(&dev->t10_alua.tg_pt_gps_lock); list_for_each_entry(tg_pt_gp, - &su_dev->t10_alua.tg_pt_gps_list, + &dev->t10_alua.tg_pt_gps_list, tg_pt_gp_list) { if (!tg_pt_gp->tg_pt_gp_valid_id) @@ -981,7 +975,7 @@ int core_alua_do_port_transition( } atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt); smp_mb__after_atomic_inc(); - spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); + spin_unlock(&dev->t10_alua.tg_pt_gps_lock); /* * core_alua_do_transition_tg_pt() will always return * success. @@ -989,11 +983,11 @@ int core_alua_do_port_transition( core_alua_do_transition_tg_pt(tg_pt_gp, port, nacl, md_buf, new_state, explict); - spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); + spin_lock(&dev->t10_alua.tg_pt_gps_lock); atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt); smp_mb__after_atomic_dec(); } - spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); + spin_unlock(&dev->t10_alua.tg_pt_gps_lock); spin_lock(&lu_gp->lu_gp_lock); atomic_dec(&lu_gp_mem->lu_gp_mem_ref_cnt); @@ -1268,14 +1262,9 @@ void core_alua_free_lu_gp(struct t10_alua_lu_gp *lu_gp) void core_alua_free_lu_gp_mem(struct se_device *dev) { - struct se_subsystem_dev *su_dev = dev->se_sub_dev; - struct t10_alua *alua = &su_dev->t10_alua; struct t10_alua_lu_gp *lu_gp; struct t10_alua_lu_gp_member *lu_gp_mem; - if (alua->alua_type != SPC3_ALUA_EMULATED) - return; - lu_gp_mem = dev->dev_alua_lu_gp_mem; if (!lu_gp_mem) return; @@ -1358,10 +1347,8 @@ void __core_alua_drop_lu_gp_mem( spin_unlock(&lu_gp->lu_gp_lock); } -struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp( - struct se_subsystem_dev *su_dev, - const char *name, - int def_group) +struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(struct se_device *dev, + const char *name, int def_group) { struct t10_alua_tg_pt_gp *tg_pt_gp; @@ -1375,7 +1362,7 @@ struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp( mutex_init(&tg_pt_gp->tg_pt_gp_md_mutex); spin_lock_init(&tg_pt_gp->tg_pt_gp_lock); atomic_set(&tg_pt_gp->tg_pt_gp_ref_cnt, 0); - tg_pt_gp->tg_pt_gp_su_dev = su_dev; + tg_pt_gp->tg_pt_gp_dev = dev; tg_pt_gp->tg_pt_gp_md_buf_len = ALUA_MD_BUF_LEN; atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state, ALUA_ACCESS_STATE_ACTIVE_OPTMIZED); @@ -1392,14 +1379,14 @@ struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp( tg_pt_gp->tg_pt_gp_implict_trans_secs = ALUA_DEFAULT_IMPLICT_TRANS_SECS; if (def_group) { - spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); + spin_lock(&dev->t10_alua.tg_pt_gps_lock); tg_pt_gp->tg_pt_gp_id = - su_dev->t10_alua.alua_tg_pt_gps_counter++; + dev->t10_alua.alua_tg_pt_gps_counter++; tg_pt_gp->tg_pt_gp_valid_id = 1; - su_dev->t10_alua.alua_tg_pt_gps_count++; + dev->t10_alua.alua_tg_pt_gps_count++; list_add_tail(&tg_pt_gp->tg_pt_gp_list, - &su_dev->t10_alua.tg_pt_gps_list); - spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); + &dev->t10_alua.tg_pt_gps_list); + spin_unlock(&dev->t10_alua.tg_pt_gps_lock); } return tg_pt_gp; @@ -1409,9 +1396,10 @@ int core_alua_set_tg_pt_gp_id( struct t10_alua_tg_pt_gp *tg_pt_gp, u16 tg_pt_gp_id) { - struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev; + struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; struct t10_alua_tg_pt_gp *tg_pt_gp_tmp; u16 tg_pt_gp_id_tmp; + /* * The tg_pt_gp->tg_pt_gp_id may only be set once.. */ @@ -1421,19 +1409,19 @@ int core_alua_set_tg_pt_gp_id( return -EINVAL; } - spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); - if (su_dev->t10_alua.alua_tg_pt_gps_count == 0x0000ffff) { + spin_lock(&dev->t10_alua.tg_pt_gps_lock); + if (dev->t10_alua.alua_tg_pt_gps_count == 0x0000ffff) { pr_err("Maximum ALUA alua_tg_pt_gps_count:" " 0x0000ffff reached\n"); - spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); + spin_unlock(&dev->t10_alua.tg_pt_gps_lock); kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp); return -ENOSPC; } again: tg_pt_gp_id_tmp = (tg_pt_gp_id != 0) ? tg_pt_gp_id : - su_dev->t10_alua.alua_tg_pt_gps_counter++; + dev->t10_alua.alua_tg_pt_gps_counter++; - list_for_each_entry(tg_pt_gp_tmp, &su_dev->t10_alua.tg_pt_gps_list, + list_for_each_entry(tg_pt_gp_tmp, &dev->t10_alua.tg_pt_gps_list, tg_pt_gp_list) { if (tg_pt_gp_tmp->tg_pt_gp_id == tg_pt_gp_id_tmp) { if (!tg_pt_gp_id) @@ -1441,7 +1429,7 @@ again: pr_err("ALUA Target Port Group ID: %hu already" " exists, ignoring request\n", tg_pt_gp_id); - spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); + spin_unlock(&dev->t10_alua.tg_pt_gps_lock); return -EINVAL; } } @@ -1449,9 +1437,9 @@ again: tg_pt_gp->tg_pt_gp_id = tg_pt_gp_id_tmp; tg_pt_gp->tg_pt_gp_valid_id = 1; list_add_tail(&tg_pt_gp->tg_pt_gp_list, - &su_dev->t10_alua.tg_pt_gps_list); - su_dev->t10_alua.alua_tg_pt_gps_count++; - spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); + &dev->t10_alua.tg_pt_gps_list); + dev->t10_alua.alua_tg_pt_gps_count++; + spin_unlock(&dev->t10_alua.tg_pt_gps_lock); return 0; } @@ -1480,8 +1468,9 @@ struct t10_alua_tg_pt_gp_member *core_alua_allocate_tg_pt_gp_mem( void core_alua_free_tg_pt_gp( struct t10_alua_tg_pt_gp *tg_pt_gp) { - struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev; + struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *tg_pt_gp_mem_tmp; + /* * Once we have reached this point, config_item_put() has already * been called from target_core_alua_drop_tg_pt_gp(). @@ -1490,10 +1479,11 @@ void core_alua_free_tg_pt_gp( * no assications *OR* explict ALUA via SET_TARGET_PORT_GROUPS * can be made while we are releasing struct t10_alua_tg_pt_gp. */ - spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); + spin_lock(&dev->t10_alua.tg_pt_gps_lock); list_del(&tg_pt_gp->tg_pt_gp_list); - su_dev->t10_alua.alua_tg_pt_gps_counter--; - spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); + dev->t10_alua.alua_tg_pt_gps_counter--; + spin_unlock(&dev->t10_alua.tg_pt_gps_lock); + /* * Allow a struct t10_alua_tg_pt_gp_member * referenced by * core_alua_get_tg_pt_gp_by_name() in @@ -1502,6 +1492,7 @@ void core_alua_free_tg_pt_gp( */ while (atomic_read(&tg_pt_gp->tg_pt_gp_ref_cnt)) cpu_relax(); + /* * Release reference to struct t10_alua_tg_pt_gp from all associated * struct se_port. @@ -1525,9 +1516,9 @@ void core_alua_free_tg_pt_gp( * default_tg_pt_gp. */ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - if (tg_pt_gp != su_dev->t10_alua.default_tg_pt_gp) { + if (tg_pt_gp != dev->t10_alua.default_tg_pt_gp) { __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, - su_dev->t10_alua.default_tg_pt_gp); + dev->t10_alua.default_tg_pt_gp); } else tg_pt_gp_mem->tg_pt_gp = NULL; spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); @@ -1541,14 +1532,9 @@ void core_alua_free_tg_pt_gp( void core_alua_free_tg_pt_gp_mem(struct se_port *port) { - struct se_subsystem_dev *su_dev = port->sep_lun->lun_se_dev->se_sub_dev; - struct t10_alua *alua = &su_dev->t10_alua; struct t10_alua_tg_pt_gp *tg_pt_gp; struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; - if (alua->alua_type != SPC3_ALUA_EMULATED) - return; - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; if (!tg_pt_gp_mem) return; @@ -1574,25 +1560,24 @@ void core_alua_free_tg_pt_gp_mem(struct se_port *port) } static struct t10_alua_tg_pt_gp *core_alua_get_tg_pt_gp_by_name( - struct se_subsystem_dev *su_dev, - const char *name) + struct se_device *dev, const char *name) { struct t10_alua_tg_pt_gp *tg_pt_gp; struct config_item *ci; - spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); - list_for_each_entry(tg_pt_gp, &su_dev->t10_alua.tg_pt_gps_list, + spin_lock(&dev->t10_alua.tg_pt_gps_lock); + list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list, tg_pt_gp_list) { if (!tg_pt_gp->tg_pt_gp_valid_id) continue; ci = &tg_pt_gp->tg_pt_gp_group.cg_item; if (!strcmp(config_item_name(ci), name)) { atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt); - spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); + spin_unlock(&dev->t10_alua.tg_pt_gps_lock); return tg_pt_gp; } } - spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); + spin_unlock(&dev->t10_alua.tg_pt_gps_lock); return NULL; } @@ -1600,11 +1585,11 @@ static struct t10_alua_tg_pt_gp *core_alua_get_tg_pt_gp_by_name( static void core_alua_put_tg_pt_gp_from_name( struct t10_alua_tg_pt_gp *tg_pt_gp) { - struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev; + struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; - spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); + spin_lock(&dev->t10_alua.tg_pt_gps_lock); atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt); - spin_unlock(&su_dev->t10_alua.tg_pt_gps_lock); + spin_unlock(&dev->t10_alua.tg_pt_gps_lock); } /* @@ -1640,16 +1625,11 @@ static void __core_alua_drop_tg_pt_gp_mem( ssize_t core_alua_show_tg_pt_gp_info(struct se_port *port, char *page) { - struct se_subsystem_dev *su_dev = port->sep_lun->lun_se_dev->se_sub_dev; struct config_item *tg_pt_ci; - struct t10_alua *alua = &su_dev->t10_alua; struct t10_alua_tg_pt_gp *tg_pt_gp; struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; ssize_t len = 0; - if (alua->alua_type != SPC3_ALUA_EMULATED) - return len; - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; if (!tg_pt_gp_mem) return len; @@ -1683,7 +1663,7 @@ ssize_t core_alua_store_tg_pt_gp_info( { struct se_portal_group *tpg; struct se_lun *lun; - struct se_subsystem_dev *su_dev = port->sep_lun->lun_se_dev->se_sub_dev; + struct se_device *dev = port->sep_lun->lun_se_dev; struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *tg_pt_gp_new = NULL; struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; unsigned char buf[TG_PT_GROUP_NAME_BUF]; @@ -1692,13 +1672,9 @@ ssize_t core_alua_store_tg_pt_gp_info( tpg = port->sep_tpg; lun = port->sep_lun; - if (su_dev->t10_alua.alua_type != SPC3_ALUA_EMULATED) { - pr_warn("SPC3_ALUA_EMULATED not enabled for" - " %s/tpgt_%hu/%s\n", tpg->se_tpg_tfo->tpg_get_wwn(tpg), - tpg->se_tpg_tfo->tpg_get_tag(tpg), - config_item_name(&lun->lun_group.cg_item)); - return -EINVAL; - } + tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; + if (!tg_pt_gp_mem) + return 0; if (count > TG_PT_GROUP_NAME_BUF) { pr_err("ALUA Target Port Group alias too large!\n"); @@ -1716,18 +1692,11 @@ ssize_t core_alua_store_tg_pt_gp_info( * struct t10_alua_tg_pt_gp. This reference is released with * core_alua_put_tg_pt_gp_from_name() below. */ - tg_pt_gp_new = core_alua_get_tg_pt_gp_by_name(su_dev, + tg_pt_gp_new = core_alua_get_tg_pt_gp_by_name(dev, strstrip(buf)); if (!tg_pt_gp_new) return -ENODEV; } - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) { - if (tg_pt_gp_new) - core_alua_put_tg_pt_gp_from_name(tg_pt_gp_new); - pr_err("NULL struct se_port->sep_alua_tg_pt_gp_mem pointer\n"); - return -EINVAL; - } spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; @@ -1750,7 +1719,7 @@ ssize_t core_alua_store_tg_pt_gp_info( __core_alua_drop_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp); __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, - su_dev->t10_alua.default_tg_pt_gp); + dev->t10_alua.default_tg_pt_gp); spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); return count; @@ -2054,32 +2023,12 @@ ssize_t core_alua_store_secondary_write_metadata( return count; } -int core_setup_alua(struct se_device *dev, int force_pt) +int core_setup_alua(struct se_device *dev) { - struct se_subsystem_dev *su_dev = dev->se_sub_dev; - struct t10_alua *alua = &su_dev->t10_alua; - struct t10_alua_lu_gp_member *lu_gp_mem; - /* - * If this device is from Target_Core_Mod/pSCSI, use the ALUA logic - * of the Underlying SCSI hardware. In Linux/SCSI terms, this can - * cause a problem because libata and some SATA RAID HBAs appear - * under Linux/SCSI, but emulate SCSI logic themselves. - */ - if (((dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) && - !(dev->se_sub_dev->se_dev_attrib.emulate_alua)) || force_pt) { - alua->alua_type = SPC_ALUA_PASSTHROUGH; - alua->alua_state_check = &core_alua_state_check_nop; - pr_debug("%s: Using SPC_ALUA_PASSTHROUGH, no ALUA" - " emulation\n", dev->transport->name); - return 0; - } - /* - * If SPC-3 or above is reported by real or emulated struct se_device, - * use emulated ALUA. - */ - if (dev->transport->get_device_rev(dev) >= SCSI_3) { - pr_debug("%s: Enabling ALUA Emulation for SPC-3" - " device\n", dev->transport->name); + if (dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV && + !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) { + struct t10_alua_lu_gp_member *lu_gp_mem; + /* * Associate this struct se_device with the default ALUA * LUN Group. @@ -2088,8 +2037,6 @@ int core_setup_alua(struct se_device *dev, int force_pt) if (IS_ERR(lu_gp_mem)) return PTR_ERR(lu_gp_mem); - alua->alua_type = SPC3_ALUA_EMULATED; - alua->alua_state_check = &core_alua_state_check; spin_lock(&lu_gp_mem->lu_gp_mem_lock); __core_alua_attach_lu_gp_mem(lu_gp_mem, default_lu_gp); @@ -2098,11 +2045,6 @@ int core_setup_alua(struct se_device *dev, int force_pt) pr_debug("%s: Adding to default ALUA LU Group:" " core/alua/lu_gps/default_lu_gp\n", dev->transport->name); - } else { - alua->alua_type = SPC2_ALUA_DISABLED; - alua->alua_state_check = &core_alua_state_check_nop; - pr_debug("%s: Disabling ALUA Emulation for SPC-2" - " device\n", dev->transport->name); } return 0; diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h index f920c170d47b..e539c3e7f4ad 100644 --- a/drivers/target/target_core_alua.h +++ b/drivers/target/target_core_alua.h @@ -72,8 +72,8 @@ extern struct kmem_cache *t10_alua_lu_gp_mem_cache; extern struct kmem_cache *t10_alua_tg_pt_gp_cache; extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; -extern int target_emulate_report_target_port_groups(struct se_cmd *); -extern int target_emulate_set_target_port_groups(struct se_cmd *); +extern sense_reason_t target_emulate_report_target_port_groups(struct se_cmd *); +extern sense_reason_t target_emulate_set_target_port_groups(struct se_cmd *); extern int core_alua_check_nonop_delay(struct se_cmd *); extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *, struct se_device *, struct se_port *, @@ -91,7 +91,7 @@ extern void __core_alua_drop_lu_gp_mem(struct t10_alua_lu_gp_member *, struct t10_alua_lu_gp *); extern void core_alua_drop_lu_gp_dev(struct se_device *); extern struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp( - struct se_subsystem_dev *, const char *, int); + struct se_device *, const char *, int); extern int core_alua_set_tg_pt_gp_id(struct t10_alua_tg_pt_gp *, u16); extern struct t10_alua_tg_pt_gp_member *core_alua_allocate_tg_pt_gp_mem( struct se_port *); @@ -131,6 +131,7 @@ extern ssize_t core_alua_show_secondary_write_metadata(struct se_lun *, char *); extern ssize_t core_alua_store_secondary_write_metadata(struct se_lun *, const char *, size_t); -extern int core_setup_alua(struct se_device *, int); +extern int core_setup_alua(struct se_device *); +extern sense_reason_t target_alua_state_check(struct se_cmd *cmd); #endif /* TARGET_CORE_ALUA_H */ diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 015f5be27bf6..4efb61b8d001 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -3,8 +3,7 @@ * * This file contains ConfigFS logic for the Generic Target Engine project. * - * Copyright (c) 2008-2011 Rising Tide Systems - * Copyright (c) 2008-2011 Linux-iSCSI.org + * (c) Copyright 2008-2012 RisingTide Systems LLC. * * Nicholas A. Bellinger <nab@kernel.org> * @@ -565,21 +564,8 @@ static ssize_t target_core_dev_show_attr_##_name( \ struct se_dev_attrib *da, \ char *page) \ { \ - struct se_device *dev; \ - struct se_subsystem_dev *se_dev = da->da_sub_dev; \ - ssize_t rb; \ - \ - spin_lock(&se_dev->se_dev_lock); \ - dev = se_dev->se_dev_ptr; \ - if (!dev) { \ - spin_unlock(&se_dev->se_dev_lock); \ - return -ENODEV; \ - } \ - rb = snprintf(page, PAGE_SIZE, "%u\n", \ - (u32)dev->se_sub_dev->se_dev_attrib._name); \ - spin_unlock(&se_dev->se_dev_lock); \ - \ - return rb; \ + return snprintf(page, PAGE_SIZE, "%u\n", \ + (u32)da->da_dev->dev_attrib._name); \ } #define DEF_DEV_ATTRIB_STORE(_name) \ @@ -588,26 +574,16 @@ static ssize_t target_core_dev_store_attr_##_name( \ const char *page, \ size_t count) \ { \ - struct se_device *dev; \ - struct se_subsystem_dev *se_dev = da->da_sub_dev; \ unsigned long val; \ int ret; \ \ - spin_lock(&se_dev->se_dev_lock); \ - dev = se_dev->se_dev_ptr; \ - if (!dev) { \ - spin_unlock(&se_dev->se_dev_lock); \ - return -ENODEV; \ - } \ ret = strict_strtoul(page, 0, &val); \ if (ret < 0) { \ - spin_unlock(&se_dev->se_dev_lock); \ pr_err("strict_strtoul() failed with" \ " ret: %d\n", ret); \ return -EINVAL; \ } \ - ret = se_dev_set_##_name(dev, (u32)val); \ - spin_unlock(&se_dev->se_dev_lock); \ + ret = se_dev_set_##_name(da->da_dev, (u32)val); \ \ return (!ret) ? count : -EINVAL; \ } @@ -699,6 +675,9 @@ SE_DEV_ATTR(unmap_granularity, S_IRUGO | S_IWUSR); DEF_DEV_ATTRIB(unmap_granularity_alignment); SE_DEV_ATTR(unmap_granularity_alignment, S_IRUGO | S_IWUSR); +DEF_DEV_ATTRIB(max_write_same_len); +SE_DEV_ATTR(max_write_same_len, S_IRUGO | S_IWUSR); + CONFIGFS_EATTR_OPS(target_core_dev_attrib, se_dev_attrib, da_group); static struct configfs_attribute *target_core_dev_attrib_attrs[] = { @@ -724,6 +703,7 @@ static struct configfs_attribute *target_core_dev_attrib_attrs[] = { &target_core_dev_attrib_max_unmap_block_desc_count.attr, &target_core_dev_attrib_unmap_granularity.attr, &target_core_dev_attrib_unmap_granularity_alignment.attr, + &target_core_dev_attrib_max_write_same_len.attr, NULL, }; @@ -764,13 +744,6 @@ static ssize_t target_core_dev_wwn_show_attr_vpd_unit_serial( struct t10_wwn *t10_wwn, char *page) { - struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev; - struct se_device *dev; - - dev = se_dev->se_dev_ptr; - if (!dev) - return -ENODEV; - return sprintf(page, "T10 VPD Unit Serial Number: %s\n", &t10_wwn->unit_serial[0]); } @@ -780,8 +753,7 @@ static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial( const char *page, size_t count) { - struct se_subsystem_dev *su_dev = t10_wwn->t10_sub_dev; - struct se_device *dev; + struct se_device *dev = t10_wwn->t10_dev; unsigned char buf[INQUIRY_VPD_SERIAL_LEN]; /* @@ -794,7 +766,7 @@ static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial( * it is doing 'the right thing' wrt a world wide unique * VPD Unit Serial Number that OS dependent multipath can depend on. */ - if (su_dev->su_dev_flags & SDF_FIRMWARE_VPD_UNIT_SERIAL) { + if (dev->dev_flags & DF_FIRMWARE_VPD_UNIT_SERIAL) { pr_err("Underlying SCSI device firmware provided VPD" " Unit Serial, ignoring request\n"); return -EOPNOTSUPP; @@ -811,15 +783,13 @@ static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial( * (underneath the initiator side OS dependent multipath code) * could cause negative effects. */ - dev = su_dev->se_dev_ptr; - if (dev) { - if (atomic_read(&dev->dev_export_obj.obj_access_count)) { - pr_err("Unable to set VPD Unit Serial while" - " active %d $FABRIC_MOD exports exist\n", - atomic_read(&dev->dev_export_obj.obj_access_count)); - return -EINVAL; - } + if (dev->export_count) { + pr_err("Unable to set VPD Unit Serial while" + " active %d $FABRIC_MOD exports exist\n", + dev->export_count); + return -EINVAL; } + /* * This currently assumes ASCII encoding for emulated VPD Unit Serial. * @@ -828,12 +798,12 @@ static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial( */ memset(buf, 0, INQUIRY_VPD_SERIAL_LEN); snprintf(buf, INQUIRY_VPD_SERIAL_LEN, "%s", page); - snprintf(su_dev->t10_wwn.unit_serial, INQUIRY_VPD_SERIAL_LEN, + snprintf(dev->t10_wwn.unit_serial, INQUIRY_VPD_SERIAL_LEN, "%s", strstrip(buf)); - su_dev->su_dev_flags |= SDF_EMULATED_VPD_UNIT_SERIAL; + dev->dev_flags |= DF_EMULATED_VPD_UNIT_SERIAL; pr_debug("Target_Core_ConfigFS: Set emulated VPD Unit Serial:" - " %s\n", su_dev->t10_wwn.unit_serial); + " %s\n", dev->t10_wwn.unit_serial); return count; } @@ -847,16 +817,10 @@ static ssize_t target_core_dev_wwn_show_attr_vpd_protocol_identifier( struct t10_wwn *t10_wwn, char *page) { - struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev; - struct se_device *dev; struct t10_vpd *vpd; unsigned char buf[VPD_TMP_BUF_SIZE]; ssize_t len = 0; - dev = se_dev->se_dev_ptr; - if (!dev) - return -ENODEV; - memset(buf, 0, VPD_TMP_BUF_SIZE); spin_lock(&t10_wwn->t10_vpd_lock); @@ -894,16 +858,10 @@ static ssize_t target_core_dev_wwn_show_attr_##_name( \ struct t10_wwn *t10_wwn, \ char *page) \ { \ - struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev; \ - struct se_device *dev; \ struct t10_vpd *vpd; \ unsigned char buf[VPD_TMP_BUF_SIZE]; \ ssize_t len = 0; \ \ - dev = se_dev->se_dev_ptr; \ - if (!dev) \ - return -ENODEV; \ - \ spin_lock(&t10_wwn->t10_vpd_lock); \ list_for_each_entry(vpd, &t10_wwn->t10_vpd_list, vpd_list) { \ if (vpd->association != _assoc) \ @@ -1003,7 +961,7 @@ static struct config_item_type target_core_dev_wwn_cit = { /* Start functions for struct config_item_type target_core_dev_pr_cit */ -CONFIGFS_EATTR_STRUCT(target_core_dev_pr, se_subsystem_dev); +CONFIGFS_EATTR_STRUCT(target_core_dev_pr, se_device); #define SE_DEV_PR_ATTR(_name, _mode) \ static struct target_core_dev_pr_attribute target_core_dev_pr_##_name = \ __CONFIGFS_EATTR(_name, _mode, \ @@ -1015,13 +973,8 @@ static struct target_core_dev_pr_attribute target_core_dev_pr_##_name = \ __CONFIGFS_EATTR_RO(_name, \ target_core_dev_pr_show_attr_##_name); -/* - * res_holder - */ -static ssize_t target_core_dev_pr_show_spc3_res( - struct se_device *dev, - char *page, - ssize_t *len) +static ssize_t target_core_dev_pr_show_spc3_res(struct se_device *dev, + char *page) { struct se_node_acl *se_nacl; struct t10_pr_registration *pr_reg; @@ -1030,134 +983,82 @@ static ssize_t target_core_dev_pr_show_spc3_res( memset(i_buf, 0, PR_REG_ISID_ID_LEN); - spin_lock(&dev->dev_reservation_lock); pr_reg = dev->dev_pr_res_holder; - if (!pr_reg) { - *len += sprintf(page + *len, "No SPC-3 Reservation holder\n"); - spin_unlock(&dev->dev_reservation_lock); - return *len; - } + if (!pr_reg) + return sprintf(page, "No SPC-3 Reservation holder\n"); + se_nacl = pr_reg->pr_reg_nacl; prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], PR_REG_ISID_ID_LEN); - *len += sprintf(page + *len, "SPC-3 Reservation: %s Initiator: %s%s\n", + return sprintf(page, "SPC-3 Reservation: %s Initiator: %s%s\n", se_nacl->se_tpg->se_tpg_tfo->get_fabric_name(), se_nacl->initiatorname, (prf_isid) ? &i_buf[0] : ""); - spin_unlock(&dev->dev_reservation_lock); - - return *len; } -static ssize_t target_core_dev_pr_show_spc2_res( - struct se_device *dev, - char *page, - ssize_t *len) +static ssize_t target_core_dev_pr_show_spc2_res(struct se_device *dev, + char *page) { struct se_node_acl *se_nacl; + ssize_t len; - spin_lock(&dev->dev_reservation_lock); se_nacl = dev->dev_reserved_node_acl; - if (!se_nacl) { - *len += sprintf(page + *len, "No SPC-2 Reservation holder\n"); - spin_unlock(&dev->dev_reservation_lock); - return *len; + if (se_nacl) { + len = sprintf(page, + "SPC-2 Reservation: %s Initiator: %s\n", + se_nacl->se_tpg->se_tpg_tfo->get_fabric_name(), + se_nacl->initiatorname); + } else { + len = sprintf(page, "No SPC-2 Reservation holder\n"); } - *len += sprintf(page + *len, "SPC-2 Reservation: %s Initiator: %s\n", - se_nacl->se_tpg->se_tpg_tfo->get_fabric_name(), - se_nacl->initiatorname); - spin_unlock(&dev->dev_reservation_lock); - - return *len; + return len; } -static ssize_t target_core_dev_pr_show_attr_res_holder( - struct se_subsystem_dev *su_dev, - char *page) +static ssize_t target_core_dev_pr_show_attr_res_holder(struct se_device *dev, + char *page) { - ssize_t len = 0; + int ret; - if (!su_dev->se_dev_ptr) - return -ENODEV; - - switch (su_dev->t10_pr.res_type) { - case SPC3_PERSISTENT_RESERVATIONS: - target_core_dev_pr_show_spc3_res(su_dev->se_dev_ptr, - page, &len); - break; - case SPC2_RESERVATIONS: - target_core_dev_pr_show_spc2_res(su_dev->se_dev_ptr, - page, &len); - break; - case SPC_PASSTHROUGH: - len += sprintf(page+len, "Passthrough\n"); - break; - default: - len += sprintf(page+len, "Unknown\n"); - break; - } + if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + return sprintf(page, "Passthrough\n"); - return len; + spin_lock(&dev->dev_reservation_lock); + if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) + ret = target_core_dev_pr_show_spc2_res(dev, page); + else + ret = target_core_dev_pr_show_spc3_res(dev, page); + spin_unlock(&dev->dev_reservation_lock); + return ret; } SE_DEV_PR_ATTR_RO(res_holder); -/* - * res_pr_all_tgt_pts - */ static ssize_t target_core_dev_pr_show_attr_res_pr_all_tgt_pts( - struct se_subsystem_dev *su_dev, - char *page) + struct se_device *dev, char *page) { - struct se_device *dev; - struct t10_pr_registration *pr_reg; ssize_t len = 0; - dev = su_dev->se_dev_ptr; - if (!dev) - return -ENODEV; - - if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) - return len; - spin_lock(&dev->dev_reservation_lock); - pr_reg = dev->dev_pr_res_holder; - if (!pr_reg) { + if (!dev->dev_pr_res_holder) { len = sprintf(page, "No SPC-3 Reservation holder\n"); - spin_unlock(&dev->dev_reservation_lock); - return len; - } - /* - * See All Target Ports (ALL_TG_PT) bit in spcr17, section 6.14.3 - * Basic PERSISTENT RESERVER OUT parameter list, page 290 - */ - if (pr_reg->pr_reg_all_tg_pt) + } else if (dev->dev_pr_res_holder->pr_reg_all_tg_pt) { len = sprintf(page, "SPC-3 Reservation: All Target" " Ports registration\n"); - else + } else { len = sprintf(page, "SPC-3 Reservation: Single" " Target Port registration\n"); - spin_unlock(&dev->dev_reservation_lock); + } + spin_unlock(&dev->dev_reservation_lock); return len; } SE_DEV_PR_ATTR_RO(res_pr_all_tgt_pts); -/* - * res_pr_generation - */ static ssize_t target_core_dev_pr_show_attr_res_pr_generation( - struct se_subsystem_dev *su_dev, - char *page) + struct se_device *dev, char *page) { - if (!su_dev->se_dev_ptr) - return -ENODEV; - - if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) - return 0; - - return sprintf(page, "0x%08x\n", su_dev->t10_pr.pr_generation); + return sprintf(page, "0x%08x\n", dev->t10_pr.pr_generation); } SE_DEV_PR_ATTR_RO(res_pr_generation); @@ -1166,10 +1067,8 @@ SE_DEV_PR_ATTR_RO(res_pr_generation); * res_pr_holder_tg_port */ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port( - struct se_subsystem_dev *su_dev, - char *page) + struct se_device *dev, char *page) { - struct se_device *dev; struct se_node_acl *se_nacl; struct se_lun *lun; struct se_portal_group *se_tpg; @@ -1177,20 +1076,13 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port( struct target_core_fabric_ops *tfo; ssize_t len = 0; - dev = su_dev->se_dev_ptr; - if (!dev) - return -ENODEV; - - if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) - return len; - spin_lock(&dev->dev_reservation_lock); pr_reg = dev->dev_pr_res_holder; if (!pr_reg) { len = sprintf(page, "No SPC-3 Reservation holder\n"); - spin_unlock(&dev->dev_reservation_lock); - return len; + goto out_unlock; } + se_nacl = pr_reg->pr_reg_nacl; se_tpg = se_nacl->se_tpg; lun = pr_reg->pr_reg_tg_pt_lun; @@ -1204,19 +1096,16 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port( " %s Logical Unit: %u\n", lun->lun_sep->sep_rtpi, tfo->get_fabric_name(), tfo->tpg_get_tag(se_tpg), tfo->get_fabric_name(), lun->unpacked_lun); - spin_unlock(&dev->dev_reservation_lock); +out_unlock: + spin_unlock(&dev->dev_reservation_lock); return len; } SE_DEV_PR_ATTR_RO(res_pr_holder_tg_port); -/* - * res_pr_registered_i_pts - */ static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts( - struct se_subsystem_dev *su_dev, - char *page) + struct se_device *dev, char *page) { struct target_core_fabric_ops *tfo; struct t10_pr_registration *pr_reg; @@ -1225,16 +1114,10 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts( ssize_t len = 0; int reg_count = 0, prf_isid; - if (!su_dev->se_dev_ptr) - return -ENODEV; - - if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) - return len; - len += sprintf(page+len, "SPC-3 PR Registrations:\n"); - spin_lock(&su_dev->t10_pr.registration_lock); - list_for_each_entry(pr_reg, &su_dev->t10_pr.registration_list, + spin_lock(&dev->t10_pr.registration_lock); + list_for_each_entry(pr_reg, &dev->t10_pr.registration_list, pr_reg_list) { memset(buf, 0, 384); @@ -1254,7 +1137,7 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts( len += sprintf(page+len, "%s", buf); reg_count++; } - spin_unlock(&su_dev->t10_pr.registration_lock); + spin_unlock(&dev->t10_pr.registration_lock); if (!reg_count) len += sprintf(page+len, "None\n"); @@ -1264,88 +1147,48 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts( SE_DEV_PR_ATTR_RO(res_pr_registered_i_pts); -/* - * res_pr_type - */ static ssize_t target_core_dev_pr_show_attr_res_pr_type( - struct se_subsystem_dev *su_dev, - char *page) + struct se_device *dev, char *page) { - struct se_device *dev; struct t10_pr_registration *pr_reg; ssize_t len = 0; - dev = su_dev->se_dev_ptr; - if (!dev) - return -ENODEV; - - if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) - return len; - spin_lock(&dev->dev_reservation_lock); pr_reg = dev->dev_pr_res_holder; - if (!pr_reg) { + if (pr_reg) { + len = sprintf(page, "SPC-3 Reservation Type: %s\n", + core_scsi3_pr_dump_type(pr_reg->pr_res_type)); + } else { len = sprintf(page, "No SPC-3 Reservation holder\n"); - spin_unlock(&dev->dev_reservation_lock); - return len; } - len = sprintf(page, "SPC-3 Reservation Type: %s\n", - core_scsi3_pr_dump_type(pr_reg->pr_res_type)); - spin_unlock(&dev->dev_reservation_lock); + spin_unlock(&dev->dev_reservation_lock); return len; } SE_DEV_PR_ATTR_RO(res_pr_type); -/* - * res_type - */ static ssize_t target_core_dev_pr_show_attr_res_type( - struct se_subsystem_dev *su_dev, - char *page) + struct se_device *dev, char *page) { - ssize_t len = 0; - - if (!su_dev->se_dev_ptr) - return -ENODEV; - - switch (su_dev->t10_pr.res_type) { - case SPC3_PERSISTENT_RESERVATIONS: - len = sprintf(page, "SPC3_PERSISTENT_RESERVATIONS\n"); - break; - case SPC2_RESERVATIONS: - len = sprintf(page, "SPC2_RESERVATIONS\n"); - break; - case SPC_PASSTHROUGH: - len = sprintf(page, "SPC_PASSTHROUGH\n"); - break; - default: - len = sprintf(page, "UNKNOWN\n"); - break; - } - - return len; + if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + return sprintf(page, "SPC_PASSTHROUGH\n"); + else if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) + return sprintf(page, "SPC2_RESERVATIONS\n"); + else + return sprintf(page, "SPC3_PERSISTENT_RESERVATIONS\n"); } SE_DEV_PR_ATTR_RO(res_type); -/* - * res_aptpl_active - */ - static ssize_t target_core_dev_pr_show_attr_res_aptpl_active( - struct se_subsystem_dev *su_dev, - char *page) + struct se_device *dev, char *page) { - if (!su_dev->se_dev_ptr) - return -ENODEV; - - if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) + if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) return 0; return sprintf(page, "APTPL Bit Status: %s\n", - (su_dev->t10_pr.pr_aptpl_active) ? "Activated" : "Disabled"); + (dev->t10_pr.pr_aptpl_active) ? "Activated" : "Disabled"); } SE_DEV_PR_ATTR_RO(res_aptpl_active); @@ -1354,13 +1197,9 @@ SE_DEV_PR_ATTR_RO(res_aptpl_active); * res_aptpl_metadata */ static ssize_t target_core_dev_pr_show_attr_res_aptpl_metadata( - struct se_subsystem_dev *su_dev, - char *page) + struct se_device *dev, char *page) { - if (!su_dev->se_dev_ptr) - return -ENODEV; - - if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) + if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) return 0; return sprintf(page, "Ready to process PR APTPL metadata..\n"); @@ -1392,11 +1231,10 @@ static match_table_t tokens = { }; static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( - struct se_subsystem_dev *su_dev, + struct se_device *dev, const char *page, size_t count) { - struct se_device *dev; unsigned char *i_fabric = NULL, *i_port = NULL, *isid = NULL; unsigned char *t_fabric = NULL, *t_port = NULL; char *orig, *ptr, *arg_p, *opts; @@ -1408,14 +1246,12 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( u16 port_rpti = 0, tpgt = 0; u8 type = 0, scope; - dev = su_dev->se_dev_ptr; - if (!dev) - return -ENODEV; - - if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) + if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + return 0; + if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) return 0; - if (atomic_read(&dev->dev_export_obj.obj_access_count)) { + if (dev->export_count) { pr_debug("Unable to process APTPL metadata while" " active fabric exports exist\n"); return -EINVAL; @@ -1558,7 +1394,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( goto out; } - ret = core_scsi3_alloc_aptpl_registration(&su_dev->t10_pr, sa_res_key, + ret = core_scsi3_alloc_aptpl_registration(&dev->t10_pr, sa_res_key, i_port, isid, mapped_lun, t_port, tpgt, target_lun, res_holder, all_tg_pt, type); out: @@ -1573,7 +1409,7 @@ out: SE_DEV_PR_ATTR(res_aptpl_metadata, S_IRUGO | S_IWUSR); -CONFIGFS_EATTR_OPS(target_core_dev_pr, se_subsystem_dev, se_dev_pr_group); +CONFIGFS_EATTR_OPS(target_core_dev_pr, se_device, dev_pr_group); static struct configfs_attribute *target_core_dev_pr_attrs[] = { &target_core_dev_pr_res_holder.attr, @@ -1605,18 +1441,14 @@ static struct config_item_type target_core_dev_pr_cit = { static ssize_t target_core_show_dev_info(void *p, char *page) { - struct se_subsystem_dev *se_dev = p; - struct se_hba *hba = se_dev->se_dev_hba; - struct se_subsystem_api *t = hba->transport; + struct se_device *dev = p; + struct se_subsystem_api *t = dev->transport; int bl = 0; ssize_t read_bytes = 0; - if (!se_dev->se_dev_ptr) - return -ENODEV; - - transport_dump_dev_state(se_dev->se_dev_ptr, page, &bl); + transport_dump_dev_state(dev, page, &bl); read_bytes += bl; - read_bytes += t->show_configfs_dev_params(hba, se_dev, page+read_bytes); + read_bytes += t->show_configfs_dev_params(dev, page+read_bytes); return read_bytes; } @@ -1633,17 +1465,10 @@ static ssize_t target_core_store_dev_control( const char *page, size_t count) { - struct se_subsystem_dev *se_dev = p; - struct se_hba *hba = se_dev->se_dev_hba; - struct se_subsystem_api *t = hba->transport; + struct se_device *dev = p; + struct se_subsystem_api *t = dev->transport; - if (!se_dev->se_dev_su_ptr) { - pr_err("Unable to locate struct se_subsystem_dev>se" - "_dev_su_ptr\n"); - return -EINVAL; - } - - return t->set_configfs_dev_params(hba, se_dev, page, count); + return t->set_configfs_dev_params(dev, page, count); } static struct target_core_configfs_attribute target_core_attr_dev_control = { @@ -1656,12 +1481,12 @@ static struct target_core_configfs_attribute target_core_attr_dev_control = { static ssize_t target_core_show_dev_alias(void *p, char *page) { - struct se_subsystem_dev *se_dev = p; + struct se_device *dev = p; - if (!(se_dev->su_dev_flags & SDF_USING_ALIAS)) + if (!(dev->dev_flags & DF_USING_ALIAS)) return 0; - return snprintf(page, PAGE_SIZE, "%s\n", se_dev->se_dev_alias); + return snprintf(page, PAGE_SIZE, "%s\n", dev->dev_alias); } static ssize_t target_core_store_dev_alias( @@ -1669,8 +1494,8 @@ static ssize_t target_core_store_dev_alias( const char *page, size_t count) { - struct se_subsystem_dev *se_dev = p; - struct se_hba *hba = se_dev->se_dev_hba; + struct se_device *dev = p; + struct se_hba *hba = dev->se_hba; ssize_t read_bytes; if (count > (SE_DEV_ALIAS_LEN-1)) { @@ -1680,19 +1505,18 @@ static ssize_t target_core_store_dev_alias( return -EINVAL; } - read_bytes = snprintf(&se_dev->se_dev_alias[0], SE_DEV_ALIAS_LEN, - "%s", page); + read_bytes = snprintf(&dev->dev_alias[0], SE_DEV_ALIAS_LEN, "%s", page); if (!read_bytes) return -EINVAL; - if (se_dev->se_dev_alias[read_bytes - 1] == '\n') - se_dev->se_dev_alias[read_bytes - 1] = '\0'; + if (dev->dev_alias[read_bytes - 1] == '\n') + dev->dev_alias[read_bytes - 1] = '\0'; - se_dev->su_dev_flags |= SDF_USING_ALIAS; + dev->dev_flags |= DF_USING_ALIAS; pr_debug("Target_Core_ConfigFS: %s/%s set alias: %s\n", config_item_name(&hba->hba_group.cg_item), - config_item_name(&se_dev->se_dev_group.cg_item), - se_dev->se_dev_alias); + config_item_name(&dev->dev_group.cg_item), + dev->dev_alias); return read_bytes; } @@ -1707,12 +1531,12 @@ static struct target_core_configfs_attribute target_core_attr_dev_alias = { static ssize_t target_core_show_dev_udev_path(void *p, char *page) { - struct se_subsystem_dev *se_dev = p; + struct se_device *dev = p; - if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH)) + if (!(dev->dev_flags & DF_USING_UDEV_PATH)) return 0; - return snprintf(page, PAGE_SIZE, "%s\n", se_dev->se_dev_udev_path); + return snprintf(page, PAGE_SIZE, "%s\n", dev->udev_path); } static ssize_t target_core_store_dev_udev_path( @@ -1720,8 +1544,8 @@ static ssize_t target_core_store_dev_udev_path( const char *page, size_t count) { - struct se_subsystem_dev *se_dev = p; - struct se_hba *hba = se_dev->se_dev_hba; + struct se_device *dev = p; + struct se_hba *hba = dev->se_hba; ssize_t read_bytes; if (count > (SE_UDEV_PATH_LEN-1)) { @@ -1731,19 +1555,19 @@ static ssize_t target_core_store_dev_udev_path( return -EINVAL; } - read_bytes = snprintf(&se_dev->se_dev_udev_path[0], SE_UDEV_PATH_LEN, + read_bytes = snprintf(&dev->udev_path[0], SE_UDEV_PATH_LEN, "%s", page); if (!read_bytes) return -EINVAL; - if (se_dev->se_dev_udev_path[read_bytes - 1] == '\n') - se_dev->se_dev_udev_path[read_bytes - 1] = '\0'; + if (dev->udev_path[read_bytes - 1] == '\n') + dev->udev_path[read_bytes - 1] = '\0'; - se_dev->su_dev_flags |= SDF_USING_UDEV_PATH; + dev->dev_flags |= DF_USING_UDEV_PATH; pr_debug("Target_Core_ConfigFS: %s/%s set udev_path: %s\n", config_item_name(&hba->hba_group.cg_item), - config_item_name(&se_dev->se_dev_group.cg_item), - se_dev->se_dev_udev_path); + config_item_name(&dev->dev_group.cg_item), + dev->udev_path); return read_bytes; } @@ -1761,11 +1585,9 @@ static ssize_t target_core_store_dev_enable( const char *page, size_t count) { - struct se_subsystem_dev *se_dev = p; - struct se_device *dev; - struct se_hba *hba = se_dev->se_dev_hba; - struct se_subsystem_api *t = hba->transport; + struct se_device *dev = p; char *ptr; + int ret; ptr = strstr(page, "1"); if (!ptr) { @@ -1773,25 +1595,10 @@ static ssize_t target_core_store_dev_enable( " is \"1\"\n"); return -EINVAL; } - if (se_dev->se_dev_ptr) { - pr_err("se_dev->se_dev_ptr already set for storage" - " object\n"); - return -EEXIST; - } - - if (t->check_configfs_dev_params(hba, se_dev) < 0) - return -EINVAL; - - dev = t->create_virtdevice(hba, se_dev, se_dev->se_dev_su_ptr); - if (IS_ERR(dev)) - return PTR_ERR(dev); - else if (!dev) - return -EINVAL; - - se_dev->se_dev_ptr = dev; - pr_debug("Target_Core_ConfigFS: Registered se_dev->se_dev_ptr:" - " %p\n", se_dev->se_dev_ptr); + ret = target_configure_device(dev); + if (ret) + return ret; return count; } @@ -1805,26 +1612,15 @@ static struct target_core_configfs_attribute target_core_attr_dev_enable = { static ssize_t target_core_show_alua_lu_gp(void *p, char *page) { - struct se_device *dev; - struct se_subsystem_dev *su_dev = p; + struct se_device *dev = p; struct config_item *lu_ci; struct t10_alua_lu_gp *lu_gp; struct t10_alua_lu_gp_member *lu_gp_mem; ssize_t len = 0; - dev = su_dev->se_dev_ptr; - if (!dev) - return -ENODEV; - - if (su_dev->t10_alua.alua_type != SPC3_ALUA_EMULATED) - return len; - lu_gp_mem = dev->dev_alua_lu_gp_mem; - if (!lu_gp_mem) { - pr_err("NULL struct se_device->dev_alua_lu_gp_mem" - " pointer\n"); - return -EINVAL; - } + if (!lu_gp_mem) + return 0; spin_lock(&lu_gp_mem->lu_gp_mem_lock); lu_gp = lu_gp_mem->lu_gp; @@ -1843,24 +1639,17 @@ static ssize_t target_core_store_alua_lu_gp( const char *page, size_t count) { - struct se_device *dev; - struct se_subsystem_dev *su_dev = p; - struct se_hba *hba = su_dev->se_dev_hba; + struct se_device *dev = p; + struct se_hba *hba = dev->se_hba; struct t10_alua_lu_gp *lu_gp = NULL, *lu_gp_new = NULL; struct t10_alua_lu_gp_member *lu_gp_mem; unsigned char buf[LU_GROUP_NAME_BUF]; int move = 0; - dev = su_dev->se_dev_ptr; - if (!dev) - return -ENODEV; + lu_gp_mem = dev->dev_alua_lu_gp_mem; + if (!lu_gp_mem) + return 0; - if (su_dev->t10_alua.alua_type != SPC3_ALUA_EMULATED) { - pr_warn("SPC3_ALUA_EMULATED not enabled for %s/%s\n", - config_item_name(&hba->hba_group.cg_item), - config_item_name(&su_dev->se_dev_group.cg_item)); - return -EINVAL; - } if (count > LU_GROUP_NAME_BUF) { pr_err("ALUA LU Group Alias too large!\n"); return -EINVAL; @@ -1881,14 +1670,6 @@ static ssize_t target_core_store_alua_lu_gp( if (!lu_gp_new) return -ENODEV; } - lu_gp_mem = dev->dev_alua_lu_gp_mem; - if (!lu_gp_mem) { - if (lu_gp_new) - core_alua_put_lu_gp_from_name(lu_gp_new); - pr_err("NULL struct se_device->dev_alua_lu_gp_mem" - " pointer\n"); - return -EINVAL; - } spin_lock(&lu_gp_mem->lu_gp_mem_lock); lu_gp = lu_gp_mem->lu_gp; @@ -1902,7 +1683,7 @@ static ssize_t target_core_store_alua_lu_gp( " from ALUA LU Group: core/alua/lu_gps/%s, ID:" " %hu\n", config_item_name(&hba->hba_group.cg_item), - config_item_name(&su_dev->se_dev_group.cg_item), + config_item_name(&dev->dev_group.cg_item), config_item_name(&lu_gp->lu_gp_group.cg_item), lu_gp->lu_gp_id); @@ -1927,7 +1708,7 @@ static ssize_t target_core_store_alua_lu_gp( " core/alua/lu_gps/%s, ID: %hu\n", (move) ? "Moving" : "Adding", config_item_name(&hba->hba_group.cg_item), - config_item_name(&su_dev->se_dev_group.cg_item), + config_item_name(&dev->dev_group.cg_item), config_item_name(&lu_gp_new->lu_gp_group.cg_item), lu_gp_new->lu_gp_id); @@ -1955,69 +1736,44 @@ static struct configfs_attribute *lio_core_dev_attrs[] = { static void target_core_dev_release(struct config_item *item) { - struct se_subsystem_dev *se_dev = container_of(to_config_group(item), - struct se_subsystem_dev, se_dev_group); - struct se_hba *hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); - struct se_subsystem_api *t = hba->transport; - struct config_group *dev_cg = &se_dev->se_dev_group; + struct config_group *dev_cg = to_config_group(item); + struct se_device *dev = + container_of(dev_cg, struct se_device, dev_group); kfree(dev_cg->default_groups); - /* - * This pointer will set when the storage is enabled with: - *`echo 1 > $CONFIGFS/core/$HBA/$DEV/dev_enable` - */ - if (se_dev->se_dev_ptr) { - pr_debug("Target_Core_ConfigFS: Calling se_free_" - "virtual_device() for se_dev_ptr: %p\n", - se_dev->se_dev_ptr); - - se_free_virtual_device(se_dev->se_dev_ptr, hba); - } else { - /* - * Release struct se_subsystem_dev->se_dev_su_ptr.. - */ - pr_debug("Target_Core_ConfigFS: Calling t->free_" - "device() for se_dev_su_ptr: %p\n", - se_dev->se_dev_su_ptr); - - t->free_device(se_dev->se_dev_su_ptr); - } - - pr_debug("Target_Core_ConfigFS: Deallocating se_subsystem" - "_dev_t: %p\n", se_dev); - kfree(se_dev); + target_free_device(dev); } static ssize_t target_core_dev_show(struct config_item *item, struct configfs_attribute *attr, char *page) { - struct se_subsystem_dev *se_dev = container_of( - to_config_group(item), struct se_subsystem_dev, - se_dev_group); + struct config_group *dev_cg = to_config_group(item); + struct se_device *dev = + container_of(dev_cg, struct se_device, dev_group); struct target_core_configfs_attribute *tc_attr = container_of( attr, struct target_core_configfs_attribute, attr); if (!tc_attr->show) return -EINVAL; - return tc_attr->show(se_dev, page); + return tc_attr->show(dev, page); } static ssize_t target_core_dev_store(struct config_item *item, struct configfs_attribute *attr, const char *page, size_t count) { - struct se_subsystem_dev *se_dev = container_of( - to_config_group(item), struct se_subsystem_dev, - se_dev_group); + struct config_group *dev_cg = to_config_group(item); + struct se_device *dev = + container_of(dev_cg, struct se_device, dev_group); struct target_core_configfs_attribute *tc_attr = container_of( attr, struct target_core_configfs_attribute, attr); if (!tc_attr->store) return -EINVAL; - return tc_attr->store(se_dev, page, count); + return tc_attr->store(dev, page, count); } static struct configfs_item_operations target_core_dev_item_ops = { @@ -2107,7 +1863,6 @@ static ssize_t target_core_alua_lu_gp_show_attr_members( { struct se_device *dev; struct se_hba *hba; - struct se_subsystem_dev *su_dev; struct t10_alua_lu_gp_member *lu_gp_mem; ssize_t len = 0, cur_len; unsigned char buf[LU_GROUP_NAME_BUF]; @@ -2117,12 +1872,11 @@ static ssize_t target_core_alua_lu_gp_show_attr_members( spin_lock(&lu_gp->lu_gp_lock); list_for_each_entry(lu_gp_mem, &lu_gp->lu_gp_mem_list, lu_gp_mem_list) { dev = lu_gp_mem->lu_gp_mem_dev; - su_dev = dev->se_sub_dev; - hba = su_dev->se_dev_hba; + hba = dev->se_hba; cur_len = snprintf(buf, LU_GROUP_NAME_BUF, "%s/%s\n", config_item_name(&hba->hba_group.cg_item), - config_item_name(&su_dev->se_dev_group.cg_item)); + config_item_name(&dev->dev_group.cg_item)); cur_len++; /* Extra byte for NULL terminator */ if ((cur_len + len) > PAGE_SIZE) { @@ -2260,7 +2014,7 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state( const char *page, size_t count) { - struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev; + struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; unsigned long tmp; int new_state, ret; @@ -2284,7 +2038,7 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state( return -EINVAL; } - ret = core_alua_do_port_transition(tg_pt_gp, su_dev->se_dev_ptr, + ret = core_alua_do_port_transition(tg_pt_gp, dev, NULL, NULL, new_state, 0); return (!ret) ? count : -EINVAL; } @@ -2620,11 +2374,10 @@ static struct config_group *target_core_alua_create_tg_pt_gp( struct t10_alua *alua = container_of(group, struct t10_alua, alua_tg_pt_gps_group); struct t10_alua_tg_pt_gp *tg_pt_gp; - struct se_subsystem_dev *su_dev = alua->t10_sub_dev; struct config_group *alua_tg_pt_gp_cg = NULL; struct config_item *alua_tg_pt_gp_ci = NULL; - tg_pt_gp = core_alua_allocate_tg_pt_gp(su_dev, name, 0); + tg_pt_gp = core_alua_allocate_tg_pt_gp(alua->t10_dev, name, 0); if (!tg_pt_gp) return NULL; @@ -2721,10 +2474,10 @@ static struct config_group *target_core_make_subdev( const char *name) { struct t10_alua_tg_pt_gp *tg_pt_gp; - struct se_subsystem_dev *se_dev; struct se_subsystem_api *t; struct config_item *hba_ci = &group->cg_item; struct se_hba *hba = item_to_hba(hba_ci); + struct se_device *dev; struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL; struct config_group *dev_stat_grp = NULL; int errno = -ENOMEM, ret; @@ -2737,120 +2490,80 @@ static struct config_group *target_core_make_subdev( */ t = hba->transport; - se_dev = kzalloc(sizeof(struct se_subsystem_dev), GFP_KERNEL); - if (!se_dev) { - pr_err("Unable to allocate memory for" - " struct se_subsystem_dev\n"); - goto unlock; - } - INIT_LIST_HEAD(&se_dev->t10_wwn.t10_vpd_list); - spin_lock_init(&se_dev->t10_wwn.t10_vpd_lock); - INIT_LIST_HEAD(&se_dev->t10_pr.registration_list); - INIT_LIST_HEAD(&se_dev->t10_pr.aptpl_reg_list); - spin_lock_init(&se_dev->t10_pr.registration_lock); - spin_lock_init(&se_dev->t10_pr.aptpl_reg_lock); - INIT_LIST_HEAD(&se_dev->t10_alua.tg_pt_gps_list); - spin_lock_init(&se_dev->t10_alua.tg_pt_gps_lock); - spin_lock_init(&se_dev->se_dev_lock); - se_dev->t10_pr.pr_aptpl_buf_len = PR_APTPL_BUF_LEN; - se_dev->t10_wwn.t10_sub_dev = se_dev; - se_dev->t10_alua.t10_sub_dev = se_dev; - se_dev->se_dev_attrib.da_sub_dev = se_dev; - - se_dev->se_dev_hba = hba; - dev_cg = &se_dev->se_dev_group; - - dev_cg->default_groups = kzalloc(sizeof(struct config_group) * 7, + dev = target_alloc_device(hba, name); + if (!dev) + goto out_unlock; + + dev_cg = &dev->dev_group; + + dev_cg->default_groups = kmalloc(sizeof(struct config_group *) * 6, GFP_KERNEL); if (!dev_cg->default_groups) - goto out; - /* - * Set se_dev_su_ptr from struct se_subsystem_api returned void ptr - * for ->allocate_virtdevice() - * - * se_dev->se_dev_ptr will be set after ->create_virtdev() - * has been called successfully in the next level up in the - * configfs tree for device object's struct config_group. - */ - se_dev->se_dev_su_ptr = t->allocate_virtdevice(hba, name); - if (!se_dev->se_dev_su_ptr) { - pr_err("Unable to locate subsystem dependent pointer" - " from allocate_virtdevice()\n"); - goto out; - } + goto out_free_device; - config_group_init_type_name(&se_dev->se_dev_group, name, - &target_core_dev_cit); - config_group_init_type_name(&se_dev->se_dev_attrib.da_group, "attrib", + config_group_init_type_name(dev_cg, name, &target_core_dev_cit); + config_group_init_type_name(&dev->dev_attrib.da_group, "attrib", &target_core_dev_attrib_cit); - config_group_init_type_name(&se_dev->se_dev_pr_group, "pr", + config_group_init_type_name(&dev->dev_pr_group, "pr", &target_core_dev_pr_cit); - config_group_init_type_name(&se_dev->t10_wwn.t10_wwn_group, "wwn", + config_group_init_type_name(&dev->t10_wwn.t10_wwn_group, "wwn", &target_core_dev_wwn_cit); - config_group_init_type_name(&se_dev->t10_alua.alua_tg_pt_gps_group, + config_group_init_type_name(&dev->t10_alua.alua_tg_pt_gps_group, "alua", &target_core_alua_tg_pt_gps_cit); - config_group_init_type_name(&se_dev->dev_stat_grps.stat_group, + config_group_init_type_name(&dev->dev_stat_grps.stat_group, "statistics", &target_core_stat_cit); - dev_cg->default_groups[0] = &se_dev->se_dev_attrib.da_group; - dev_cg->default_groups[1] = &se_dev->se_dev_pr_group; - dev_cg->default_groups[2] = &se_dev->t10_wwn.t10_wwn_group; - dev_cg->default_groups[3] = &se_dev->t10_alua.alua_tg_pt_gps_group; - dev_cg->default_groups[4] = &se_dev->dev_stat_grps.stat_group; + dev_cg->default_groups[0] = &dev->dev_attrib.da_group; + dev_cg->default_groups[1] = &dev->dev_pr_group; + dev_cg->default_groups[2] = &dev->t10_wwn.t10_wwn_group; + dev_cg->default_groups[3] = &dev->t10_alua.alua_tg_pt_gps_group; + dev_cg->default_groups[4] = &dev->dev_stat_grps.stat_group; dev_cg->default_groups[5] = NULL; /* * Add core/$HBA/$DEV/alua/default_tg_pt_gp */ - tg_pt_gp = core_alua_allocate_tg_pt_gp(se_dev, "default_tg_pt_gp", 1); + tg_pt_gp = core_alua_allocate_tg_pt_gp(dev, "default_tg_pt_gp", 1); if (!tg_pt_gp) - goto out; + goto out_free_dev_cg_default_groups; + dev->t10_alua.default_tg_pt_gp = tg_pt_gp; - tg_pt_gp_cg = &se_dev->t10_alua.alua_tg_pt_gps_group; - tg_pt_gp_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, + tg_pt_gp_cg = &dev->t10_alua.alua_tg_pt_gps_group; + tg_pt_gp_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, GFP_KERNEL); if (!tg_pt_gp_cg->default_groups) { pr_err("Unable to allocate tg_pt_gp_cg->" "default_groups\n"); - goto out; + goto out_free_tg_pt_gp; } config_group_init_type_name(&tg_pt_gp->tg_pt_gp_group, "default_tg_pt_gp", &target_core_alua_tg_pt_gp_cit); tg_pt_gp_cg->default_groups[0] = &tg_pt_gp->tg_pt_gp_group; tg_pt_gp_cg->default_groups[1] = NULL; - se_dev->t10_alua.default_tg_pt_gp = tg_pt_gp; /* * Add core/$HBA/$DEV/statistics/ default groups */ - dev_stat_grp = &se_dev->dev_stat_grps.stat_group; - dev_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 4, + dev_stat_grp = &dev->dev_stat_grps.stat_group; + dev_stat_grp->default_groups = kmalloc(sizeof(struct config_group *) * 4, GFP_KERNEL); if (!dev_stat_grp->default_groups) { pr_err("Unable to allocate dev_stat_grp->default_groups\n"); - goto out; + goto out_free_tg_pt_gp_cg_default_groups; } - target_stat_setup_dev_default_groups(se_dev); - - pr_debug("Target_Core_ConfigFS: Allocated struct se_subsystem_dev:" - " %p se_dev_su_ptr: %p\n", se_dev, se_dev->se_dev_su_ptr); + target_stat_setup_dev_default_groups(dev); mutex_unlock(&hba->hba_access_mutex); - return &se_dev->se_dev_group; -out: - if (se_dev->t10_alua.default_tg_pt_gp) { - core_alua_free_tg_pt_gp(se_dev->t10_alua.default_tg_pt_gp); - se_dev->t10_alua.default_tg_pt_gp = NULL; - } - if (dev_stat_grp) - kfree(dev_stat_grp->default_groups); - if (tg_pt_gp_cg) - kfree(tg_pt_gp_cg->default_groups); - if (dev_cg) - kfree(dev_cg->default_groups); - if (se_dev->se_dev_su_ptr) - t->free_device(se_dev->se_dev_su_ptr); - kfree(se_dev); -unlock: + return dev_cg; + +out_free_tg_pt_gp_cg_default_groups: + kfree(tg_pt_gp_cg->default_groups); +out_free_tg_pt_gp: + core_alua_free_tg_pt_gp(tg_pt_gp); +out_free_dev_cg_default_groups: + kfree(dev_cg->default_groups); +out_free_device: + target_free_device(dev); +out_unlock: mutex_unlock(&hba->hba_access_mutex); return ERR_PTR(errno); } @@ -2859,18 +2572,19 @@ static void target_core_drop_subdev( struct config_group *group, struct config_item *item) { - struct se_subsystem_dev *se_dev = container_of(to_config_group(item), - struct se_subsystem_dev, se_dev_group); + struct config_group *dev_cg = to_config_group(item); + struct se_device *dev = + container_of(dev_cg, struct se_device, dev_group); struct se_hba *hba; struct config_item *df_item; - struct config_group *dev_cg, *tg_pt_gp_cg, *dev_stat_grp; + struct config_group *tg_pt_gp_cg, *dev_stat_grp; int i; - hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); + hba = item_to_hba(&dev->se_hba->hba_group.cg_item); mutex_lock(&hba->hba_access_mutex); - dev_stat_grp = &se_dev->dev_stat_grps.stat_group; + dev_stat_grp = &dev->dev_stat_grps.stat_group; for (i = 0; dev_stat_grp->default_groups[i]; i++) { df_item = &dev_stat_grp->default_groups[i]->cg_item; dev_stat_grp->default_groups[i] = NULL; @@ -2878,7 +2592,7 @@ static void target_core_drop_subdev( } kfree(dev_stat_grp->default_groups); - tg_pt_gp_cg = &se_dev->t10_alua.alua_tg_pt_gps_group; + tg_pt_gp_cg = &dev->t10_alua.alua_tg_pt_gps_group; for (i = 0; tg_pt_gp_cg->default_groups[i]; i++) { df_item = &tg_pt_gp_cg->default_groups[i]->cg_item; tg_pt_gp_cg->default_groups[i] = NULL; @@ -2889,17 +2603,15 @@ static void target_core_drop_subdev( * core_alua_free_tg_pt_gp() is called from ->default_tg_pt_gp * directly from target_core_alua_tg_pt_gp_release(). */ - se_dev->t10_alua.default_tg_pt_gp = NULL; + dev->t10_alua.default_tg_pt_gp = NULL; - dev_cg = &se_dev->se_dev_group; for (i = 0; dev_cg->default_groups[i]; i++) { df_item = &dev_cg->default_groups[i]->cg_item; dev_cg->default_groups[i] = NULL; config_item_put(df_item); } /* - * The releasing of se_dev and associated se_dev->se_dev_ptr is done - * from target_core_dev_item_ops->release() ->target_core_dev_release(). + * se_dev is released from target_core_dev_item_ops->release() */ config_item_put(item); mutex_unlock(&hba->hba_access_mutex); @@ -2962,13 +2674,10 @@ static ssize_t target_core_hba_store_attr_hba_mode(struct se_hba *hba, return -EINVAL; } - spin_lock(&hba->device_lock); - if (!list_empty(&hba->hba_dev_list)) { + if (hba->dev_count) { pr_err("Unable to set hba_mode with active devices\n"); - spin_unlock(&hba->device_lock); return -EINVAL; } - spin_unlock(&hba->device_lock); ret = transport->pmode_enable_hba(hba, mode_flag); if (ret < 0) @@ -3120,7 +2829,7 @@ static int __init target_core_init_configfs(void) * and ALUA Logical Unit Group and Target Port Group infrastructure. */ target_cg = &subsys->su_group; - target_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, + target_cg->default_groups = kmalloc(sizeof(struct config_group) * 2, GFP_KERNEL); if (!target_cg->default_groups) { pr_err("Unable to allocate target_cg->default_groups\n"); @@ -3136,7 +2845,7 @@ static int __init target_core_init_configfs(void) * Create ALUA infrastructure under /sys/kernel/config/target/core/alua/ */ hba_cg = &target_core_hbagroup; - hba_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, + hba_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, GFP_KERNEL); if (!hba_cg->default_groups) { pr_err("Unable to allocate hba_cg->default_groups\n"); @@ -3152,7 +2861,7 @@ static int __init target_core_init_configfs(void) * groups under /sys/kernel/config/target/core/alua/ */ alua_cg = &alua_group; - alua_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, + alua_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, GFP_KERNEL); if (!alua_cg->default_groups) { pr_err("Unable to allocate alua_cg->default_groups\n"); @@ -3174,7 +2883,7 @@ static int __init target_core_init_configfs(void) } lu_gp_cg = &alua_lu_gps_group; - lu_gp_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, + lu_gp_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, GFP_KERNEL); if (!lu_gp_cg->default_groups) { pr_err("Unable to allocate lu_gp_cg->default_groups\n"); @@ -3206,7 +2915,8 @@ static int __init target_core_init_configfs(void) if (ret < 0) goto out; - if (core_dev_setup_virtual_lun0() < 0) + ret = core_dev_setup_virtual_lun0(); + if (ret < 0) goto out; return 0; diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 8d774da16320..e2695101bb99 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -4,10 +4,7 @@ * This file contains the TCM Virtual Device and Disk Transport * agnostic related functions. * - * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc. - * Copyright (c) 2005-2006 SBE, Inc. All Rights Reserved. - * Copyright (c) 2007-2010 Rising Tide Systems - * Copyright (c) 2008-2010 Linux-iSCSI.org + * (c) Copyright 2003-2012 RisingTide Systems LLC. * * Nicholas A. Bellinger <nab@kernel.org> * @@ -50,26 +47,20 @@ #include "target_core_pr.h" #include "target_core_ua.h" -static void se_dev_start(struct se_device *dev); -static void se_dev_stop(struct se_device *dev); - static struct se_hba *lun0_hba; -static struct se_subsystem_dev *lun0_su_dev; /* not static, needed by tpg.c */ struct se_device *g_lun0_dev; -int transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) +sense_reason_t +transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) { struct se_lun *se_lun = NULL; struct se_session *se_sess = se_cmd->se_sess; struct se_device *dev; unsigned long flags; - if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) { - se_cmd->scsi_sense_reason = TCM_NON_EXISTENT_LUN; - se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - return -ENODEV; - } + if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) + return TCM_NON_EXISTENT_LUN; spin_lock_irqsave(&se_sess->se_node_acl->device_list_lock, flags); se_cmd->se_deve = se_sess->se_node_acl->device_list[unpacked_lun]; @@ -81,14 +72,12 @@ int transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) if ((se_cmd->data_direction == DMA_TO_DEVICE) && (deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)) { - se_cmd->scsi_sense_reason = TCM_WRITE_PROTECTED; - se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; pr_err("TARGET_CORE[%s]: Detected WRITE_PROTECTED LUN" " Access for 0x%08x\n", se_cmd->se_tfo->get_fabric_name(), unpacked_lun); spin_unlock_irqrestore(&se_sess->se_node_acl->device_list_lock, flags); - return -EACCES; + return TCM_WRITE_PROTECTED; } if (se_cmd->data_direction == DMA_TO_DEVICE) @@ -113,38 +102,24 @@ int transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) * MappedLUN=0 exists for this Initiator Port. */ if (unpacked_lun != 0) { - se_cmd->scsi_sense_reason = TCM_NON_EXISTENT_LUN; - se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; pr_err("TARGET_CORE[%s]: Detected NON_EXISTENT_LUN" " Access for 0x%08x\n", se_cmd->se_tfo->get_fabric_name(), unpacked_lun); - return -ENODEV; + return TCM_NON_EXISTENT_LUN; } /* * Force WRITE PROTECT for virtual LUN 0 */ if ((se_cmd->data_direction != DMA_FROM_DEVICE) && - (se_cmd->data_direction != DMA_NONE)) { - se_cmd->scsi_sense_reason = TCM_WRITE_PROTECTED; - se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - return -EACCES; - } + (se_cmd->data_direction != DMA_NONE)) + return TCM_WRITE_PROTECTED; se_lun = &se_sess->se_tpg->tpg_virt_lun0; se_cmd->se_lun = &se_sess->se_tpg->tpg_virt_lun0; se_cmd->orig_fe_lun = 0; se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; } - /* - * Determine if the struct se_lun is online. - * FIXME: Check for LUN_RESET + UNIT Attention - */ - if (se_dev_check_online(se_lun->lun_se_dev) != 0) { - se_cmd->scsi_sense_reason = TCM_NON_EXISTENT_LUN; - se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - return -ENODEV; - } /* Directly associate cmd with se_dev */ se_cmd->se_dev = se_lun->lun_se_dev; @@ -175,11 +150,8 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u32 unpacked_lun) struct se_tmr_req *se_tmr = se_cmd->se_tmr_req; unsigned long flags; - if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) { - se_cmd->scsi_sense_reason = TCM_NON_EXISTENT_LUN; - se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) return -ENODEV; - } spin_lock_irqsave(&se_sess->se_node_acl->device_list_lock, flags); se_cmd->se_deve = se_sess->se_node_acl->device_list[unpacked_lun]; @@ -199,15 +171,6 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u32 unpacked_lun) " Access for 0x%08x\n", se_cmd->se_tfo->get_fabric_name(), unpacked_lun); - se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - return -ENODEV; - } - /* - * Determine if the struct se_lun is online. - * FIXME: Check for LUN_RESET + UNIT Attention - */ - if (se_dev_check_online(se_lun->lun_se_dev) != 0) { - se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; return -ENODEV; } @@ -565,7 +528,6 @@ static void core_export_port( struct se_port *port, struct se_lun *lun) { - struct se_subsystem_dev *su_dev = dev->se_sub_dev; struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem = NULL; spin_lock(&dev->se_port_lock); @@ -578,7 +540,8 @@ static void core_export_port( list_add_tail(&port->sep_list, &dev->dev_sep_list); spin_unlock(&dev->se_port_lock); - if (su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { + if (dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV && + !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) { tg_pt_gp_mem = core_alua_allocate_tg_pt_gp_mem(port); if (IS_ERR(tg_pt_gp_mem) || !tg_pt_gp_mem) { pr_err("Unable to allocate t10_alua_tg_pt" @@ -587,7 +550,7 @@ static void core_export_port( } spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, - su_dev->t10_alua.default_tg_pt_gp); + dev->t10_alua.default_tg_pt_gp); spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); pr_debug("%s/%s: Adding to default ALUA Target Port" " Group: alua/default_tg_pt_gp\n", @@ -625,6 +588,7 @@ int core_dev_export( struct se_portal_group *tpg, struct se_lun *lun) { + struct se_hba *hba = dev->se_hba; struct se_port *port; port = core_alloc_port(dev); @@ -632,9 +596,11 @@ int core_dev_export( return PTR_ERR(port); lun->lun_se_dev = dev; - se_dev_start(dev); - atomic_inc(&dev->dev_export_obj.obj_access_count); + spin_lock(&hba->device_lock); + dev->export_count++; + spin_unlock(&hba->device_lock); + core_export_port(dev, tpg, port, lun); return 0; } @@ -644,6 +610,7 @@ void core_dev_unexport( struct se_portal_group *tpg, struct se_lun *lun) { + struct se_hba *hba = dev->se_hba; struct se_port *port = lun->lun_sep; spin_lock(&lun->lun_sep_lock); @@ -654,284 +621,54 @@ void core_dev_unexport( spin_unlock(&lun->lun_sep_lock); spin_lock(&dev->se_port_lock); - atomic_dec(&dev->dev_export_obj.obj_access_count); core_release_port(dev, port); spin_unlock(&dev->se_port_lock); - se_dev_stop(dev); - lun->lun_se_dev = NULL; -} - -int target_report_luns(struct se_cmd *se_cmd) -{ - struct se_dev_entry *deve; - struct se_session *se_sess = se_cmd->se_sess; - unsigned char *buf; - u32 lun_count = 0, offset = 8, i; - - if (se_cmd->data_length < 16) { - pr_warn("REPORT LUNS allocation length %u too small\n", - se_cmd->data_length); - se_cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -EINVAL; - } - - buf = transport_kmap_data_sg(se_cmd); - if (!buf) - return -ENOMEM; - - /* - * If no struct se_session pointer is present, this struct se_cmd is - * coming via a target_core_mod PASSTHROUGH op, and not through - * a $FABRIC_MOD. In that case, report LUN=0 only. - */ - if (!se_sess) { - int_to_scsilun(0, (struct scsi_lun *)&buf[offset]); - lun_count = 1; - goto done; - } - - spin_lock_irq(&se_sess->se_node_acl->device_list_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - deve = se_sess->se_node_acl->device_list[i]; - if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)) - continue; - /* - * We determine the correct LUN LIST LENGTH even once we - * have reached the initial allocation length. - * See SPC2-R20 7.19. - */ - lun_count++; - if ((offset + 8) > se_cmd->data_length) - continue; - - int_to_scsilun(deve->mapped_lun, (struct scsi_lun *)&buf[offset]); - offset += 8; - } - spin_unlock_irq(&se_sess->se_node_acl->device_list_lock); - - /* - * See SPC3 r07, page 159. - */ -done: - lun_count *= 8; - buf[0] = ((lun_count >> 24) & 0xff); - buf[1] = ((lun_count >> 16) & 0xff); - buf[2] = ((lun_count >> 8) & 0xff); - buf[3] = (lun_count & 0xff); - transport_kunmap_data_sg(se_cmd); - - target_complete_cmd(se_cmd, GOOD); - return 0; -} - -/* se_release_device_for_hba(): - * - * - */ -void se_release_device_for_hba(struct se_device *dev) -{ - struct se_hba *hba = dev->se_hba; - - if ((dev->dev_status & TRANSPORT_DEVICE_ACTIVATED) || - (dev->dev_status & TRANSPORT_DEVICE_DEACTIVATED) || - (dev->dev_status & TRANSPORT_DEVICE_SHUTDOWN) || - (dev->dev_status & TRANSPORT_DEVICE_OFFLINE_ACTIVATED) || - (dev->dev_status & TRANSPORT_DEVICE_OFFLINE_DEACTIVATED)) - se_dev_stop(dev); - - if (dev->dev_ptr) { - destroy_workqueue(dev->tmr_wq); - if (dev->transport->free_device) - dev->transport->free_device(dev->dev_ptr); - } - spin_lock(&hba->device_lock); - list_del(&dev->dev_list); - hba->dev_count--; + dev->export_count--; spin_unlock(&hba->device_lock); - core_scsi3_free_all_registrations(dev); - se_release_vpd_for_dev(dev); - - kfree(dev); + lun->lun_se_dev = NULL; } -void se_release_vpd_for_dev(struct se_device *dev) +static void se_release_vpd_for_dev(struct se_device *dev) { struct t10_vpd *vpd, *vpd_tmp; - spin_lock(&dev->se_sub_dev->t10_wwn.t10_vpd_lock); + spin_lock(&dev->t10_wwn.t10_vpd_lock); list_for_each_entry_safe(vpd, vpd_tmp, - &dev->se_sub_dev->t10_wwn.t10_vpd_list, vpd_list) { + &dev->t10_wwn.t10_vpd_list, vpd_list) { list_del(&vpd->vpd_list); kfree(vpd); } - spin_unlock(&dev->se_sub_dev->t10_wwn.t10_vpd_lock); -} - -/* se_free_virtual_device(): - * - * Used for IBLOCK, RAMDISK, and FILEIO Transport Drivers. - */ -int se_free_virtual_device(struct se_device *dev, struct se_hba *hba) -{ - if (!list_empty(&dev->dev_sep_list)) - dump_stack(); - - core_alua_free_lu_gp_mem(dev); - se_release_device_for_hba(dev); - - return 0; -} - -static void se_dev_start(struct se_device *dev) -{ - struct se_hba *hba = dev->se_hba; - - spin_lock(&hba->device_lock); - atomic_inc(&dev->dev_obj.obj_access_count); - if (atomic_read(&dev->dev_obj.obj_access_count) == 1) { - if (dev->dev_status & TRANSPORT_DEVICE_DEACTIVATED) { - dev->dev_status &= ~TRANSPORT_DEVICE_DEACTIVATED; - dev->dev_status |= TRANSPORT_DEVICE_ACTIVATED; - } else if (dev->dev_status & - TRANSPORT_DEVICE_OFFLINE_DEACTIVATED) { - dev->dev_status &= - ~TRANSPORT_DEVICE_OFFLINE_DEACTIVATED; - dev->dev_status |= TRANSPORT_DEVICE_OFFLINE_ACTIVATED; - } - } - spin_unlock(&hba->device_lock); -} - -static void se_dev_stop(struct se_device *dev) -{ - struct se_hba *hba = dev->se_hba; - - spin_lock(&hba->device_lock); - atomic_dec(&dev->dev_obj.obj_access_count); - if (atomic_read(&dev->dev_obj.obj_access_count) == 0) { - if (dev->dev_status & TRANSPORT_DEVICE_ACTIVATED) { - dev->dev_status &= ~TRANSPORT_DEVICE_ACTIVATED; - dev->dev_status |= TRANSPORT_DEVICE_DEACTIVATED; - } else if (dev->dev_status & - TRANSPORT_DEVICE_OFFLINE_ACTIVATED) { - dev->dev_status &= ~TRANSPORT_DEVICE_OFFLINE_ACTIVATED; - dev->dev_status |= TRANSPORT_DEVICE_OFFLINE_DEACTIVATED; - } - } - spin_unlock(&hba->device_lock); -} - -int se_dev_check_online(struct se_device *dev) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&dev->dev_status_lock, flags); - ret = ((dev->dev_status & TRANSPORT_DEVICE_ACTIVATED) || - (dev->dev_status & TRANSPORT_DEVICE_DEACTIVATED)) ? 0 : 1; - spin_unlock_irqrestore(&dev->dev_status_lock, flags); - - return ret; -} - -int se_dev_check_shutdown(struct se_device *dev) -{ - int ret; - - spin_lock_irq(&dev->dev_status_lock); - ret = (dev->dev_status & TRANSPORT_DEVICE_SHUTDOWN); - spin_unlock_irq(&dev->dev_status_lock); - - return ret; + spin_unlock(&dev->t10_wwn.t10_vpd_lock); } static u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size) { - u32 tmp, aligned_max_sectors; + u32 aligned_max_sectors; + u32 alignment; /* * Limit max_sectors to a PAGE_SIZE aligned value for modern * transport_allocate_data_tasks() operation. */ - tmp = rounddown((max_sectors * block_size), PAGE_SIZE); - aligned_max_sectors = (tmp / block_size); - if (max_sectors != aligned_max_sectors) { - printk(KERN_INFO "Rounding down aligned max_sectors from %u" - " to %u\n", max_sectors, aligned_max_sectors); - return aligned_max_sectors; - } - - return max_sectors; -} + alignment = max(1ul, PAGE_SIZE / block_size); + aligned_max_sectors = rounddown(max_sectors, alignment); -void se_dev_set_default_attribs( - struct se_device *dev, - struct se_dev_limits *dev_limits) -{ - struct queue_limits *limits = &dev_limits->limits; - - dev->se_sub_dev->se_dev_attrib.emulate_dpo = DA_EMULATE_DPO; - dev->se_sub_dev->se_dev_attrib.emulate_fua_write = DA_EMULATE_FUA_WRITE; - dev->se_sub_dev->se_dev_attrib.emulate_fua_read = DA_EMULATE_FUA_READ; - dev->se_sub_dev->se_dev_attrib.emulate_write_cache = DA_EMULATE_WRITE_CACHE; - dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl = DA_EMULATE_UA_INTLLCK_CTRL; - dev->se_sub_dev->se_dev_attrib.emulate_tas = DA_EMULATE_TAS; - dev->se_sub_dev->se_dev_attrib.emulate_tpu = DA_EMULATE_TPU; - dev->se_sub_dev->se_dev_attrib.emulate_tpws = DA_EMULATE_TPWS; - dev->se_sub_dev->se_dev_attrib.emulate_reservations = DA_EMULATE_RESERVATIONS; - dev->se_sub_dev->se_dev_attrib.emulate_alua = DA_EMULATE_ALUA; - dev->se_sub_dev->se_dev_attrib.enforce_pr_isids = DA_ENFORCE_PR_ISIDS; - dev->se_sub_dev->se_dev_attrib.is_nonrot = DA_IS_NONROT; - dev->se_sub_dev->se_dev_attrib.emulate_rest_reord = DA_EMULATE_REST_REORD; - /* - * The TPU=1 and TPWS=1 settings will be set in TCM/IBLOCK - * iblock_create_virtdevice() from struct queue_limits values - * if blk_queue_discard()==1 - */ - dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count = DA_MAX_UNMAP_LBA_COUNT; - dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count = - DA_MAX_UNMAP_BLOCK_DESC_COUNT; - dev->se_sub_dev->se_dev_attrib.unmap_granularity = DA_UNMAP_GRANULARITY_DEFAULT; - dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment = - DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT; - /* - * block_size is based on subsystem plugin dependent requirements. - */ - dev->se_sub_dev->se_dev_attrib.hw_block_size = limits->logical_block_size; - dev->se_sub_dev->se_dev_attrib.block_size = limits->logical_block_size; - /* - * Align max_hw_sectors down to PAGE_SIZE I/O transfers - */ - limits->max_hw_sectors = se_dev_align_max_sectors(limits->max_hw_sectors, - limits->logical_block_size); - dev->se_sub_dev->se_dev_attrib.hw_max_sectors = limits->max_hw_sectors; + if (max_sectors != aligned_max_sectors) + pr_info("Rounding down aligned max_sectors from %u to %u\n", + max_sectors, aligned_max_sectors); - /* - * Set fabric_max_sectors, which is reported in block limits - * VPD page (B0h). - */ - dev->se_sub_dev->se_dev_attrib.fabric_max_sectors = DA_FABRIC_MAX_SECTORS; - /* - * Set optimal_sectors from fabric_max_sectors, which can be - * lowered via configfs. - */ - dev->se_sub_dev->se_dev_attrib.optimal_sectors = DA_FABRIC_MAX_SECTORS; - /* - * queue_depth is based on subsystem plugin dependent requirements. - */ - dev->se_sub_dev->se_dev_attrib.hw_queue_depth = dev_limits->hw_queue_depth; - dev->se_sub_dev->se_dev_attrib.queue_depth = dev_limits->queue_depth; + return aligned_max_sectors; } int se_dev_set_max_unmap_lba_count( struct se_device *dev, u32 max_unmap_lba_count) { - dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count = max_unmap_lba_count; + dev->dev_attrib.max_unmap_lba_count = max_unmap_lba_count; pr_debug("dev[%p]: Set max_unmap_lba_count: %u\n", - dev, dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count); + dev, dev->dev_attrib.max_unmap_lba_count); return 0; } @@ -939,10 +676,10 @@ int se_dev_set_max_unmap_block_desc_count( struct se_device *dev, u32 max_unmap_block_desc_count) { - dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count = + dev->dev_attrib.max_unmap_block_desc_count = max_unmap_block_desc_count; pr_debug("dev[%p]: Set max_unmap_block_desc_count: %u\n", - dev, dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count); + dev, dev->dev_attrib.max_unmap_block_desc_count); return 0; } @@ -950,9 +687,9 @@ int se_dev_set_unmap_granularity( struct se_device *dev, u32 unmap_granularity) { - dev->se_sub_dev->se_dev_attrib.unmap_granularity = unmap_granularity; + dev->dev_attrib.unmap_granularity = unmap_granularity; pr_debug("dev[%p]: Set unmap_granularity: %u\n", - dev, dev->se_sub_dev->se_dev_attrib.unmap_granularity); + dev, dev->dev_attrib.unmap_granularity); return 0; } @@ -960,9 +697,19 @@ int se_dev_set_unmap_granularity_alignment( struct se_device *dev, u32 unmap_granularity_alignment) { - dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment = unmap_granularity_alignment; + dev->dev_attrib.unmap_granularity_alignment = unmap_granularity_alignment; pr_debug("dev[%p]: Set unmap_granularity_alignment: %u\n", - dev, dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment); + dev, dev->dev_attrib.unmap_granularity_alignment); + return 0; +} + +int se_dev_set_max_write_same_len( + struct se_device *dev, + u32 max_write_same_len) +{ + dev->dev_attrib.max_write_same_len = max_write_same_len; + pr_debug("dev[%p]: Set max_write_same_len: %u\n", + dev, dev->dev_attrib.max_write_same_len); return 0; } @@ -993,9 +740,9 @@ int se_dev_set_emulate_fua_write(struct se_device *dev, int flag) pr_err("emulate_fua_write not supported for pSCSI\n"); return -EINVAL; } - dev->se_sub_dev->se_dev_attrib.emulate_fua_write = flag; + dev->dev_attrib.emulate_fua_write = flag; pr_debug("dev[%p]: SE Device Forced Unit Access WRITEs: %d\n", - dev, dev->se_sub_dev->se_dev_attrib.emulate_fua_write); + dev, dev->dev_attrib.emulate_fua_write); return 0; } @@ -1025,9 +772,9 @@ int se_dev_set_emulate_write_cache(struct se_device *dev, int flag) pr_err("emulate_write_cache not supported for pSCSI\n"); return -EINVAL; } - dev->se_sub_dev->se_dev_attrib.emulate_write_cache = flag; + dev->dev_attrib.emulate_write_cache = flag; pr_debug("dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n", - dev, dev->se_sub_dev->se_dev_attrib.emulate_write_cache); + dev, dev->dev_attrib.emulate_write_cache); return 0; } @@ -1038,16 +785,15 @@ int se_dev_set_emulate_ua_intlck_ctrl(struct se_device *dev, int flag) return -EINVAL; } - if (atomic_read(&dev->dev_export_obj.obj_access_count)) { + if (dev->export_count) { pr_err("dev[%p]: Unable to change SE Device" - " UA_INTRLCK_CTRL while dev_export_obj: %d count" - " exists\n", dev, - atomic_read(&dev->dev_export_obj.obj_access_count)); + " UA_INTRLCK_CTRL while export_count is %d\n", + dev, dev->export_count); return -EINVAL; } - dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl = flag; + dev->dev_attrib.emulate_ua_intlck_ctrl = flag; pr_debug("dev[%p]: SE Device UA_INTRLCK_CTRL flag: %d\n", - dev, dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl); + dev, dev->dev_attrib.emulate_ua_intlck_ctrl); return 0; } @@ -1059,15 +805,15 @@ int se_dev_set_emulate_tas(struct se_device *dev, int flag) return -EINVAL; } - if (atomic_read(&dev->dev_export_obj.obj_access_count)) { + if (dev->export_count) { pr_err("dev[%p]: Unable to change SE Device TAS while" - " dev_export_obj: %d count exists\n", dev, - atomic_read(&dev->dev_export_obj.obj_access_count)); + " export_count is %d\n", + dev, dev->export_count); return -EINVAL; } - dev->se_sub_dev->se_dev_attrib.emulate_tas = flag; + dev->dev_attrib.emulate_tas = flag; pr_debug("dev[%p]: SE Device TASK_ABORTED status bit: %s\n", - dev, (dev->se_sub_dev->se_dev_attrib.emulate_tas) ? "Enabled" : "Disabled"); + dev, (dev->dev_attrib.emulate_tas) ? "Enabled" : "Disabled"); return 0; } @@ -1082,12 +828,12 @@ int se_dev_set_emulate_tpu(struct se_device *dev, int flag) * We expect this value to be non-zero when generic Block Layer * Discard supported is detected iblock_create_virtdevice(). */ - if (flag && !dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) { + if (flag && !dev->dev_attrib.max_unmap_block_desc_count) { pr_err("Generic Block Discard not supported\n"); return -ENOSYS; } - dev->se_sub_dev->se_dev_attrib.emulate_tpu = flag; + dev->dev_attrib.emulate_tpu = flag; pr_debug("dev[%p]: SE Device Thin Provisioning UNMAP bit: %d\n", dev, flag); return 0; @@ -1103,12 +849,12 @@ int se_dev_set_emulate_tpws(struct se_device *dev, int flag) * We expect this value to be non-zero when generic Block Layer * Discard supported is detected iblock_create_virtdevice(). */ - if (flag && !dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) { + if (flag && !dev->dev_attrib.max_unmap_block_desc_count) { pr_err("Generic Block Discard not supported\n"); return -ENOSYS; } - dev->se_sub_dev->se_dev_attrib.emulate_tpws = flag; + dev->dev_attrib.emulate_tpws = flag; pr_debug("dev[%p]: SE Device Thin Provisioning WRITE_SAME: %d\n", dev, flag); return 0; @@ -1120,9 +866,9 @@ int se_dev_set_enforce_pr_isids(struct se_device *dev, int flag) pr_err("Illegal value %d\n", flag); return -EINVAL; } - dev->se_sub_dev->se_dev_attrib.enforce_pr_isids = flag; + dev->dev_attrib.enforce_pr_isids = flag; pr_debug("dev[%p]: SE Device enforce_pr_isids bit: %s\n", dev, - (dev->se_sub_dev->se_dev_attrib.enforce_pr_isids) ? "Enabled" : "Disabled"); + (dev->dev_attrib.enforce_pr_isids) ? "Enabled" : "Disabled"); return 0; } @@ -1132,7 +878,7 @@ int se_dev_set_is_nonrot(struct se_device *dev, int flag) printk(KERN_ERR "Illegal value %d\n", flag); return -EINVAL; } - dev->se_sub_dev->se_dev_attrib.is_nonrot = flag; + dev->dev_attrib.is_nonrot = flag; pr_debug("dev[%p]: SE Device is_nonrot bit: %d\n", dev, flag); return 0; @@ -1145,7 +891,7 @@ int se_dev_set_emulate_rest_reord(struct se_device *dev, int flag) " reordering not implemented\n", dev); return -ENOSYS; } - dev->se_sub_dev->se_dev_attrib.emulate_rest_reord = flag; + dev->dev_attrib.emulate_rest_reord = flag; pr_debug("dev[%p]: SE Device emulate_rest_reord: %d\n", dev, flag); return 0; } @@ -1155,10 +901,10 @@ int se_dev_set_emulate_rest_reord(struct se_device *dev, int flag) */ int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth) { - if (atomic_read(&dev->dev_export_obj.obj_access_count)) { + if (dev->export_count) { pr_err("dev[%p]: Unable to change SE Device TCQ while" - " dev_export_obj: %d count exists\n", dev, - atomic_read(&dev->dev_export_obj.obj_access_count)); + " export_count is %d\n", + dev, dev->export_count); return -EINVAL; } if (!queue_depth) { @@ -1168,26 +914,26 @@ int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth) } if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) { - if (queue_depth > dev->se_sub_dev->se_dev_attrib.hw_queue_depth) { + if (queue_depth > dev->dev_attrib.hw_queue_depth) { pr_err("dev[%p]: Passed queue_depth: %u" " exceeds TCM/SE_Device TCQ: %u\n", dev, queue_depth, - dev->se_sub_dev->se_dev_attrib.hw_queue_depth); + dev->dev_attrib.hw_queue_depth); return -EINVAL; } } else { - if (queue_depth > dev->se_sub_dev->se_dev_attrib.queue_depth) { - if (queue_depth > dev->se_sub_dev->se_dev_attrib.hw_queue_depth) { + if (queue_depth > dev->dev_attrib.queue_depth) { + if (queue_depth > dev->dev_attrib.hw_queue_depth) { pr_err("dev[%p]: Passed queue_depth:" " %u exceeds TCM/SE_Device MAX" " TCQ: %u\n", dev, queue_depth, - dev->se_sub_dev->se_dev_attrib.hw_queue_depth); + dev->dev_attrib.hw_queue_depth); return -EINVAL; } } } - dev->se_sub_dev->se_dev_attrib.queue_depth = dev->queue_depth = queue_depth; + dev->dev_attrib.queue_depth = dev->queue_depth = queue_depth; pr_debug("dev[%p]: SE Device TCQ Depth changed to: %u\n", dev, queue_depth); return 0; @@ -1195,10 +941,10 @@ int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth) int se_dev_set_fabric_max_sectors(struct se_device *dev, u32 fabric_max_sectors) { - if (atomic_read(&dev->dev_export_obj.obj_access_count)) { + if (dev->export_count) { pr_err("dev[%p]: Unable to change SE Device" - " fabric_max_sectors while dev_export_obj: %d count exists\n", - dev, atomic_read(&dev->dev_export_obj.obj_access_count)); + " fabric_max_sectors while export_count is %d\n", + dev, dev->export_count); return -EINVAL; } if (!fabric_max_sectors) { @@ -1213,11 +959,11 @@ int se_dev_set_fabric_max_sectors(struct se_device *dev, u32 fabric_max_sectors) return -EINVAL; } if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) { - if (fabric_max_sectors > dev->se_sub_dev->se_dev_attrib.hw_max_sectors) { + if (fabric_max_sectors > dev->dev_attrib.hw_max_sectors) { pr_err("dev[%p]: Passed fabric_max_sectors: %u" " greater than TCM/SE_Device max_sectors:" " %u\n", dev, fabric_max_sectors, - dev->se_sub_dev->se_dev_attrib.hw_max_sectors); + dev->dev_attrib.hw_max_sectors); return -EINVAL; } } else { @@ -1233,9 +979,9 @@ int se_dev_set_fabric_max_sectors(struct se_device *dev, u32 fabric_max_sectors) * Align max_sectors down to PAGE_SIZE to follow transport_allocate_data_tasks() */ fabric_max_sectors = se_dev_align_max_sectors(fabric_max_sectors, - dev->se_sub_dev->se_dev_attrib.block_size); + dev->dev_attrib.block_size); - dev->se_sub_dev->se_dev_attrib.fabric_max_sectors = fabric_max_sectors; + dev->dev_attrib.fabric_max_sectors = fabric_max_sectors; pr_debug("dev[%p]: SE Device max_sectors changed to %u\n", dev, fabric_max_sectors); return 0; @@ -1243,10 +989,10 @@ int se_dev_set_fabric_max_sectors(struct se_device *dev, u32 fabric_max_sectors) int se_dev_set_optimal_sectors(struct se_device *dev, u32 optimal_sectors) { - if (atomic_read(&dev->dev_export_obj.obj_access_count)) { + if (dev->export_count) { pr_err("dev[%p]: Unable to change SE Device" - " optimal_sectors while dev_export_obj: %d count exists\n", - dev, atomic_read(&dev->dev_export_obj.obj_access_count)); + " optimal_sectors while export_count is %d\n", + dev, dev->export_count); return -EINVAL; } if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) { @@ -1254,14 +1000,14 @@ int se_dev_set_optimal_sectors(struct se_device *dev, u32 optimal_sectors) " changed for TCM/pSCSI\n", dev); return -EINVAL; } - if (optimal_sectors > dev->se_sub_dev->se_dev_attrib.fabric_max_sectors) { + if (optimal_sectors > dev->dev_attrib.fabric_max_sectors) { pr_err("dev[%p]: Passed optimal_sectors %u cannot be" " greater than fabric_max_sectors: %u\n", dev, - optimal_sectors, dev->se_sub_dev->se_dev_attrib.fabric_max_sectors); + optimal_sectors, dev->dev_attrib.fabric_max_sectors); return -EINVAL; } - dev->se_sub_dev->se_dev_attrib.optimal_sectors = optimal_sectors; + dev->dev_attrib.optimal_sectors = optimal_sectors; pr_debug("dev[%p]: SE Device optimal_sectors changed to %u\n", dev, optimal_sectors); return 0; @@ -1269,10 +1015,10 @@ int se_dev_set_optimal_sectors(struct se_device *dev, u32 optimal_sectors) int se_dev_set_block_size(struct se_device *dev, u32 block_size) { - if (atomic_read(&dev->dev_export_obj.obj_access_count)) { + if (dev->export_count) { pr_err("dev[%p]: Unable to change SE Device block_size" - " while dev_export_obj: %d count exists\n", dev, - atomic_read(&dev->dev_export_obj.obj_access_count)); + " while export_count is %d\n", + dev, dev->export_count); return -EINVAL; } @@ -1293,7 +1039,7 @@ int se_dev_set_block_size(struct se_device *dev, u32 block_size) return -EINVAL; } - dev->se_sub_dev->se_dev_attrib.block_size = block_size; + dev->dev_attrib.block_size = block_size; pr_debug("dev[%p]: SE Device block_size changed to %u\n", dev, block_size); return 0; @@ -1307,12 +1053,6 @@ struct se_lun *core_dev_add_lun( struct se_lun *lun_p; int rc; - if (atomic_read(&dev->dev_access_obj.obj_access_count) != 0) { - pr_err("Unable to export struct se_device while dev_access_obj: %d\n", - atomic_read(&dev->dev_access_obj.obj_access_count)); - return ERR_PTR(-EACCES); - } - lun_p = core_tpg_pre_addlun(tpg, lun); if (IS_ERR(lun_p)) return lun_p; @@ -1568,12 +1308,211 @@ void core_dev_free_initiator_node_lun_acl( kfree(lacl); } +static void scsi_dump_inquiry(struct se_device *dev) +{ + struct t10_wwn *wwn = &dev->t10_wwn; + char buf[17]; + int i, device_type; + /* + * Print Linux/SCSI style INQUIRY formatting to the kernel ring buffer + */ + for (i = 0; i < 8; i++) + if (wwn->vendor[i] >= 0x20) + buf[i] = wwn->vendor[i]; + else + buf[i] = ' '; + buf[i] = '\0'; + pr_debug(" Vendor: %s\n", buf); + + for (i = 0; i < 16; i++) + if (wwn->model[i] >= 0x20) + buf[i] = wwn->model[i]; + else + buf[i] = ' '; + buf[i] = '\0'; + pr_debug(" Model: %s\n", buf); + + for (i = 0; i < 4; i++) + if (wwn->revision[i] >= 0x20) + buf[i] = wwn->revision[i]; + else + buf[i] = ' '; + buf[i] = '\0'; + pr_debug(" Revision: %s\n", buf); + + device_type = dev->transport->get_device_type(dev); + pr_debug(" Type: %s ", scsi_device_type(device_type)); +} + +struct se_device *target_alloc_device(struct se_hba *hba, const char *name) +{ + struct se_device *dev; + + dev = hba->transport->alloc_device(hba, name); + if (!dev) + return NULL; + + dev->dev_link_magic = SE_DEV_LINK_MAGIC; + dev->se_hba = hba; + dev->transport = hba->transport; + + INIT_LIST_HEAD(&dev->dev_list); + INIT_LIST_HEAD(&dev->dev_sep_list); + INIT_LIST_HEAD(&dev->dev_tmr_list); + INIT_LIST_HEAD(&dev->delayed_cmd_list); + INIT_LIST_HEAD(&dev->state_list); + INIT_LIST_HEAD(&dev->qf_cmd_list); + spin_lock_init(&dev->stats_lock); + spin_lock_init(&dev->execute_task_lock); + spin_lock_init(&dev->delayed_cmd_lock); + spin_lock_init(&dev->dev_reservation_lock); + spin_lock_init(&dev->se_port_lock); + spin_lock_init(&dev->se_tmr_lock); + spin_lock_init(&dev->qf_cmd_lock); + atomic_set(&dev->dev_ordered_id, 0); + INIT_LIST_HEAD(&dev->t10_wwn.t10_vpd_list); + spin_lock_init(&dev->t10_wwn.t10_vpd_lock); + INIT_LIST_HEAD(&dev->t10_pr.registration_list); + INIT_LIST_HEAD(&dev->t10_pr.aptpl_reg_list); + spin_lock_init(&dev->t10_pr.registration_lock); + spin_lock_init(&dev->t10_pr.aptpl_reg_lock); + INIT_LIST_HEAD(&dev->t10_alua.tg_pt_gps_list); + spin_lock_init(&dev->t10_alua.tg_pt_gps_lock); + + dev->t10_pr.pr_aptpl_buf_len = PR_APTPL_BUF_LEN; + dev->t10_wwn.t10_dev = dev; + dev->t10_alua.t10_dev = dev; + + dev->dev_attrib.da_dev = dev; + dev->dev_attrib.emulate_dpo = DA_EMULATE_DPO; + dev->dev_attrib.emulate_fua_write = DA_EMULATE_FUA_WRITE; + dev->dev_attrib.emulate_fua_read = DA_EMULATE_FUA_READ; + dev->dev_attrib.emulate_write_cache = DA_EMULATE_WRITE_CACHE; + dev->dev_attrib.emulate_ua_intlck_ctrl = DA_EMULATE_UA_INTLLCK_CTRL; + dev->dev_attrib.emulate_tas = DA_EMULATE_TAS; + dev->dev_attrib.emulate_tpu = DA_EMULATE_TPU; + dev->dev_attrib.emulate_tpws = DA_EMULATE_TPWS; + dev->dev_attrib.enforce_pr_isids = DA_ENFORCE_PR_ISIDS; + dev->dev_attrib.is_nonrot = DA_IS_NONROT; + dev->dev_attrib.emulate_rest_reord = DA_EMULATE_REST_REORD; + dev->dev_attrib.max_unmap_lba_count = DA_MAX_UNMAP_LBA_COUNT; + dev->dev_attrib.max_unmap_block_desc_count = + DA_MAX_UNMAP_BLOCK_DESC_COUNT; + dev->dev_attrib.unmap_granularity = DA_UNMAP_GRANULARITY_DEFAULT; + dev->dev_attrib.unmap_granularity_alignment = + DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT; + dev->dev_attrib.max_write_same_len = DA_MAX_WRITE_SAME_LEN; + dev->dev_attrib.fabric_max_sectors = DA_FABRIC_MAX_SECTORS; + dev->dev_attrib.optimal_sectors = DA_FABRIC_MAX_SECTORS; + + return dev; +} + +int target_configure_device(struct se_device *dev) +{ + struct se_hba *hba = dev->se_hba; + int ret; + + if (dev->dev_flags & DF_CONFIGURED) { + pr_err("se_dev->se_dev_ptr already set for storage" + " object\n"); + return -EEXIST; + } + + ret = dev->transport->configure_device(dev); + if (ret) + goto out; + dev->dev_flags |= DF_CONFIGURED; + + /* + * XXX: there is not much point to have two different values here.. + */ + dev->dev_attrib.block_size = dev->dev_attrib.hw_block_size; + dev->dev_attrib.queue_depth = dev->dev_attrib.hw_queue_depth; + + /* + * Align max_hw_sectors down to PAGE_SIZE I/O transfers + */ + dev->dev_attrib.hw_max_sectors = + se_dev_align_max_sectors(dev->dev_attrib.hw_max_sectors, + dev->dev_attrib.hw_block_size); + + dev->dev_index = scsi_get_new_index(SCSI_DEVICE_INDEX); + dev->creation_time = get_jiffies_64(); + + ret = core_setup_alua(dev); + if (ret) + goto out; + + /* + * Startup the struct se_device processing thread + */ + 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); + ret = -ENOMEM; + goto out_free_alua; + } + + /* + * Setup work_queue for QUEUE_FULL + */ + INIT_WORK(&dev->qf_work_queue, target_qf_do_work); + + /* + * Preload the initial INQUIRY const values if we are doing + * anything virtual (IBLOCK, FILEIO, RAMDISK), but not for TCM/pSCSI + * passthrough because this is being provided by the backend LLD. + */ + if (dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) { + strncpy(&dev->t10_wwn.vendor[0], "LIO-ORG", 8); + strncpy(&dev->t10_wwn.model[0], + dev->transport->inquiry_prod, 16); + strncpy(&dev->t10_wwn.revision[0], + dev->transport->inquiry_rev, 4); + } + + scsi_dump_inquiry(dev); + + spin_lock(&hba->device_lock); + hba->dev_count++; + spin_unlock(&hba->device_lock); + return 0; + +out_free_alua: + core_alua_free_lu_gp_mem(dev); +out: + se_release_vpd_for_dev(dev); + return ret; +} + +void target_free_device(struct se_device *dev) +{ + struct se_hba *hba = dev->se_hba; + + WARN_ON(!list_empty(&dev->dev_sep_list)); + + if (dev->dev_flags & DF_CONFIGURED) { + destroy_workqueue(dev->tmr_wq); + + spin_lock(&hba->device_lock); + hba->dev_count--; + spin_unlock(&hba->device_lock); + } + + core_alua_free_lu_gp_mem(dev); + core_scsi3_free_all_registrations(dev); + se_release_vpd_for_dev(dev); + + dev->transport->free_device(dev); +} + int core_dev_setup_virtual_lun0(void) { struct se_hba *hba; struct se_device *dev; - struct se_subsystem_dev *se_dev = NULL; - struct se_subsystem_api *t; char buf[16]; int ret; @@ -1581,60 +1520,28 @@ int core_dev_setup_virtual_lun0(void) if (IS_ERR(hba)) return PTR_ERR(hba); - lun0_hba = hba; - t = hba->transport; - - se_dev = kzalloc(sizeof(struct se_subsystem_dev), GFP_KERNEL); - if (!se_dev) { - pr_err("Unable to allocate memory for" - " struct se_subsystem_dev\n"); + dev = target_alloc_device(hba, "virt_lun0"); + if (!dev) { ret = -ENOMEM; - goto out; + goto out_free_hba; } - INIT_LIST_HEAD(&se_dev->t10_wwn.t10_vpd_list); - spin_lock_init(&se_dev->t10_wwn.t10_vpd_lock); - INIT_LIST_HEAD(&se_dev->t10_pr.registration_list); - INIT_LIST_HEAD(&se_dev->t10_pr.aptpl_reg_list); - spin_lock_init(&se_dev->t10_pr.registration_lock); - spin_lock_init(&se_dev->t10_pr.aptpl_reg_lock); - INIT_LIST_HEAD(&se_dev->t10_alua.tg_pt_gps_list); - spin_lock_init(&se_dev->t10_alua.tg_pt_gps_lock); - spin_lock_init(&se_dev->se_dev_lock); - se_dev->t10_pr.pr_aptpl_buf_len = PR_APTPL_BUF_LEN; - se_dev->t10_wwn.t10_sub_dev = se_dev; - se_dev->t10_alua.t10_sub_dev = se_dev; - se_dev->se_dev_attrib.da_sub_dev = se_dev; - se_dev->se_dev_hba = hba; - - se_dev->se_dev_su_ptr = t->allocate_virtdevice(hba, "virt_lun0"); - if (!se_dev->se_dev_su_ptr) { - pr_err("Unable to locate subsystem dependent pointer" - " from allocate_virtdevice()\n"); - ret = -ENOMEM; - goto out; - } - lun0_su_dev = se_dev; memset(buf, 0, 16); sprintf(buf, "rd_pages=8"); - t->set_configfs_dev_params(hba, se_dev, buf, sizeof(buf)); + hba->transport->set_configfs_dev_params(dev, buf, sizeof(buf)); - dev = t->create_virtdevice(hba, se_dev, se_dev->se_dev_su_ptr); - if (IS_ERR(dev)) { - ret = PTR_ERR(dev); - goto out; - } - se_dev->se_dev_ptr = dev; - g_lun0_dev = dev; + ret = target_configure_device(dev); + if (ret) + goto out_free_se_dev; + lun0_hba = hba; + g_lun0_dev = dev; return 0; -out: - lun0_su_dev = NULL; - kfree(se_dev); - if (lun0_hba) { - core_delete_hba(lun0_hba); - lun0_hba = NULL; - } + +out_free_se_dev: + target_free_device(dev); +out_free_hba: + core_delete_hba(hba); return ret; } @@ -1642,14 +1549,11 @@ out: void core_dev_release_virtual_lun0(void) { struct se_hba *hba = lun0_hba; - struct se_subsystem_dev *su_dev = lun0_su_dev; if (!hba) return; if (g_lun0_dev) - se_free_virtual_device(g_lun0_dev, hba); - - kfree(su_dev); + target_free_device(g_lun0_dev); core_delete_hba(hba); } diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index bca737bb813d..810263dfa4a1 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -4,10 +4,9 @@ * This file contains generic fabric module configfs infrastructure for * TCM v4.x code * - * Copyright (c) 2010,2011 Rising Tide Systems - * Copyright (c) 2010,2011 Linux-iSCSI.org + * (c) Copyright 2010-2012 RisingTide Systems LLC. * - * Copyright (c) Nicholas A. Bellinger <nab@linux-iscsi.org> + * Nicholas A. Bellinger <nab@linux-iscsi.org> * * 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 @@ -71,6 +70,12 @@ static int target_fabric_mappedlun_link( struct se_portal_group *se_tpg; struct config_item *nacl_ci, *tpg_ci, *tpg_ci_s, *wwn_ci, *wwn_ci_s; int ret = 0, lun_access; + + if (lun->lun_link_magic != SE_LUN_LINK_MAGIC) { + pr_err("Bad lun->lun_link_magic, not a valid lun_ci pointer:" + " %p to struct lun: %p\n", lun_ci, lun); + return -EFAULT; + } /* * Ensure that the source port exists */ @@ -358,7 +363,7 @@ static struct config_group *target_fabric_make_mappedlun( } lacl_cg = &lacl->se_lun_group; - lacl_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, + lacl_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, GFP_KERNEL); if (!lacl_cg->default_groups) { pr_err("Unable to allocate lacl_cg->default_groups\n"); @@ -374,7 +379,7 @@ static struct config_group *target_fabric_make_mappedlun( lacl_cg->default_groups[1] = NULL; ml_stat_grp = &lacl->ml_stat_grps.stat_group; - ml_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 3, + ml_stat_grp->default_groups = kmalloc(sizeof(struct config_group *) * 3, GFP_KERNEL); if (!ml_stat_grp->default_groups) { pr_err("Unable to allocate ml_stat_grp->default_groups\n"); @@ -734,17 +739,21 @@ static int target_fabric_port_link( struct config_item *se_dev_ci) { struct config_item *tpg_ci; - struct se_device *dev; struct se_lun *lun = container_of(to_config_group(lun_ci), struct se_lun, lun_group); struct se_lun *lun_p; struct se_portal_group *se_tpg; - struct se_subsystem_dev *se_dev = container_of( - to_config_group(se_dev_ci), struct se_subsystem_dev, - se_dev_group); + struct se_device *dev = + container_of(to_config_group(se_dev_ci), struct se_device, dev_group); struct target_fabric_configfs *tf; int ret; + if (dev->dev_link_magic != SE_DEV_LINK_MAGIC) { + pr_err("Bad dev->dev_link_magic, not a valid se_dev_ci pointer:" + " %p to struct se_device: %p\n", se_dev_ci, dev); + return -EFAULT; + } + tpg_ci = &lun_ci->ci_parent->ci_group->cg_item; se_tpg = container_of(to_config_group(tpg_ci), struct se_portal_group, tpg_group); @@ -755,14 +764,6 @@ static int target_fabric_port_link( return -EEXIST; } - dev = se_dev->se_dev_ptr; - if (!dev) { - pr_err("Unable to locate struct se_device pointer from" - " %s\n", config_item_name(se_dev_ci)); - ret = -ENODEV; - goto out; - } - 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"); @@ -869,7 +870,7 @@ static struct config_group *target_fabric_make_lun( return ERR_PTR(-EINVAL); lun_cg = &lun->lun_group; - lun_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, + lun_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, GFP_KERNEL); if (!lun_cg->default_groups) { pr_err("Unable to allocate lun_cg->default_groups\n"); diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index e460d6233a0a..687b0b0a4aa6 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -4,8 +4,7 @@ * This file contains generic high level protocol identifier and PR * handlers for TCM fabric modules * - * Copyright (c) 2010 Rising Tide Systems, Inc. - * Copyright (c) 2010 Linux-iSCSI.org + * (c) Copyright 2010-2012 RisingTide Systems LLC. * * Nicholas A. Bellinger <nab@linux-iscsi.org> * diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 0360383dfb94..b9c88497e8f0 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -3,10 +3,7 @@ * * This file contains the Storage Engine <-> FILEIO transport specific functions * - * Copyright (c) 2005 PyX Technologies, Inc. - * Copyright (c) 2005-2006 SBE, Inc. All Rights Reserved. - * Copyright (c) 2007-2010 Rising Tide Systems - * Copyright (c) 2008-2010 Linux-iSCSI.org + * (c) Copyright 2005-2012 RisingTide Systems LLC. * * Nicholas A. Bellinger <nab@kernel.org> * @@ -41,7 +38,10 @@ #include "target_core_file.h" -static struct se_subsystem_api fileio_template; +static inline struct fd_dev *FD_DEV(struct se_device *dev) +{ + return container_of(dev, struct fd_dev, dev); +} /* fd_attach_hba(): (Part of se_subsystem_api_t template) * @@ -82,7 +82,7 @@ static void fd_detach_hba(struct se_hba *hba) hba->hba_ptr = NULL; } -static void *fd_allocate_virtdevice(struct se_hba *hba, const char *name) +static struct se_device *fd_alloc_device(struct se_hba *hba, const char *name) { struct fd_dev *fd_dev; struct fd_host *fd_host = hba->hba_ptr; @@ -97,34 +97,28 @@ static void *fd_allocate_virtdevice(struct se_hba *hba, const char *name) pr_debug("FILEIO: Allocated fd_dev for %p\n", name); - return fd_dev; + return &fd_dev->dev; } -/* fd_create_virtdevice(): (Part of se_subsystem_api_t template) - * - * - */ -static struct se_device *fd_create_virtdevice( - struct se_hba *hba, - struct se_subsystem_dev *se_dev, - void *p) +static int fd_configure_device(struct se_device *dev) { - struct se_device *dev; - struct se_dev_limits dev_limits; - struct queue_limits *limits; - struct fd_dev *fd_dev = p; - struct fd_host *fd_host = hba->hba_ptr; + struct fd_dev *fd_dev = FD_DEV(dev); + struct fd_host *fd_host = dev->se_hba->hba_ptr; struct file *file; struct inode *inode = NULL; - int dev_flags = 0, flags, ret = -EINVAL; + int flags, ret = -EINVAL; - memset(&dev_limits, 0, sizeof(struct se_dev_limits)); + if (!(fd_dev->fbd_flags & FBDF_HAS_PATH)) { + pr_err("Missing fd_dev_name=\n"); + return -EINVAL; + } /* * Use O_DSYNC by default instead of O_SYNC to forgo syncing * of pure timestamp updates. */ flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC; + /* * Optionally allow fd_buffered_io=1 to be enabled for people * who want use the fs buffer cache as an WriteCache mechanism. @@ -154,22 +148,17 @@ static struct se_device *fd_create_virtdevice( */ inode = file->f_mapping->host; if (S_ISBLK(inode->i_mode)) { - struct request_queue *q; + struct request_queue *q = bdev_get_queue(inode->i_bdev); unsigned long long dev_size; - /* - * Setup the local scope queue_limits from struct request_queue->limits - * to pass into transport_add_device_to_core_hba() as struct se_dev_limits. - */ - q = bdev_get_queue(inode->i_bdev); - limits = &dev_limits.limits; - limits->logical_block_size = bdev_logical_block_size(inode->i_bdev); - limits->max_hw_sectors = queue_max_hw_sectors(q); - limits->max_sectors = queue_max_sectors(q); + + dev->dev_attrib.hw_block_size = + bdev_logical_block_size(inode->i_bdev); + dev->dev_attrib.hw_max_sectors = queue_max_hw_sectors(q); + /* * Determine the number of bytes from i_size_read() minus * one (1) logical sector from underlying struct block_device */ - fd_dev->fd_block_size = bdev_logical_block_size(inode->i_bdev); dev_size = (i_size_read(file->f_mapping->host) - fd_dev->fd_block_size); @@ -185,26 +174,18 @@ static struct se_device *fd_create_virtdevice( goto fail; } - limits = &dev_limits.limits; - limits->logical_block_size = FD_BLOCKSIZE; - limits->max_hw_sectors = FD_MAX_SECTORS; - limits->max_sectors = FD_MAX_SECTORS; - fd_dev->fd_block_size = FD_BLOCKSIZE; + dev->dev_attrib.hw_block_size = FD_BLOCKSIZE; + dev->dev_attrib.hw_max_sectors = FD_MAX_SECTORS; } - dev_limits.hw_queue_depth = FD_MAX_DEVICE_QUEUE_DEPTH; - dev_limits.queue_depth = FD_DEVICE_QUEUE_DEPTH; + fd_dev->fd_block_size = dev->dev_attrib.hw_block_size; - dev = transport_add_device_to_core_hba(hba, &fileio_template, - se_dev, dev_flags, fd_dev, - &dev_limits, "FILEIO", FD_VERSION); - if (!dev) - goto fail; + dev->dev_attrib.hw_queue_depth = FD_MAX_DEVICE_QUEUE_DEPTH; if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) { pr_debug("FILEIO: Forcing setting of emulate_write_cache=1" " with FDBD_HAS_BUFFERED_IO_WCE\n"); - dev->se_sub_dev->se_dev_attrib.emulate_write_cache = 1; + dev->dev_attrib.emulate_write_cache = 1; } fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++; @@ -214,22 +195,18 @@ static struct se_device *fd_create_virtdevice( " %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id, fd_dev->fd_dev_name, fd_dev->fd_dev_size); - return dev; + return 0; fail: if (fd_dev->fd_file) { filp_close(fd_dev->fd_file, NULL); fd_dev->fd_file = NULL; } - return ERR_PTR(ret); + return ret; } -/* fd_free_device(): (Part of se_subsystem_api_t template) - * - * - */ -static void fd_free_device(void *p) +static void fd_free_device(struct se_device *dev) { - struct fd_dev *fd_dev = p; + struct fd_dev *fd_dev = FD_DEV(dev); if (fd_dev->fd_file) { filp_close(fd_dev->fd_file, NULL); @@ -239,17 +216,16 @@ static void fd_free_device(void *p) kfree(fd_dev); } -static int fd_do_readv(struct se_cmd *cmd, struct scatterlist *sgl, - u32 sgl_nents) +static int fd_do_rw(struct se_cmd *cmd, struct scatterlist *sgl, + u32 sgl_nents, int is_write) { struct se_device *se_dev = cmd->se_dev; - struct fd_dev *dev = se_dev->dev_ptr; + struct fd_dev *dev = FD_DEV(se_dev); struct file *fd = dev->fd_file; struct scatterlist *sg; struct iovec *iov; mm_segment_t old_fs; - loff_t pos = (cmd->t_task_lba * - se_dev->se_sub_dev->se_dev_attrib.block_size); + loff_t pos = (cmd->t_task_lba * se_dev->dev_attrib.block_size); int ret = 0, i; iov = kzalloc(sizeof(struct iovec) * sgl_nents, GFP_KERNEL); @@ -260,81 +236,58 @@ static int fd_do_readv(struct se_cmd *cmd, struct scatterlist *sgl, for_each_sg(sgl, sg, sgl_nents, i) { iov[i].iov_len = sg->length; - iov[i].iov_base = sg_virt(sg); + iov[i].iov_base = kmap(sg_page(sg)) + sg->offset; } old_fs = get_fs(); set_fs(get_ds()); - ret = vfs_readv(fd, &iov[0], sgl_nents, &pos); + + if (is_write) + ret = vfs_writev(fd, &iov[0], sgl_nents, &pos); + else + ret = vfs_readv(fd, &iov[0], sgl_nents, &pos); + set_fs(old_fs); + for_each_sg(sgl, sg, sgl_nents, i) + kunmap(sg_page(sg)); + kfree(iov); - /* - * Return zeros and GOOD status even if the READ did not return - * the expected virt_size for struct file w/o a backing struct - * block_device. - */ - if (S_ISBLK(fd->f_dentry->d_inode->i_mode)) { + + if (is_write) { if (ret < 0 || ret != cmd->data_length) { - pr_err("vfs_readv() returned %d," - " expecting %d for S_ISBLK\n", ret, - (int)cmd->data_length); + pr_err("%s() write returned %d\n", __func__, ret); return (ret < 0 ? ret : -EINVAL); } } else { - if (ret < 0) { - pr_err("vfs_readv() returned %d for non" - " S_ISBLK\n", ret); - return ret; + /* + * Return zeros and GOOD status even if the READ did not return + * the expected virt_size for struct file w/o a backing struct + * block_device. + */ + if (S_ISBLK(fd->f_dentry->d_inode->i_mode)) { + if (ret < 0 || ret != cmd->data_length) { + pr_err("%s() returned %d, expecting %u for " + "S_ISBLK\n", __func__, ret, + cmd->data_length); + return (ret < 0 ? ret : -EINVAL); + } + } else { + if (ret < 0) { + pr_err("%s() returned %d for non S_ISBLK\n", + __func__, ret); + return ret; + } } } - - return 1; -} - -static int fd_do_writev(struct se_cmd *cmd, struct scatterlist *sgl, - u32 sgl_nents) -{ - struct se_device *se_dev = cmd->se_dev; - struct fd_dev *dev = se_dev->dev_ptr; - struct file *fd = dev->fd_file; - struct scatterlist *sg; - struct iovec *iov; - mm_segment_t old_fs; - loff_t pos = (cmd->t_task_lba * - se_dev->se_sub_dev->se_dev_attrib.block_size); - int ret, i = 0; - - iov = kzalloc(sizeof(struct iovec) * sgl_nents, GFP_KERNEL); - if (!iov) { - pr_err("Unable to allocate fd_do_writev iov[]\n"); - return -ENOMEM; - } - - for_each_sg(sgl, sg, sgl_nents, i) { - iov[i].iov_len = sg->length; - iov[i].iov_base = sg_virt(sg); - } - - old_fs = get_fs(); - set_fs(get_ds()); - ret = vfs_writev(fd, &iov[0], sgl_nents, &pos); - set_fs(old_fs); - - kfree(iov); - - if (ret < 0 || ret != cmd->data_length) { - pr_err("vfs_writev() returned %d\n", ret); - return (ret < 0 ? ret : -EINVAL); - } - return 1; } -static int fd_execute_sync_cache(struct se_cmd *cmd) +static sense_reason_t +fd_execute_sync_cache(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - struct fd_dev *fd_dev = dev->dev_ptr; + struct fd_dev *fd_dev = FD_DEV(dev); int immed = (cmd->t_task_cdb[1] & 0x2); loff_t start, end; int ret; @@ -353,7 +306,7 @@ static int fd_execute_sync_cache(struct se_cmd *cmd) start = 0; end = LLONG_MAX; } else { - start = cmd->t_task_lba * dev->se_sub_dev->se_dev_attrib.block_size; + start = cmd->t_task_lba * dev->dev_attrib.block_size; if (cmd->data_length) end = start + cmd->data_length; else @@ -367,17 +320,16 @@ static int fd_execute_sync_cache(struct se_cmd *cmd) if (immed) return 0; - if (ret) { - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + if (ret) target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION); - } else { + else target_complete_cmd(cmd, SAM_STAT_GOOD); - } return 0; } -static int fd_execute_rw(struct se_cmd *cmd) +static sense_reason_t +fd_execute_rw(struct se_cmd *cmd) { struct scatterlist *sgl = cmd->t_data_sg; u32 sgl_nents = cmd->t_data_nents; @@ -390,30 +342,29 @@ static int fd_execute_rw(struct se_cmd *cmd) * physical memory addresses to struct iovec virtual memory. */ if (data_direction == DMA_FROM_DEVICE) { - ret = fd_do_readv(cmd, sgl, sgl_nents); + ret = fd_do_rw(cmd, sgl, sgl_nents, 0); } else { - ret = fd_do_writev(cmd, sgl, sgl_nents); + ret = fd_do_rw(cmd, sgl, sgl_nents, 1); /* * Perform implict vfs_fsync_range() for fd_do_writev() ops * for SCSI WRITEs with Forced Unit Access (FUA) set. * Allow this to happen independent of WCE=0 setting. */ if (ret > 0 && - dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 && + dev->dev_attrib.emulate_fua_write > 0 && (cmd->se_cmd_flags & SCF_FUA)) { - struct fd_dev *fd_dev = dev->dev_ptr; + struct fd_dev *fd_dev = FD_DEV(dev); loff_t start = cmd->t_task_lba * - dev->se_sub_dev->se_dev_attrib.block_size; + dev->dev_attrib.block_size; loff_t end = start + cmd->data_length; vfs_fsync_range(fd_dev->fd_file, start, end, 1); } } - if (ret < 0) { - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return ret; - } + if (ret < 0) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + if (ret) target_complete_cmd(cmd, SAM_STAT_GOOD); return 0; @@ -430,12 +381,10 @@ static match_table_t tokens = { {Opt_err, NULL} }; -static ssize_t fd_set_configfs_dev_params( - struct se_hba *hba, - struct se_subsystem_dev *se_dev, - const char *page, ssize_t count) +static ssize_t fd_set_configfs_dev_params(struct se_device *dev, + const char *page, ssize_t count) { - struct fd_dev *fd_dev = se_dev->se_dev_su_ptr; + struct fd_dev *fd_dev = FD_DEV(dev); char *orig, *ptr, *arg_p, *opts; substring_t args[MAX_OPT_ARGS]; int ret = 0, arg, token; @@ -502,24 +451,9 @@ out: return (!ret) ? count : ret; } -static ssize_t fd_check_configfs_dev_params(struct se_hba *hba, struct se_subsystem_dev *se_dev) +static ssize_t fd_show_configfs_dev_params(struct se_device *dev, char *b) { - struct fd_dev *fd_dev = se_dev->se_dev_su_ptr; - - if (!(fd_dev->fbd_flags & FBDF_HAS_PATH)) { - pr_err("Missing fd_dev_name=\n"); - return -EINVAL; - } - - return 0; -} - -static ssize_t fd_show_configfs_dev_params( - struct se_hba *hba, - struct se_subsystem_dev *se_dev, - char *b) -{ - struct fd_dev *fd_dev = se_dev->se_dev_su_ptr; + struct fd_dev *fd_dev = FD_DEV(dev); ssize_t bl = 0; bl = sprintf(b + bl, "TCM FILEIO ID: %u", fd_dev->fd_dev_id); @@ -530,27 +464,9 @@ static ssize_t fd_show_configfs_dev_params( return bl; } -/* fd_get_device_rev(): (Part of se_subsystem_api_t template) - * - * - */ -static u32 fd_get_device_rev(struct se_device *dev) -{ - return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */ -} - -/* fd_get_device_type(): (Part of se_subsystem_api_t template) - * - * - */ -static u32 fd_get_device_type(struct se_device *dev) -{ - return TYPE_DISK; -} - static sector_t fd_get_blocks(struct se_device *dev) { - struct fd_dev *fd_dev = dev->dev_ptr; + struct fd_dev *fd_dev = FD_DEV(dev); struct file *f = fd_dev->fd_file; struct inode *i = f->f_mapping->host; unsigned long long dev_size; @@ -564,34 +480,35 @@ static sector_t fd_get_blocks(struct se_device *dev) else dev_size = fd_dev->fd_dev_size; - return div_u64(dev_size, dev->se_sub_dev->se_dev_attrib.block_size); + return div_u64(dev_size, dev->dev_attrib.block_size); } -static struct spc_ops fd_spc_ops = { +static struct sbc_ops fd_sbc_ops = { .execute_rw = fd_execute_rw, .execute_sync_cache = fd_execute_sync_cache, }; -static int fd_parse_cdb(struct se_cmd *cmd) +static sense_reason_t +fd_parse_cdb(struct se_cmd *cmd) { - return sbc_parse_cdb(cmd, &fd_spc_ops); + return sbc_parse_cdb(cmd, &fd_sbc_ops); } static struct se_subsystem_api fileio_template = { .name = "fileio", + .inquiry_prod = "FILEIO", + .inquiry_rev = FD_VERSION, .owner = THIS_MODULE, .transport_type = TRANSPORT_PLUGIN_VHBA_PDEV, .attach_hba = fd_attach_hba, .detach_hba = fd_detach_hba, - .allocate_virtdevice = fd_allocate_virtdevice, - .create_virtdevice = fd_create_virtdevice, + .alloc_device = fd_alloc_device, + .configure_device = fd_configure_device, .free_device = fd_free_device, .parse_cdb = fd_parse_cdb, - .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, - .get_device_rev = fd_get_device_rev, - .get_device_type = fd_get_device_type, + .get_device_type = sbc_get_device_type, .get_blocks = fd_get_blocks, }; diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h index 876ae53ef5b8..bc02b018ae46 100644 --- a/drivers/target/target_core_file.h +++ b/drivers/target/target_core_file.h @@ -17,6 +17,8 @@ #define FDBD_HAS_BUFFERED_IO_WCE 0x04 struct fd_dev { + struct se_device dev; + u32 fbd_flags; unsigned char fd_dev_name[FD_MAX_DEV_NAME]; /* Unique Ramdisk Device ID in Ramdisk HBA */ diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c index 3dd1bd4b6f71..d2616cd48f1e 100644 --- a/drivers/target/target_core_hba.c +++ b/drivers/target/target_core_hba.c @@ -3,10 +3,7 @@ * * This file contains the TCM HBA Transport related functions. * - * Copyright (c) 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 + * (c) Copyright 2003-2012 RisingTide Systems LLC. * * Nicholas A. Bellinger <nab@kernel.org> * @@ -113,7 +110,6 @@ core_alloc_hba(const char *plugin_name, u32 plugin_dep_id, u32 hba_flags) return ERR_PTR(-ENOMEM); } - INIT_LIST_HEAD(&hba->hba_dev_list); spin_lock_init(&hba->device_lock); mutex_init(&hba->hba_access_mutex); @@ -152,8 +148,7 @@ out_free_hba: int core_delete_hba(struct se_hba *hba) { - if (!list_empty(&hba->hba_dev_list)) - dump_stack(); + WARN_ON(hba->dev_count); hba->transport->detach_hba(hba); diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 57d7674c5013..b526d23dcd4f 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -4,10 +4,7 @@ * This file contains the Storage Engine <-> Linux BlockIO transport * specific functions. * - * Copyright (c) 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 + * (c) Copyright 2003-2012 RisingTide Systems LLC. * * Nicholas A. Bellinger <nab@kernel.org> * @@ -50,9 +47,13 @@ #define IBLOCK_MAX_BIO_PER_TASK 32 /* max # of bios to submit at a time */ #define IBLOCK_BIO_POOL_SIZE 128 -static struct se_subsystem_api iblock_template; +static inline struct iblock_dev *IBLOCK_DEV(struct se_device *dev) +{ + return container_of(dev, struct iblock_dev, dev); +} + -static void iblock_bio_done(struct bio *, int); +static struct se_subsystem_api iblock_template; /* iblock_attach_hba(): (Part of se_subsystem_api_t template) * @@ -70,7 +71,7 @@ static void iblock_detach_hba(struct se_hba *hba) { } -static void *iblock_allocate_virtdevice(struct se_hba *hba, const char *name) +static struct se_device *iblock_alloc_device(struct se_hba *hba, const char *name) { struct iblock_dev *ib_dev = NULL; @@ -82,40 +83,28 @@ static void *iblock_allocate_virtdevice(struct se_hba *hba, const char *name) pr_debug( "IBLOCK: Allocated ib_dev for %s\n", name); - return ib_dev; + return &ib_dev->dev; } -static struct se_device *iblock_create_virtdevice( - struct se_hba *hba, - struct se_subsystem_dev *se_dev, - void *p) +static int iblock_configure_device(struct se_device *dev) { - struct iblock_dev *ib_dev = p; - struct se_device *dev; - struct se_dev_limits dev_limits; - struct block_device *bd = NULL; + struct iblock_dev *ib_dev = IBLOCK_DEV(dev); struct request_queue *q; - struct queue_limits *limits; - u32 dev_flags = 0; + struct block_device *bd = NULL; fmode_t mode; - int ret = -EINVAL; + int ret = -ENOMEM; - if (!ib_dev) { - pr_err("Unable to locate struct iblock_dev parameter\n"); - return ERR_PTR(ret); + if (!(ib_dev->ibd_flags & IBDF_HAS_UDEV_PATH)) { + pr_err("Missing udev_path= parameters for IBLOCK\n"); + return -EINVAL; } - memset(&dev_limits, 0, sizeof(struct se_dev_limits)); ib_dev->ibd_bio_set = bioset_create(IBLOCK_BIO_POOL_SIZE, 0); if (!ib_dev->ibd_bio_set) { - pr_err("IBLOCK: Unable to create bioset()\n"); - return ERR_PTR(-ENOMEM); + pr_err("IBLOCK: Unable to create bioset\n"); + goto out; } - pr_debug("IBLOCK: Created bio_set()\n"); - /* - * iblock_check_configfs_dev_params() ensures that ib_dev->ibd_udev_path - * must already have been set in order for echo 1 > $HBA/$DEV/enable to run. - */ + pr_debug( "IBLOCK: Claiming struct block_device: %s\n", ib_dev->ibd_udev_path); @@ -126,27 +115,15 @@ static struct se_device *iblock_create_virtdevice( bd = blkdev_get_by_path(ib_dev->ibd_udev_path, mode, ib_dev); if (IS_ERR(bd)) { ret = PTR_ERR(bd); - goto failed; + goto out_free_bioset; } - /* - * Setup the local scope queue_limits from struct request_queue->limits - * to pass into transport_add_device_to_core_hba() as struct se_dev_limits. - */ - q = bdev_get_queue(bd); - limits = &dev_limits.limits; - limits->logical_block_size = bdev_logical_block_size(bd); - limits->max_hw_sectors = UINT_MAX; - limits->max_sectors = UINT_MAX; - dev_limits.hw_queue_depth = q->nr_requests; - dev_limits.queue_depth = q->nr_requests; - ib_dev->ibd_bd = bd; - dev = transport_add_device_to_core_hba(hba, - &iblock_template, se_dev, dev_flags, ib_dev, - &dev_limits, "IBLOCK", IBLOCK_VERSION); - if (!dev) - goto failed; + q = bdev_get_queue(bd); + + dev->dev_attrib.hw_block_size = bdev_logical_block_size(bd); + dev->dev_attrib.hw_max_sectors = UINT_MAX; + dev->dev_attrib.hw_queue_depth = q->nr_requests; /* * Check if the underlying struct block_device request_queue supports @@ -154,38 +131,41 @@ static struct se_device *iblock_create_virtdevice( * in ATA and we need to set TPE=1 */ if (blk_queue_discard(q)) { - dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count = + dev->dev_attrib.max_unmap_lba_count = q->limits.max_discard_sectors; + /* * Currently hardcoded to 1 in Linux/SCSI code.. */ - dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count = 1; - dev->se_sub_dev->se_dev_attrib.unmap_granularity = + dev->dev_attrib.max_unmap_block_desc_count = 1; + dev->dev_attrib.unmap_granularity = q->limits.discard_granularity >> 9; - dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment = + dev->dev_attrib.unmap_granularity_alignment = q->limits.discard_alignment; pr_debug("IBLOCK: BLOCK Discard support available," " disabled by default\n"); } + /* + * Enable write same emulation for IBLOCK and use 0xFFFF as + * the smaller WRITE_SAME(10) only has a two-byte block count. + */ + dev->dev_attrib.max_write_same_len = 0xFFFF; if (blk_queue_nonrot(q)) - dev->se_sub_dev->se_dev_attrib.is_nonrot = 1; - - return dev; + dev->dev_attrib.is_nonrot = 1; + return 0; -failed: - if (ib_dev->ibd_bio_set) { - bioset_free(ib_dev->ibd_bio_set); - ib_dev->ibd_bio_set = NULL; - } - ib_dev->ibd_bd = NULL; - return ERR_PTR(ret); +out_free_bioset: + bioset_free(ib_dev->ibd_bio_set); + ib_dev->ibd_bio_set = NULL; +out: + return ret; } -static void iblock_free_device(void *p) +static void iblock_free_device(struct se_device *dev) { - struct iblock_dev *ib_dev = p; + struct iblock_dev *ib_dev = IBLOCK_DEV(dev); if (ib_dev->ibd_bd != NULL) blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); @@ -203,12 +183,12 @@ static unsigned long long iblock_emulate_read_cap_with_block_size( bdev_logical_block_size(bd)) - 1); u32 block_size = bdev_logical_block_size(bd); - if (block_size == dev->se_sub_dev->se_dev_attrib.block_size) + if (block_size == dev->dev_attrib.block_size) return blocks_long; switch (block_size) { case 4096: - switch (dev->se_sub_dev->se_dev_attrib.block_size) { + switch (dev->dev_attrib.block_size) { case 2048: blocks_long <<= 1; break; @@ -222,7 +202,7 @@ static unsigned long long iblock_emulate_read_cap_with_block_size( } break; case 2048: - switch (dev->se_sub_dev->se_dev_attrib.block_size) { + switch (dev->dev_attrib.block_size) { case 4096: blocks_long >>= 1; break; @@ -237,7 +217,7 @@ static unsigned long long iblock_emulate_read_cap_with_block_size( } break; case 1024: - switch (dev->se_sub_dev->se_dev_attrib.block_size) { + switch (dev->dev_attrib.block_size) { case 4096: blocks_long >>= 2; break; @@ -252,7 +232,7 @@ static unsigned long long iblock_emulate_read_cap_with_block_size( } break; case 512: - switch (dev->se_sub_dev->se_dev_attrib.block_size) { + switch (dev->dev_attrib.block_size) { case 4096: blocks_long >>= 3; break; @@ -273,6 +253,87 @@ static unsigned long long iblock_emulate_read_cap_with_block_size( return blocks_long; } +static void iblock_complete_cmd(struct se_cmd *cmd) +{ + struct iblock_req *ibr = cmd->priv; + u8 status; + + if (!atomic_dec_and_test(&ibr->pending)) + return; + + if (atomic_read(&ibr->ib_bio_err_cnt)) + status = SAM_STAT_CHECK_CONDITION; + else + status = SAM_STAT_GOOD; + + target_complete_cmd(cmd, status); + kfree(ibr); +} + +static void iblock_bio_done(struct bio *bio, int err) +{ + struct se_cmd *cmd = bio->bi_private; + struct iblock_req *ibr = cmd->priv; + + /* + * Set -EIO if !BIO_UPTODATE and the passed is still err=0 + */ + if (!test_bit(BIO_UPTODATE, &bio->bi_flags) && !err) + err = -EIO; + + if (err != 0) { + pr_err("test_bit(BIO_UPTODATE) failed for bio: %p," + " err: %d\n", bio, err); + /* + * Bump the ib_bio_err_cnt and release bio. + */ + atomic_inc(&ibr->ib_bio_err_cnt); + smp_mb__after_atomic_inc(); + } + + bio_put(bio); + + iblock_complete_cmd(cmd); +} + +static struct bio * +iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num) +{ + struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev); + struct bio *bio; + + /* + * Only allocate as many vector entries as the bio code allows us to, + * we'll loop later on until we have handled the whole request. + */ + if (sg_num > BIO_MAX_PAGES) + sg_num = BIO_MAX_PAGES; + + bio = bio_alloc_bioset(GFP_NOIO, sg_num, ib_dev->ibd_bio_set); + if (!bio) { + pr_err("Unable to allocate memory for bio\n"); + return NULL; + } + + bio->bi_bdev = ib_dev->ibd_bd; + bio->bi_private = cmd; + bio->bi_end_io = &iblock_bio_done; + bio->bi_sector = lba; + + return bio; +} + +static void iblock_submit_bios(struct bio_list *list, int rw) +{ + struct blk_plug plug; + struct bio *bio; + + blk_start_plug(&plug); + while ((bio = bio_list_pop(list))) + submit_bio(rw, bio); + blk_finish_plug(&plug); +} + static void iblock_end_io_flush(struct bio *bio, int err) { struct se_cmd *cmd = bio->bi_private; @@ -281,13 +342,10 @@ static void iblock_end_io_flush(struct bio *bio, int err) pr_err("IBLOCK: cache flush failed: %d\n", err); if (cmd) { - if (err) { - cmd->scsi_sense_reason = - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + if (err) target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION); - } else { + else target_complete_cmd(cmd, SAM_STAT_GOOD); - } } bio_put(bio); @@ -297,9 +355,10 @@ 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 int iblock_execute_sync_cache(struct se_cmd *cmd) +static sense_reason_t +iblock_execute_sync_cache(struct se_cmd *cmd) { - struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr; + struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev); int immed = (cmd->t_task_cdb[1] & 0x2); struct bio *bio; @@ -319,25 +378,27 @@ static int iblock_execute_sync_cache(struct se_cmd *cmd) return 0; } -static int iblock_execute_unmap(struct se_cmd *cmd) +static sense_reason_t +iblock_execute_unmap(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - struct iblock_dev *ibd = dev->dev_ptr; + struct iblock_dev *ib_dev = IBLOCK_DEV(dev); unsigned char *buf, *ptr = NULL; sector_t lba; int size; u32 range; - int ret = 0; - int dl, bd_dl; + sense_reason_t ret = 0; + int dl, bd_dl, err; if (cmd->data_length < 8) { pr_warn("UNMAP parameter list length %u too small\n", cmd->data_length); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - return -EINVAL; + return TCM_INVALID_PARAMETER_LIST; } buf = transport_kmap_data_sg(cmd); + if (!buf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; dl = get_unaligned_be16(&buf[0]); bd_dl = get_unaligned_be16(&buf[2]); @@ -349,9 +410,8 @@ static int iblock_execute_unmap(struct se_cmd *cmd) else size = 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; + if (size / 16 > dev->dev_attrib.max_unmap_block_desc_count) { + ret = TCM_INVALID_PARAMETER_LIST; goto err; } @@ -366,23 +426,22 @@ 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; + if (range > dev->dev_attrib.max_unmap_lba_count) { + ret = TCM_INVALID_PARAMETER_LIST; goto err; } if (lba + range > dev->transport->get_blocks(dev) + 1) { - cmd->scsi_sense_reason = TCM_ADDRESS_OUT_OF_RANGE; - ret = -EINVAL; + ret = TCM_ADDRESS_OUT_OF_RANGE; goto err; } - ret = blkdev_issue_discard(ibd->ibd_bd, lba, range, + err = blkdev_issue_discard(ib_dev->ibd_bd, lba, range, GFP_KERNEL, 0); - if (ret < 0) { + if (err < 0) { pr_err("blkdev_issue_discard() failed: %d\n", - ret); + err); + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; goto err; } @@ -397,23 +456,86 @@ err: return ret; } -static int iblock_execute_write_same(struct se_cmd *cmd) +static sense_reason_t +iblock_execute_write_same_unmap(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; + struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev); + int rc; + + rc = blkdev_issue_discard(ib_dev->ibd_bd, cmd->t_task_lba, + spc_get_write_same_sectors(cmd), GFP_KERNEL, 0); + if (rc < 0) { + pr_warn("blkdev_issue_discard() failed: %d\n", rc); + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } target_complete_cmd(cmd, GOOD); return 0; } +static sense_reason_t +iblock_execute_write_same(struct se_cmd *cmd) +{ + struct iblock_req *ibr; + struct scatterlist *sg; + struct bio *bio; + struct bio_list list; + sector_t block_lba = cmd->t_task_lba; + sector_t sectors = spc_get_write_same_sectors(cmd); + + sg = &cmd->t_data_sg[0]; + + if (cmd->t_data_nents > 1 || + sg->length != cmd->se_dev->dev_attrib.block_size) { + pr_err("WRITE_SAME: Illegal SGL t_data_nents: %u length: %u" + " block_size: %u\n", cmd->t_data_nents, sg->length, + cmd->se_dev->dev_attrib.block_size); + return TCM_INVALID_CDB_FIELD; + } + + ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL); + if (!ibr) + goto fail; + cmd->priv = ibr; + + bio = iblock_get_bio(cmd, block_lba, 1); + if (!bio) + goto fail_free_ibr; + + bio_list_init(&list); + bio_list_add(&list, bio); + + atomic_set(&ibr->pending, 1); + + while (sectors) { + while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset) + != sg->length) { + + bio = iblock_get_bio(cmd, block_lba, 1); + if (!bio) + goto fail_put_bios; + + atomic_inc(&ibr->pending); + bio_list_add(&list, bio); + } + + /* Always in 512 byte units for Linux/Block */ + block_lba += sg->length >> IBLOCK_LBA_SHIFT; + sectors -= 1; + } + + iblock_submit_bios(&list, WRITE); + return 0; + +fail_put_bios: + while ((bio = bio_list_pop(&list))) + bio_put(bio); +fail_free_ibr: + kfree(ibr); +fail: + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +} + enum { Opt_udev_path, Opt_readonly, Opt_force, Opt_err }; @@ -425,11 +547,10 @@ static match_table_t tokens = { {Opt_err, NULL} }; -static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba, - struct se_subsystem_dev *se_dev, - const char *page, ssize_t count) +static ssize_t iblock_set_configfs_dev_params(struct se_device *dev, + const char *page, ssize_t count) { - struct iblock_dev *ib_dev = se_dev->se_dev_su_ptr; + struct iblock_dev *ib_dev = IBLOCK_DEV(dev); char *orig, *ptr, *arg_p, *opts; substring_t args[MAX_OPT_ARGS]; int ret = 0, token; @@ -491,43 +612,26 @@ out: return (!ret) ? count : ret; } -static ssize_t iblock_check_configfs_dev_params( - struct se_hba *hba, - struct se_subsystem_dev *se_dev) +static ssize_t iblock_show_configfs_dev_params(struct se_device *dev, char *b) { - struct iblock_dev *ibd = se_dev->se_dev_su_ptr; - - if (!(ibd->ibd_flags & IBDF_HAS_UDEV_PATH)) { - pr_err("Missing udev_path= parameters for IBLOCK\n"); - return -EINVAL; - } - - return 0; -} - -static ssize_t iblock_show_configfs_dev_params( - struct se_hba *hba, - struct se_subsystem_dev *se_dev, - char *b) -{ - struct iblock_dev *ibd = se_dev->se_dev_su_ptr; - struct block_device *bd = ibd->ibd_bd; + struct iblock_dev *ib_dev = IBLOCK_DEV(dev); + struct block_device *bd = ib_dev->ibd_bd; char buf[BDEVNAME_SIZE]; ssize_t bl = 0; if (bd) bl += sprintf(b + bl, "iBlock device: %s", bdevname(bd, buf)); - if (ibd->ibd_flags & IBDF_HAS_UDEV_PATH) + if (ib_dev->ibd_flags & IBDF_HAS_UDEV_PATH) bl += sprintf(b + bl, " UDEV PATH: %s", - ibd->ibd_udev_path); - bl += sprintf(b + bl, " readonly: %d\n", ibd->ibd_readonly); + ib_dev->ibd_udev_path); + bl += sprintf(b + bl, " readonly: %d\n", ib_dev->ibd_readonly); bl += sprintf(b + bl, " "); if (bd) { bl += sprintf(b + bl, "Major: %d Minor: %d %s\n", MAJOR(bd->bd_dev), MINOR(bd->bd_dev), (!bd->bd_contains) ? - "" : (bd->bd_holder == ibd) ? + "" : (bd->bd_holder == ib_dev) ? "CLAIMED: IBLOCK" : "CLAIMED: OS"); } else { bl += sprintf(b + bl, "Major: 0 Minor: 0\n"); @@ -536,61 +640,8 @@ static ssize_t iblock_show_configfs_dev_params( return bl; } -static void iblock_complete_cmd(struct se_cmd *cmd) -{ - struct iblock_req *ibr = cmd->priv; - u8 status; - - if (!atomic_dec_and_test(&ibr->pending)) - return; - - if (atomic_read(&ibr->ib_bio_err_cnt)) - status = SAM_STAT_CHECK_CONDITION; - else - status = SAM_STAT_GOOD; - - target_complete_cmd(cmd, status); - kfree(ibr); -} - -static struct bio * -iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num) -{ - struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr; - struct bio *bio; - - /* - * Only allocate as many vector entries as the bio code allows us to, - * we'll loop later on until we have handled the whole request. - */ - if (sg_num > BIO_MAX_PAGES) - sg_num = BIO_MAX_PAGES; - - bio = bio_alloc_bioset(GFP_NOIO, sg_num, ib_dev->ibd_bio_set); - if (!bio) { - pr_err("Unable to allocate memory for bio\n"); - return NULL; - } - - bio->bi_bdev = ib_dev->ibd_bd; - bio->bi_private = cmd; - bio->bi_end_io = &iblock_bio_done; - bio->bi_sector = lba; - return bio; -} - -static void iblock_submit_bios(struct bio_list *list, int rw) -{ - struct blk_plug plug; - struct bio *bio; - - blk_start_plug(&plug); - while ((bio = bio_list_pop(list))) - submit_bio(rw, bio); - blk_finish_plug(&plug); -} - -static int iblock_execute_rw(struct se_cmd *cmd) +static sense_reason_t +iblock_execute_rw(struct se_cmd *cmd) { struct scatterlist *sgl = cmd->t_data_sg; u32 sgl_nents = cmd->t_data_nents; @@ -611,8 +662,8 @@ static int iblock_execute_rw(struct se_cmd *cmd) * Force data to disk if we pretend to not have a volatile * write cache, or the initiator set the Force Unit Access bit. */ - if (dev->se_sub_dev->se_dev_attrib.emulate_write_cache == 0 || - (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 && + if (dev->dev_attrib.emulate_write_cache == 0 || + (dev->dev_attrib.emulate_fua_write > 0 && (cmd->se_cmd_flags & SCF_FUA))) rw = WRITE_FUA; else @@ -625,19 +676,18 @@ static int iblock_execute_rw(struct se_cmd *cmd) * Convert the blocksize advertised to the initiator to the 512 byte * units unconditionally used by the Linux block layer. */ - if (dev->se_sub_dev->se_dev_attrib.block_size == 4096) + if (dev->dev_attrib.block_size == 4096) block_lba = (cmd->t_task_lba << 3); - else if (dev->se_sub_dev->se_dev_attrib.block_size == 2048) + else if (dev->dev_attrib.block_size == 2048) block_lba = (cmd->t_task_lba << 2); - else if (dev->se_sub_dev->se_dev_attrib.block_size == 1024) + else if (dev->dev_attrib.block_size == 1024) block_lba = (cmd->t_task_lba << 1); - else if (dev->se_sub_dev->se_dev_attrib.block_size == 512) + else if (dev->dev_attrib.block_size == 512) block_lba = cmd->t_task_lba; else { pr_err("Unsupported SCSI -> BLOCK LBA conversion:" - " %u\n", dev->se_sub_dev->se_dev_attrib.block_size); - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -ENOSYS; + " %u\n", dev->dev_attrib.block_size); + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL); @@ -697,83 +747,48 @@ fail_put_bios: bio_put(bio); fail_free_ibr: kfree(ibr); - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; fail: - return -ENOMEM; -} - -static u32 iblock_get_device_rev(struct se_device *dev) -{ - return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */ -} - -static u32 iblock_get_device_type(struct se_device *dev) -{ - return TYPE_DISK; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } static sector_t iblock_get_blocks(struct se_device *dev) { - struct iblock_dev *ibd = dev->dev_ptr; - struct block_device *bd = ibd->ibd_bd; + struct iblock_dev *ib_dev = IBLOCK_DEV(dev); + struct block_device *bd = ib_dev->ibd_bd; struct request_queue *q = bdev_get_queue(bd); return iblock_emulate_read_cap_with_block_size(dev, bd, q); } -static void iblock_bio_done(struct bio *bio, int err) -{ - struct se_cmd *cmd = bio->bi_private; - struct iblock_req *ibr = cmd->priv; - - /* - * Set -EIO if !BIO_UPTODATE and the passed is still err=0 - */ - if (!test_bit(BIO_UPTODATE, &bio->bi_flags) && !err) - err = -EIO; - - if (err != 0) { - pr_err("test_bit(BIO_UPTODATE) failed for bio: %p," - " err: %d\n", bio, err); - /* - * Bump the ib_bio_err_cnt and release bio. - */ - atomic_inc(&ibr->ib_bio_err_cnt); - smp_mb__after_atomic_inc(); - } - - bio_put(bio); - - iblock_complete_cmd(cmd); -} - -static struct spc_ops iblock_spc_ops = { +static struct sbc_ops iblock_sbc_ops = { .execute_rw = iblock_execute_rw, .execute_sync_cache = iblock_execute_sync_cache, .execute_write_same = iblock_execute_write_same, + .execute_write_same_unmap = iblock_execute_write_same_unmap, .execute_unmap = iblock_execute_unmap, }; -static int iblock_parse_cdb(struct se_cmd *cmd) +static sense_reason_t +iblock_parse_cdb(struct se_cmd *cmd) { - return sbc_parse_cdb(cmd, &iblock_spc_ops); + return sbc_parse_cdb(cmd, &iblock_sbc_ops); } static struct se_subsystem_api iblock_template = { .name = "iblock", + .inquiry_prod = "IBLOCK", + .inquiry_rev = IBLOCK_VERSION, .owner = THIS_MODULE, .transport_type = TRANSPORT_PLUGIN_VHBA_PDEV, .attach_hba = iblock_attach_hba, .detach_hba = iblock_detach_hba, - .allocate_virtdevice = iblock_allocate_virtdevice, - .create_virtdevice = iblock_create_virtdevice, + .alloc_device = iblock_alloc_device, + .configure_device = iblock_configure_device, .free_device = iblock_free_device, .parse_cdb = iblock_parse_cdb, - .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, - .get_device_rev = iblock_get_device_rev, - .get_device_type = iblock_get_device_type, + .get_device_type = sbc_get_device_type, .get_blocks = iblock_get_blocks, }; diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h index 533627ae79ec..01c2afd81500 100644 --- a/drivers/target/target_core_iblock.h +++ b/drivers/target/target_core_iblock.h @@ -14,6 +14,7 @@ struct iblock_req { #define IBDF_HAS_UDEV_PATH 0x01 struct iblock_dev { + struct se_device dev; unsigned char ibd_udev_path[SE_UDEV_PATH_LEN]; u32 ibd_flags; struct bio_set *ibd_bio_set; diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 0fd428225d11..93e9c1f580b0 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -19,18 +19,12 @@ int core_dev_export(struct se_device *, struct se_portal_group *, struct se_lun *); void core_dev_unexport(struct se_device *, struct se_portal_group *, struct se_lun *); -int target_report_luns(struct se_cmd *); -void se_release_device_for_hba(struct se_device *); -void se_release_vpd_for_dev(struct se_device *); -int se_free_virtual_device(struct se_device *, struct se_hba *); -int se_dev_check_online(struct se_device *); -int se_dev_check_shutdown(struct se_device *); -void se_dev_set_default_attribs(struct se_device *, struct se_dev_limits *); int se_dev_set_task_timeout(struct se_device *, u32); int se_dev_set_max_unmap_lba_count(struct se_device *, u32); int se_dev_set_max_unmap_block_desc_count(struct se_device *, u32); int se_dev_set_unmap_granularity(struct se_device *, u32); int se_dev_set_unmap_granularity_alignment(struct se_device *, u32); +int se_dev_set_max_write_same_len(struct se_device *, u32); int se_dev_set_emulate_dpo(struct se_device *, int); int se_dev_set_emulate_fua_write(struct se_device *, int); int se_dev_set_emulate_fua_read(struct se_device *, int); @@ -60,6 +54,9 @@ void core_dev_free_initiator_node_lun_acl(struct se_portal_group *, struct se_lun_acl *lacl); int core_dev_setup_virtual_lun0(void); void core_dev_release_virtual_lun0(void); +struct se_device *target_alloc_device(struct se_hba *hba, const char *name); +int target_configure_device(struct se_device *dev); +void target_free_device(struct se_device *); /* target_core_hba.c */ struct se_hba *core_alloc_hba(const char *, u32, u32); @@ -105,10 +102,11 @@ 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); +sense_reason_t target_cmd_size_check(struct se_cmd *cmd, unsigned int size); +void target_qf_do_work(struct work_struct *work); /* target_core_stat.c */ -void target_stat_setup_dev_default_groups(struct se_subsystem_dev *); +void target_stat_setup_dev_default_groups(struct se_device *); void target_stat_setup_port_default_groups(struct se_lun *); void target_stat_setup_mappedlun_default_groups(struct se_lun_acl *); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 8c323a98c4a0..8e0290b38e43 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -4,8 +4,7 @@ * This file contains SPC-3 compliant persistent reservations and * legacy SPC-2 reservations with compatible reservation handling (CRH=1) * - * Copyright (c) 2009, 2010 Rising Tide Systems - * Copyright (c) 2009, 2010 Linux-iSCSI.org + * (c) Copyright 2009-2012 RisingTide Systems LLC. * * Nicholas A. Bellinger <nab@kernel.org> * @@ -68,49 +67,33 @@ int core_pr_dump_initiator_port( static void __core_scsi3_complete_pro_release(struct se_device *, struct se_node_acl *, struct t10_pr_registration *, int); -static int core_scsi2_reservation_seq_non_holder( - struct se_cmd *cmd, - unsigned char *cdb, - u32 pr_reg_type) +static sense_reason_t +target_scsi2_reservation_check(struct se_cmd *cmd) { - switch (cdb[0]) { + struct se_device *dev = cmd->se_dev; + struct se_session *sess = cmd->se_sess; + + switch (cmd->t_task_cdb[0]) { case INQUIRY: case RELEASE: case RELEASE_10: return 0; default: - return 1; + break; } - return 1; -} - -static int core_scsi2_reservation_check(struct se_cmd *cmd, u32 *pr_reg_type) -{ - struct se_device *dev = cmd->se_dev; - struct se_session *sess = cmd->se_sess; - int ret; - - if (!sess) + if (!dev->dev_reserved_node_acl || !sess) return 0; - spin_lock(&dev->dev_reservation_lock); - if (!dev->dev_reserved_node_acl || !sess) { - spin_unlock(&dev->dev_reservation_lock); - return 0; - } - if (dev->dev_reserved_node_acl != sess->se_node_acl) { - spin_unlock(&dev->dev_reservation_lock); - return -EINVAL; - } - if (!(dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID)) { - spin_unlock(&dev->dev_reservation_lock); - return 0; + if (dev->dev_reserved_node_acl != sess->se_node_acl) + return TCM_RESERVATION_CONFLICT; + + if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS_WITH_ISID) { + if (dev->dev_res_bin_isid != sess->sess_bin_isid) + return TCM_RESERVATION_CONFLICT; } - ret = (dev->dev_res_bin_isid == sess->sess_bin_isid) ? 0 : -EINVAL; - spin_unlock(&dev->dev_reservation_lock); - return ret; + return 0; } static struct t10_pr_registration *core_scsi3_locate_pr_reg(struct se_device *, @@ -120,15 +103,11 @@ static void core_scsi3_put_pr_reg(struct t10_pr_registration *); static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd) { struct se_session *se_sess = cmd->se_sess; - struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; + struct se_device *dev = cmd->se_dev; struct t10_pr_registration *pr_reg; - struct t10_reservation *pr_tmpl = &su_dev->t10_pr; - int crh = (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS); + struct t10_reservation *pr_tmpl = &dev->t10_pr; int conflict = 0; - if (!crh) - return -EINVAL; - pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, se_sess); if (pr_reg) { @@ -186,32 +165,28 @@ static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd) pr_err("Received legacy SPC-2 RESERVE/RELEASE" " while active SPC-3 registrations exist," " returning RESERVATION_CONFLICT\n"); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; return -EBUSY; } return 0; } -int target_scsi2_reservation_release(struct se_cmd *cmd) +sense_reason_t +target_scsi2_reservation_release(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; struct se_session *sess = cmd->se_sess; struct se_portal_group *tpg; - int ret = 0, rc; + int rc; if (!sess || !sess->se_tpg) goto out; rc = target_check_scsi2_reservation_conflict(cmd); if (rc == 1) goto out; - else if (rc < 0) { - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - ret = -EINVAL; - goto out; - } + if (rc < 0) + return TCM_RESERVATION_CONFLICT; - ret = 0; spin_lock(&dev->dev_reservation_lock); if (!dev->dev_reserved_node_acl || !sess) goto out_unlock; @@ -223,10 +198,10 @@ int target_scsi2_reservation_release(struct se_cmd *cmd) goto out_unlock; dev->dev_reserved_node_acl = NULL; - dev->dev_flags &= ~DF_SPC2_RESERVATIONS; - if (dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID) { + dev->dev_reservation_flags &= ~DRF_SPC2_RESERVATIONS; + if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS_WITH_ISID) { dev->dev_res_bin_isid = 0; - dev->dev_flags &= ~DF_SPC2_RESERVATIONS_WITH_ISID; + dev->dev_reservation_flags &= ~DRF_SPC2_RESERVATIONS_WITH_ISID; } tpg = sess->se_tpg; pr_debug("SCSI-2 Released reservation for %s LUN: %u ->" @@ -237,25 +212,24 @@ int target_scsi2_reservation_release(struct se_cmd *cmd) out_unlock: spin_unlock(&dev->dev_reservation_lock); out: - if (!ret) - target_complete_cmd(cmd, GOOD); - return ret; + target_complete_cmd(cmd, GOOD); + return 0; } -int target_scsi2_reservation_reserve(struct se_cmd *cmd) +sense_reason_t +target_scsi2_reservation_reserve(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; struct se_session *sess = cmd->se_sess; struct se_portal_group *tpg; - int ret = 0, rc; + sense_reason_t ret = 0; + int rc; if ((cmd->t_task_cdb[1] & 0x01) && (cmd->t_task_cdb[1] & 0x02)) { pr_err("LongIO and Obselete Bits set, returning" " ILLEGAL_REQUEST\n"); - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; - ret = -EINVAL; - goto out; + return TCM_UNSUPPORTED_SCSI_OPCODE; } /* * This is currently the case for target_core_mod passthrough struct se_cmd @@ -266,13 +240,10 @@ int target_scsi2_reservation_reserve(struct se_cmd *cmd) rc = target_check_scsi2_reservation_conflict(cmd); if (rc == 1) goto out; - else if (rc < 0) { - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - ret = -EINVAL; - goto out; - } - ret = 0; + if (rc < 0) + return TCM_RESERVATION_CONFLICT; + tpg = sess->se_tpg; spin_lock(&dev->dev_reservation_lock); if (dev->dev_reserved_node_acl && @@ -286,16 +257,15 @@ int target_scsi2_reservation_reserve(struct se_cmd *cmd) " from %s \n", cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, sess->se_node_acl->initiatorname); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - ret = -EINVAL; + ret = TCM_RESERVATION_CONFLICT; goto out_unlock; } dev->dev_reserved_node_acl = sess->se_node_acl; - dev->dev_flags |= DF_SPC2_RESERVATIONS; + dev->dev_reservation_flags |= DRF_SPC2_RESERVATIONS; if (sess->sess_bin_isid != 0) { dev->dev_res_bin_isid = sess->sess_bin_isid; - dev->dev_flags |= DF_SPC2_RESERVATIONS_WITH_ISID; + dev->dev_reservation_flags |= DRF_SPC2_RESERVATIONS_WITH_ISID; } pr_debug("SCSI-2 Reserved %s LUN: %u -> MAPPED LUN: %u" " for %s\n", tpg->se_tpg_tfo->get_fabric_name(), @@ -319,9 +289,9 @@ out: */ static int core_scsi3_pr_seq_non_holder( struct se_cmd *cmd, - unsigned char *cdb, u32 pr_reg_type) { + unsigned char *cdb = cmd->t_task_cdb; struct se_dev_entry *se_deve; struct se_session *se_sess = cmd->se_sess; int other_cdb = 0, ignore_reg; @@ -330,17 +300,11 @@ static int core_scsi3_pr_seq_non_holder( int we = 0; /* Write Exclusive */ int legacy = 0; /* Act like a legacy device and return * RESERVATION CONFLICT on some CDBs */ - /* - * A legacy SPC-2 reservation is being held. - */ - if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) - return core_scsi2_reservation_seq_non_holder(cmd, - cdb, pr_reg_type); se_deve = se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; /* * Determine if the registration should be ignored due to - * non-matching ISIDs in core_scsi3_pr_reservation_check(). + * non-matching ISIDs in target_scsi3_pr_reservation_check(). */ ignore_reg = (pr_reg_type & 0x80000000); if (ignore_reg) @@ -563,10 +527,41 @@ static int core_scsi3_pr_seq_non_holder( return 1; /* Conflict by default */ } +static sense_reason_t +target_scsi3_pr_reservation_check(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + struct se_session *sess = cmd->se_sess; + u32 pr_reg_type; + + if (!dev->dev_pr_res_holder) + return 0; + + pr_reg_type = dev->dev_pr_res_holder->pr_res_type; + cmd->pr_res_key = dev->dev_pr_res_holder->pr_res_key; + if (dev->dev_pr_res_holder->pr_reg_nacl != sess->se_node_acl) + goto check_nonholder; + + if (dev->dev_pr_res_holder->isid_present_at_reg) { + if (dev->dev_pr_res_holder->pr_reg_bin_isid != + sess->sess_bin_isid) { + pr_reg_type |= 0x80000000; + goto check_nonholder; + } + } + + return 0; + +check_nonholder: + if (core_scsi3_pr_seq_non_holder(cmd, pr_reg_type)) + return TCM_RESERVATION_CONFLICT; + return 0; +} + static u32 core_scsi3_pr_generation(struct se_device *dev) { - struct se_subsystem_dev *su_dev = dev->se_sub_dev; u32 prg; + /* * PRGeneration field shall contain the value of a 32-bit wrapping * counter mainted by the device server. @@ -577,56 +572,12 @@ static u32 core_scsi3_pr_generation(struct se_device *dev) * See spc4r17 section 6.3.12 READ_KEYS service action */ spin_lock(&dev->dev_reservation_lock); - prg = su_dev->t10_pr.pr_generation++; + prg = dev->t10_pr.pr_generation++; spin_unlock(&dev->dev_reservation_lock); return prg; } -static int core_scsi3_pr_reservation_check( - struct se_cmd *cmd, - u32 *pr_reg_type) -{ - struct se_device *dev = cmd->se_dev; - struct se_session *sess = cmd->se_sess; - int ret; - - if (!sess) - return 0; - /* - * A legacy SPC-2 reservation is being held. - */ - if (dev->dev_flags & DF_SPC2_RESERVATIONS) - return core_scsi2_reservation_check(cmd, pr_reg_type); - - spin_lock(&dev->dev_reservation_lock); - if (!dev->dev_pr_res_holder) { - spin_unlock(&dev->dev_reservation_lock); - return 0; - } - *pr_reg_type = dev->dev_pr_res_holder->pr_res_type; - cmd->pr_res_key = dev->dev_pr_res_holder->pr_res_key; - if (dev->dev_pr_res_holder->pr_reg_nacl != sess->se_node_acl) { - spin_unlock(&dev->dev_reservation_lock); - return -EINVAL; - } - if (!dev->dev_pr_res_holder->isid_present_at_reg) { - spin_unlock(&dev->dev_reservation_lock); - return 0; - } - ret = (dev->dev_pr_res_holder->pr_reg_bin_isid == - sess->sess_bin_isid) ? 0 : -EINVAL; - /* - * Use bit in *pr_reg_type to notify ISID mismatch in - * core_scsi3_pr_seq_non_holder(). - */ - if (ret != 0) - *pr_reg_type |= 0x80000000; - spin_unlock(&dev->dev_reservation_lock); - - return ret; -} - static struct t10_pr_registration *__core_scsi3_do_alloc_registration( struct se_device *dev, struct se_node_acl *nacl, @@ -636,7 +587,6 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration( int all_tg_pt, int aptpl) { - struct se_subsystem_dev *su_dev = dev->se_sub_dev; struct t10_pr_registration *pr_reg; pr_reg = kmem_cache_zalloc(t10_pr_reg_cache, GFP_ATOMIC); @@ -645,7 +595,7 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration( return NULL; } - pr_reg->pr_aptpl_buf = kzalloc(su_dev->t10_pr.pr_aptpl_buf_len, + pr_reg->pr_aptpl_buf = kzalloc(dev->t10_pr.pr_aptpl_buf_len, GFP_ATOMIC); if (!pr_reg->pr_aptpl_buf) { pr_err("Unable to allocate pr_reg->pr_aptpl_buf\n"); @@ -929,7 +879,7 @@ static int __core_scsi3_check_aptpl_registration( struct se_dev_entry *deve) { struct t10_pr_registration *pr_reg, *pr_reg_tmp; - struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; + struct t10_reservation *pr_tmpl = &dev->t10_pr; unsigned char i_port[PR_APTPL_MAX_IPORT_LEN]; unsigned char t_port[PR_APTPL_MAX_TPORT_LEN]; u16 tpgt; @@ -996,11 +946,10 @@ int core_scsi3_check_aptpl_registration( struct se_lun *lun, struct se_lun_acl *lun_acl) { - struct se_subsystem_dev *su_dev = dev->se_sub_dev; struct se_node_acl *nacl = lun_acl->se_lun_nacl; struct se_dev_entry *deve = nacl->device_list[lun_acl->mapped_lun]; - if (su_dev->t10_pr.res_type != SPC3_PERSISTENT_RESERVATIONS) + if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) return 0; return __core_scsi3_check_aptpl_registration(dev, tpg, lun, @@ -1051,10 +1000,9 @@ static void __core_scsi3_add_registration( int register_type, int register_move) { - struct se_subsystem_dev *su_dev = dev->se_sub_dev; struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; - struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; + struct t10_reservation *pr_tmpl = &dev->t10_pr; /* * Increment PRgeneration counter for struct se_device upon a successful @@ -1066,7 +1014,7 @@ static void __core_scsi3_add_registration( * for the REGISTER. */ pr_reg->pr_res_generation = (register_move) ? - su_dev->t10_pr.pr_generation++ : + dev->t10_pr.pr_generation++ : core_scsi3_pr_generation(dev); spin_lock(&pr_tmpl->registration_lock); @@ -1135,7 +1083,7 @@ static struct t10_pr_registration *__core_scsi3_locate_pr_reg( struct se_node_acl *nacl, unsigned char *isid) { - struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; + struct t10_reservation *pr_tmpl = &dev->t10_pr; struct t10_pr_registration *pr_reg, *pr_reg_tmp; struct se_portal_group *tpg; @@ -1160,7 +1108,7 @@ static struct t10_pr_registration *__core_scsi3_locate_pr_reg( * for fabric modules (iSCSI) requiring them. */ if (tpg->se_tpg_tfo->sess_get_initiator_sid != NULL) { - if (dev->se_sub_dev->se_dev_attrib.enforce_pr_isids) + if (dev->dev_attrib.enforce_pr_isids) continue; } atomic_inc(&pr_reg->pr_res_holders); @@ -1274,7 +1222,7 @@ static void __core_scsi3_free_registration( { struct target_core_fabric_ops *tfo = pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo; - struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; + struct t10_reservation *pr_tmpl = &dev->t10_pr; char i_buf[PR_REG_ISID_ID_LEN]; int prf_isid; @@ -1335,7 +1283,7 @@ void core_scsi3_free_pr_reg_from_nacl( struct se_device *dev, struct se_node_acl *nacl) { - struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; + struct t10_reservation *pr_tmpl = &dev->t10_pr; struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_res_holder; /* * If the passed se_node_acl matches the reservation holder, @@ -1365,7 +1313,7 @@ void core_scsi3_free_pr_reg_from_nacl( void core_scsi3_free_all_registrations( struct se_device *dev) { - struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; + struct t10_reservation *pr_tmpl = &dev->t10_pr; struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_res_holder; spin_lock(&dev->dev_reservation_lock); @@ -1479,7 +1427,8 @@ static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve) smp_mb__after_atomic_dec(); } -static int core_scsi3_decode_spec_i_port( +static sense_reason_t +core_scsi3_decode_spec_i_port( struct se_cmd *cmd, struct se_portal_group *tpg, unsigned char *l_isid, @@ -1501,8 +1450,9 @@ static int core_scsi3_decode_spec_i_port( unsigned char *buf; unsigned char *ptr, *i_str = NULL, proto_ident, tmp_proto_ident; char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN]; + sense_reason_t ret; u32 tpdl, tid_len = 0; - int ret, dest_local_nexus, prf_isid; + int dest_local_nexus, prf_isid; u32 dest_rtpi = 0; memset(dest_iport, 0, 64); @@ -1517,8 +1467,7 @@ static int core_scsi3_decode_spec_i_port( tidh_new = kzalloc(sizeof(struct pr_transport_id_holder), GFP_KERNEL); if (!tidh_new) { pr_err("Unable to allocate tidh_new\n"); - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -EINVAL; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } INIT_LIST_HEAD(&tidh_new->dest_list); tidh_new->dest_tpg = tpg; @@ -1530,8 +1479,7 @@ static int core_scsi3_decode_spec_i_port( sa_res_key, all_tg_pt, aptpl); if (!local_pr_reg) { kfree(tidh_new); - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -ENOMEM; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } tidh_new->dest_pr_reg = local_pr_reg; /* @@ -1545,12 +1493,16 @@ static int core_scsi3_decode_spec_i_port( if (cmd->data_length < 28) { pr_warn("SPC-PR: Received PR OUT parameter list" " length too small: %u\n", cmd->data_length); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - ret = -EINVAL; + ret = TCM_INVALID_PARAMETER_LIST; goto out; } buf = transport_kmap_data_sg(cmd); + if (!buf) { + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + goto out; + } + /* * For a PERSISTENT RESERVE OUT specify initiator ports payload, * first extract TransportID Parameter Data Length, and make sure @@ -1565,9 +1517,8 @@ static int core_scsi3_decode_spec_i_port( pr_err("SPC-3 PR: Illegal tpdl: %u + 28 byte header" " does not equal CDB data_length: %u\n", tpdl, cmd->data_length); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - ret = -EINVAL; - goto out; + ret = TCM_INVALID_PARAMETER_LIST; + goto out_unmap; } /* * Start processing the received transport IDs using the @@ -1610,16 +1561,13 @@ static int core_scsi3_decode_spec_i_port( smp_mb__after_atomic_inc(); spin_unlock(&dev->se_port_lock); - ret = core_scsi3_tpg_depend_item(tmp_tpg); - if (ret != 0) { + if (core_scsi3_tpg_depend_item(tmp_tpg)) { pr_err(" core_scsi3_tpg_depend_item()" " for tmp_tpg\n"); atomic_dec(&tmp_tpg->tpg_pr_ref_count); smp_mb__after_atomic_dec(); - cmd->scsi_sense_reason = - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - ret = -EINVAL; - goto out; + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + goto out_unmap; } /* * Locate the destination initiator ACL to be registered @@ -1641,17 +1589,14 @@ static int core_scsi3_decode_spec_i_port( continue; } - ret = core_scsi3_nodeacl_depend_item(dest_node_acl); - if (ret != 0) { + if (core_scsi3_nodeacl_depend_item(dest_node_acl)) { pr_err("configfs_depend_item() failed" " for dest_node_acl->acl_group\n"); atomic_dec(&dest_node_acl->acl_pr_ref_count); smp_mb__after_atomic_dec(); core_scsi3_tpg_undepend_item(tmp_tpg); - cmd->scsi_sense_reason = - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - ret = -EINVAL; - goto out; + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + goto out_unmap; } dest_tpg = tmp_tpg; @@ -1668,9 +1613,8 @@ static int core_scsi3_decode_spec_i_port( if (!dest_tpg) { pr_err("SPC-3 PR SPEC_I_PT: Unable to locate" " dest_tpg\n"); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - ret = -EINVAL; - goto out; + ret = TCM_INVALID_PARAMETER_LIST; + goto out_unmap; } pr_debug("SPC-3 PR SPEC_I_PT: Got %s data_length: %u tpdl: %u" @@ -1683,9 +1627,8 @@ static int core_scsi3_decode_spec_i_port( " %u for Transport ID: %s\n", tid_len, ptr); core_scsi3_nodeacl_undepend_item(dest_node_acl); core_scsi3_tpg_undepend_item(dest_tpg); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - ret = -EINVAL; - goto out; + ret = TCM_INVALID_PARAMETER_LIST; + goto out_unmap; } /* * Locate the desintation struct se_dev_entry pointer for matching @@ -1702,23 +1645,19 @@ static int core_scsi3_decode_spec_i_port( core_scsi3_nodeacl_undepend_item(dest_node_acl); core_scsi3_tpg_undepend_item(dest_tpg); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - ret = -EINVAL; - goto out; + ret = TCM_INVALID_PARAMETER_LIST; + goto out_unmap; } - ret = core_scsi3_lunacl_depend_item(dest_se_deve); - if (ret < 0) { + if (core_scsi3_lunacl_depend_item(dest_se_deve)) { pr_err("core_scsi3_lunacl_depend_item()" " failed\n"); atomic_dec(&dest_se_deve->pr_ref_count); smp_mb__after_atomic_dec(); core_scsi3_nodeacl_undepend_item(dest_node_acl); core_scsi3_tpg_undepend_item(dest_tpg); - cmd->scsi_sense_reason = - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - ret = -EINVAL; - goto out; + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + goto out_unmap; } pr_debug("SPC-3 PR SPEC_I_PT: Located %s Node: %s" @@ -1754,10 +1693,8 @@ static int core_scsi3_decode_spec_i_port( core_scsi3_lunacl_undepend_item(dest_se_deve); core_scsi3_nodeacl_undepend_item(dest_node_acl); core_scsi3_tpg_undepend_item(dest_tpg); - cmd->scsi_sense_reason = - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - ret = -ENOMEM; - goto out; + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + goto out_unmap; } INIT_LIST_HEAD(&tidh_new->dest_list); tidh_new->dest_tpg = dest_tpg; @@ -1788,9 +1725,8 @@ static int core_scsi3_decode_spec_i_port( core_scsi3_nodeacl_undepend_item(dest_node_acl); core_scsi3_tpg_undepend_item(dest_tpg); kfree(tidh_new); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - ret = -EINVAL; - goto out; + ret = TCM_INVALID_PARAMETER_LIST; + goto out_unmap; } tidh_new->dest_pr_reg = dest_pr_reg; list_add_tail(&tidh_new->dest_list, &tid_dest_list); @@ -1848,8 +1784,9 @@ static int core_scsi3_decode_spec_i_port( } return 0; -out: +out_unmap: transport_kunmap_data_sg(cmd); +out: /* * For the failure case, release everything from tid_dest_list * including *dest_pr_reg and the configfs dependances.. @@ -1899,7 +1836,6 @@ static int __core_scsi3_update_aptpl_buf( { struct se_lun *lun; struct se_portal_group *tpg; - struct se_subsystem_dev *su_dev = dev->se_sub_dev; struct t10_pr_registration *pr_reg; unsigned char tmp[512], isid_buf[32]; ssize_t len = 0; @@ -1917,8 +1853,8 @@ static int __core_scsi3_update_aptpl_buf( /* * Walk the registration list.. */ - spin_lock(&su_dev->t10_pr.registration_lock); - list_for_each_entry(pr_reg, &su_dev->t10_pr.registration_list, + spin_lock(&dev->t10_pr.registration_lock); + list_for_each_entry(pr_reg, &dev->t10_pr.registration_list, pr_reg_list) { tmp[0] = '\0'; @@ -1963,7 +1899,7 @@ static int __core_scsi3_update_aptpl_buf( if ((len + strlen(tmp) >= pr_aptpl_buf_len)) { pr_err("Unable to update renaming" " APTPL metadata\n"); - spin_unlock(&su_dev->t10_pr.registration_lock); + spin_unlock(&dev->t10_pr.registration_lock); return -EMSGSIZE; } len += sprintf(buf+len, "%s", tmp); @@ -1981,13 +1917,13 @@ static int __core_scsi3_update_aptpl_buf( if ((len + strlen(tmp) >= pr_aptpl_buf_len)) { pr_err("Unable to update renaming" " APTPL metadata\n"); - spin_unlock(&su_dev->t10_pr.registration_lock); + spin_unlock(&dev->t10_pr.registration_lock); return -EMSGSIZE; } len += sprintf(buf+len, "%s", tmp); reg_count++; } - spin_unlock(&su_dev->t10_pr.registration_lock); + spin_unlock(&dev->t10_pr.registration_lock); if (!reg_count) len += sprintf(buf+len, "No Registrations or Reservations"); @@ -2019,7 +1955,7 @@ static int __core_scsi3_write_aptpl_to_file( unsigned char *buf, u32 pr_aptpl_buf_len) { - struct t10_wwn *wwn = &dev->se_sub_dev->t10_wwn; + struct t10_wwn *wwn = &dev->t10_wwn; struct file *file; struct iovec iov[1]; mm_segment_t old_fs; @@ -2065,14 +2001,15 @@ static int __core_scsi3_write_aptpl_to_file( return 0; } -static int core_scsi3_update_and_write_aptpl( - struct se_device *dev, - unsigned char *in_buf, - u32 in_pr_aptpl_buf_len) +static int +core_scsi3_update_and_write_aptpl(struct se_device *dev, unsigned char *in_buf, + u32 in_pr_aptpl_buf_len) { unsigned char null_buf[64], *buf; u32 pr_aptpl_buf_len; - int ret, clear_aptpl_metadata = 0; + int clear_aptpl_metadata = 0; + int ret; + /* * Can be called with a NULL pointer from PROUT service action CLEAR */ @@ -2094,25 +2031,17 @@ static int core_scsi3_update_and_write_aptpl( clear_aptpl_metadata); if (ret != 0) return ret; + /* * __core_scsi3_write_aptpl_to_file() will call strlen() * on the passed buf to determine pr_aptpl_buf_len. */ - ret = __core_scsi3_write_aptpl_to_file(dev, buf, 0); - if (ret != 0) - return ret; - - return ret; + return __core_scsi3_write_aptpl_to_file(dev, buf, 0); } -static int core_scsi3_emulate_pro_register( - struct se_cmd *cmd, - u64 res_key, - u64 sa_res_key, - int aptpl, - int all_tg_pt, - int spec_i_pt, - int ignore_key) +static sense_reason_t +core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, + int aptpl, int all_tg_pt, int spec_i_pt, int ignore_key) { struct se_session *se_sess = cmd->se_sess; struct se_device *dev = cmd->se_dev; @@ -2120,16 +2049,16 @@ static int core_scsi3_emulate_pro_register( struct se_lun *se_lun = cmd->se_lun; struct se_portal_group *se_tpg; struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_reg_tmp, *pr_reg_e; - struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; + struct t10_reservation *pr_tmpl = &dev->t10_pr; /* Used for APTPL metadata w/ UNREGISTER */ unsigned char *pr_aptpl_buf = NULL; unsigned char isid_buf[PR_REG_ISID_LEN], *isid_ptr = NULL; - int pr_holder = 0, ret = 0, type; + sense_reason_t ret = TCM_NO_SENSE; + int pr_holder = 0, type; if (!se_sess || !se_lun) { pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -EINVAL; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } se_tpg = se_sess->se_tpg; se_deve = se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; @@ -2148,8 +2077,7 @@ static int core_scsi3_emulate_pro_register( if (res_key) { pr_warn("SPC-3 PR: Reservation Key non-zero" " for SA REGISTER, returning CONFLICT\n"); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - return -EINVAL; + return TCM_RESERVATION_CONFLICT; } /* * Do nothing but return GOOD status. @@ -2163,15 +2091,13 @@ static int core_scsi3_emulate_pro_register( * Port Endpoint that the PRO was received from on the * Logical Unit of the SCSI device server. */ - ret = core_scsi3_alloc_registration(cmd->se_dev, + if (core_scsi3_alloc_registration(cmd->se_dev, se_sess->se_node_acl, se_deve, isid_ptr, sa_res_key, all_tg_pt, aptpl, - ignore_key, 0); - if (ret != 0) { + ignore_key, 0)) { pr_err("Unable to allocate" " struct t10_pr_registration\n"); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - return -EINVAL; + return TCM_INVALID_PARAMETER_LIST; } } else { /* @@ -2205,201 +2131,192 @@ static int core_scsi3_emulate_pro_register( pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, se_sess); - ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, + if (core_scsi3_update_and_write_aptpl(cmd->se_dev, &pr_reg->pr_aptpl_buf[0], - pr_tmpl->pr_aptpl_buf_len); - if (!ret) { + pr_tmpl->pr_aptpl_buf_len)) { pr_tmpl->pr_aptpl_active = 1; pr_debug("SPC-3 PR: Set APTPL Bit Activated for REGISTER\n"); } - core_scsi3_put_pr_reg(pr_reg); - return ret; - } else { - /* - * Locate the existing *pr_reg via struct se_node_acl pointers - */ - pr_reg = pr_reg_e; - type = pr_reg->pr_res_type; - - if (!ignore_key) { - if (res_key != pr_reg->pr_res_key) { - pr_err("SPC-3 PR REGISTER: Received" - " res_key: 0x%016Lx does not match" - " existing SA REGISTER res_key:" - " 0x%016Lx\n", res_key, - pr_reg->pr_res_key); - core_scsi3_put_pr_reg(pr_reg); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - return -EINVAL; - } + goto out_put_pr_reg; + } + + /* + * Locate the existing *pr_reg via struct se_node_acl pointers + */ + pr_reg = pr_reg_e; + type = pr_reg->pr_res_type; + + if (!ignore_key) { + if (res_key != pr_reg->pr_res_key) { + pr_err("SPC-3 PR REGISTER: Received" + " res_key: 0x%016Lx does not match" + " existing SA REGISTER res_key:" + " 0x%016Lx\n", res_key, + pr_reg->pr_res_key); + ret = TCM_RESERVATION_CONFLICT; + goto out_put_pr_reg; } - if (spec_i_pt) { - pr_err("SPC-3 PR UNREGISTER: SPEC_I_PT" - " set while sa_res_key=0\n"); - core_scsi3_put_pr_reg(pr_reg); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - return -EINVAL; + } + + if (spec_i_pt) { + pr_err("SPC-3 PR UNREGISTER: SPEC_I_PT" + " set while sa_res_key=0\n"); + ret = TCM_INVALID_PARAMETER_LIST; + goto out_put_pr_reg; + } + + /* + * An existing ALL_TG_PT=1 registration being released + * must also set ALL_TG_PT=1 in the incoming PROUT. + */ + if (pr_reg->pr_reg_all_tg_pt && !(all_tg_pt)) { + pr_err("SPC-3 PR UNREGISTER: ALL_TG_PT=1" + " registration exists, but ALL_TG_PT=1 bit not" + " present in received PROUT\n"); + ret = TCM_INVALID_CDB_FIELD; + goto out_put_pr_reg; + } + + /* + * Allocate APTPL metadata buffer used for UNREGISTER ops + */ + if (aptpl) { + pr_aptpl_buf = kzalloc(pr_tmpl->pr_aptpl_buf_len, + GFP_KERNEL); + if (!pr_aptpl_buf) { + pr_err("Unable to allocate" + " pr_aptpl_buf\n"); + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + goto out_put_pr_reg; } - /* - * An existing ALL_TG_PT=1 registration being released - * must also set ALL_TG_PT=1 in the incoming PROUT. - */ - if (pr_reg->pr_reg_all_tg_pt && !(all_tg_pt)) { - pr_err("SPC-3 PR UNREGISTER: ALL_TG_PT=1" - " registration exists, but ALL_TG_PT=1 bit not" - " present in received PROUT\n"); - core_scsi3_put_pr_reg(pr_reg); - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -EINVAL; + } + + /* + * sa_res_key=0 Unregister Reservation Key for registered I_T + * Nexus sa_res_key=1 Change Reservation Key for registered I_T + * Nexus. + */ + if (!sa_res_key) { + pr_holder = core_scsi3_check_implict_release( + cmd->se_dev, pr_reg); + if (pr_holder < 0) { + kfree(pr_aptpl_buf); + ret = TCM_RESERVATION_CONFLICT; + goto out_put_pr_reg; } + + spin_lock(&pr_tmpl->registration_lock); /* - * Allocate APTPL metadata buffer used for UNREGISTER ops + * Release all ALL_TG_PT=1 for the matching SCSI Initiator Port + * and matching pr_res_key. */ - if (aptpl) { - pr_aptpl_buf = kzalloc(pr_tmpl->pr_aptpl_buf_len, - GFP_KERNEL); - if (!pr_aptpl_buf) { - pr_err("Unable to allocate" - " pr_aptpl_buf\n"); - core_scsi3_put_pr_reg(pr_reg); - cmd->scsi_sense_reason = - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -EINVAL; + if (pr_reg->pr_reg_all_tg_pt) { + list_for_each_entry_safe(pr_reg_p, pr_reg_tmp, + &pr_tmpl->registration_list, + pr_reg_list) { + + if (!pr_reg_p->pr_reg_all_tg_pt) + continue; + if (pr_reg_p->pr_res_key != res_key) + continue; + if (pr_reg == pr_reg_p) + continue; + if (strcmp(pr_reg->pr_reg_nacl->initiatorname, + pr_reg_p->pr_reg_nacl->initiatorname)) + continue; + + __core_scsi3_free_registration(dev, + pr_reg_p, NULL, 0); } } + /* - * sa_res_key=0 Unregister Reservation Key for registered I_T - * Nexus sa_res_key=1 Change Reservation Key for registered I_T - * Nexus. + * Release the calling I_T Nexus registration now.. */ - if (!sa_res_key) { - pr_holder = core_scsi3_check_implict_release( - cmd->se_dev, pr_reg); - if (pr_holder < 0) { - kfree(pr_aptpl_buf); - core_scsi3_put_pr_reg(pr_reg); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - return -EINVAL; - } - - spin_lock(&pr_tmpl->registration_lock); - /* - * Release all ALL_TG_PT=1 for the matching SCSI Initiator Port - * and matching pr_res_key. - */ - if (pr_reg->pr_reg_all_tg_pt) { - list_for_each_entry_safe(pr_reg_p, pr_reg_tmp, - &pr_tmpl->registration_list, - pr_reg_list) { - - if (!pr_reg_p->pr_reg_all_tg_pt) - continue; + __core_scsi3_free_registration(cmd->se_dev, pr_reg, NULL, 1); - if (pr_reg_p->pr_res_key != res_key) - continue; - - if (pr_reg == pr_reg_p) - continue; - - if (strcmp(pr_reg->pr_reg_nacl->initiatorname, - pr_reg_p->pr_reg_nacl->initiatorname)) - continue; - - __core_scsi3_free_registration(dev, - pr_reg_p, NULL, 0); - } - } - /* - * Release the calling I_T Nexus registration now.. - */ - __core_scsi3_free_registration(cmd->se_dev, pr_reg, - NULL, 1); - /* - * From spc4r17, section 5.7.11.3 Unregistering - * - * If the persistent reservation is a registrants only - * type, the device server shall establish a unit - * attention condition for the initiator port associated - * with every registered I_T nexus except for the I_T - * nexus on which the PERSISTENT RESERVE OUT command was - * received, with the additional sense code set to - * RESERVATIONS RELEASED. - */ - if (pr_holder && - ((type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) || - (type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY))) { - list_for_each_entry(pr_reg_p, - &pr_tmpl->registration_list, - pr_reg_list) { - - core_scsi3_ua_allocate( - pr_reg_p->pr_reg_nacl, - pr_reg_p->pr_res_mapped_lun, - 0x2A, - ASCQ_2AH_RESERVATIONS_RELEASED); - } + /* + * From spc4r17, section 5.7.11.3 Unregistering + * + * If the persistent reservation is a registrants only + * type, the device server shall establish a unit + * attention condition for the initiator port associated + * with every registered I_T nexus except for the I_T + * nexus on which the PERSISTENT RESERVE OUT command was + * received, with the additional sense code set to + * RESERVATIONS RELEASED. + */ + if (pr_holder && + (type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY || + type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY)) { + list_for_each_entry(pr_reg_p, + &pr_tmpl->registration_list, + pr_reg_list) { + + core_scsi3_ua_allocate( + pr_reg_p->pr_reg_nacl, + pr_reg_p->pr_res_mapped_lun, + 0x2A, + ASCQ_2AH_RESERVATIONS_RELEASED); } - spin_unlock(&pr_tmpl->registration_lock); + } + spin_unlock(&pr_tmpl->registration_lock); - if (!aptpl) { - pr_tmpl->pr_aptpl_active = 0; - core_scsi3_update_and_write_aptpl(dev, NULL, 0); - pr_debug("SPC-3 PR: Set APTPL Bit Deactivated" - " for UNREGISTER\n"); - return 0; - } + if (!aptpl) { + pr_tmpl->pr_aptpl_active = 0; + core_scsi3_update_and_write_aptpl(dev, NULL, 0); + pr_debug("SPC-3 PR: Set APTPL Bit Deactivated" + " for UNREGISTER\n"); + return 0; + } - ret = core_scsi3_update_and_write_aptpl(dev, - &pr_aptpl_buf[0], - pr_tmpl->pr_aptpl_buf_len); - if (!ret) { - pr_tmpl->pr_aptpl_active = 1; - pr_debug("SPC-3 PR: Set APTPL Bit Activated" - " for UNREGISTER\n"); - } + if (!core_scsi3_update_and_write_aptpl(dev, &pr_aptpl_buf[0], + pr_tmpl->pr_aptpl_buf_len)) { + pr_tmpl->pr_aptpl_active = 1; + pr_debug("SPC-3 PR: Set APTPL Bit Activated" + " for UNREGISTER\n"); + } - kfree(pr_aptpl_buf); - return ret; - } else { - /* - * Increment PRgeneration counter for struct se_device" - * upon a successful REGISTER, see spc4r17 section 6.3.2 - * READ_KEYS service action. - */ - pr_reg->pr_res_generation = core_scsi3_pr_generation( - cmd->se_dev); - pr_reg->pr_res_key = sa_res_key; - pr_debug("SPC-3 PR [%s] REGISTER%s: Changed Reservation" - " Key for %s to: 0x%016Lx PRgeneration:" - " 0x%08x\n", cmd->se_tfo->get_fabric_name(), - (ignore_key) ? "_AND_IGNORE_EXISTING_KEY" : "", - pr_reg->pr_reg_nacl->initiatorname, - pr_reg->pr_res_key, pr_reg->pr_res_generation); - - if (!aptpl) { - pr_tmpl->pr_aptpl_active = 0; - core_scsi3_update_and_write_aptpl(dev, NULL, 0); - core_scsi3_put_pr_reg(pr_reg); - pr_debug("SPC-3 PR: Set APTPL Bit Deactivated" - " for REGISTER\n"); - return 0; - } + goto out_free_aptpl_buf; + } - ret = core_scsi3_update_and_write_aptpl(dev, - &pr_aptpl_buf[0], - pr_tmpl->pr_aptpl_buf_len); - if (!ret) { - pr_tmpl->pr_aptpl_active = 1; - pr_debug("SPC-3 PR: Set APTPL Bit Activated" - " for REGISTER\n"); - } + /* + * Increment PRgeneration counter for struct se_device" + * upon a successful REGISTER, see spc4r17 section 6.3.2 + * READ_KEYS service action. + */ + pr_reg->pr_res_generation = core_scsi3_pr_generation(cmd->se_dev); + pr_reg->pr_res_key = sa_res_key; + pr_debug("SPC-3 PR [%s] REGISTER%s: Changed Reservation" + " Key for %s to: 0x%016Lx PRgeneration:" + " 0x%08x\n", cmd->se_tfo->get_fabric_name(), + (ignore_key) ? "_AND_IGNORE_EXISTING_KEY" : "", + pr_reg->pr_reg_nacl->initiatorname, + pr_reg->pr_res_key, pr_reg->pr_res_generation); - kfree(pr_aptpl_buf); - core_scsi3_put_pr_reg(pr_reg); - } + if (!aptpl) { + pr_tmpl->pr_aptpl_active = 0; + core_scsi3_update_and_write_aptpl(dev, NULL, 0); + pr_debug("SPC-3 PR: Set APTPL Bit Deactivated" + " for REGISTER\n"); + ret = 0; + goto out_put_pr_reg; } - return 0; + + if (!core_scsi3_update_and_write_aptpl(dev, &pr_aptpl_buf[0], + pr_tmpl->pr_aptpl_buf_len)) { + pr_tmpl->pr_aptpl_active = 1; + pr_debug("SPC-3 PR: Set APTPL Bit Activated" + " for REGISTER\n"); + } + +out_free_aptpl_buf: + kfree(pr_aptpl_buf); + ret = 0; +out_put_pr_reg: + core_scsi3_put_pr_reg(pr_reg); + return ret; } unsigned char *core_scsi3_pr_dump_type(int type) @@ -2424,26 +2341,23 @@ unsigned char *core_scsi3_pr_dump_type(int type) return "Unknown SPC-3 PR Type"; } -static int core_scsi3_pro_reserve( - struct se_cmd *cmd, - struct se_device *dev, - int type, - int scope, - u64 res_key) +static sense_reason_t +core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key) { + struct se_device *dev = cmd->se_dev; struct se_session *se_sess = cmd->se_sess; struct se_lun *se_lun = cmd->se_lun; struct t10_pr_registration *pr_reg, *pr_res_holder; - struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; + struct t10_reservation *pr_tmpl = &dev->t10_pr; char i_buf[PR_REG_ISID_ID_LEN]; - int ret, prf_isid; + sense_reason_t ret; + int prf_isid; memset(i_buf, 0, PR_REG_ISID_ID_LEN); if (!se_sess || !se_lun) { pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -EINVAL; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } /* * Locate the existing *pr_reg via struct se_node_acl pointers @@ -2453,8 +2367,7 @@ static int core_scsi3_pro_reserve( if (!pr_reg) { pr_err("SPC-3 PR: Unable to locate" " PR_REGISTERED *pr_reg for RESERVE\n"); - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -EINVAL; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } /* * From spc4r17 Section 5.7.9: Reserving: @@ -2469,9 +2382,8 @@ static int core_scsi3_pro_reserve( pr_err("SPC-3 PR RESERVE: Received res_key: 0x%016Lx" " does not match existing SA REGISTER res_key:" " 0x%016Lx\n", res_key, pr_reg->pr_res_key); - core_scsi3_put_pr_reg(pr_reg); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - return -EINVAL; + ret = TCM_RESERVATION_CONFLICT; + goto out_put_pr_reg; } /* * From spc4r17 Section 5.7.9: Reserving: @@ -2485,9 +2397,8 @@ static int core_scsi3_pro_reserve( */ if (scope != PR_SCOPE_LU_SCOPE) { pr_err("SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope); - core_scsi3_put_pr_reg(pr_reg); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - return -EINVAL; + ret = TCM_INVALID_PARAMETER_LIST; + goto out_put_pr_reg; } /* * See if we have an existing PR reservation holder pointer at @@ -2518,9 +2429,8 @@ static int core_scsi3_pro_reserve( pr_res_holder->pr_reg_nacl->initiatorname); spin_unlock(&dev->dev_reservation_lock); - core_scsi3_put_pr_reg(pr_reg); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - return -EINVAL; + ret = TCM_RESERVATION_CONFLICT; + goto out_put_pr_reg; } /* * From spc4r17 Section 5.7.9: Reserving: @@ -2542,9 +2452,8 @@ static int core_scsi3_pro_reserve( pr_res_holder->pr_reg_nacl->initiatorname); spin_unlock(&dev->dev_reservation_lock); - core_scsi3_put_pr_reg(pr_reg); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - return -EINVAL; + ret = TCM_RESERVATION_CONFLICT; + goto out_put_pr_reg; } /* * From spc4r17 Section 5.7.9: Reserving: @@ -2557,8 +2466,8 @@ static int core_scsi3_pro_reserve( * shall completethe command with GOOD status. */ spin_unlock(&dev->dev_reservation_lock); - core_scsi3_put_pr_reg(pr_reg); - return 0; + ret = 0; + goto out_put_pr_reg; } /* * Otherwise, our *pr_reg becomes the PR reservation holder for said @@ -2582,27 +2491,24 @@ static int core_scsi3_pro_reserve( spin_unlock(&dev->dev_reservation_lock); if (pr_tmpl->pr_aptpl_active) { - ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, + if (!core_scsi3_update_and_write_aptpl(cmd->se_dev, &pr_reg->pr_aptpl_buf[0], - pr_tmpl->pr_aptpl_buf_len); - if (!ret) + pr_tmpl->pr_aptpl_buf_len)) { pr_debug("SPC-3 PR: Updated APTPL metadata" " for RESERVE\n"); + } } + ret = 0; +out_put_pr_reg: core_scsi3_put_pr_reg(pr_reg); - return 0; + return ret; } -static int core_scsi3_emulate_pro_reserve( - struct se_cmd *cmd, - int type, - int scope, - u64 res_key) +static sense_reason_t +core_scsi3_emulate_pro_reserve(struct se_cmd *cmd, int type, int scope, + u64 res_key) { - struct se_device *dev = cmd->se_dev; - int ret = 0; - switch (type) { case PR_TYPE_WRITE_EXCLUSIVE: case PR_TYPE_EXCLUSIVE_ACCESS: @@ -2610,16 +2516,12 @@ static int core_scsi3_emulate_pro_reserve( case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY: case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG: - ret = core_scsi3_pro_reserve(cmd, dev, type, scope, res_key); - break; + return core_scsi3_pro_reserve(cmd, type, scope, res_key); default: pr_err("SPC-3 PR: Unknown Service Action RESERVE Type:" " 0x%02x\n", type); - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -EINVAL; + return TCM_INVALID_CDB_FIELD; } - - return ret; } /* @@ -2657,23 +2559,21 @@ static void __core_scsi3_complete_pro_release( pr_reg->pr_res_holder = pr_reg->pr_res_type = pr_reg->pr_res_scope = 0; } -static int core_scsi3_emulate_pro_release( - struct se_cmd *cmd, - int type, - int scope, - u64 res_key) +static sense_reason_t +core_scsi3_emulate_pro_release(struct se_cmd *cmd, int type, int scope, + u64 res_key) { struct se_device *dev = cmd->se_dev; struct se_session *se_sess = cmd->se_sess; struct se_lun *se_lun = cmd->se_lun; struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_res_holder; - struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; - int ret, all_reg = 0; + struct t10_reservation *pr_tmpl = &dev->t10_pr; + int all_reg = 0; + sense_reason_t ret = 0; if (!se_sess || !se_lun) { pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -EINVAL; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } /* * Locate the existing *pr_reg via struct se_node_acl pointers @@ -2682,8 +2582,7 @@ static int core_scsi3_emulate_pro_release( if (!pr_reg) { pr_err("SPC-3 PR: Unable to locate" " PR_REGISTERED *pr_reg for RELEASE\n"); - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -EINVAL; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } /* * From spc4r17 Section 5.7.11.2 Releasing: @@ -2704,8 +2603,7 @@ static int core_scsi3_emulate_pro_release( * No persistent reservation, return GOOD status. */ spin_unlock(&dev->dev_reservation_lock); - core_scsi3_put_pr_reg(pr_reg); - return 0; + goto out_put_pr_reg; } if ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || (pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) @@ -2718,9 +2616,9 @@ static int core_scsi3_emulate_pro_release( * persistent reservation holder. return GOOD status. */ spin_unlock(&dev->dev_reservation_lock); - core_scsi3_put_pr_reg(pr_reg); - return 0; + goto out_put_pr_reg; } + /* * From spc4r17 Section 5.7.11.2 Releasing: * @@ -2740,9 +2638,8 @@ static int core_scsi3_emulate_pro_release( " does not match existing SA REGISTER res_key:" " 0x%016Lx\n", res_key, pr_reg->pr_res_key); spin_unlock(&dev->dev_reservation_lock); - core_scsi3_put_pr_reg(pr_reg); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - return -EINVAL; + ret = TCM_RESERVATION_CONFLICT; + goto out_put_pr_reg; } /* * From spc4r17 Section 5.7.11.2 Releasing and above: @@ -2763,9 +2660,8 @@ static int core_scsi3_emulate_pro_release( pr_res_holder->pr_reg_nacl->initiatorname); spin_unlock(&dev->dev_reservation_lock); - core_scsi3_put_pr_reg(pr_reg); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - return -EINVAL; + ret = TCM_RESERVATION_CONFLICT; + goto out_put_pr_reg; } /* * In response to a persistent reservation release request from the @@ -2818,25 +2714,23 @@ static int core_scsi3_emulate_pro_release( write_aptpl: if (pr_tmpl->pr_aptpl_active) { - ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, - &pr_reg->pr_aptpl_buf[0], - pr_tmpl->pr_aptpl_buf_len); - if (!ret) + if (!core_scsi3_update_and_write_aptpl(cmd->se_dev, + &pr_reg->pr_aptpl_buf[0], pr_tmpl->pr_aptpl_buf_len)) { pr_debug("SPC-3 PR: Updated APTPL metadata for RELEASE\n"); + } } - +out_put_pr_reg: core_scsi3_put_pr_reg(pr_reg); - return 0; + return ret; } -static int core_scsi3_emulate_pro_clear( - struct se_cmd *cmd, - u64 res_key) +static sense_reason_t +core_scsi3_emulate_pro_clear(struct se_cmd *cmd, u64 res_key) { struct se_device *dev = cmd->se_dev; struct se_node_acl *pr_reg_nacl; struct se_session *se_sess = cmd->se_sess; - struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; + struct t10_reservation *pr_tmpl = &dev->t10_pr; struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder; u32 pr_res_mapped_lun = 0; int calling_it_nexus = 0; @@ -2848,8 +2742,7 @@ static int core_scsi3_emulate_pro_clear( if (!pr_reg_n) { pr_err("SPC-3 PR: Unable to locate" " PR_REGISTERED *pr_reg for CLEAR\n"); - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -EINVAL; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } /* * From spc4r17 section 5.7.11.6, Clearing: @@ -2868,8 +2761,7 @@ static int core_scsi3_emulate_pro_clear( " existing SA REGISTER res_key:" " 0x%016Lx\n", res_key, pr_reg_n->pr_res_key); core_scsi3_put_pr_reg(pr_reg_n); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - return -EINVAL; + return TCM_RESERVATION_CONFLICT; } /* * a) Release the persistent reservation, if any; @@ -2993,28 +2885,22 @@ static void core_scsi3_release_preempt_and_abort( } } -static int core_scsi3_pro_preempt( - struct se_cmd *cmd, - int type, - int scope, - u64 res_key, - u64 sa_res_key, - int abort) +static sense_reason_t +core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key, + u64 sa_res_key, int abort) { struct se_device *dev = cmd->se_dev; struct se_node_acl *pr_reg_nacl; struct se_session *se_sess = cmd->se_sess; LIST_HEAD(preempt_and_abort_list); struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder; - struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; + struct t10_reservation *pr_tmpl = &dev->t10_pr; u32 pr_res_mapped_lun = 0; int all_reg = 0, calling_it_nexus = 0, released_regs = 0; - int prh_type = 0, prh_scope = 0, ret; + int prh_type = 0, prh_scope = 0; - if (!se_sess) { - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -EINVAL; - } + if (!se_sess) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; pr_reg_n = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, se_sess); @@ -3022,19 +2908,16 @@ static int core_scsi3_pro_preempt( pr_err("SPC-3 PR: Unable to locate" " PR_REGISTERED *pr_reg for PREEMPT%s\n", (abort) ? "_AND_ABORT" : ""); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - return -EINVAL; + return TCM_RESERVATION_CONFLICT; } if (pr_reg_n->pr_res_key != res_key) { core_scsi3_put_pr_reg(pr_reg_n); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - return -EINVAL; + return TCM_RESERVATION_CONFLICT; } if (scope != PR_SCOPE_LU_SCOPE) { pr_err("SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope); core_scsi3_put_pr_reg(pr_reg_n); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - return -EINVAL; + return TCM_INVALID_PARAMETER_LIST; } spin_lock(&dev->dev_reservation_lock); @@ -3047,8 +2930,7 @@ static int core_scsi3_pro_preempt( if (!all_reg && !sa_res_key) { spin_unlock(&dev->dev_reservation_lock); core_scsi3_put_pr_reg(pr_reg_n); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - return -EINVAL; + return TCM_INVALID_PARAMETER_LIST; } /* * From spc4r17, section 5.7.11.4.4 Removing Registrations: @@ -3142,8 +3024,7 @@ static int core_scsi3_pro_preempt( if (!released_regs) { spin_unlock(&dev->dev_reservation_lock); core_scsi3_put_pr_reg(pr_reg_n); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - return -EINVAL; + return TCM_RESERVATION_CONFLICT; } /* * For an existing all registrants type reservation @@ -3162,13 +3043,13 @@ static int core_scsi3_pro_preempt( spin_unlock(&dev->dev_reservation_lock); if (pr_tmpl->pr_aptpl_active) { - ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, + if (!core_scsi3_update_and_write_aptpl(cmd->se_dev, &pr_reg_n->pr_aptpl_buf[0], - pr_tmpl->pr_aptpl_buf_len); - if (!ret) + pr_tmpl->pr_aptpl_buf_len)) { pr_debug("SPC-3 PR: Updated APTPL" " metadata for PREEMPT%s\n", (abort) ? "_AND_ABORT" : ""); + } } core_scsi3_put_pr_reg(pr_reg_n); @@ -3298,12 +3179,12 @@ static int core_scsi3_pro_preempt( } if (pr_tmpl->pr_aptpl_active) { - ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, + if (!core_scsi3_update_and_write_aptpl(cmd->se_dev, &pr_reg_n->pr_aptpl_buf[0], - pr_tmpl->pr_aptpl_buf_len); - if (!ret) + pr_tmpl->pr_aptpl_buf_len)) { pr_debug("SPC-3 PR: Updated APTPL metadata for PREEMPT" - "%s\n", (abort) ? "_AND_ABORT" : ""); + "%s\n", abort ? "_AND_ABORT" : ""); + } } core_scsi3_put_pr_reg(pr_reg_n); @@ -3311,16 +3192,10 @@ static int core_scsi3_pro_preempt( return 0; } -static int core_scsi3_emulate_pro_preempt( - struct se_cmd *cmd, - int type, - int scope, - u64 res_key, - u64 sa_res_key, - int abort) +static sense_reason_t +core_scsi3_emulate_pro_preempt(struct se_cmd *cmd, int type, int scope, + u64 res_key, u64 sa_res_key, int abort) { - int ret = 0; - switch (type) { case PR_TYPE_WRITE_EXCLUSIVE: case PR_TYPE_EXCLUSIVE_ACCESS: @@ -3328,26 +3203,19 @@ static int core_scsi3_emulate_pro_preempt( case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY: case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG: - ret = core_scsi3_pro_preempt(cmd, type, scope, - res_key, sa_res_key, abort); - break; + return core_scsi3_pro_preempt(cmd, type, scope, res_key, + sa_res_key, abort); default: pr_err("SPC-3 PR: Unknown Service Action PREEMPT%s" " Type: 0x%02x\n", (abort) ? "_AND_ABORT" : "", type); - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -EINVAL; + return TCM_INVALID_CDB_FIELD; } - - return ret; } -static int core_scsi3_emulate_pro_register_and_move( - struct se_cmd *cmd, - u64 res_key, - u64 sa_res_key, - int aptpl, - int unreg) +static sense_reason_t +core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, + u64 sa_res_key, int aptpl, int unreg) { struct se_session *se_sess = cmd->se_sess; struct se_device *dev = cmd->se_dev; @@ -3358,20 +3226,21 @@ static int core_scsi3_emulate_pro_register_and_move( struct se_portal_group *se_tpg, *dest_se_tpg = NULL; struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops; struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg; - struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; + struct t10_reservation *pr_tmpl = &dev->t10_pr; unsigned char *buf; unsigned char *initiator_str; char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN]; u32 tid_len, tmp_tid_len; - int new_reg = 0, type, scope, ret, matching_iname, prf_isid; + int new_reg = 0, type, scope, matching_iname, prf_isid; + sense_reason_t ret; unsigned short rtpi; unsigned char proto_ident; if (!se_sess || !se_lun) { pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -EINVAL; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } + memset(dest_iport, 0, 64); memset(i_buf, 0, PR_REG_ISID_ID_LEN); se_tpg = se_sess->se_tpg; @@ -3387,8 +3256,7 @@ static int core_scsi3_emulate_pro_register_and_move( if (!pr_reg) { pr_err("SPC-3 PR: Unable to locate PR_REGISTERED" " *pr_reg for REGISTER_AND_MOVE\n"); - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -EINVAL; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } /* * The provided reservation key much match the existing reservation key @@ -3398,9 +3266,8 @@ static int core_scsi3_emulate_pro_register_and_move( pr_warn("SPC-3 PR REGISTER_AND_MOVE: Received" " res_key: 0x%016Lx does not match existing SA REGISTER" " res_key: 0x%016Lx\n", res_key, pr_reg->pr_res_key); - core_scsi3_put_pr_reg(pr_reg); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - return -EINVAL; + ret = TCM_RESERVATION_CONFLICT; + goto out_put_pr_reg; } /* * The service active reservation key needs to be non zero @@ -3408,9 +3275,8 @@ static int core_scsi3_emulate_pro_register_and_move( if (!sa_res_key) { pr_warn("SPC-3 PR REGISTER_AND_MOVE: Received zero" " sa_res_key\n"); - core_scsi3_put_pr_reg(pr_reg); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - return -EINVAL; + ret = TCM_INVALID_PARAMETER_LIST; + goto out_put_pr_reg; } /* @@ -3419,6 +3285,11 @@ static int core_scsi3_emulate_pro_register_and_move( * information. */ buf = transport_kmap_data_sg(cmd); + if (!buf) { + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + goto out_put_pr_reg; + } + rtpi = (buf[18] & 0xff) << 8; rtpi |= buf[19] & 0xff; tid_len = (buf[20] & 0xff) << 24; @@ -3432,9 +3303,8 @@ static int core_scsi3_emulate_pro_register_and_move( pr_err("SPC-3 PR: Illegal tid_len: %u + 24 byte header" " does not equal CDB data_length: %u\n", tid_len, cmd->data_length); - core_scsi3_put_pr_reg(pr_reg); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - return -EINVAL; + ret = TCM_INVALID_PARAMETER_LIST; + goto out_put_pr_reg; } spin_lock(&dev->se_port_lock); @@ -3452,15 +3322,13 @@ static int core_scsi3_emulate_pro_register_and_move( smp_mb__after_atomic_inc(); spin_unlock(&dev->se_port_lock); - ret = core_scsi3_tpg_depend_item(dest_se_tpg); - if (ret != 0) { + if (core_scsi3_tpg_depend_item(dest_se_tpg)) { pr_err("core_scsi3_tpg_depend_item() failed" " for dest_se_tpg\n"); atomic_dec(&dest_se_tpg->tpg_pr_ref_count); smp_mb__after_atomic_dec(); - core_scsi3_put_pr_reg(pr_reg); - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -EINVAL; + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + goto out_put_pr_reg; } spin_lock(&dev->se_port_lock); @@ -3472,12 +3340,15 @@ static int core_scsi3_emulate_pro_register_and_move( pr_err("SPC-3 PR REGISTER_AND_MOVE: Unable to locate" " fabric ops from Relative Target Port Identifier:" " %hu\n", rtpi); - core_scsi3_put_pr_reg(pr_reg); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - return -EINVAL; + ret = TCM_INVALID_PARAMETER_LIST; + goto out_put_pr_reg; } buf = transport_kmap_data_sg(cmd); + if (!buf) { + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + goto out_put_pr_reg; + } proto_ident = (buf[24] & 0x0f); pr_debug("SPC-3 PR REGISTER_AND_MOVE: Extracted Protocol Identifier:" @@ -3489,16 +3360,14 @@ static int core_scsi3_emulate_pro_register_and_move( " from fabric: %s\n", proto_ident, dest_tf_ops->get_fabric_proto_ident(dest_se_tpg), dest_tf_ops->get_fabric_name()); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - ret = -EINVAL; + ret = TCM_INVALID_PARAMETER_LIST; goto out; } if (dest_tf_ops->tpg_parse_pr_out_transport_id == NULL) { pr_err("SPC-3 PR REGISTER_AND_MOVE: Fabric does not" " containg a valid tpg_parse_pr_out_transport_id" " function pointer\n"); - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - ret = -EINVAL; + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; goto out; } initiator_str = dest_tf_ops->tpg_parse_pr_out_transport_id(dest_se_tpg, @@ -3506,8 +3375,7 @@ static int core_scsi3_emulate_pro_register_and_move( if (!initiator_str) { pr_err("SPC-3 PR REGISTER_AND_MOVE: Unable to locate" " initiator_str from Transport ID\n"); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - ret = -EINVAL; + ret = TCM_INVALID_PARAMETER_LIST; goto out; } @@ -3536,8 +3404,7 @@ static int core_scsi3_emulate_pro_register_and_move( pr_err("SPC-3 PR REGISTER_AND_MOVE: TransportID: %s" " matches: %s on received I_T Nexus\n", initiator_str, pr_reg_nacl->initiatorname); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - ret = -EINVAL; + ret = TCM_INVALID_PARAMETER_LIST; goto out; } if (!strcmp(iport_ptr, pr_reg->pr_reg_isid)) { @@ -3545,8 +3412,7 @@ static int core_scsi3_emulate_pro_register_and_move( " matches: %s %s on received I_T Nexus\n", initiator_str, iport_ptr, pr_reg_nacl->initiatorname, pr_reg->pr_reg_isid); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - ret = -EINVAL; + ret = TCM_INVALID_PARAMETER_LIST; goto out; } after_iport_check: @@ -3566,19 +3432,17 @@ after_iport_check: pr_err("Unable to locate %s dest_node_acl for" " TransportID%s\n", dest_tf_ops->get_fabric_name(), initiator_str); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - ret = -EINVAL; + ret = TCM_INVALID_PARAMETER_LIST; goto out; } - ret = core_scsi3_nodeacl_depend_item(dest_node_acl); - if (ret != 0) { + + if (core_scsi3_nodeacl_depend_item(dest_node_acl)) { pr_err("core_scsi3_nodeacl_depend_item() for" " dest_node_acl\n"); atomic_dec(&dest_node_acl->acl_pr_ref_count); smp_mb__after_atomic_dec(); dest_node_acl = NULL; - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - ret = -EINVAL; + ret = TCM_INVALID_PARAMETER_LIST; goto out; } @@ -3594,19 +3458,16 @@ after_iport_check: if (!dest_se_deve) { pr_err("Unable to locate %s dest_se_deve from RTPI:" " %hu\n", dest_tf_ops->get_fabric_name(), rtpi); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - ret = -EINVAL; + ret = TCM_INVALID_PARAMETER_LIST; goto out; } - ret = core_scsi3_lunacl_depend_item(dest_se_deve); - if (ret < 0) { + if (core_scsi3_lunacl_depend_item(dest_se_deve)) { pr_err("core_scsi3_lunacl_depend_item() failed\n"); atomic_dec(&dest_se_deve->pr_ref_count); smp_mb__after_atomic_dec(); dest_se_deve = NULL; - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - ret = -EINVAL; + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; goto out; } @@ -3625,8 +3486,7 @@ after_iport_check: pr_warn("SPC-3 PR REGISTER_AND_MOVE: No reservation" " currently held\n"); spin_unlock(&dev->dev_reservation_lock); - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - ret = -EINVAL; + ret = TCM_INVALID_CDB_FIELD; goto out; } /* @@ -3639,8 +3499,7 @@ after_iport_check: pr_warn("SPC-3 PR REGISTER_AND_MOVE: Calling I_T" " Nexus is not reservation holder\n"); spin_unlock(&dev->dev_reservation_lock); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - ret = -EINVAL; + ret = TCM_RESERVATION_CONFLICT; goto out; } /* @@ -3658,8 +3517,7 @@ after_iport_check: " reservation for type: %s\n", core_scsi3_pr_dump_type(pr_res_holder->pr_res_type)); spin_unlock(&dev->dev_reservation_lock); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - ret = -EINVAL; + ret = TCM_RESERVATION_CONFLICT; goto out; } pr_res_nacl = pr_res_holder->pr_reg_nacl; @@ -3691,13 +3549,11 @@ after_iport_check: dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, iport_ptr); if (!dest_pr_reg) { - ret = core_scsi3_alloc_registration(cmd->se_dev, + if (core_scsi3_alloc_registration(cmd->se_dev, dest_node_acl, dest_se_deve, iport_ptr, - sa_res_key, 0, aptpl, 2, 1); - if (ret != 0) { + sa_res_key, 0, aptpl, 2, 1)) { spin_unlock(&dev->dev_reservation_lock); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - ret = -EINVAL; + ret = TCM_INVALID_PARAMETER_LIST; goto out; } dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, @@ -3768,12 +3624,12 @@ after_iport_check: " REGISTER_AND_MOVE\n"); } else { pr_tmpl->pr_aptpl_active = 1; - ret = core_scsi3_update_and_write_aptpl(cmd->se_dev, + if (!core_scsi3_update_and_write_aptpl(cmd->se_dev, &dest_pr_reg->pr_aptpl_buf[0], - pr_tmpl->pr_aptpl_buf_len); - if (!ret) + pr_tmpl->pr_aptpl_buf_len)) { pr_debug("SPC-3 PR: Set APTPL Bit Activated for" " REGISTER_AND_MOVE\n"); + } } transport_kunmap_data_sg(cmd); @@ -3788,6 +3644,8 @@ out: if (dest_node_acl) core_scsi3_nodeacl_undepend_item(dest_node_acl); core_scsi3_tpg_undepend_item(dest_se_tpg); + +out_put_pr_reg: core_scsi3_put_pr_reg(pr_reg); return ret; } @@ -3805,14 +3663,15 @@ static unsigned long long core_scsi3_extract_reservation_key(unsigned char *cdb) /* * See spc4r17 section 6.14 Table 170 */ -int target_scsi3_emulate_pr_out(struct se_cmd *cmd) +sense_reason_t +target_scsi3_emulate_pr_out(struct se_cmd *cmd) { unsigned char *cdb = &cmd->t_task_cdb[0]; unsigned char *buf; u64 res_key, sa_res_key; int sa, scope, type, aptpl; int spec_i_pt = 0, all_tg_pt = 0, unreg = 0; - int ret; + sense_reason_t ret; /* * Following spc2r20 5.5.1 Reservations overview: @@ -3823,32 +3682,26 @@ int target_scsi3_emulate_pr_out(struct se_cmd *cmd) * initiator or service action and shall terminate with a RESERVATION * CONFLICT status. */ - if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) { + if (cmd->se_dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) { pr_err("Received PERSISTENT_RESERVE CDB while legacy" " SPC-2 reservation is held, returning" " RESERVATION_CONFLICT\n"); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - ret = -EINVAL; - goto out; + return TCM_RESERVATION_CONFLICT; } /* * FIXME: A NULL struct se_session pointer means an this is not coming from * a $FABRIC_MOD's nexus, but from internal passthrough ops. */ - if (!cmd->se_sess) { - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - ret = -EINVAL; - goto out; - } + if (!cmd->se_sess) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; if (cmd->data_length < 24) { pr_warn("SPC-PR: Received PR OUT parameter list" " length too small: %u\n", cmd->data_length); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - ret = -EINVAL; - goto out; + return TCM_INVALID_PARAMETER_LIST; } + /* * From the PERSISTENT_RESERVE_OUT command descriptor block (CDB) */ @@ -3857,6 +3710,9 @@ int target_scsi3_emulate_pr_out(struct se_cmd *cmd) type = (cdb[2] & 0x0f); buf = transport_kmap_data_sg(cmd); + if (!buf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + /* * From PERSISTENT_RESERVE_OUT parameter list (payload) */ @@ -3880,11 +3736,8 @@ int target_scsi3_emulate_pr_out(struct se_cmd *cmd) /* * SPEC_I_PT=1 is only valid for Service action: REGISTER */ - if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER)) { - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - ret = -EINVAL; - goto out; - } + if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER)) + return TCM_INVALID_PARAMETER_LIST; /* * From spc4r17 section 6.14: @@ -3899,10 +3752,9 @@ int target_scsi3_emulate_pr_out(struct se_cmd *cmd) (cmd->data_length != 24)) { pr_warn("SPC-PR: Received PR OUT illegal parameter" " list length: %u\n", cmd->data_length); - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - ret = -EINVAL; - goto out; + return TCM_INVALID_PARAMETER_LIST; } + /* * (core_scsi3_emulate_pro_* function parameters * are defined by spc4r17 Table 174: @@ -3941,12 +3793,9 @@ int target_scsi3_emulate_pr_out(struct se_cmd *cmd) default: pr_err("Unknown PERSISTENT_RESERVE_OUT service" " action: 0x%02x\n", cdb[1] & 0x1f); - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - ret = -EINVAL; - break; + return TCM_INVALID_CDB_FIELD; } -out: if (!ret) target_complete_cmd(cmd, GOOD); return ret; @@ -3957,10 +3806,10 @@ out: * * See spc4r17 section 5.7.6.2 and section 6.13.2, Table 160 */ -static int core_scsi3_pri_read_keys(struct se_cmd *cmd) +static sense_reason_t +core_scsi3_pri_read_keys(struct se_cmd *cmd) { - struct se_device *se_dev = cmd->se_dev; - struct se_subsystem_dev *su_dev = se_dev->se_sub_dev; + struct se_device *dev = cmd->se_dev; struct t10_pr_registration *pr_reg; unsigned char *buf; u32 add_len = 0, off = 8; @@ -3968,18 +3817,20 @@ static int core_scsi3_pri_read_keys(struct se_cmd *cmd) if (cmd->data_length < 8) { pr_err("PRIN SA READ_KEYS SCSI Data Length: %u" " too small\n", cmd->data_length); - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -EINVAL; + return TCM_INVALID_CDB_FIELD; } buf = transport_kmap_data_sg(cmd); - buf[0] = ((su_dev->t10_pr.pr_generation >> 24) & 0xff); - buf[1] = ((su_dev->t10_pr.pr_generation >> 16) & 0xff); - buf[2] = ((su_dev->t10_pr.pr_generation >> 8) & 0xff); - buf[3] = (su_dev->t10_pr.pr_generation & 0xff); + if (!buf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - spin_lock(&su_dev->t10_pr.registration_lock); - list_for_each_entry(pr_reg, &su_dev->t10_pr.registration_list, + buf[0] = ((dev->t10_pr.pr_generation >> 24) & 0xff); + buf[1] = ((dev->t10_pr.pr_generation >> 16) & 0xff); + buf[2] = ((dev->t10_pr.pr_generation >> 8) & 0xff); + buf[3] = (dev->t10_pr.pr_generation & 0xff); + + spin_lock(&dev->t10_pr.registration_lock); + list_for_each_entry(pr_reg, &dev->t10_pr.registration_list, pr_reg_list) { /* * Check for overflow of 8byte PRI READ_KEYS payload and @@ -3999,7 +3850,7 @@ static int core_scsi3_pri_read_keys(struct se_cmd *cmd) add_len += 8; } - spin_unlock(&su_dev->t10_pr.registration_lock); + spin_unlock(&dev->t10_pr.registration_lock); buf[4] = ((add_len >> 24) & 0xff); buf[5] = ((add_len >> 16) & 0xff); @@ -4016,10 +3867,10 @@ static int core_scsi3_pri_read_keys(struct se_cmd *cmd) * * See spc4r17 section 5.7.6.3 and section 6.13.3.2 Table 161 and 162 */ -static int core_scsi3_pri_read_reservation(struct se_cmd *cmd) +static sense_reason_t +core_scsi3_pri_read_reservation(struct se_cmd *cmd) { - struct se_device *se_dev = cmd->se_dev; - struct se_subsystem_dev *su_dev = se_dev->se_sub_dev; + struct se_device *dev = cmd->se_dev; struct t10_pr_registration *pr_reg; unsigned char *buf; u64 pr_res_key; @@ -4028,18 +3879,20 @@ static int core_scsi3_pri_read_reservation(struct se_cmd *cmd) if (cmd->data_length < 8) { pr_err("PRIN SA READ_RESERVATIONS SCSI Data Length: %u" " too small\n", cmd->data_length); - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -EINVAL; + return TCM_INVALID_CDB_FIELD; } buf = transport_kmap_data_sg(cmd); - buf[0] = ((su_dev->t10_pr.pr_generation >> 24) & 0xff); - buf[1] = ((su_dev->t10_pr.pr_generation >> 16) & 0xff); - buf[2] = ((su_dev->t10_pr.pr_generation >> 8) & 0xff); - buf[3] = (su_dev->t10_pr.pr_generation & 0xff); + if (!buf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - spin_lock(&se_dev->dev_reservation_lock); - pr_reg = se_dev->dev_pr_res_holder; + buf[0] = ((dev->t10_pr.pr_generation >> 24) & 0xff); + buf[1] = ((dev->t10_pr.pr_generation >> 16) & 0xff); + buf[2] = ((dev->t10_pr.pr_generation >> 8) & 0xff); + buf[3] = (dev->t10_pr.pr_generation & 0xff); + + spin_lock(&dev->dev_reservation_lock); + pr_reg = dev->dev_pr_res_holder; if (pr_reg) { /* * Set the hardcoded Additional Length @@ -4090,7 +3943,7 @@ static int core_scsi3_pri_read_reservation(struct se_cmd *cmd) } err: - spin_unlock(&se_dev->dev_reservation_lock); + spin_unlock(&dev->dev_reservation_lock); transport_kunmap_data_sg(cmd); return 0; @@ -4101,21 +3954,23 @@ err: * * See spc4r17 section 6.13.4 Table 165 */ -static int core_scsi3_pri_report_capabilities(struct se_cmd *cmd) +static sense_reason_t +core_scsi3_pri_report_capabilities(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr; + struct t10_reservation *pr_tmpl = &dev->t10_pr; unsigned char *buf; u16 add_len = 8; /* Hardcoded to 8. */ if (cmd->data_length < 6) { pr_err("PRIN SA REPORT_CAPABILITIES SCSI Data Length:" " %u too small\n", cmd->data_length); - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -EINVAL; + return TCM_INVALID_CDB_FIELD; } buf = transport_kmap_data_sg(cmd); + if (!buf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; buf[0] = ((add_len << 8) & 0xff); buf[1] = (add_len & 0xff); @@ -4157,14 +4012,14 @@ static int core_scsi3_pri_report_capabilities(struct se_cmd *cmd) * * See spc4r17 section 6.13.5 Table 168 and 169 */ -static int core_scsi3_pri_read_full_status(struct se_cmd *cmd) +static sense_reason_t +core_scsi3_pri_read_full_status(struct se_cmd *cmd) { - struct se_device *se_dev = cmd->se_dev; + struct se_device *dev = cmd->se_dev; struct se_node_acl *se_nacl; - struct se_subsystem_dev *su_dev = se_dev->se_sub_dev; struct se_portal_group *se_tpg; struct t10_pr_registration *pr_reg, *pr_reg_tmp; - struct t10_reservation *pr_tmpl = &se_dev->se_sub_dev->t10_pr; + struct t10_reservation *pr_tmpl = &dev->t10_pr; unsigned char *buf; u32 add_desc_len = 0, add_len = 0, desc_len, exp_desc_len; u32 off = 8; /* off into first Full Status descriptor */ @@ -4173,16 +4028,17 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd) if (cmd->data_length < 8) { pr_err("PRIN SA READ_FULL_STATUS SCSI Data Length: %u" " too small\n", cmd->data_length); - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -EINVAL; + return TCM_INVALID_CDB_FIELD; } buf = transport_kmap_data_sg(cmd); + if (!buf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - buf[0] = ((su_dev->t10_pr.pr_generation >> 24) & 0xff); - buf[1] = ((su_dev->t10_pr.pr_generation >> 16) & 0xff); - buf[2] = ((su_dev->t10_pr.pr_generation >> 8) & 0xff); - buf[3] = (su_dev->t10_pr.pr_generation & 0xff); + buf[0] = ((dev->t10_pr.pr_generation >> 24) & 0xff); + buf[1] = ((dev->t10_pr.pr_generation >> 16) & 0xff); + buf[2] = ((dev->t10_pr.pr_generation >> 8) & 0xff); + buf[3] = (dev->t10_pr.pr_generation & 0xff); spin_lock(&pr_tmpl->registration_lock); list_for_each_entry_safe(pr_reg, pr_reg_tmp, @@ -4303,9 +4159,10 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd) return 0; } -int target_scsi3_emulate_pr_in(struct se_cmd *cmd) +sense_reason_t +target_scsi3_emulate_pr_in(struct se_cmd *cmd) { - int ret; + sense_reason_t ret; /* * Following spc2r20 5.5.1 Reservations overview: @@ -4316,12 +4173,11 @@ int target_scsi3_emulate_pr_in(struct se_cmd *cmd) * initiator or service action and shall terminate with a RESERVATION * CONFLICT status. */ - if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) { + if (cmd->se_dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) { pr_err("Received PERSISTENT_RESERVE CDB while legacy" " SPC-2 reservation is held, returning" " RESERVATION_CONFLICT\n"); - cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; - return -EINVAL; + return TCM_RESERVATION_CONFLICT; } switch (cmd->t_task_cdb[1] & 0x1f) { @@ -4340,9 +4196,7 @@ int target_scsi3_emulate_pr_in(struct se_cmd *cmd) default: pr_err("Unknown PERSISTENT_RESERVE_IN service" " action: 0x%02x\n", cmd->t_task_cdb[1] & 0x1f); - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - ret = -EINVAL; - break; + return TCM_INVALID_CDB_FIELD; } if (!ret) @@ -4350,56 +4204,25 @@ int target_scsi3_emulate_pr_in(struct se_cmd *cmd) return ret; } -static int core_pt_reservation_check(struct se_cmd *cmd, u32 *pr_res_type) -{ - return 0; -} - -static int core_pt_seq_non_holder( - struct se_cmd *cmd, - unsigned char *cdb, - u32 pr_reg_type) +sense_reason_t +target_check_reservation(struct se_cmd *cmd) { - return 0; -} + struct se_device *dev = cmd->se_dev; + sense_reason_t ret; -int core_setup_reservations(struct se_device *dev, int force_pt) -{ - struct se_subsystem_dev *su_dev = dev->se_sub_dev; - struct t10_reservation *rest = &su_dev->t10_pr; - /* - * If this device is from Target_Core_Mod/pSCSI, use the reservations - * of the Underlying SCSI hardware. In Linux/SCSI terms, this can - * cause a problem because libata and some SATA RAID HBAs appear - * under Linux/SCSI, but to emulate reservations themselves. - */ - if (((dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) && - !(dev->se_sub_dev->se_dev_attrib.emulate_reservations)) || force_pt) { - rest->res_type = SPC_PASSTHROUGH; - rest->pr_ops.t10_reservation_check = &core_pt_reservation_check; - rest->pr_ops.t10_seq_non_holder = &core_pt_seq_non_holder; - pr_debug("%s: Using SPC_PASSTHROUGH, no reservation" - " emulation\n", dev->transport->name); + if (!cmd->se_sess) + return 0; + if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE) + return 0; + if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) return 0; - } - /* - * If SPC-3 or above is reported by real or emulated struct se_device, - * use emulated Persistent Reservations. - */ - if (dev->transport->get_device_rev(dev) >= SCSI_3) { - rest->res_type = SPC3_PERSISTENT_RESERVATIONS; - rest->pr_ops.t10_reservation_check = &core_scsi3_pr_reservation_check; - rest->pr_ops.t10_seq_non_holder = &core_scsi3_pr_seq_non_holder; - pr_debug("%s: Using SPC3_PERSISTENT_RESERVATIONS" - " emulation\n", dev->transport->name); - } else { - rest->res_type = SPC2_RESERVATIONS; - rest->pr_ops.t10_reservation_check = &core_scsi2_reservation_check; - rest->pr_ops.t10_seq_non_holder = - &core_scsi2_reservation_seq_non_holder; - pr_debug("%s: Using SPC2_RESERVATIONS emulation\n", - dev->transport->name); - } - return 0; + spin_lock(&dev->dev_reservation_lock); + if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) + ret = target_scsi2_reservation_check(cmd); + else + ret = target_scsi3_pr_reservation_check(cmd); + spin_unlock(&dev->dev_reservation_lock); + + return ret; } diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h index af6c460d886d..b4a004247ab2 100644 --- a/drivers/target/target_core_pr.h +++ b/drivers/target/target_core_pr.h @@ -47,8 +47,8 @@ extern struct kmem_cache *t10_pr_reg_cache; extern int core_pr_dump_initiator_port(struct t10_pr_registration *, char *, u32); -extern int target_scsi2_reservation_release(struct se_cmd *); -extern int target_scsi2_reservation_reserve(struct se_cmd *); +extern sense_reason_t target_scsi2_reservation_release(struct se_cmd *); +extern sense_reason_t target_scsi2_reservation_reserve(struct se_cmd *); extern int core_scsi3_alloc_aptpl_registration( struct t10_reservation *, u64, unsigned char *, unsigned char *, u32, @@ -61,8 +61,8 @@ extern void core_scsi3_free_pr_reg_from_nacl(struct se_device *, extern void core_scsi3_free_all_registrations(struct se_device *); extern unsigned char *core_scsi3_pr_dump_type(int); -extern int target_scsi3_emulate_pr_in(struct se_cmd *); -extern int target_scsi3_emulate_pr_out(struct se_cmd *); -extern int core_setup_reservations(struct se_device *, int); +extern sense_reason_t target_scsi3_emulate_pr_in(struct se_cmd *); +extern sense_reason_t target_scsi3_emulate_pr_out(struct se_cmd *); +extern sense_reason_t target_check_reservation(struct se_cmd *); #endif /* TARGET_CORE_PR_H */ diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 617c086a8a02..2bcfd79cf595 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -3,10 +3,7 @@ * * This file contains the generic target mode <-> Linux SCSI subsystem plugin. * - * Copyright (c) 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 + * (c) Copyright 2003-2012 RisingTide Systems LLC. * * Nicholas A. Bellinger <nab@kernel.org> * @@ -53,9 +50,14 @@ #define ISPRINT(a) ((a >= ' ') && (a <= '~')) +static inline struct pscsi_dev_virt *PSCSI_DEV(struct se_device *dev) +{ + return container_of(dev, struct pscsi_dev_virt, dev); +} + static struct se_subsystem_api pscsi_template; -static int pscsi_execute_cmd(struct se_cmd *cmd); +static sense_reason_t pscsi_execute_cmd(struct se_cmd *cmd); static void pscsi_req_done(struct request *, int); /* pscsi_attach_hba(): @@ -219,7 +221,7 @@ pscsi_get_inquiry_vpd_serial(struct scsi_device *sdev, struct t10_wwn *wwn) snprintf(&wwn->unit_serial[0], INQUIRY_VPD_SERIAL_LEN, "%s", &buf[4]); - wwn->t10_sub_dev->su_dev_flags |= SDF_FIRMWARE_VPD_UNIT_SERIAL; + wwn->t10_dev->dev_flags |= DF_FIRMWARE_VPD_UNIT_SERIAL; kfree(buf); return 0; @@ -299,23 +301,13 @@ out: kfree(buf); } -/* pscsi_add_device_to_list(): - * - * - */ -static struct se_device *pscsi_add_device_to_list( - struct se_hba *hba, - struct se_subsystem_dev *se_dev, - struct pscsi_dev_virt *pdv, - struct scsi_device *sd, - int dev_flags) +static int pscsi_add_device_to_list(struct se_device *dev, + struct scsi_device *sd) { - struct se_device *dev; - struct se_dev_limits dev_limits; - struct request_queue *q; - struct queue_limits *limits; + struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); + struct request_queue *q = sd->request_queue; - memset(&dev_limits, 0, sizeof(struct se_dev_limits)); + pdv->pdv_sd = sd; if (!sd->queue_depth) { sd->queue_depth = PSCSI_DEFAULT_QUEUEDEPTH; @@ -324,54 +316,27 @@ static struct se_device *pscsi_add_device_to_list( " queue_depth to %d\n", sd->channel, sd->id, sd->lun, sd->queue_depth); } - /* - * Setup the local scope queue_limits from struct request_queue->limits - * to pass into transport_add_device_to_core_hba() as struct se_dev_limits. - */ - q = sd->request_queue; - limits = &dev_limits.limits; - limits->logical_block_size = sd->sector_size; - limits->max_hw_sectors = min_t(int, sd->host->max_sectors, queue_max_hw_sectors(q)); - limits->max_sectors = min_t(int, sd->host->max_sectors, queue_max_sectors(q)); - dev_limits.hw_queue_depth = sd->queue_depth; - dev_limits.queue_depth = sd->queue_depth; - /* - * Setup our standard INQUIRY info into se_dev->t10_wwn - */ - pscsi_set_inquiry_info(sd, &se_dev->t10_wwn); + + dev->dev_attrib.hw_block_size = sd->sector_size; + dev->dev_attrib.hw_max_sectors = + min_t(int, sd->host->max_sectors, queue_max_hw_sectors(q)); + dev->dev_attrib.hw_queue_depth = sd->queue_depth; /* - * Set the pointer pdv->pdv_sd to from passed struct scsi_device, - * which has already been referenced with Linux SCSI code with - * scsi_device_get() in this file's pscsi_create_virtdevice(). - * - * The passthrough operations called by the transport_add_device_* - * function below will require this pointer to be set for passthroug - * ops. - * - * For the shutdown case in pscsi_free_device(), this struct - * scsi_device reference is released with Linux SCSI code - * scsi_device_put() and the pdv->pdv_sd cleared. + * Setup our standard INQUIRY info into se_dev->t10_wwn */ - pdv->pdv_sd = sd; - dev = transport_add_device_to_core_hba(hba, &pscsi_template, - se_dev, dev_flags, pdv, - &dev_limits, NULL, NULL); - if (!dev) { - pdv->pdv_sd = NULL; - return NULL; - } + pscsi_set_inquiry_info(sd, &dev->t10_wwn); /* * Locate VPD WWN Information used for various purposes within * the Storage Engine. */ - if (!pscsi_get_inquiry_vpd_serial(sd, &se_dev->t10_wwn)) { + if (!pscsi_get_inquiry_vpd_serial(sd, &dev->t10_wwn)) { /* * If VPD Unit Serial returned GOOD status, try * VPD Device Identification page (0x83). */ - pscsi_get_inquiry_vpd_device_ident(sd, &se_dev->t10_wwn); + pscsi_get_inquiry_vpd_device_ident(sd, &dev->t10_wwn); } /* @@ -379,10 +344,11 @@ static struct se_device *pscsi_add_device_to_list( */ if (sd->type == TYPE_TAPE) pscsi_tape_read_blocksize(dev, sd); - return dev; + return 0; } -static void *pscsi_allocate_virtdevice(struct se_hba *hba, const char *name) +static struct se_device *pscsi_alloc_device(struct se_hba *hba, + const char *name) { struct pscsi_dev_virt *pdv; @@ -391,139 +357,125 @@ static void *pscsi_allocate_virtdevice(struct se_hba *hba, const char *name) pr_err("Unable to allocate memory for struct pscsi_dev_virt\n"); return NULL; } - pdv->pdv_se_hba = hba; pr_debug("PSCSI: Allocated pdv: %p for %s\n", pdv, name); - return pdv; + return &pdv->dev; } /* * Called with struct Scsi_Host->host_lock called. */ -static struct se_device *pscsi_create_type_disk( - struct scsi_device *sd, - struct pscsi_dev_virt *pdv, - struct se_subsystem_dev *se_dev, - struct se_hba *hba) +static int pscsi_create_type_disk(struct se_device *dev, struct scsi_device *sd) __releases(sh->host_lock) { - struct se_device *dev; - struct pscsi_hba_virt *phv = pdv->pdv_se_hba->hba_ptr; + struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr; + struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); struct Scsi_Host *sh = sd->host; struct block_device *bd; - u32 dev_flags = 0; + int ret; if (scsi_device_get(sd)) { pr_err("scsi_device_get() failed for %d:%d:%d:%d\n", sh->host_no, sd->channel, sd->id, sd->lun); spin_unlock_irq(sh->host_lock); - return NULL; + return -EIO; } spin_unlock_irq(sh->host_lock); /* * Claim exclusive struct block_device access to struct scsi_device * for TYPE_DISK using supplied udev_path */ - bd = blkdev_get_by_path(se_dev->se_dev_udev_path, + bd = blkdev_get_by_path(dev->udev_path, FMODE_WRITE|FMODE_READ|FMODE_EXCL, pdv); if (IS_ERR(bd)) { pr_err("pSCSI: blkdev_get_by_path() failed\n"); scsi_device_put(sd); - return NULL; + return PTR_ERR(bd); } pdv->pdv_bd = bd; - dev = pscsi_add_device_to_list(hba, se_dev, pdv, sd, dev_flags); - if (!dev) { + ret = pscsi_add_device_to_list(dev, sd); + if (ret) { blkdev_put(pdv->pdv_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); scsi_device_put(sd); - return NULL; + return ret; } + pr_debug("CORE_PSCSI[%d] - Added TYPE_DISK for %d:%d:%d:%d\n", phv->phv_host_id, sh->host_no, sd->channel, sd->id, sd->lun); - - return dev; + return 0; } /* * Called with struct Scsi_Host->host_lock called. */ -static struct se_device *pscsi_create_type_rom( - struct scsi_device *sd, - struct pscsi_dev_virt *pdv, - struct se_subsystem_dev *se_dev, - struct se_hba *hba) +static int pscsi_create_type_rom(struct se_device *dev, struct scsi_device *sd) __releases(sh->host_lock) { - struct se_device *dev; - struct pscsi_hba_virt *phv = pdv->pdv_se_hba->hba_ptr; + struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr; struct Scsi_Host *sh = sd->host; - u32 dev_flags = 0; + int ret; if (scsi_device_get(sd)) { pr_err("scsi_device_get() failed for %d:%d:%d:%d\n", sh->host_no, sd->channel, sd->id, sd->lun); spin_unlock_irq(sh->host_lock); - return NULL; + return -EIO; } spin_unlock_irq(sh->host_lock); - dev = pscsi_add_device_to_list(hba, se_dev, pdv, sd, dev_flags); - if (!dev) { + ret = pscsi_add_device_to_list(dev, sd); + if (ret) { scsi_device_put(sd); - return NULL; + return ret; } pr_debug("CORE_PSCSI[%d] - Added Type: %s for %d:%d:%d:%d\n", phv->phv_host_id, scsi_device_type(sd->type), sh->host_no, sd->channel, sd->id, sd->lun); - return dev; + return 0; } /* - *Called with struct Scsi_Host->host_lock called. + * Called with struct Scsi_Host->host_lock called. */ -static struct se_device *pscsi_create_type_other( - struct scsi_device *sd, - struct pscsi_dev_virt *pdv, - struct se_subsystem_dev *se_dev, - struct se_hba *hba) +static int pscsi_create_type_other(struct se_device *dev, + struct scsi_device *sd) __releases(sh->host_lock) { - struct se_device *dev; - struct pscsi_hba_virt *phv = pdv->pdv_se_hba->hba_ptr; + struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr; struct Scsi_Host *sh = sd->host; - u32 dev_flags = 0; + int ret; spin_unlock_irq(sh->host_lock); - dev = pscsi_add_device_to_list(hba, se_dev, pdv, sd, dev_flags); - if (!dev) - return NULL; + ret = pscsi_add_device_to_list(dev, sd); + if (ret) + return ret; pr_debug("CORE_PSCSI[%d] - Added Type: %s for %d:%d:%d:%d\n", phv->phv_host_id, scsi_device_type(sd->type), sh->host_no, sd->channel, sd->id, sd->lun); - - return dev; + return 0; } -static struct se_device *pscsi_create_virtdevice( - struct se_hba *hba, - struct se_subsystem_dev *se_dev, - void *p) +static int pscsi_configure_device(struct se_device *dev) { - struct pscsi_dev_virt *pdv = p; - struct se_device *dev; + struct se_hba *hba = dev->se_hba; + struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); struct scsi_device *sd; - struct pscsi_hba_virt *phv = hba->hba_ptr; + struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr; struct Scsi_Host *sh = phv->phv_lld_host; int legacy_mode_enable = 0; + int ret; - if (!pdv) { - pr_err("Unable to locate struct pscsi_dev_virt" - " parameter\n"); - return ERR_PTR(-EINVAL); + if (!(pdv->pdv_flags & PDF_HAS_CHANNEL_ID) || + !(pdv->pdv_flags & PDF_HAS_TARGET_ID) || + !(pdv->pdv_flags & PDF_HAS_LUN_ID)) { + pr_err("Missing scsi_channel_id=, scsi_target_id= and" + " scsi_lun_id= parameters\n"); + return -EINVAL; } + /* * If not running in PHV_LLD_SCSI_HOST_NO mode, locate the * struct Scsi_Host we will need to bring the TCM/pSCSI object online @@ -532,16 +484,16 @@ static struct se_device *pscsi_create_virtdevice( if (phv->phv_mode == PHV_LLD_SCSI_HOST_NO) { pr_err("pSCSI: Unable to locate struct" " Scsi_Host for PHV_LLD_SCSI_HOST_NO\n"); - return ERR_PTR(-ENODEV); + return -ENODEV; } /* * For the newer PHV_VIRTUAL_HOST_ID struct scsi_device * reference, we enforce that udev_path has been set */ - if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH)) { + if (!(dev->dev_flags & DF_USING_UDEV_PATH)) { pr_err("pSCSI: udev_path attribute has not" " been set before ENABLE=1\n"); - return ERR_PTR(-EINVAL); + return -EINVAL; } /* * If no scsi_host_id= was passed for PHV_VIRTUAL_HOST_ID, @@ -549,17 +501,14 @@ static struct se_device *pscsi_create_virtdevice( * and enable for PHV_LLD_SCSI_HOST_NO mode. */ if (!(pdv->pdv_flags & PDF_HAS_VIRT_HOST_ID)) { - spin_lock(&hba->device_lock); - if (!list_empty(&hba->hba_dev_list)) { + if (hba->dev_count) { pr_err("pSCSI: Unable to set hba_mode" " with active devices\n"); - spin_unlock(&hba->device_lock); - return ERR_PTR(-EEXIST); + return -EEXIST; } - spin_unlock(&hba->device_lock); if (pscsi_pmode_enable_hba(hba, 1) != 1) - return ERR_PTR(-ENODEV); + return -ENODEV; legacy_mode_enable = 1; hba->hba_flags |= HBA_FLAGS_PSCSI_MODE; @@ -569,14 +518,14 @@ static struct se_device *pscsi_create_virtdevice( if (IS_ERR(sh)) { pr_err("pSCSI: Unable to locate" " pdv_host_id: %d\n", pdv->pdv_host_id); - return ERR_CAST(sh); + return PTR_ERR(sh); } } } else { if (phv->phv_mode == PHV_VIRTUAL_HOST_ID) { pr_err("pSCSI: PHV_VIRTUAL_HOST_ID set while" " struct Scsi_Host exists\n"); - return ERR_PTR(-EEXIST); + return -EEXIST; } } @@ -593,17 +542,17 @@ static struct se_device *pscsi_create_virtdevice( */ switch (sd->type) { case TYPE_DISK: - dev = pscsi_create_type_disk(sd, pdv, se_dev, hba); + ret = pscsi_create_type_disk(dev, sd); break; case TYPE_ROM: - dev = pscsi_create_type_rom(sd, pdv, se_dev, hba); + ret = pscsi_create_type_rom(dev, sd); break; default: - dev = pscsi_create_type_other(sd, pdv, se_dev, hba); + ret = pscsi_create_type_other(dev, sd); break; } - if (!dev) { + if (ret) { if (phv->phv_mode == PHV_VIRTUAL_HOST_ID) scsi_host_put(sh); else if (legacy_mode_enable) { @@ -611,9 +560,9 @@ static struct se_device *pscsi_create_virtdevice( hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE; } pdv->pdv_sd = NULL; - return ERR_PTR(-ENODEV); + return ret; } - return dev; + return 0; } spin_unlock_irq(sh->host_lock); @@ -627,17 +576,13 @@ static struct se_device *pscsi_create_virtdevice( hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE; } - return ERR_PTR(-ENODEV); + return -ENODEV; } -/* pscsi_free_device(): (Part of se_subsystem_api_t template) - * - * - */ -static void pscsi_free_device(void *p) +static void pscsi_free_device(struct se_device *dev) { - struct pscsi_dev_virt *pdv = p; - struct pscsi_hba_virt *phv = pdv->pdv_se_hba->hba_ptr; + struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); + struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr; struct scsi_device *sd = pdv->pdv_sd; if (sd) { @@ -670,7 +615,7 @@ static void pscsi_free_device(void *p) static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg, unsigned char *sense_buffer) { - struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr; + struct pscsi_dev_virt *pdv = PSCSI_DEV(cmd->se_dev); struct scsi_device *sd = pdv->pdv_sd; int result; struct pscsi_plugin_task *pt = cmd->priv; @@ -694,7 +639,11 @@ static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg, if (((cdb[0] == MODE_SENSE) || (cdb[0] == MODE_SENSE_10)) && (status_byte(result) << 1) == SAM_STAT_GOOD) { if (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) { - unsigned char *buf = transport_kmap_data_sg(cmd); + unsigned char *buf; + + buf = transport_kmap_data_sg(cmd); + if (!buf) + ; /* XXX: TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE */ if (cdb[0] == MODE_SENSE_10) { if (!(buf[3] & 0x80)) @@ -770,13 +719,11 @@ static match_table_t tokens = { {Opt_err, NULL} }; -static ssize_t pscsi_set_configfs_dev_params(struct se_hba *hba, - struct se_subsystem_dev *se_dev, - const char *page, - ssize_t count) +static ssize_t pscsi_set_configfs_dev_params(struct se_device *dev, + const char *page, ssize_t count) { - struct pscsi_dev_virt *pdv = se_dev->se_dev_su_ptr; - struct pscsi_hba_virt *phv = hba->hba_ptr; + struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); + struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr; char *orig, *ptr, *opts; substring_t args[MAX_OPT_ARGS]; int ret = 0, arg, token; @@ -841,29 +788,10 @@ out: return (!ret) ? count : ret; } -static ssize_t pscsi_check_configfs_dev_params( - struct se_hba *hba, - struct se_subsystem_dev *se_dev) +static ssize_t pscsi_show_configfs_dev_params(struct se_device *dev, char *b) { - struct pscsi_dev_virt *pdv = se_dev->se_dev_su_ptr; - - if (!(pdv->pdv_flags & PDF_HAS_CHANNEL_ID) || - !(pdv->pdv_flags & PDF_HAS_TARGET_ID) || - !(pdv->pdv_flags & PDF_HAS_LUN_ID)) { - pr_err("Missing scsi_channel_id=, scsi_target_id= and" - " scsi_lun_id= parameters\n"); - return -EINVAL; - } - - return 0; -} - -static ssize_t pscsi_show_configfs_dev_params(struct se_hba *hba, - struct se_subsystem_dev *se_dev, - char *b) -{ - struct pscsi_hba_virt *phv = hba->hba_ptr; - struct pscsi_dev_virt *pdv = se_dev->se_dev_su_ptr; + struct pscsi_hba_virt *phv = dev->se_hba->hba_ptr; + struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); struct scsi_device *sd = pdv->pdv_sd; unsigned char host_id[16]; ssize_t bl; @@ -929,11 +857,11 @@ static inline struct bio *pscsi_get_bio(int sg_num) return bio; } -static int pscsi_map_sg(struct se_cmd *cmd, struct scatterlist *sgl, - u32 sgl_nents, enum dma_data_direction data_direction, - struct bio **hbio) +static sense_reason_t +pscsi_map_sg(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, + enum dma_data_direction data_direction, struct bio **hbio) { - struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr; + struct pscsi_dev_virt *pdv = PSCSI_DEV(cmd->se_dev); struct bio *bio = NULL, *tbio = NULL; struct page *page; struct scatterlist *sg; @@ -1019,7 +947,7 @@ static int pscsi_map_sg(struct se_cmd *cmd, struct scatterlist *sgl, } } - return sgl_nents; + return 0; fail: while (*hbio) { bio = *hbio; @@ -1027,8 +955,7 @@ fail: bio->bi_next = NULL; bio_endio(bio, 0); /* XXX: should be error */ } - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -ENOMEM; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } /* @@ -1055,17 +982,13 @@ static inline void pscsi_clear_cdb_lun(unsigned char *cdb) } } -static int pscsi_parse_cdb(struct se_cmd *cmd) +static sense_reason_t +pscsi_parse_cdb(struct se_cmd *cmd) { unsigned char *cdb = cmd->t_task_cdb; - unsigned int dummy_size; - int ret; - 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; - } + if (cmd->se_cmd_flags & SCF_BIDI) + return TCM_UNSUPPORTED_SCSI_OPCODE; pscsi_clear_cdb_lun(cdb); @@ -1076,10 +999,8 @@ static int pscsi_parse_cdb(struct se_cmd *cmd) */ switch (cdb[0]) { case REPORT_LUNS: - ret = spc_parse_cdb(cmd, &dummy_size); - if (ret) - return ret; - break; + cmd->execute_cmd = spc_emulate_report_luns; + return 0; case READ_6: case READ_10: case READ_12: @@ -1093,22 +1014,21 @@ static int pscsi_parse_cdb(struct se_cmd *cmd) /* FALLTHROUGH*/ default: cmd->execute_cmd = pscsi_execute_cmd; - break; + return 0; } - - return 0; } -static int pscsi_execute_cmd(struct se_cmd *cmd) +static sense_reason_t +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_dev_virt *pdv = PSCSI_DEV(cmd->se_dev); struct pscsi_plugin_task *pt; struct request *req; struct bio *hbio; - int ret; + sense_reason_t ret; /* * Dynamically alloc cdb space, since it may be larger than @@ -1116,8 +1036,7 @@ static int pscsi_execute_cmd(struct se_cmd *cmd) */ pt = kzalloc(sizeof(*pt) + scsi_command_size(cmd->t_task_cdb), GFP_KERNEL); if (!pt) { - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -ENOMEM; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } cmd->priv = pt; @@ -1131,24 +1050,21 @@ static int pscsi_execute_cmd(struct se_cmd *cmd) if (!req || IS_ERR(req)) { pr_err("PSCSI: blk_get_request() failed: %ld\n", req ? IS_ERR(req) : -ENOMEM); - cmd->scsi_sense_reason = - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; goto fail; } } else { BUG_ON(!cmd->data_length); ret = pscsi_map_sg(cmd, sgl, sgl_nents, data_direction, &hbio); - if (ret < 0) { - cmd->scsi_sense_reason = - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + if (ret) goto fail; - } req = blk_make_request(pdv->pdv_sd->request_queue, hbio, GFP_KERNEL); if (IS_ERR(req)) { pr_err("pSCSI: blk_make_request() failed\n"); + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; goto fail_free_bio; } } @@ -1179,22 +1095,10 @@ fail_free_bio: bio->bi_next = NULL; bio_endio(bio, 0); /* XXX: should be error */ } - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; fail: kfree(pt); - return -ENOMEM; -} - -/* pscsi_get_device_rev(): - * - * - */ -static u32 pscsi_get_device_rev(struct se_device *dev) -{ - struct pscsi_dev_virt *pdv = dev->dev_ptr; - struct scsi_device *sd = pdv->pdv_sd; - - return (sd->scsi_level - 1) ? sd->scsi_level - 1 : 1; + return ret; } /* pscsi_get_device_type(): @@ -1203,7 +1107,7 @@ static u32 pscsi_get_device_rev(struct se_device *dev) */ static u32 pscsi_get_device_type(struct se_device *dev) { - struct pscsi_dev_virt *pdv = dev->dev_ptr; + struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); struct scsi_device *sd = pdv->pdv_sd; return sd->type; @@ -1211,7 +1115,7 @@ static u32 pscsi_get_device_type(struct se_device *dev) static sector_t pscsi_get_blocks(struct se_device *dev) { - struct pscsi_dev_virt *pdv = dev->dev_ptr; + struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); if (pdv->pdv_bd && pdv->pdv_bd->bd_part) return pdv->pdv_bd->bd_part->nr_sects; @@ -1243,7 +1147,6 @@ static void pscsi_req_done(struct request *req, int uptodate) pr_debug("PSCSI Host Byte exception at cmd: %p CDB:" " 0x%02x Result: 0x%08x\n", cmd, pt->pscsi_cdb[0], pt->pscsi_result); - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION); break; } @@ -1259,15 +1162,13 @@ static struct se_subsystem_api pscsi_template = { .attach_hba = pscsi_attach_hba, .detach_hba = pscsi_detach_hba, .pmode_enable_hba = pscsi_pmode_enable_hba, - .allocate_virtdevice = pscsi_allocate_virtdevice, - .create_virtdevice = pscsi_create_virtdevice, + .alloc_device = pscsi_alloc_device, + .configure_device = pscsi_configure_device, .free_device = pscsi_free_device, .transport_complete = pscsi_transport_complete, .parse_cdb = pscsi_parse_cdb, - .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, - .get_device_rev = pscsi_get_device_rev, .get_device_type = pscsi_get_device_type, .get_blocks = pscsi_get_blocks, }; diff --git a/drivers/target/target_core_pscsi.h b/drivers/target/target_core_pscsi.h index bc1e5e11eca0..1bd757dff8ee 100644 --- a/drivers/target/target_core_pscsi.h +++ b/drivers/target/target_core_pscsi.h @@ -37,6 +37,7 @@ struct pscsi_plugin_task { #define PDF_HAS_VIRT_HOST_ID 0x20 struct pscsi_dev_virt { + struct se_device dev; int pdv_flags; int pdv_host_id; int pdv_channel_id; @@ -44,7 +45,6 @@ struct pscsi_dev_virt { int pdv_lun_id; struct block_device *pdv_bd; struct scsi_device *pdv_sd; - struct se_hba *pdv_se_hba; } ____cacheline_aligned; typedef enum phv_modes { diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index d00bbe33ff8b..0457de362e68 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -4,10 +4,7 @@ * This file contains the Storage Engine <-> Ramdisk transport * specific functions. * - * Copyright (c) 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 + * (c) Copyright 2003-2012 RisingTide Systems LLC. * * Nicholas A. Bellinger <nab@kernel.org> * @@ -41,7 +38,10 @@ #include "target_core_rd.h" -static struct se_subsystem_api rd_mcp_template; +static inline struct rd_dev *RD_DEV(struct se_device *dev) +{ + return container_of(dev, struct rd_dev, dev); +} /* rd_attach_hba(): (Part of se_subsystem_api_t template) * @@ -196,7 +196,7 @@ static int rd_build_device_space(struct rd_dev *rd_dev) return 0; } -static void *rd_allocate_virtdevice(struct se_hba *hba, const char *name) +static struct se_device *rd_alloc_device(struct se_hba *hba, const char *name) { struct rd_dev *rd_dev; struct rd_host *rd_host = hba->hba_ptr; @@ -209,39 +209,27 @@ static void *rd_allocate_virtdevice(struct se_hba *hba, const char *name) rd_dev->rd_host = rd_host; - return rd_dev; + return &rd_dev->dev; } -static struct se_device *rd_create_virtdevice(struct se_hba *hba, - struct se_subsystem_dev *se_dev, void *p) +static int rd_configure_device(struct se_device *dev) { - struct se_device *dev; - struct se_dev_limits dev_limits; - struct rd_dev *rd_dev = p; - struct rd_host *rd_host = hba->hba_ptr; - int dev_flags = 0, ret; - char prod[16], rev[4]; + struct rd_dev *rd_dev = RD_DEV(dev); + struct rd_host *rd_host = dev->se_hba->hba_ptr; + int ret; - memset(&dev_limits, 0, sizeof(struct se_dev_limits)); + if (!(rd_dev->rd_flags & RDF_HAS_PAGE_COUNT)) { + pr_debug("Missing rd_pages= parameter\n"); + return -EINVAL; + } ret = rd_build_device_space(rd_dev); if (ret < 0) goto fail; - snprintf(prod, 16, "RAMDISK-MCP"); - snprintf(rev, 4, "%s", RD_MCP_VERSION); - - dev_limits.limits.logical_block_size = RD_BLOCKSIZE; - dev_limits.limits.max_hw_sectors = UINT_MAX; - dev_limits.limits.max_sectors = UINT_MAX; - dev_limits.hw_queue_depth = RD_MAX_DEVICE_QUEUE_DEPTH; - dev_limits.queue_depth = RD_DEVICE_QUEUE_DEPTH; - - dev = transport_add_device_to_core_hba(hba, - &rd_mcp_template, se_dev, dev_flags, rd_dev, - &dev_limits, prod, rev); - if (!dev) - goto fail; + dev->dev_attrib.hw_block_size = RD_BLOCKSIZE; + dev->dev_attrib.hw_max_sectors = UINT_MAX; + dev->dev_attrib.hw_queue_depth = RD_MAX_DEVICE_QUEUE_DEPTH; rd_dev->rd_dev_id = rd_host->rd_host_dev_id_count++; @@ -251,16 +239,16 @@ static struct se_device *rd_create_virtdevice(struct se_hba *hba, rd_dev->sg_table_count, (unsigned long)(rd_dev->rd_page_count * PAGE_SIZE)); - return dev; + return 0; fail: rd_release_device_space(rd_dev); - return ERR_PTR(ret); + return ret; } -static void rd_free_device(void *p) +static void rd_free_device(struct se_device *dev) { - struct rd_dev *rd_dev = p; + struct rd_dev *rd_dev = RD_DEV(dev); rd_release_device_space(rd_dev); kfree(rd_dev); @@ -284,13 +272,14 @@ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page) return NULL; } -static int rd_execute_rw(struct se_cmd *cmd) +static sense_reason_t +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 *dev = RD_DEV(se_dev); struct rd_dev_sg_table *table; struct scatterlist *rd_sg; struct sg_mapping_iter m; @@ -300,14 +289,14 @@ static int rd_execute_rw(struct se_cmd *cmd) u32 src_len; u64 tmp; - tmp = cmd->t_task_lba * se_dev->se_sub_dev->se_dev_attrib.block_size; + tmp = cmd->t_task_lba * se_dev->dev_attrib.block_size; rd_offset = do_div(tmp, PAGE_SIZE); rd_page = tmp; rd_size = cmd->data_length; table = rd_get_sg_table(dev, rd_page); if (!table) - return -EINVAL; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; rd_sg = &table->sg_table[rd_page - table->page_start_offset]; @@ -357,7 +346,7 @@ static int rd_execute_rw(struct se_cmd *cmd) table = rd_get_sg_table(dev, rd_page); if (!table) { sg_miter_stop(&m); - return -EINVAL; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } /* since we increment, the first sg entry is correct */ @@ -378,13 +367,10 @@ static match_table_t tokens = { {Opt_err, NULL} }; -static ssize_t rd_set_configfs_dev_params( - struct se_hba *hba, - struct se_subsystem_dev *se_dev, - const char *page, - ssize_t count) +static ssize_t rd_set_configfs_dev_params(struct se_device *dev, + const char *page, ssize_t count) { - struct rd_dev *rd_dev = se_dev->se_dev_su_ptr; + struct rd_dev *rd_dev = RD_DEV(dev); char *orig, *ptr, *opts; substring_t args[MAX_OPT_ARGS]; int ret = 0, arg, token; @@ -417,24 +403,10 @@ static ssize_t rd_set_configfs_dev_params( return (!ret) ? count : ret; } -static ssize_t rd_check_configfs_dev_params(struct se_hba *hba, struct se_subsystem_dev *se_dev) +static ssize_t rd_show_configfs_dev_params(struct se_device *dev, char *b) { - struct rd_dev *rd_dev = se_dev->se_dev_su_ptr; + struct rd_dev *rd_dev = RD_DEV(dev); - if (!(rd_dev->rd_flags & RDF_HAS_PAGE_COUNT)) { - pr_debug("Missing rd_pages= parameter\n"); - return -EINVAL; - } - - return 0; -} - -static ssize_t rd_show_configfs_dev_params( - struct se_hba *hba, - struct se_subsystem_dev *se_dev, - char *b) -{ - struct rd_dev *rd_dev = se_dev->se_dev_su_ptr; ssize_t bl = sprintf(b, "TCM RamDisk ID: %u RamDisk Makeup: rd_mcp\n", rd_dev->rd_dev_id); bl += sprintf(b + bl, " PAGES/PAGE_SIZE: %u*%lu" @@ -443,48 +415,40 @@ static ssize_t rd_show_configfs_dev_params( return bl; } -static u32 rd_get_device_rev(struct se_device *dev) -{ - return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */ -} - -static u32 rd_get_device_type(struct se_device *dev) -{ - return TYPE_DISK; -} - static sector_t rd_get_blocks(struct se_device *dev) { - struct rd_dev *rd_dev = dev->dev_ptr; + struct rd_dev *rd_dev = RD_DEV(dev); + unsigned long long blocks_long = ((rd_dev->rd_page_count * PAGE_SIZE) / - dev->se_sub_dev->se_dev_attrib.block_size) - 1; + dev->dev_attrib.block_size) - 1; return blocks_long; } -static struct spc_ops rd_spc_ops = { +static struct sbc_ops rd_sbc_ops = { .execute_rw = rd_execute_rw, }; -static int rd_parse_cdb(struct se_cmd *cmd) +static sense_reason_t +rd_parse_cdb(struct se_cmd *cmd) { - return sbc_parse_cdb(cmd, &rd_spc_ops); + return sbc_parse_cdb(cmd, &rd_sbc_ops); } static struct se_subsystem_api rd_mcp_template = { .name = "rd_mcp", + .inquiry_prod = "RAMDISK-MCP", + .inquiry_rev = RD_MCP_VERSION, .transport_type = TRANSPORT_PLUGIN_VHBA_VDEV, .attach_hba = rd_attach_hba, .detach_hba = rd_detach_hba, - .allocate_virtdevice = rd_allocate_virtdevice, - .create_virtdevice = rd_create_virtdevice, + .alloc_device = rd_alloc_device, + .configure_device = rd_configure_device, .free_device = rd_free_device, .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, - .get_device_rev = rd_get_device_rev, - .get_device_type = rd_get_device_type, + .get_device_type = sbc_get_device_type, .get_blocks = rd_get_blocks, }; diff --git a/drivers/target/target_core_rd.h b/drivers/target/target_core_rd.h index 21458125fe51..933b38b6e563 100644 --- a/drivers/target/target_core_rd.h +++ b/drivers/target/target_core_rd.h @@ -24,6 +24,7 @@ struct rd_dev_sg_table { #define RDF_HAS_PAGE_COUNT 0x01 struct rd_dev { + struct se_device dev; u32 rd_flags; /* Unique Ramdisk Device ID in Ramdisk HBA */ u32 rd_dev_id; diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 868f8aa04f13..26a6d183ccb1 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -1,10 +1,7 @@ /* * 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 + * (c) Copyright 2002-2012 RisingTide Systems LLC. * * Nicholas A. Bellinger <nab@kernel.org> * @@ -37,7 +34,8 @@ #include "target_core_ua.h" -static int sbc_emulate_readcapacity(struct se_cmd *cmd) +static sense_reason_t +sbc_emulate_readcapacity(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; unsigned long long blocks_long = dev->transport->get_blocks(dev); @@ -54,22 +52,24 @@ static int sbc_emulate_readcapacity(struct se_cmd *cmd) 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; + buf[4] = (dev->dev_attrib.block_size >> 24) & 0xff; + buf[5] = (dev->dev_attrib.block_size >> 16) & 0xff; + buf[6] = (dev->dev_attrib.block_size >> 8) & 0xff; + buf[7] = dev->dev_attrib.block_size & 0xff; rbuf = transport_kmap_data_sg(cmd); - if (rbuf) { - memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); - transport_kunmap_data_sg(cmd); - } + if (!rbuf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + + memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); + transport_kunmap_data_sg(cmd); target_complete_cmd(cmd, GOOD); return 0; } -static int sbc_emulate_readcapacity_16(struct se_cmd *cmd) +static sense_reason_t +sbc_emulate_readcapacity_16(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; unsigned char *rbuf; @@ -85,28 +85,29 @@ static int sbc_emulate_readcapacity_16(struct se_cmd *cmd) 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; + buf[8] = (dev->dev_attrib.block_size >> 24) & 0xff; + buf[9] = (dev->dev_attrib.block_size >> 16) & 0xff; + buf[10] = (dev->dev_attrib.block_size >> 8) & 0xff; + buf[11] = dev->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) + if (dev->dev_attrib.emulate_tpu || dev->dev_attrib.emulate_tpws) buf[14] = 0x80; rbuf = transport_kmap_data_sg(cmd); - if (rbuf) { - memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); - transport_kunmap_data_sg(cmd); - } + if (!rbuf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + + memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); + transport_kunmap_data_sg(cmd); target_complete_cmd(cmd, GOOD); return 0; } -int spc_get_write_same_sectors(struct se_cmd *cmd) +sector_t spc_get_write_same_sectors(struct se_cmd *cmd) { u32 num_blocks; @@ -129,7 +130,8 @@ int spc_get_write_same_sectors(struct se_cmd *cmd) } EXPORT_SYMBOL(spc_get_write_same_sectors); -static int sbc_emulate_verify(struct se_cmd *cmd) +static sense_reason_t +sbc_emulate_noop(struct se_cmd *cmd) { target_complete_cmd(cmd, GOOD); return 0; @@ -137,7 +139,7 @@ static int sbc_emulate_verify(struct se_cmd *cmd) 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; + return cmd->se_dev->dev_attrib.block_size * sectors; } static int sbc_check_valid_sectors(struct se_cmd *cmd) @@ -146,7 +148,7 @@ static int sbc_check_valid_sectors(struct se_cmd *cmd) unsigned long long end_lba; u32 sectors; - sectors = cmd->data_length / dev->se_sub_dev->se_dev_attrib.block_size; + sectors = cmd->data_length / dev->dev_attrib.block_size; end_lba = dev->transport->get_blocks(dev) + 1; if (cmd->t_task_lba + sectors > end_lba) { @@ -230,26 +232,37 @@ static inline unsigned long long transport_lba_64_ext(unsigned char *cdb) return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; } -static int sbc_write_same_supported(struct se_device *dev, - unsigned char *flags) +static sense_reason_t +sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *ops) { + unsigned int sectors = spc_get_write_same_sectors(cmd); + if ((flags[0] & 0x04) || (flags[0] & 0x02)) { pr_err("WRITE_SAME PBDATA and LBDATA" " bits not supported for Block Discard" " Emulation\n"); - return -ENOSYS; + return TCM_UNSUPPORTED_SCSI_OPCODE; + } + if (sectors > cmd->se_dev->dev_attrib.max_write_same_len) { + pr_warn("WRITE_SAME sectors: %u exceeds max_write_same_len: %u\n", + sectors, cmd->se_dev->dev_attrib.max_write_same_len); + return TCM_INVALID_CDB_FIELD; } - /* - * Currently for the emulated case we only accept - * tpws with the UNMAP=1 bit set. + * Special case for WRITE_SAME w/ UNMAP=1 that ends up getting + * translated into block discard requests within backend code. */ - if (!(flags[0] & 0x08)) { - pr_err("WRITE_SAME w/o UNMAP bit not" - " supported for Block Discard Emulation\n"); - return -ENOSYS; + if (flags[0] & 0x08) { + if (!ops->execute_write_same_unmap) + return TCM_UNSUPPORTED_SCSI_OPCODE; + + cmd->execute_cmd = ops->execute_write_same_unmap; + return 0; } + if (!ops->execute_write_same) + return TCM_UNSUPPORTED_SCSI_OPCODE; + cmd->execute_cmd = ops->execute_write_same; return 0; } @@ -307,14 +320,14 @@ out: kfree(buf); } -int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) +sense_reason_t +sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) { - 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; + sense_reason_t ret; switch (cdb[0]) { case READ_6: @@ -373,9 +386,9 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) cmd->execute_cmd = ops->execute_rw; break; case XDWRITEREAD_10: - if ((cmd->data_direction != DMA_TO_DEVICE) || + if (cmd->data_direction != DMA_TO_DEVICE || !(cmd->se_cmd_flags & SCF_BIDI)) - goto out_invalid_cdb_field; + return TCM_INVALID_CDB_FIELD; sectors = transport_get_sectors_10(cdb); cmd->t_task_lba = transport_lba_32(cdb); @@ -413,27 +426,24 @@ 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" " supported\n"); - goto out_invalid_cdb_field; + return TCM_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 = ops->execute_write_same; + ret = sbc_setup_write_same(cmd, &cdb[10], ops); + if (ret) + return ret; break; default: pr_err("VARIABLE_LENGTH_CMD service action" " 0x%04x not supported\n", service_action); - goto out_unsupported_cdb; + return TCM_UNSUPPORTED_SCSI_OPCODE; } break; } @@ -449,7 +459,7 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) default: pr_err("Unsupported SA: 0x%02x\n", cmd->t_task_cdb[1] & 0x1f); - goto out_invalid_cdb_field; + return TCM_INVALID_CDB_FIELD; } size = (cdb[10] << 24) | (cdb[11] << 16) | (cdb[12] << 8) | cdb[13]; @@ -457,7 +467,7 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) case SYNCHRONIZE_CACHE: case SYNCHRONIZE_CACHE_16: if (!ops->execute_sync_cache) - goto out_unsupported_cdb; + return TCM_UNSUPPORTED_SCSI_OPCODE; /* * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE @@ -478,42 +488,36 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) */ if (cmd->t_task_lba || sectors) { if (sbc_check_valid_sectors(cmd) < 0) - goto out_invalid_cdb_field; + return TCM_INVALID_CDB_FIELD; } cmd->execute_cmd = ops->execute_sync_cache; break; case UNMAP: if (!ops->execute_unmap) - goto out_unsupported_cdb; + return TCM_UNSUPPORTED_SCSI_OPCODE; size = get_unaligned_be16(&cdb[7]); cmd->execute_cmd = ops->execute_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"); - goto out_invalid_cdb_field; + return TCM_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 = ops->execute_write_same; + ret = sbc_setup_write_same(cmd, &cdb[1], ops); + if (ret) + return ret; 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"); - goto out_invalid_cdb_field; + return TCM_INVALID_CDB_FIELD; } size = sbc_get_size(cmd, 1); @@ -523,13 +527,25 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) * 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 = ops->execute_write_same; + ret = sbc_setup_write_same(cmd, &cdb[1], ops); + if (ret) + return ret; break; case VERIFY: size = 0; - cmd->execute_cmd = sbc_emulate_verify; + cmd->execute_cmd = sbc_emulate_noop; + break; + case REZERO_UNIT: + case SEEK_6: + case SEEK_10: + /* + * There are still clients out there which use these old SCSI-2 + * commands. This mainly happens when running VMs with legacy + * guest systems, connected via SCSI command pass-through to + * iSCSI targets. Make them happy and return status GOOD. + */ + size = 0; + cmd->execute_cmd = sbc_emulate_noop; break; default: ret = spc_parse_cdb(cmd, &size); @@ -539,24 +555,24 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) /* 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; + return TCM_UNSUPPORTED_SCSI_OPCODE; if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { unsigned long long end_lba; - if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) { + if (sectors > dev->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; + dev->dev_attrib.fabric_max_sectors); + return TCM_INVALID_CDB_FIELD; } - if (sectors > su_dev->se_dev_attrib.hw_max_sectors) { + if (sectors > dev->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; + dev->dev_attrib.hw_max_sectors); + return TCM_INVALID_CDB_FIELD; } end_lba = dev->transport->get_blocks(dev) + 1; @@ -564,25 +580,18 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops) pr_err("cmd exceeds last lba %llu " "(lba %llu, sectors %u)\n", end_lba, cmd->t_task_lba, sectors); - goto out_invalid_cdb_field; + return TCM_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: - 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; + return target_cmd_size_check(cmd, size); } EXPORT_SYMBOL(sbc_parse_cdb); + +u32 sbc_get_device_type(struct se_device *dev) +{ + return TYPE_DISK; +} +EXPORT_SYMBOL(sbc_get_device_type); diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 9229bd9ad61b..84f9e96e8ace 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -1,10 +1,7 @@ /* * 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 + * (c) Copyright 2002-2012 RisingTide Systems LLC. * * Nicholas A. Bellinger <nab@kernel.org> * @@ -69,7 +66,8 @@ static void spc_fill_alua_data(struct se_port *port, unsigned char *buf) spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); } -static int spc_emulate_inquiry_std(struct se_cmd *cmd, char *buf) +static sense_reason_t +spc_emulate_inquiry_std(struct se_cmd *cmd, char *buf) { struct se_lun *lun = cmd->se_lun; struct se_device *dev = cmd->se_dev; @@ -78,7 +76,7 @@ static int spc_emulate_inquiry_std(struct se_cmd *cmd, char *buf) if (dev->transport->get_device_type(dev) == TYPE_TAPE) buf[1] = 0x80; - buf[2] = dev->transport->get_device_rev(dev); + buf[2] = 0x05; /* SPC-3 */ /* * NORMACA and HISUP = 0, RESPONSE DATA FORMAT = 2 @@ -95,34 +93,32 @@ static int spc_emulate_inquiry_std(struct se_cmd *cmd, char *buf) /* * 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); + 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); + snprintf(&buf[16], 16, "%s", dev->t10_wwn.model); + snprintf(&buf[32], 4, "%s", 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) +static sense_reason_t +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) { + if (dev->dev_flags & DF_EMULATED_VPD_UNIT_SERIAL) { u32 unit_serial_len; - unit_serial_len = strlen(dev->se_sub_dev->t10_wwn.unit_serial); + unit_serial_len = strlen(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 += sprintf(&buf[4], "%s", dev->t10_wwn.unit_serial); len++; /* Extra Byte for NULL Terminator */ buf[3] = len; } @@ -132,7 +128,7 @@ static int spc_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) 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]; + unsigned char *p = &dev->t10_wwn.unit_serial[0]; int cnt; bool next = true; @@ -164,7 +160,8 @@ static void spc_parse_naa_6h_vendor_specific(struct se_device *dev, * 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) +static sense_reason_t +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; @@ -173,7 +170,7 @@ static int spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) 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]; + unsigned char *prod = &dev->t10_wwn.model[0]; u32 prod_len; u32 unit_serial_len, off = 0; u16 len = 0, id_len; @@ -188,7 +185,7 @@ static int spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) * /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)) + if (!(dev->dev_flags & DF_EMULATED_VPD_UNIT_SERIAL)) goto check_t10_vend_desc; /* CODE SET == Binary */ @@ -236,14 +233,12 @@ check_t10_vend_desc: 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]); + if (dev->dev_flags & DF_EMULATED_VPD_UNIT_SERIAL) { + unit_serial_len = strlen(&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]); + &dev->t10_wwn.unit_serial[0]); } buf[off] = 0x2; /* ASCII */ buf[off+1] = 0x1; /* T10 Vendor ID */ @@ -298,10 +293,6 @@ check_t10_vend_desc: * 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; @@ -415,20 +406,22 @@ check_scsi_name: } /* Extended INQUIRY Data VPD Page */ -static int spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) +static sense_reason_t +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) + if (cmd->se_dev->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) +static sense_reason_t +spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) { struct se_device *dev = cmd->se_dev; u32 max_sectors; @@ -439,7 +432,7 @@ static int spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) * 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) + if (dev->dev_attrib.emulate_tpu || dev->dev_attrib.emulate_tpws) have_tp = 1; buf[0] = dev->transport->get_device_type(dev); @@ -456,62 +449,70 @@ static int spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) /* * 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); + max_sectors = min(dev->dev_attrib.fabric_max_sectors, + dev->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]); + put_unaligned_be32(dev->dev_attrib.optimal_sectors, &buf[12]); /* * Exit now if we don't support TP. */ if (!have_tp) - return 0; + goto max_write_same; /* * Set MAXIMUM UNMAP LBA COUNT */ - put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count, &buf[20]); + put_unaligned_be32(dev->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, + put_unaligned_be32(dev->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]); + put_unaligned_be32(dev->dev_attrib.unmap_granularity, &buf[28]); /* * UNMAP GRANULARITY ALIGNMENT */ - put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment, + put_unaligned_be32(dev->dev_attrib.unmap_granularity_alignment, &buf[32]); - if (dev->se_sub_dev->se_dev_attrib.unmap_granularity_alignment != 0) + if (dev->dev_attrib.unmap_granularity_alignment != 0) buf[32] |= 0x80; /* Set the UGAVALID bit */ + /* + * MAXIMUM WRITE SAME LENGTH + */ +max_write_same: + put_unaligned_be64(dev->dev_attrib.max_write_same_len, &buf[36]); + return 0; } /* Block Device Characteristics VPD page */ -static int spc_emulate_evpd_b1(struct se_cmd *cmd, unsigned char *buf) +static sense_reason_t +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; + buf[5] = dev->dev_attrib.is_nonrot ? 1 : 0; return 0; } /* Thin Provisioning VPD */ -static int spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf) +static sense_reason_t +spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf) { struct se_device *dev = cmd->se_dev; @@ -546,7 +547,7 @@ static int spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf) * 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) + if (dev->dev_attrib.emulate_tpu != 0) buf[5] = 0x80; /* @@ -555,17 +556,18 @@ static int spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf) * 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) + if (dev->dev_attrib.emulate_tpws != 0) buf[5] |= 0x40; return 0; } -static int spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf); +static sense_reason_t +spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf); static struct { uint8_t page; - int (*emulate)(struct se_cmd *, unsigned char *); + sense_reason_t (*emulate)(struct se_cmd *, unsigned char *); } evpd_handlers[] = { { .page = 0x00, .emulate = spc_emulate_evpd_00 }, { .page = 0x80, .emulate = spc_emulate_evpd_80 }, @@ -577,7 +579,8 @@ static struct { }; /* supported vital product data pages */ -static int spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) +static sense_reason_t +spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) { int p; @@ -586,8 +589,7 @@ static int spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) * 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) { + if (cmd->se_dev->dev_flags & DF_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; @@ -596,14 +598,18 @@ static int spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) return 0; } -static int spc_emulate_inquiry(struct se_cmd *cmd) +static sense_reason_t +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 *rbuf; unsigned char *cdb = cmd->t_task_cdb; unsigned char buf[SE_INQUIRY_BUF]; - int p, ret; + sense_reason_t ret; + int p; + + memset(buf, 0, SE_INQUIRY_BUF); if (dev == tpg->tpg_virt_lun0.lun_se_dev) buf[0] = 0x3f; /* Not connected */ @@ -614,8 +620,7 @@ static int spc_emulate_inquiry(struct se_cmd *cmd) 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; + ret = TCM_INVALID_CDB_FIELD; goto out; } @@ -632,33 +637,43 @@ static int spc_emulate_inquiry(struct se_cmd *cmd) } pr_err("Unknown VPD Code: 0x%02x\n", cdb[2]); - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - ret = -EINVAL; + ret = TCM_INVALID_CDB_FIELD; out: rbuf = transport_kmap_data_sg(cmd); - if (rbuf) { - memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); - transport_kunmap_data_sg(cmd); - } + if (!rbuf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + + memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); + transport_kunmap_data_sg(cmd); if (!ret) target_complete_cmd(cmd, GOOD); return ret; } -static int spc_modesense_rwrecovery(unsigned char *p) +static int spc_modesense_rwrecovery(struct se_device *dev, u8 pc, u8 *p) { p[0] = 0x01; p[1] = 0x0a; + /* No changeable values for now */ + if (pc == 1) + goto out; + +out: return 12; } -static int spc_modesense_control(struct se_device *dev, unsigned char *p) +static int spc_modesense_control(struct se_device *dev, u8 pc, u8 *p) { p[0] = 0x0a; p[1] = 0x0a; + + /* No changeable values for now */ + if (pc == 1) + goto out; + p[2] = 2; /* * From spc4r23, 7.4.7 Control mode page @@ -688,7 +703,7 @@ static int spc_modesense_control(struct se_device *dev, unsigned char *p) * 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; + p[3] = (dev->dev_attrib.emulate_rest_reord == 1) ? 0x00 : 0x10; /* * From spc4r17, section 7.4.6 Control mode Page * @@ -718,8 +733,8 @@ static int spc_modesense_control(struct se_device *dev, unsigned char *p) * 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; + p[4] = (dev->dev_attrib.emulate_ua_intlck_ctrl == 2) ? 0x30 : + (dev->dev_attrib.emulate_ua_intlck_ctrl == 1) ? 0x20 : 0x00; /* * From spc4r17, section 7.4.6 Control mode Page * @@ -732,25 +747,56 @@ static int spc_modesense_control(struct se_device *dev, unsigned char *p) * 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[5] = (dev->dev_attrib.emulate_tas) ? 0x40 : 0x00; p[8] = 0xff; p[9] = 0xff; p[11] = 30; +out: return 12; } -static int spc_modesense_caching(struct se_device *dev, unsigned char *p) +static int spc_modesense_caching(struct se_device *dev, u8 pc, u8 *p) { p[0] = 0x08; p[1] = 0x12; - if (dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) + + /* No changeable values for now */ + if (pc == 1) + goto out; + + if (dev->dev_attrib.emulate_write_cache > 0) p[2] = 0x04; /* Write Cache Enable */ p[12] = 0x20; /* Disabled Read Ahead */ +out: return 20; } +static int spc_modesense_informational_exceptions(struct se_device *dev, u8 pc, unsigned char *p) +{ + p[0] = 0x1c; + p[1] = 0x0a; + + /* No changeable values for now */ + if (pc == 1) + goto out; + +out: + return 12; +} + +static struct { + uint8_t page; + uint8_t subpage; + int (*emulate)(struct se_device *, u8, unsigned char *); +} modesense_handlers[] = { + { .page = 0x01, .subpage = 0x00, .emulate = spc_modesense_rwrecovery }, + { .page = 0x08, .subpage = 0x00, .emulate = spc_modesense_caching }, + { .page = 0x0a, .subpage = 0x00, .emulate = spc_modesense_control }, + { .page = 0x1c, .subpage = 0x00, .emulate = spc_modesense_informational_exceptions }, +}; + static void spc_modesense_write_protect(unsigned char *buf, int type) { /* @@ -777,82 +823,224 @@ static void spc_modesense_dpofua(unsigned char *buf, int type) } } -static int spc_emulate_modesense(struct se_cmd *cmd) +static int spc_modesense_blockdesc(unsigned char *buf, u64 blocks, u32 block_size) +{ + *buf++ = 8; + put_unaligned_be32(min(blocks, 0xffffffffull), buf); + buf += 4; + put_unaligned_be32(block_size, buf); + return 9; +} + +static int spc_modesense_long_blockdesc(unsigned char *buf, u64 blocks, u32 block_size) +{ + if (blocks <= 0xffffffff) + return spc_modesense_blockdesc(buf + 3, blocks, block_size) + 3; + + *buf++ = 1; /* LONGLBA */ + buf += 2; + *buf++ = 16; + put_unaligned_be64(blocks, buf); + buf += 12; + put_unaligned_be32(block_size, buf); + + return 17; +} + +static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; char *cdb = cmd->t_task_cdb; - unsigned char *rbuf; + unsigned char *buf, *map_buf; int type = dev->transport->get_device_type(dev); int ten = (cmd->t_task_cdb[0] == MODE_SENSE_10); - u32 offset = ten ? 8 : 4; + bool dbd = !!(cdb[1] & 0x08); + bool llba = ten ? !!(cdb[1] & 0x10) : false; + u8 pc = cdb[2] >> 6; + u8 page = cdb[2] & 0x3f; + u8 subpage = cdb[3]; int length = 0; - unsigned char buf[SE_MODE_PAGE_BUF]; - - memset(buf, 0, SE_MODE_PAGE_BUF); + int ret; + int i; - 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; + map_buf = transport_kmap_data_sg(cmd); + if (!map_buf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + /* + * 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_MODE_PAGE_BUF && + (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)) { + buf = kzalloc(SE_MODE_PAGE_BUF, GFP_KERNEL); + if (!buf) { + transport_kunmap_data_sg(cmd); + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } + } else { + buf = map_buf; } - offset += length; - - if (ten) { - offset -= 2; - buf[0] = (offset >> 8) & 0xff; - buf[1] = offset & 0xff; - offset += 2; - - 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); + /* + * Skip over MODE DATA LENGTH + MEDIUM TYPE fields to byte 3 for + * MODE_SENSE_10 and byte 2 for MODE_SENSE (6). + */ + length = ten ? 3 : 2; + + /* DEVICE-SPECIFIC PARAMETER */ + 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[length], type); + + if ((dev->dev_attrib.emulate_write_cache > 0) && + (dev->dev_attrib.emulate_fua_write > 0)) + spc_modesense_dpofua(&buf[length], type); + + ++length; + + /* BLOCK DESCRIPTOR */ + + /* + * For now we only include a block descriptor for disk (SBC) + * devices; other command sets use a slightly different format. + */ + if (!dbd && type == TYPE_DISK) { + u64 blocks = dev->transport->get_blocks(dev); + u32 block_size = dev->dev_attrib.block_size; + + if (ten) { + if (llba) { + length += spc_modesense_long_blockdesc(&buf[length], + blocks, block_size); + } else { + length += 3; + length += spc_modesense_blockdesc(&buf[length], + blocks, block_size); + } + } else { + length += spc_modesense_blockdesc(&buf[length], blocks, + block_size); + } } else { - offset -= 1; - buf[0] = offset & 0xff; - offset += 1; - - 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 (ten) + length += 4; + else + length += 1; } - rbuf = transport_kmap_data_sg(cmd); - if (rbuf) { - memcpy(rbuf, buf, min(offset, cmd->data_length)); - transport_kunmap_data_sg(cmd); + if (page == 0x3f) { + if (subpage != 0x00 && subpage != 0xff) { + pr_warn("MODE_SENSE: Invalid subpage code: 0x%02x\n", subpage); + kfree(buf); + transport_kunmap_data_sg(cmd); + return TCM_INVALID_CDB_FIELD; + } + + for (i = 0; i < ARRAY_SIZE(modesense_handlers); ++i) { + /* + * Tricky way to say all subpage 00h for + * subpage==0, all subpages for subpage==0xff + * (and we just checked above that those are + * the only two possibilities). + */ + if ((modesense_handlers[i].subpage & ~subpage) == 0) { + ret = modesense_handlers[i].emulate(dev, pc, &buf[length]); + if (!ten && length + ret >= 255) + break; + length += ret; + } + } + + goto set_length; + } + + for (i = 0; i < ARRAY_SIZE(modesense_handlers); ++i) + if (modesense_handlers[i].page == page && + modesense_handlers[i].subpage == subpage) { + length += modesense_handlers[i].emulate(dev, pc, &buf[length]); + goto set_length; + } + + /* + * We don't intend to implement: + * - obsolete page 03h "format parameters" (checked by Solaris) + */ + if (page != 0x03) + pr_err("MODE SENSE: unimplemented page/subpage: 0x%02x/0x%02x\n", + page, subpage); + + transport_kunmap_data_sg(cmd); + return TCM_UNKNOWN_MODE_PAGE; + +set_length: + if (ten) + put_unaligned_be16(length - 2, buf); + else + buf[0] = length - 1; + + if (buf != map_buf) { + memcpy(map_buf, buf, cmd->data_length); + kfree(buf); } + transport_kunmap_data_sg(cmd); target_complete_cmd(cmd, GOOD); return 0; } -static int spc_emulate_request_sense(struct se_cmd *cmd) +static sense_reason_t spc_emulate_modeselect(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + char *cdb = cmd->t_task_cdb; + bool ten = cdb[0] == MODE_SELECT_10; + int off = ten ? 8 : 4; + bool pf = !!(cdb[1] & 0x10); + u8 page, subpage; + unsigned char *buf; + unsigned char tbuf[SE_MODE_PAGE_BUF]; + int length; + int ret = 0; + int i; + + buf = transport_kmap_data_sg(cmd); + if (!buf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + + if (!pf) { + ret = TCM_INVALID_CDB_FIELD; + goto out; + } + + page = buf[off] & 0x3f; + subpage = buf[off] & 0x40 ? buf[off + 1] : 0; + + for (i = 0; i < ARRAY_SIZE(modesense_handlers); ++i) + if (modesense_handlers[i].page == page && + modesense_handlers[i].subpage == subpage) { + memset(tbuf, 0, SE_MODE_PAGE_BUF); + length = modesense_handlers[i].emulate(dev, 0, tbuf); + goto check_contents; + } + + ret = TCM_UNKNOWN_MODE_PAGE; + goto out; + +check_contents: + if (memcmp(buf + off, tbuf, length)) + ret = TCM_INVALID_PARAMETER_LIST; + +out: + transport_kunmap_data_sg(cmd); + + if (!ret) + target_complete_cmd(cmd, GOOD); + return ret; +} + +static sense_reason_t spc_emulate_request_sense(struct se_cmd *cmd) { unsigned char *cdb = cmd->t_task_cdb; unsigned char *rbuf; @@ -864,19 +1052,14 @@ static int spc_emulate_request_sense(struct se_cmd *cmd) if (cdb[1] & 0x01) { pr_err("REQUEST_SENSE description emulation not" " supported\n"); - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -ENOSYS; + return TCM_INVALID_CDB_FIELD; } rbuf = transport_kmap_data_sg(cmd); - if (cmd->scsi_sense_reason != 0) { - /* - * Out of memory. We will fail with CHECK CONDITION, so - * we must not clear the unit attention condition. - */ - target_complete_cmd(cmd, CHECK_CONDITION); - return 0; - } else if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) { + if (!rbuf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + + if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) { /* * CURRENT ERROR, UNIT ATTENTION */ @@ -903,33 +1086,97 @@ static int spc_emulate_request_sense(struct se_cmd *cmd) buf[7] = 0x0A; } - if (rbuf) { - memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); - transport_kunmap_data_sg(cmd); + memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); + transport_kunmap_data_sg(cmd); + + target_complete_cmd(cmd, GOOD); + return 0; +} + +sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd) +{ + struct se_dev_entry *deve; + struct se_session *sess = cmd->se_sess; + unsigned char *buf; + u32 lun_count = 0, offset = 8, i; + + if (cmd->data_length < 16) { + pr_warn("REPORT LUNS allocation length %u too small\n", + cmd->data_length); + return TCM_INVALID_CDB_FIELD; + } + + buf = transport_kmap_data_sg(cmd); + if (!buf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + + /* + * If no struct se_session pointer is present, this struct se_cmd is + * coming via a target_core_mod PASSTHROUGH op, and not through + * a $FABRIC_MOD. In that case, report LUN=0 only. + */ + if (!sess) { + int_to_scsilun(0, (struct scsi_lun *)&buf[offset]); + lun_count = 1; + goto done; + } + + spin_lock_irq(&sess->se_node_acl->device_list_lock); + for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { + deve = sess->se_node_acl->device_list[i]; + if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)) + continue; + /* + * We determine the correct LUN LIST LENGTH even once we + * have reached the initial allocation length. + * See SPC2-R20 7.19. + */ + lun_count++; + if ((offset + 8) > cmd->data_length) + continue; + + int_to_scsilun(deve->mapped_lun, (struct scsi_lun *)&buf[offset]); + offset += 8; } + spin_unlock_irq(&sess->se_node_acl->device_list_lock); + + /* + * See SPC3 r07, page 159. + */ +done: + lun_count *= 8; + buf[0] = ((lun_count >> 24) & 0xff); + buf[1] = ((lun_count >> 16) & 0xff); + buf[2] = ((lun_count >> 8) & 0xff); + buf[3] = (lun_count & 0xff); + transport_kunmap_data_sg(cmd); target_complete_cmd(cmd, GOOD); return 0; } +EXPORT_SYMBOL(spc_emulate_report_luns); -static int spc_emulate_testunitready(struct se_cmd *cmd) +static sense_reason_t +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) +sense_reason_t +spc_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; switch (cdb[0]) { case MODE_SELECT: *size = cdb[4]; + cmd->execute_cmd = spc_emulate_modeselect; break; case MODE_SELECT_10: *size = (cdb[7] << 8) + cdb[8]; + cmd->execute_cmd = spc_emulate_modeselect; break; case MODE_SENSE: *size = cdb[4]; @@ -944,14 +1191,12 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) *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]; + cmd->execute_cmd = target_scsi3_emulate_pr_in; 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->execute_cmd = target_scsi3_emulate_pr_out; break; case RELEASE: case RELEASE_10: @@ -960,8 +1205,7 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) else *size = cmd->data_length; - if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) - cmd->execute_cmd = target_scsi2_reservation_release; + cmd->execute_cmd = target_scsi2_reservation_release; break; case RESERVE: case RESERVE_10: @@ -974,15 +1218,7 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) 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; + cmd->execute_cmd = target_scsi2_reservation_reserve; break; case REQUEST_SENSE: *size = cdb[4]; @@ -995,8 +1231,7 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) * 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; + cmd->sam_task_attr = MSG_HEAD_TAG; cmd->execute_cmd = spc_emulate_inquiry; break; case SECURITY_PROTOCOL_IN: @@ -1018,14 +1253,13 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) *size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; break; case REPORT_LUNS: - cmd->execute_cmd = target_report_luns; + cmd->execute_cmd = spc_emulate_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; + cmd->sam_task_attr = MSG_HEAD_TAG; break; case TEST_UNIT_READY: cmd->execute_cmd = spc_emulate_testunitready; @@ -1037,8 +1271,7 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) * 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) { + if ((cdb[1] & 0x1f) == MI_REPORT_TARGET_PGS) { cmd->execute_cmd = target_emulate_report_target_port_groups; } @@ -1056,8 +1289,7 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) * 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) { + if (cdb[1] == MO_SET_TARGET_PGS) { cmd->execute_cmd = target_emulate_set_target_port_groups; } @@ -1073,9 +1305,7 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) 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 TCM_UNSUPPORTED_SCSI_OPCODE; } return 0; diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c index cb6b0036ae95..d154ce797180 100644 --- a/drivers/target/target_core_stat.c +++ b/drivers/target/target_core_stat.c @@ -1,13 +1,10 @@ /******************************************************************************* * Filename: target_core_stat.c * - * Copyright (c) 2011 Rising Tide Systems - * Copyright (c) 2011 Linux-iSCSI.org - * * Modern ConfigFS group context specific statistics based on original * target_core_mib.c code * - * Copyright (c) 2006-2007 SBE, Inc. All Rights Reserved. + * (c) Copyright 2006-2012 RisingTide Systems LLC. * * Nicholas A. Bellinger <nab@linux-iscsi.org> * @@ -80,13 +77,9 @@ static struct target_stat_scsi_dev_attribute \ static ssize_t target_stat_scsi_dev_show_attr_inst( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_hba *hba = se_subdev->se_dev_hba; - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); + struct se_hba *hba = dev->se_hba; return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); } @@ -95,12 +88,8 @@ DEV_STAT_SCSI_DEV_ATTR_RO(inst); static ssize_t target_stat_scsi_dev_show_attr_indx( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); } @@ -109,13 +98,6 @@ DEV_STAT_SCSI_DEV_ATTR_RO(indx); static ssize_t target_stat_scsi_dev_show_attr_role( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; - return snprintf(page, PAGE_SIZE, "Target\n"); } DEV_STAT_SCSI_DEV_ATTR_RO(role); @@ -123,12 +105,8 @@ DEV_STAT_SCSI_DEV_ATTR_RO(role); static ssize_t target_stat_scsi_dev_show_attr_ports( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_port_count); } @@ -176,13 +154,9 @@ static struct target_stat_scsi_tgt_dev_attribute \ static ssize_t target_stat_scsi_tgt_dev_show_attr_inst( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_hba *hba = se_subdev->se_dev_hba; - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); + struct se_hba *hba = dev->se_hba; return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); } @@ -191,12 +165,8 @@ DEV_STAT_SCSI_TGT_DEV_ATTR_RO(inst); static ssize_t target_stat_scsi_tgt_dev_show_attr_indx( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); } @@ -205,13 +175,6 @@ DEV_STAT_SCSI_TGT_DEV_ATTR_RO(indx); static ssize_t target_stat_scsi_tgt_dev_show_attr_num_lus( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; - return snprintf(page, PAGE_SIZE, "%u\n", LU_COUNT); } DEV_STAT_SCSI_TGT_DEV_ATTR_RO(num_lus); @@ -219,60 +182,27 @@ DEV_STAT_SCSI_TGT_DEV_ATTR_RO(num_lus); static ssize_t target_stat_scsi_tgt_dev_show_attr_status( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - char status[16]; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); - if (!dev) - return -ENODEV; - - switch (dev->dev_status) { - case TRANSPORT_DEVICE_ACTIVATED: - strcpy(status, "activated"); - break; - case TRANSPORT_DEVICE_DEACTIVATED: - strcpy(status, "deactivated"); - break; - case TRANSPORT_DEVICE_SHUTDOWN: - strcpy(status, "shutdown"); - break; - case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: - case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: - strcpy(status, "offline"); - break; - default: - sprintf(status, "unknown(%d)", dev->dev_status); - break; - } - - return snprintf(page, PAGE_SIZE, "%s\n", status); + if (dev->export_count) + return snprintf(page, PAGE_SIZE, "activated"); + else + return snprintf(page, PAGE_SIZE, "deactivated"); } DEV_STAT_SCSI_TGT_DEV_ATTR_RO(status); static ssize_t target_stat_scsi_tgt_dev_show_attr_non_access_lus( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); int non_accessible_lus; - if (!dev) - return -ENODEV; - - switch (dev->dev_status) { - case TRANSPORT_DEVICE_ACTIVATED: + if (dev->export_count) non_accessible_lus = 0; - break; - case TRANSPORT_DEVICE_DEACTIVATED: - case TRANSPORT_DEVICE_SHUTDOWN: - case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: - case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: - default: + else non_accessible_lus = 1; - break; - } return snprintf(page, PAGE_SIZE, "%u\n", non_accessible_lus); } @@ -281,12 +211,8 @@ DEV_STAT_SCSI_TGT_DEV_ATTR_RO(non_access_lus); static ssize_t target_stat_scsi_tgt_dev_show_attr_resets( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); return snprintf(page, PAGE_SIZE, "%u\n", dev->num_resets); } @@ -335,13 +261,9 @@ static struct target_stat_scsi_lu_attribute target_stat_scsi_lu_##_name = \ static ssize_t target_stat_scsi_lu_show_attr_inst( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_hba *hba = se_subdev->se_dev_hba; - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); + struct se_hba *hba = dev->se_hba; return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); } @@ -350,12 +272,8 @@ DEV_STAT_SCSI_LU_ATTR_RO(inst); static ssize_t target_stat_scsi_lu_show_attr_dev( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); } @@ -364,13 +282,6 @@ DEV_STAT_SCSI_LU_ATTR_RO(dev); static ssize_t target_stat_scsi_lu_show_attr_indx( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; - return snprintf(page, PAGE_SIZE, "%u\n", SCSI_LU_INDEX); } DEV_STAT_SCSI_LU_ATTR_RO(indx); @@ -378,12 +289,6 @@ DEV_STAT_SCSI_LU_ATTR_RO(indx); static ssize_t target_stat_scsi_lu_show_attr_lun( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; /* FIXME: scsiLuDefaultLun */ return snprintf(page, PAGE_SIZE, "%llu\n", (unsigned long long)0); } @@ -392,35 +297,28 @@ DEV_STAT_SCSI_LU_ATTR_RO(lun); static ssize_t target_stat_scsi_lu_show_attr_lu_name( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); - if (!dev) - return -ENODEV; /* scsiLuWwnName */ return snprintf(page, PAGE_SIZE, "%s\n", - (strlen(dev->se_sub_dev->t10_wwn.unit_serial)) ? - dev->se_sub_dev->t10_wwn.unit_serial : "None"); + (strlen(dev->t10_wwn.unit_serial)) ? + dev->t10_wwn.unit_serial : "None"); } DEV_STAT_SCSI_LU_ATTR_RO(lu_name); static ssize_t target_stat_scsi_lu_show_attr_vend( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); int i; - char str[sizeof(dev->se_sub_dev->t10_wwn.vendor)+1]; - - if (!dev) - return -ENODEV; + char str[sizeof(dev->t10_wwn.vendor)+1]; /* scsiLuVendorId */ - for (i = 0; i < sizeof(dev->se_sub_dev->t10_wwn.vendor); i++) - str[i] = ISPRINT(dev->se_sub_dev->t10_wwn.vendor[i]) ? - dev->se_sub_dev->t10_wwn.vendor[i] : ' '; + for (i = 0; i < sizeof(dev->t10_wwn.vendor); i++) + str[i] = ISPRINT(dev->t10_wwn.vendor[i]) ? + dev->t10_wwn.vendor[i] : ' '; str[i] = '\0'; return snprintf(page, PAGE_SIZE, "%s\n", str); } @@ -429,19 +327,15 @@ DEV_STAT_SCSI_LU_ATTR_RO(vend); static ssize_t target_stat_scsi_lu_show_attr_prod( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); int i; - char str[sizeof(dev->se_sub_dev->t10_wwn.model)+1]; - - if (!dev) - return -ENODEV; + char str[sizeof(dev->t10_wwn.model)+1]; /* scsiLuProductId */ - for (i = 0; i < sizeof(dev->se_sub_dev->t10_wwn.vendor); i++) - str[i] = ISPRINT(dev->se_sub_dev->t10_wwn.model[i]) ? - dev->se_sub_dev->t10_wwn.model[i] : ' '; + for (i = 0; i < sizeof(dev->t10_wwn.vendor); i++) + str[i] = ISPRINT(dev->t10_wwn.model[i]) ? + dev->t10_wwn.model[i] : ' '; str[i] = '\0'; return snprintf(page, PAGE_SIZE, "%s\n", str); } @@ -450,19 +344,15 @@ DEV_STAT_SCSI_LU_ATTR_RO(prod); static ssize_t target_stat_scsi_lu_show_attr_rev( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); int i; - char str[sizeof(dev->se_sub_dev->t10_wwn.revision)+1]; - - if (!dev) - return -ENODEV; + char str[sizeof(dev->t10_wwn.revision)+1]; /* scsiLuRevisionId */ - for (i = 0; i < sizeof(dev->se_sub_dev->t10_wwn.revision); i++) - str[i] = ISPRINT(dev->se_sub_dev->t10_wwn.revision[i]) ? - dev->se_sub_dev->t10_wwn.revision[i] : ' '; + for (i = 0; i < sizeof(dev->t10_wwn.revision); i++) + str[i] = ISPRINT(dev->t10_wwn.revision[i]) ? + dev->t10_wwn.revision[i] : ' '; str[i] = '\0'; return snprintf(page, PAGE_SIZE, "%s\n", str); } @@ -471,12 +361,8 @@ DEV_STAT_SCSI_LU_ATTR_RO(rev); static ssize_t target_stat_scsi_lu_show_attr_dev_type( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); /* scsiLuPeripheralType */ return snprintf(page, PAGE_SIZE, "%u\n", @@ -487,30 +373,18 @@ DEV_STAT_SCSI_LU_ATTR_RO(dev_type); static ssize_t target_stat_scsi_lu_show_attr_status( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); /* scsiLuStatus */ return snprintf(page, PAGE_SIZE, "%s\n", - (dev->dev_status == TRANSPORT_DEVICE_ACTIVATED) ? - "available" : "notavailable"); + (dev->export_count) ? "available" : "notavailable"); } DEV_STAT_SCSI_LU_ATTR_RO(status); static ssize_t target_stat_scsi_lu_show_attr_state_bit( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; - /* scsiLuState */ return snprintf(page, PAGE_SIZE, "exposed\n"); } @@ -519,12 +393,8 @@ DEV_STAT_SCSI_LU_ATTR_RO(state_bit); static ssize_t target_stat_scsi_lu_show_attr_num_cmds( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); /* scsiLuNumCommands */ return snprintf(page, PAGE_SIZE, "%llu\n", @@ -535,12 +405,8 @@ DEV_STAT_SCSI_LU_ATTR_RO(num_cmds); static ssize_t target_stat_scsi_lu_show_attr_read_mbytes( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); /* scsiLuReadMegaBytes */ return snprintf(page, PAGE_SIZE, "%u\n", (u32)(dev->read_bytes >> 20)); @@ -550,12 +416,8 @@ DEV_STAT_SCSI_LU_ATTR_RO(read_mbytes); static ssize_t target_stat_scsi_lu_show_attr_write_mbytes( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); /* scsiLuWrittenMegaBytes */ return snprintf(page, PAGE_SIZE, "%u\n", (u32)(dev->write_bytes >> 20)); @@ -565,12 +427,8 @@ DEV_STAT_SCSI_LU_ATTR_RO(write_mbytes); static ssize_t target_stat_scsi_lu_show_attr_resets( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); /* scsiLuInResets */ return snprintf(page, PAGE_SIZE, "%u\n", dev->num_resets); @@ -580,13 +438,6 @@ DEV_STAT_SCSI_LU_ATTR_RO(resets); static ssize_t target_stat_scsi_lu_show_attr_full_stat( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; - /* FIXME: scsiLuOutTaskSetFullStatus */ return snprintf(page, PAGE_SIZE, "%u\n", 0); } @@ -595,13 +446,6 @@ DEV_STAT_SCSI_LU_ATTR_RO(full_stat); static ssize_t target_stat_scsi_lu_show_attr_hs_num_cmds( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; - /* FIXME: scsiLuHSInCommands */ return snprintf(page, PAGE_SIZE, "%u\n", 0); } @@ -610,12 +454,8 @@ DEV_STAT_SCSI_LU_ATTR_RO(hs_num_cmds); static ssize_t target_stat_scsi_lu_show_attr_creation_time( struct se_dev_stat_grps *sgrps, char *page) { - struct se_subsystem_dev *se_subdev = container_of(sgrps, - struct se_subsystem_dev, dev_stat_grps); - struct se_device *dev = se_subdev->se_dev_ptr; - - if (!dev) - return -ENODEV; + struct se_device *dev = + container_of(sgrps, struct se_device, dev_stat_grps); /* scsiLuCreationTime */ return snprintf(page, PAGE_SIZE, "%u\n", (u32)(((u32)dev->creation_time - @@ -662,20 +502,20 @@ static struct config_item_type target_stat_scsi_lu_cit = { * Called from target_core_configfs.c:target_core_make_subdev() to setup * the target statistics groups + configfs CITs located in target_core_stat.c */ -void target_stat_setup_dev_default_groups(struct se_subsystem_dev *se_subdev) +void target_stat_setup_dev_default_groups(struct se_device *dev) { - struct config_group *dev_stat_grp = &se_subdev->dev_stat_grps.stat_group; + struct config_group *dev_stat_grp = &dev->dev_stat_grps.stat_group; - config_group_init_type_name(&se_subdev->dev_stat_grps.scsi_dev_group, + config_group_init_type_name(&dev->dev_stat_grps.scsi_dev_group, "scsi_dev", &target_stat_scsi_dev_cit); - config_group_init_type_name(&se_subdev->dev_stat_grps.scsi_tgt_dev_group, + config_group_init_type_name(&dev->dev_stat_grps.scsi_tgt_dev_group, "scsi_tgt_dev", &target_stat_scsi_tgt_dev_cit); - config_group_init_type_name(&se_subdev->dev_stat_grps.scsi_lu_group, + config_group_init_type_name(&dev->dev_stat_grps.scsi_lu_group, "scsi_lu", &target_stat_scsi_lu_cit); - dev_stat_grp->default_groups[0] = &se_subdev->dev_stat_grps.scsi_dev_group; - dev_stat_grp->default_groups[1] = &se_subdev->dev_stat_grps.scsi_tgt_dev_group; - dev_stat_grp->default_groups[2] = &se_subdev->dev_stat_grps.scsi_lu_group; + dev_stat_grp->default_groups[0] = &dev->dev_stat_grps.scsi_dev_group; + dev_stat_grp->default_groups[1] = &dev->dev_stat_grps.scsi_tgt_dev_group; + dev_stat_grp->default_groups[2] = &dev->dev_stat_grps.scsi_lu_group; dev_stat_grp->default_groups[3] = NULL; } @@ -1161,7 +1001,7 @@ static ssize_t target_stat_scsi_transport_show_attr_dev_name( return -ENODEV; } tpg = sep->sep_tpg; - wwn = &dev->se_sub_dev->t10_wwn; + wwn = &dev->t10_wwn; /* scsiTransportDevName */ ret = snprintf(page, PAGE_SIZE, "%s+%s\n", tpg->se_tpg_tfo->tpg_get_wwn(tpg), diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 1c59a3c23b2c..c6e0293ffdb0 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -3,8 +3,7 @@ * * This file contains SPC-3 task management infrastructure * - * Copyright (c) 2009,2010 Rising Tide Systems - * Copyright (c) 2009,2010 Linux-iSCSI.org + * (c) Copyright 2009-2012 RisingTide Systems LLC. * * Nicholas A. Bellinger <nab@kernel.org> * @@ -140,15 +139,15 @@ void core_tmr_abort_task( printk("ABORT_TASK: Found referenced %s task_tag: %u\n", se_cmd->se_tfo->get_fabric_name(), ref_tag); - spin_lock_irq(&se_cmd->t_state_lock); + spin_lock(&se_cmd->t_state_lock); if (se_cmd->transport_state & CMD_T_COMPLETE) { printk("ABORT_TASK: ref_tag: %u already complete, skipping\n", ref_tag); - spin_unlock_irq(&se_cmd->t_state_lock); + spin_unlock(&se_cmd->t_state_lock); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); goto out; } se_cmd->transport_state |= CMD_T_ABORTED; - spin_unlock_irq(&se_cmd->t_state_lock); + spin_unlock(&se_cmd->t_state_lock); list_del_init(&se_cmd->se_cmd_list); kref_get(&se_cmd->cmd_kref); @@ -371,7 +370,7 @@ int core_tmr_lun_reset( * which the command was received shall be completed with TASK ABORTED * status (see SAM-4). */ - tas = dev->se_sub_dev->se_dev_attrib.emulate_tas; + tas = dev->dev_attrib.emulate_tas; /* * Determine if this se_tmr is coming from a $FABRIC_MOD * or struct se_device passthrough.. @@ -399,10 +398,10 @@ int core_tmr_lun_reset( * LOGICAL UNIT RESET */ if (!preempt_and_abort_list && - (dev->dev_flags & DF_SPC2_RESERVATIONS)) { + (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)) { spin_lock(&dev->dev_reservation_lock); dev->dev_reserved_node_acl = NULL; - dev->dev_flags &= ~DF_SPC2_RESERVATIONS; + dev->dev_reservation_flags &= ~DRF_SPC2_RESERVATIONS; spin_unlock(&dev->dev_reservation_lock); pr_debug("LUN_RESET: SCSI-2 Released reservation\n"); } diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index a531fe282b1e..5192ac0337f7 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -3,10 +3,7 @@ * * This file contains generic Target Portal Group related functions. * - * 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 + * (c) Copyright 2002-2012 RisingTide Systems LLC. * * Nicholas A. Bellinger <nab@kernel.org> * @@ -619,6 +616,29 @@ int core_tpg_set_initiator_node_queue_depth( } EXPORT_SYMBOL(core_tpg_set_initiator_node_queue_depth); +/* core_tpg_set_initiator_node_tag(): + * + * Initiator nodeacl tags are not used internally, but may be used by + * userspace to emulate aliases or groups. + * Returns length of newly-set tag or -EINVAL. + */ +int core_tpg_set_initiator_node_tag( + struct se_portal_group *tpg, + struct se_node_acl *acl, + const char *new_tag) +{ + if (strlen(new_tag) >= MAX_ACL_TAG_SIZE) + return -EINVAL; + + if (!strncmp("NULL", new_tag, 4)) { + acl->acl_tag[0] = '\0'; + return 0; + } + + return snprintf(acl->acl_tag, MAX_ACL_TAG_SIZE, "%s", new_tag); +} +EXPORT_SYMBOL(core_tpg_set_initiator_node_tag); + static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg) { /* Set in core_dev_setup_virtual_lun0() */ @@ -672,6 +692,7 @@ int core_tpg_register( for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { lun = se_tpg->tpg_lun_list[i]; lun->unpacked_lun = i; + lun->lun_link_magic = SE_LUN_LINK_MAGIC; lun->lun_status = TRANSPORT_LUN_STATUS_FREE; atomic_set(&lun->lun_acl_count, 0); init_completion(&lun->lun_shutdown_comp); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index c33baff86aa6..bd587b70661a 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -3,10 +3,7 @@ * * This file contains the Generic Target Engine Core. * - * 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 + * (c) Copyright 2002-2012 RisingTide Systems LLC. * * Nicholas A. Bellinger <nab@kernel.org> * @@ -70,7 +67,6 @@ static void transport_handle_queue_full(struct se_cmd *cmd, static int transport_generic_get_mem(struct se_cmd *cmd); 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); int init_se_kmem_caches(void) @@ -297,7 +293,7 @@ void transport_register_session( } EXPORT_SYMBOL(transport_register_session); -void target_release_session(struct kref *kref) +static void target_release_session(struct kref *kref) { struct se_session *se_sess = container_of(kref, struct se_session, sess_kref); @@ -545,9 +541,6 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd) void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) { - if (!(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) - transport_lun_remove_cmd(cmd); - if (transport_cmd_check_stop_to_fabric(cmd)) return; if (remove) @@ -558,7 +551,8 @@ static void target_complete_failure_work(struct work_struct *work) { struct se_cmd *cmd = container_of(work, struct se_cmd, work); - transport_generic_request_failure(cmd); + transport_generic_request_failure(cmd, + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE); } /* @@ -626,7 +620,6 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) complete(&cmd->t_transport_stop_comp); return; } else if (cmd->transport_state & CMD_T_FAILED) { - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; INIT_WORK(&cmd->work, target_complete_failure_work); } else { INIT_WORK(&cmd->work, target_complete_ok_work); @@ -659,7 +652,7 @@ static void target_add_to_state_list(struct se_cmd *cmd) 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) +void target_qf_do_work(struct work_struct *work) { struct se_device *dev = container_of(work, struct se_device, qf_work_queue); @@ -712,29 +705,15 @@ void transport_dump_dev_state( int *bl) { *bl += sprintf(b + *bl, "Status: "); - switch (dev->dev_status) { - case TRANSPORT_DEVICE_ACTIVATED: + if (dev->export_count) *bl += sprintf(b + *bl, "ACTIVATED"); - break; - case TRANSPORT_DEVICE_DEACTIVATED: + else *bl += sprintf(b + *bl, "DEACTIVATED"); - break; - case TRANSPORT_DEVICE_SHUTDOWN: - *bl += sprintf(b + *bl, "SHUTDOWN"); - break; - case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: - case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: - *bl += sprintf(b + *bl, "OFFLINE"); - break; - default: - *bl += sprintf(b + *bl, "UNKNOWN=%d", dev->dev_status); - break; - } *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); + dev->dev_attrib.block_size, + dev->dev_attrib.hw_max_sectors); *bl += sprintf(b + *bl, " "); } @@ -991,186 +970,8 @@ transport_set_vpd_ident(struct t10_vpd *vpd, unsigned char *page_83) } EXPORT_SYMBOL(transport_set_vpd_ident); -static void core_setup_task_attr_emulation(struct se_device *dev) -{ - /* - * If this device is from Target_Core_Mod/pSCSI, disable the - * SAM Task Attribute emulation. - * - * This is currently not available in upsream Linux/SCSI Target - * mode code, and is assumed to be disabled while using TCM/pSCSI. - */ - if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) { - dev->dev_task_attr_type = SAM_TASK_ATTR_PASSTHROUGH; - return; - } - - dev->dev_task_attr_type = SAM_TASK_ATTR_EMULATED; - pr_debug("%s: Using SAM_TASK_ATTR_EMULATED for SPC: 0x%02x" - " device\n", dev->transport->name, - dev->transport->get_device_rev(dev)); -} - -static void scsi_dump_inquiry(struct se_device *dev) -{ - struct t10_wwn *wwn = &dev->se_sub_dev->t10_wwn; - char buf[17]; - int i, device_type; - /* - * Print Linux/SCSI style INQUIRY formatting to the kernel ring buffer - */ - for (i = 0; i < 8; i++) - if (wwn->vendor[i] >= 0x20) - buf[i] = wwn->vendor[i]; - else - buf[i] = ' '; - buf[i] = '\0'; - pr_debug(" Vendor: %s\n", buf); - - for (i = 0; i < 16; i++) - if (wwn->model[i] >= 0x20) - buf[i] = wwn->model[i]; - else - buf[i] = ' '; - buf[i] = '\0'; - pr_debug(" Model: %s\n", buf); - - for (i = 0; i < 4; i++) - if (wwn->revision[i] >= 0x20) - buf[i] = wwn->revision[i]; - else - buf[i] = ' '; - buf[i] = '\0'; - pr_debug(" Revision: %s\n", buf); - - device_type = dev->transport->get_device_type(dev); - pr_debug(" Type: %s ", scsi_device_type(device_type)); - pr_debug(" ANSI SCSI revision: %02x\n", - dev->transport->get_device_rev(dev)); -} - -struct se_device *transport_add_device_to_core_hba( - struct se_hba *hba, - struct se_subsystem_api *transport, - struct se_subsystem_dev *se_dev, - u32 device_flags, - void *transport_dev, - struct se_dev_limits *dev_limits, - const char *inquiry_prod, - const char *inquiry_rev) -{ - int force_pt; - struct se_device *dev; - - dev = kzalloc(sizeof(struct se_device), GFP_KERNEL); - if (!dev) { - pr_err("Unable to allocate memory for se_dev_t\n"); - return NULL; - } - - dev->dev_flags = device_flags; - dev->dev_status |= TRANSPORT_DEVICE_DEACTIVATED; - dev->dev_ptr = transport_dev; - dev->se_hba = hba; - dev->se_sub_dev = se_dev; - dev->transport = transport; - INIT_LIST_HEAD(&dev->dev_list); - INIT_LIST_HEAD(&dev->dev_sep_list); - INIT_LIST_HEAD(&dev->dev_tmr_list); - INIT_LIST_HEAD(&dev->delayed_cmd_list); - INIT_LIST_HEAD(&dev->state_list); - INIT_LIST_HEAD(&dev->qf_cmd_list); - spin_lock_init(&dev->execute_task_lock); - spin_lock_init(&dev->delayed_cmd_lock); - spin_lock_init(&dev->dev_reservation_lock); - spin_lock_init(&dev->dev_status_lock); - spin_lock_init(&dev->se_port_lock); - spin_lock_init(&dev->se_tmr_lock); - spin_lock_init(&dev->qf_cmd_lock); - atomic_set(&dev->dev_ordered_id, 0); - - se_dev_set_default_attribs(dev, dev_limits); - - dev->dev_index = scsi_get_new_index(SCSI_DEVICE_INDEX); - dev->creation_time = get_jiffies_64(); - spin_lock_init(&dev->stats_lock); - - spin_lock(&hba->device_lock); - list_add_tail(&dev->dev_list, &hba->hba_dev_list); - hba->dev_count++; - spin_unlock(&hba->device_lock); - /* - * Setup the SAM Task Attribute emulation for struct se_device - */ - core_setup_task_attr_emulation(dev); - /* - * Force PR and ALUA passthrough emulation with internal object use. - */ - force_pt = (hba->hba_flags & HBA_FLAGS_INTERNAL_USE); - /* - * Setup the Reservations infrastructure for struct se_device - */ - core_setup_reservations(dev, force_pt); - /* - * Setup the Asymmetric Logical Unit Assignment for struct se_device - */ - if (core_setup_alua(dev, force_pt) < 0) - goto err_dev_list; - - /* - * Startup the struct se_device processing thread - */ - 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 err_dev_list; - } - /* - * Setup work_queue for QUEUE_FULL - */ - INIT_WORK(&dev->qf_work_queue, target_qf_do_work); - /* - * Preload the initial INQUIRY const values if we are doing - * anything virtual (IBLOCK, FILEIO, RAMDISK), but not for TCM/pSCSI - * passthrough because this is being provided by the backend LLD. - * This is required so that transport_get_inquiry() copies these - * originals once back into DEV_T10_WWN(dev) for the virtual device - * setup. - */ - if (dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) { - if (!inquiry_prod || !inquiry_rev) { - pr_err("All non TCM/pSCSI plugins require" - " INQUIRY consts\n"); - goto err_wq; - } - - strncpy(&dev->se_sub_dev->t10_wwn.vendor[0], "LIO-ORG", 8); - strncpy(&dev->se_sub_dev->t10_wwn.model[0], inquiry_prod, 16); - strncpy(&dev->se_sub_dev->t10_wwn.revision[0], inquiry_rev, 4); - } - scsi_dump_inquiry(dev); - - return dev; - -err_wq: - destroy_workqueue(dev->tmr_wq); -err_dev_list: - spin_lock(&hba->device_lock); - list_del(&dev->dev_list); - hba->dev_count--; - spin_unlock(&hba->device_lock); - - se_release_vpd_for_dev(dev); - - kfree(dev); - - return NULL; -} -EXPORT_SYMBOL(transport_add_device_to_core_hba); - -int target_cmd_size_check(struct se_cmd *cmd, unsigned int size) +sense_reason_t +target_cmd_size_check(struct se_cmd *cmd, unsigned int size) { struct se_device *dev = cmd->se_dev; @@ -1185,18 +986,18 @@ int target_cmd_size_check(struct se_cmd *cmd, unsigned int size) if (cmd->data_direction == DMA_TO_DEVICE) { pr_err("Rejecting underflow/overflow" " WRITE data\n"); - goto out_invalid_cdb_field; + return TCM_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) { + if (dev->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; + return TCM_INVALID_CDB_FIELD; } /* * For the overflow case keep the existing fabric provided @@ -1216,10 +1017,6 @@ int target_cmd_size_check(struct se_cmd *cmd, unsigned int 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; } /* @@ -1259,45 +1056,41 @@ void transport_init_se_cmd( } EXPORT_SYMBOL(transport_init_se_cmd); -static int transport_check_alloc_task_attr(struct se_cmd *cmd) +static sense_reason_t +transport_check_alloc_task_attr(struct se_cmd *cmd) { + struct se_device *dev = cmd->se_dev; + /* * Check if SAM Task Attribute emulation is enabled for this * struct se_device storage object */ - if (cmd->se_dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED) + if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) return 0; if (cmd->sam_task_attr == MSG_ACA_TAG) { pr_debug("SAM Task Attribute ACA" " emulation is not supported\n"); - return -EINVAL; + return TCM_INVALID_CDB_FIELD; } /* * Used to determine when ORDERED commands should go from * Dormant to Active status. */ - cmd->se_ordered_id = atomic_inc_return(&cmd->se_dev->dev_ordered_id); + cmd->se_ordered_id = atomic_inc_return(&dev->dev_ordered_id); smp_mb__after_atomic_inc(); pr_debug("Allocated se_ordered_id: %u for Task Attr: 0x%02x on %s\n", cmd->se_ordered_id, cmd->sam_task_attr, - cmd->se_dev->transport->name); + dev->transport->name); return 0; } -/* target_setup_cmd_from_cdb(): - * - * Called from fabric RX Thread. - */ -int target_setup_cmd_from_cdb( - struct se_cmd *cmd, - unsigned char *cdb) +sense_reason_t +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; + struct se_device *dev = cmd->se_dev; unsigned long flags; - int ret; + sense_reason_t ret; /* * Ensure that the received CDB is less than the max (252 + 8) bytes @@ -1307,9 +1100,7 @@ int target_setup_cmd_from_cdb( pr_err("Received SCSI CDB with command_size: %d that" " exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n", scsi_command_size(cdb), SCSI_MAX_VARLEN_CDB_SIZE); - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -EINVAL; + return TCM_INVALID_CDB_FIELD; } /* * If the received CDB is larger than TCM_MAX_COMMAND_SIZE, @@ -1324,10 +1115,7 @@ int target_setup_cmd_from_cdb( " %u > sizeof(cmd->__t_task_cdb): %lu ops\n", scsi_command_size(cdb), (unsigned long)sizeof(cmd->__t_task_cdb)); - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -ENOMEM; + return TCM_OUT_OF_RESOURCES; } } else cmd->t_task_cdb = &cmd->__t_task_cdb[0]; @@ -1339,70 +1127,30 @@ int target_setup_cmd_from_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 = target_scsi3_ua_check(cmd); + if (ret) + return ret; - 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; - } + ret = target_alua_state_check(cmd); + if (ret) + return ret; - /* - * 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. - */ - } + ret = target_check_reservation(cmd); + if (ret) + return ret; - ret = cmd->se_dev->transport->parse_cdb(cmd); - if (ret < 0) + ret = dev->transport->parse_cdb(cmd); + if (ret) + return ret; + + ret = transport_check_alloc_task_attr(cmd); + if (ret) 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 - */ - if (transport_check_alloc_task_attr(cmd) < 0) { - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - return -EINVAL; - } spin_lock(&cmd->se_lun->lun_sep_lock); if (cmd->se_lun->lun_sep) cmd->se_lun->lun_sep->sep_stats.cmd_pdus++; @@ -1418,7 +1166,7 @@ EXPORT_SYMBOL(target_setup_cmd_from_cdb); int transport_handle_cdb_direct( struct se_cmd *cmd) { - int ret; + sense_reason_t ret; if (!cmd->se_lun) { dump_stack(); @@ -1448,13 +1196,41 @@ int transport_handle_cdb_direct( * and call transport_generic_request_failure() if necessary.. */ ret = transport_generic_new_cmd(cmd); - if (ret < 0) - transport_generic_request_failure(cmd); - + if (ret) + transport_generic_request_failure(cmd, ret); return 0; } EXPORT_SYMBOL(transport_handle_cdb_direct); +static sense_reason_t +transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *sgl, + u32 sgl_count, struct scatterlist *sgl_bidi, u32 sgl_bidi_count) +{ + if (!sgl || !sgl_count) + return 0; + + /* + * 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"); + return TCM_INVALID_CDB_FIELD; + } + + 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; + return 0; +} + /* * target_submit_cmd_map_sgls - lookup unpacked lun and submit uninitialized * se_cmd + use pre-allocated SGL memory. @@ -1487,7 +1263,8 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess struct scatterlist *sgl_bidi, u32 sgl_bidi_count) { struct se_portal_group *se_tpg; - int rc; + sense_reason_t rc; + int ret; se_tpg = se_sess->se_tpg; BUG_ON(!se_tpg); @@ -1508,9 +1285,9 @@ int target_submit_cmd_map_sgls(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. */ - rc = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); - if (rc) - return rc; + ret = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + if (ret) + return ret; /* * Signal bidirectional data payloads to target-core */ @@ -1519,16 +1296,16 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess /* * Locate se_lun pointer and attach it to struct se_cmd */ - if (transport_lookup_cmd_lun(se_cmd, unpacked_lun) < 0) { - transport_send_check_condition_and_sense(se_cmd, - se_cmd->scsi_sense_reason, 0); + rc = transport_lookup_cmd_lun(se_cmd, unpacked_lun); + if (rc) { + transport_send_check_condition_and_sense(se_cmd, rc, 0); target_put_sess_cmd(se_sess, se_cmd); return 0; } rc = target_setup_cmd_from_cdb(se_cmd, cdb); if (rc != 0) { - transport_generic_request_failure(se_cmd); + transport_generic_request_failure(se_cmd, rc); return 0; } /* @@ -1563,7 +1340,7 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess 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); + transport_generic_request_failure(se_cmd, rc); return 0; } } @@ -1616,7 +1393,8 @@ 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); + + transport_cmd_check_stop_to_fabric(se_cmd); } /** @@ -1710,16 +1488,17 @@ bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags) /* * Handle SAM-esque emulation for generic transport request failures. */ -void transport_generic_request_failure(struct se_cmd *cmd) +void transport_generic_request_failure(struct se_cmd *cmd, + sense_reason_t sense_reason) { int ret = 0; pr_debug("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08x" " CDB: 0x%02x\n", cmd, cmd->se_tfo->get_task_tag(cmd), cmd->t_task_cdb[0]); - pr_debug("-----[ i_state: %d t_state: %d scsi_sense_reason: %d\n", + pr_debug("-----[ i_state: %d t_state: %d sense_reason: %d\n", cmd->se_tfo->get_cmd_state(cmd), - cmd->t_state, cmd->scsi_sense_reason); + cmd->t_state, sense_reason); pr_debug("-----[ CMD_T_ACTIVE: %d CMD_T_STOP: %d CMD_T_SENT: %d\n", (cmd->transport_state & CMD_T_ACTIVE) != 0, (cmd->transport_state & CMD_T_STOP) != 0, @@ -1728,10 +1507,9 @@ void transport_generic_request_failure(struct se_cmd *cmd) /* * For SAM Task Attribute emulation for failed struct se_cmd */ - if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) - transport_complete_task_attr(cmd); + transport_complete_task_attr(cmd); - switch (cmd->scsi_sense_reason) { + switch (sense_reason) { case TCM_NON_EXISTENT_LUN: case TCM_UNSUPPORTED_SCSI_OPCODE: case TCM_INVALID_CDB_FIELD: @@ -1744,6 +1522,9 @@ void transport_generic_request_failure(struct se_cmd *cmd) case TCM_CHECK_CONDITION_UNIT_ATTENTION: case TCM_CHECK_CONDITION_NOT_READY: break; + case TCM_OUT_OF_RESOURCES: + sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + break; case TCM_RESERVATION_CONFLICT: /* * No SENSE Data payload for this case, set SCSI Status @@ -1760,7 +1541,7 @@ void transport_generic_request_failure(struct se_cmd *cmd) * See spc4r17, section 7.4.6 Control Mode Page, Table 349 */ if (cmd->se_sess && - cmd->se_dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl == 2) + cmd->se_dev->dev_attrib.emulate_ua_intlck_ctrl == 2) core_scsi3_ua_allocate(cmd->se_sess->se_node_acl, cmd->orig_fe_lun, 0x2C, ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS); @@ -1771,13 +1552,12 @@ void transport_generic_request_failure(struct se_cmd *cmd) goto check_stop; default: pr_err("Unknown transport error for CDB 0x%02x: %d\n", - cmd->t_task_cdb[0], cmd->scsi_sense_reason); - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + cmd->t_task_cdb[0], sense_reason); + sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; break; } - ret = transport_send_check_condition_and_sense(cmd, - cmd->scsi_sense_reason, 0); + ret = transport_send_check_condition_and_sense(cmd, sense_reason, 0); if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; @@ -1795,67 +1575,30 @@ EXPORT_SYMBOL(transport_generic_request_failure); static void __target_execute_cmd(struct se_cmd *cmd) { - int error = 0; + sense_reason_t ret; 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); - - 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); + if (cmd->execute_cmd) { + ret = cmd->execute_cmd(cmd); + if (ret) { + 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); + transport_generic_request_failure(cmd, ret); + } } } -void target_execute_cmd(struct se_cmd *cmd) +static bool target_handle_task_attr(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. - */ - 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; + if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + return false; /* * Check for the existence of HEAD_OF_QUEUE, and if true return 1 @@ -1866,7 +1609,7 @@ void target_execute_cmd(struct se_cmd *cmd) 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; + return false; case MSG_ORDERED_TAG: atomic_inc(&dev->dev_ordered_sync); smp_mb__after_atomic_inc(); @@ -1880,7 +1623,7 @@ void target_execute_cmd(struct se_cmd *cmd) * exist that need to be completed first. */ if (!atomic_read(&dev->simple_cmds)) - goto execute; + return false; break; default: /* @@ -1891,23 +1634,64 @@ void target_execute_cmd(struct se_cmd *cmd) break; } - if (atomic_read(&dev->dev_ordered_sync) != 0) { - spin_lock(&dev->delayed_cmd_lock); - list_add_tail(&cmd->se_delayed_node, &dev->delayed_cmd_list); - spin_unlock(&dev->delayed_cmd_lock); + if (atomic_read(&dev->dev_ordered_sync) == 0) + return false; - 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); + spin_lock(&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 true; +} + +void target_execute_cmd(struct se_cmd *cmd) +{ + /* + * If the received CDB has aleady been aborted stop processing it here. + */ + if (transport_check_aborted_status(cmd, 1)) { + complete(&cmd->transport_lun_stop_comp); return; } -execute: /* - * Otherwise, no ORDERED task attributes exist.. + * 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. */ - __target_execute_cmd(cmd); + 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; + cmd->transport_state |= CMD_T_ACTIVE; + spin_unlock_irq(&cmd->t_state_lock); + + if (!target_handle_task_attr(cmd)) + __target_execute_cmd(cmd); } EXPORT_SYMBOL(target_execute_cmd); @@ -1946,6 +1730,9 @@ static void transport_complete_task_attr(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; + if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + return; + if (cmd->sam_task_attr == MSG_SIMPLE_TAG) { atomic_dec(&dev->simple_cmds); smp_mb__after_atomic_dec(); @@ -1974,8 +1761,7 @@ static void transport_complete_qf(struct se_cmd *cmd) { int ret = 0; - if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) - transport_complete_task_attr(cmd); + transport_complete_task_attr(cmd); if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) { ret = cmd->se_tfo->queue_status(cmd); @@ -2033,8 +1819,8 @@ static void target_complete_ok_work(struct work_struct *work) * delayed execution list after a HEAD_OF_QUEUE or ORDERED Task * Attribute. */ - if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) - transport_complete_task_attr(cmd); + transport_complete_task_attr(cmd); + /* * Check to schedule QUEUE_FULL work, or execute an existing * cmd->transport_qf_callback() @@ -2182,9 +1968,10 @@ static void transport_put_cmd(struct se_cmd *cmd) unsigned long flags; spin_lock_irqsave(&cmd->t_state_lock, flags); - if (atomic_read(&cmd->t_fe_count)) { - if (!atomic_dec_and_test(&cmd->t_fe_count)) - goto out_busy; + if (atomic_read(&cmd->t_fe_count) && + !atomic_dec_and_test(&cmd->t_fe_count)) { + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + return; } if (cmd->transport_state & CMD_T_DEV_ACTIVE) { @@ -2196,56 +1983,7 @@ static void transport_put_cmd(struct se_cmd *cmd) transport_free_pages(cmd); transport_release_cmd(cmd); return; -out_busy: - spin_unlock_irqrestore(&cmd->t_state_lock, flags); -} - -/* - * transport_generic_map_mem_to_cmd - Use fabric-alloced pages instead of - * allocating in the core. - * @cmd: Associated se_cmd descriptor - * @mem: SGL style memory for TCM WRITE / READ - * @sg_mem_num: Number of SGL elements - * @mem_bidi_in: SGL style memory for TCM BIDI READ - * @sg_mem_bidi_num: Number of BIDI READ SGL elements - * - * Return: nonzero return cmd was rejected for -ENOMEM or inproper usage - * of parameters. - */ -int transport_generic_map_mem_to_cmd( - struct se_cmd *cmd, - struct scatterlist *sgl, - u32 sgl_count, - struct scatterlist *sgl_bidi, - u32 sgl_bidi_count) -{ - if (!sgl || !sgl_count) - return 0; - - /* - * 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; - - 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); void *transport_kmap_data_sg(struct se_cmd *cmd) { @@ -2267,10 +2005,8 @@ void *transport_kmap_data_sg(struct se_cmd *cmd) /* >1 page. use vmap */ pages = kmalloc(sizeof(*pages) * cmd->t_data_nents, GFP_KERNEL); - if (!pages) { - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + if (!pages) return NULL; - } /* convert sg[] to pages[] */ for_each_sg(cmd->t_data_sg, sg, cmd->t_data_nents, i) { @@ -2279,10 +2015,8 @@ void *transport_kmap_data_sg(struct se_cmd *cmd) cmd->t_data_vmap = vmap(pages, cmd->t_data_nents, VM_MAP, PAGE_KERNEL); kfree(pages); - if (!cmd->t_data_vmap) { - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + if (!cmd->t_data_vmap) return NULL; - } return cmd->t_data_vmap + cmd->t_data_sg[0].offset; } @@ -2348,7 +2082,8 @@ out: * might not have the payload yet, so notify the fabric via a call to * ->write_pending instead. Otherwise place it on the execution queue. */ -int transport_generic_new_cmd(struct se_cmd *cmd) +sense_reason_t +transport_generic_new_cmd(struct se_cmd *cmd) { int ret = 0; @@ -2361,7 +2096,7 @@ int transport_generic_new_cmd(struct se_cmd *cmd) cmd->data_length) { ret = transport_generic_get_mem(cmd); if (ret < 0) - goto out_fail; + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } atomic_inc(&cmd->t_fe_count); @@ -2387,14 +2122,11 @@ int transport_generic_new_cmd(struct se_cmd *cmd) if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; - if (ret < 0) - return ret; - return 1; + /* fabric drivers should only return -EAGAIN or -ENOMEM as error */ + WARN_ON(ret); + + return (!ret) ? 0 : TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -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; @@ -2838,21 +2570,9 @@ static int transport_get_sense_codes( return 0; } -static int transport_set_sense_codes( - struct se_cmd *cmd, - u8 asc, - u8 ascq) -{ - cmd->scsi_asc = asc; - cmd->scsi_ascq = ascq; - - return 0; -} - -int transport_send_check_condition_and_sense( - struct se_cmd *cmd, - u8 reason, - int from_transport) +int +transport_send_check_condition_and_sense(struct se_cmd *cmd, + sense_reason_t reason, int from_transport) { unsigned char *buffer = cmd->sense_buffer; unsigned long flags; @@ -2877,6 +2597,16 @@ int transport_send_check_condition_and_sense( * SENSE KEY values from include/scsi/scsi.h */ switch (reason) { + case TCM_NO_SENSE: + /* CURRENT ERROR */ + buffer[0] = 0x70; + buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; + /* Not Ready */ + buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY; + /* NO ADDITIONAL SENSE INFORMATION */ + buffer[SPC_ASC_KEY_OFFSET] = 0; + buffer[SPC_ASCQ_KEY_OFFSET] = 0; + break; case TCM_NON_EXISTENT_LUN: /* CURRENT ERROR */ buffer[0] = 0x70; @@ -3023,7 +2753,7 @@ int transport_send_check_condition_and_sense( /* ILLEGAL REQUEST */ buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* LOGICAL UNIT COMMUNICATION FAILURE */ - buffer[SPC_ASC_KEY_OFFSET] = 0x80; + buffer[SPC_ASC_KEY_OFFSET] = 0x08; break; } /* @@ -3043,23 +2773,19 @@ EXPORT_SYMBOL(transport_send_check_condition_and_sense); int transport_check_aborted_status(struct se_cmd *cmd, int send_status) { - int ret = 0; + if (!(cmd->transport_state & CMD_T_ABORTED)) + return 0; - if (cmd->transport_state & CMD_T_ABORTED) { - if (!send_status || - (cmd->se_cmd_flags & SCF_SENT_DELAYED_TAS)) - return 1; + if (!send_status || (cmd->se_cmd_flags & SCF_SENT_DELAYED_TAS)) + return 1; - pr_debug("Sending delayed SAM_STAT_TASK_ABORTED" - " status for CDB: 0x%02x ITT: 0x%08x\n", - cmd->t_task_cdb[0], - cmd->se_tfo->get_task_tag(cmd)); + pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB: 0x%02x ITT: 0x%08x\n", + cmd->t_task_cdb[0], cmd->se_tfo->get_task_tag(cmd)); - cmd->se_cmd_flags |= SCF_SENT_DELAYED_TAS; - cmd->se_tfo->queue_status(cmd); - ret = 1; - } - return ret; + cmd->se_cmd_flags |= SCF_SENT_DELAYED_TAS; + cmd->se_tfo->queue_status(cmd); + + return 1; } EXPORT_SYMBOL(transport_check_aborted_status); @@ -3068,7 +2794,7 @@ void transport_send_task_abort(struct se_cmd *cmd) unsigned long flags; spin_lock_irqsave(&cmd->t_state_lock, flags); - if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) { + if (cmd->se_cmd_flags & (SCF_SENT_CHECK_CONDITION | SCF_SENT_DELAYED_TAS)) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); return; } @@ -3088,6 +2814,8 @@ void transport_send_task_abort(struct se_cmd *cmd) } cmd->scsi_status = SAM_STAT_TASK_ABORTED; + transport_lun_remove_cmd(cmd); + pr_debug("Setting SAM_STAT_TASK_ABORTED status for CDB: 0x%02x," " ITT: 0x%08x\n", cmd->t_task_cdb[0], cmd->se_tfo->get_task_tag(cmd)); diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c index 6666a0c74f60..bf0e390ce2d7 100644 --- a/drivers/target/target_core_ua.c +++ b/drivers/target/target_core_ua.c @@ -3,8 +3,7 @@ * * This file contains logic for SPC-3 Unit Attention emulation * - * Copyright (c) 2009,2010 Rising Tide Systems - * Copyright (c) 2009,2010 Linux-iSCSI.org + * (c) Copyright 2009-2012 RisingTide Systems LLC. * * Nicholas A. Bellinger <nab@kernel.org> * @@ -38,9 +37,8 @@ #include "target_core_pr.h" #include "target_core_ua.h" -int core_scsi3_ua_check( - struct se_cmd *cmd, - unsigned char *cdb) +sense_reason_t +target_scsi3_ua_check(struct se_cmd *cmd) { struct se_dev_entry *deve; struct se_session *sess = cmd->se_sess; @@ -71,16 +69,14 @@ int core_scsi3_ua_check( * was received, then the device server shall process the command * and either: */ - switch (cdb[0]) { + switch (cmd->t_task_cdb[0]) { case INQUIRY: case REPORT_LUNS: case REQUEST_SENSE: return 0; default: - return -EINVAL; + return TCM_CHECK_CONDITION_UNIT_ATTENTION; } - - return -EINVAL; } int core_scsi3_ua_allocate( @@ -237,7 +233,7 @@ void core_scsi3_ua_for_check_condition( * highest priority UNIT_ATTENTION and ASC/ASCQ without * clearing it. */ - if (dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl != 0) { + if (dev->dev_attrib.emulate_ua_intlck_ctrl != 0) { *asc = ua->ua_asc; *ascq = ua->ua_ascq; break; @@ -265,8 +261,8 @@ void core_scsi3_ua_for_check_condition( " INTLCK_CTRL: %d, mapped LUN: %u, got CDB: 0x%02x" " reported ASC: 0x%02x, ASCQ: 0x%02x\n", nacl->se_tpg->se_tpg_tfo->get_fabric_name(), - (dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl != 0) ? "Reporting" : - "Releasing", dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl, + (dev->dev_attrib.emulate_ua_intlck_ctrl != 0) ? "Reporting" : + "Releasing", dev->dev_attrib.emulate_ua_intlck_ctrl, cmd->orig_fe_lun, cmd->t_task_cdb[0], *asc, *ascq); } diff --git a/drivers/target/target_core_ua.h b/drivers/target/target_core_ua.h index 6e6b03460a1a..0204952fe4d3 100644 --- a/drivers/target/target_core_ua.h +++ b/drivers/target/target_core_ua.h @@ -26,7 +26,7 @@ extern struct kmem_cache *se_ua_cache; -extern int core_scsi3_ua_check(struct se_cmd *, unsigned char *); +extern sense_reason_t target_scsi3_ua_check(struct se_cmd *); extern int core_scsi3_ua_allocate(struct se_node_acl *, u32, u8, u8); extern void core_scsi3_ua_release_all(struct se_dev_entry *); extern void core_scsi3_ua_for_check_condition(struct se_cmd *, u8 *, u8 *); diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index 9585010964ec..6659dd36e806 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -355,11 +355,11 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len, tport = ft_tport_create(rdata->local_port); if (!tport) - return 0; /* not a target for this local port */ + goto not_target; /* not a target for this local port */ acl = ft_acl_get(tport->tpg, rdata); if (!acl) - return 0; + goto not_target; /* no target for this remote */ if (!rspp) goto fill; @@ -396,12 +396,18 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len, /* * OR in our service parameters with other provider (initiator), if any. - * TBD XXX - indicate RETRY capability? */ fill: fcp_parm = ntohl(spp->spp_params); + fcp_parm &= ~FCP_SPPF_RETRY; spp->spp_params = htonl(fcp_parm | FCP_SPPF_TARG_FCN); return FC_SPP_RESP_ACK; + +not_target: + fcp_parm = ntohl(spp->spp_params); + fcp_parm &= ~FCP_SPPF_TARG_FCN; + spp->spp_params = htonl(fcp_parm); + return 0; } /** @@ -430,7 +436,6 @@ static void ft_sess_rcu_free(struct rcu_head *rcu) { struct ft_sess *sess = container_of(rcu, struct ft_sess, rcu); - transport_deregister_session(sess->se_sess); kfree(sess); } @@ -438,6 +443,7 @@ static void ft_sess_free(struct kref *kref) { struct ft_sess *sess = container_of(kref, struct ft_sess, kref); + transport_deregister_session(sess->se_sess); call_rcu(&sess->rcu, ft_sess_rcu_free); } |