diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-17 09:00:23 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-17 09:00:23 -0700 |
commit | ed09441dacc2a2d6c170aa3b1f79a041291a813f (patch) | |
tree | 95c35bdf4f0b679806984093dce627a66d0d7cf1 /drivers/scsi | |
parent | b225ee5bed70254a100896c473e6dd8c2be45c18 (diff) | |
parent | 4c393e6e457fb41169dd110c1b96a138394c2d7b (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (39 commits)
[SCSI] sd: fix compile failure with CONFIG_BLK_DEV_INTEGRITY=n
libiscsi: fix locking in iscsi_eh_device_reset
libiscsi: check reason why we are stopping iscsi session to determine error value
[SCSI] iscsi_tcp: return a descriptive error value during connection errors
[SCSI] libiscsi: rename host reset to target reset
[SCSI] iscsi class: fix endpoint id handling
[SCSI] libiscsi: Support drivers initiating session removal
[SCSI] libiscsi: fix data corruption when target has to resend data-in packets
[SCSI] sd: Switch kernel printing level for DIF messages
[SCSI] sd: Correctly handle all combinations of DIF and DIX
[SCSI] sd: Always print actual protection_type
[SCSI] sd: Issue correct protection operation
[SCSI] scsi_error: fix target reset handling
[SCSI] lpfc 8.2.8 v2 : Add statistical reporting control and additional fc vendor events
[SCSI] lpfc 8.2.8 v2 : Add sysfs control of target queue depth handling
[SCSI] lpfc 8.2.8 v2 : Revert target busy in favor of transport disrupted
[SCSI] scsi_dh_alua: remove REQ_NOMERGE
[SCSI] lpfc 8.2.8 : update driver version to 8.2.8
[SCSI] lpfc 8.2.8 : Add MSI-X support
[SCSI] lpfc 8.2.8 : Update driver to use new Host byte error code DID_TRANSPORT_DISRUPTED
...
Diffstat (limited to 'drivers/scsi')
45 files changed, 7916 insertions, 1085 deletions
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index 9785d738419..4003deefb7d 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -1364,7 +1364,8 @@ EXPORT_SYMBOL(scsi_print_sense); static const char * const hostbyte_table[]={ "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", -"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE"}; +"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE", +"DID_TRANSPORT_DISRUPTED", "DID_TRANSPORT_FAILFAST" }; #define NUM_HOSTBYTE_STRS ARRAY_SIZE(hostbyte_table) static const char * const driverbyte_table[]={ diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 708e475896b..e356b43753f 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -109,7 +109,8 @@ static struct request *get_alua_req(struct scsi_device *sdev, } rq->cmd_type = REQ_TYPE_BLOCK_PC; - rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; + rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; rq->retries = ALUA_FAILOVER_RETRIES; rq->timeout = ALUA_FAILOVER_TIMEOUT; diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index 8f45570a8a0..0e572d2c5b0 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -303,7 +303,8 @@ static struct request *get_req(struct scsi_device *sdev, int cmd, rq->cmd[4] = len; rq->cmd_type = REQ_TYPE_BLOCK_PC; - rq->cmd_flags |= REQ_FAILFAST; + rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; rq->timeout = CLARIION_TIMEOUT; rq->retries = CLARIION_RETRIES; diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c index 5e93c88ad66..9aec4ca64e5 100644 --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c @@ -112,7 +112,8 @@ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h) return SCSI_DH_RES_TEMP_UNAVAIL; req->cmd_type = REQ_TYPE_BLOCK_PC; - req->cmd_flags |= REQ_FAILFAST; + req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY); req->cmd[0] = TEST_UNIT_READY; req->timeout = HP_SW_TIMEOUT; @@ -204,7 +205,8 @@ static int hp_sw_start_stop(struct scsi_device *sdev, struct hp_sw_dh_data *h) return SCSI_DH_RES_TEMP_UNAVAIL; req->cmd_type = REQ_TYPE_BLOCK_PC; - req->cmd_flags |= REQ_FAILFAST; + req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; req->cmd_len = COMMAND_SIZE(START_STOP); req->cmd[0] = START_STOP; req->cmd[4] = 1; /* Start spin cycle */ diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 50bf95f3b5c..a43c3ed4df2 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -226,7 +226,8 @@ static struct request *get_rdac_req(struct scsi_device *sdev, } rq->cmd_type = REQ_TYPE_BLOCK_PC; - rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; + rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; rq->retries = RDAC_RETRIES; rq->timeout = RDAC_TIMEOUT; diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 4e0b7c8eb32..7650707a40d 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -2031,8 +2031,6 @@ static void ibmvfc_terminate_rport_io(struct fc_rport *rport) spin_unlock_irqrestore(shost->host_lock, flags); } else ibmvfc_issue_fc_host_lip(shost); - - scsi_target_unblock(&rport->dev); LEAVE; } diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 2a2f0094570..ed6c54cae7b 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -523,22 +523,20 @@ iscsi_tcp_cleanup_task(struct iscsi_conn *conn, struct iscsi_task *task) } /** - * iscsi_data_rsp - SCSI Data-In Response processing + * iscsi_data_in - SCSI Data-In Response processing * @conn: iscsi connection * @task: scsi command task **/ static int -iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_task *task) +iscsi_data_in(struct iscsi_conn *conn, struct iscsi_task *task) { struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr; - struct iscsi_session *session = conn->session; - struct scsi_cmnd *sc = task->sc; int datasn = be32_to_cpu(rhdr->datasn); - unsigned total_in_length = scsi_in(sc)->length; + unsigned total_in_length = scsi_in(task->sc)->length; - iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); + iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr); if (tcp_conn->in.datalen == 0) return 0; @@ -558,23 +556,6 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_task *task) return ISCSI_ERR_DATA_OFFSET; } - if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) { - sc->result = (DID_OK << 16) | rhdr->cmd_status; - conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; - if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW | - ISCSI_FLAG_DATA_OVERFLOW)) { - int res_count = be32_to_cpu(rhdr->residual_count); - - if (res_count > 0 && - (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || - res_count <= total_in_length)) - scsi_in(sc)->resid = res_count; - else - sc->result = (DID_BAD_TARGET << 16) | - rhdr->cmd_status; - } - } - conn->datain_pdus_cnt++; return 0; } @@ -774,7 +755,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) if (!task) rc = ISCSI_ERR_BAD_ITT; else - rc = iscsi_data_rsp(conn, task); + rc = iscsi_data_in(conn, task); if (rc) { spin_unlock(&conn->session->lock); break; @@ -998,7 +979,7 @@ iscsi_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, error: debug_tcp("Error receiving PDU, errno=%d\n", rc); - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + iscsi_conn_failure(conn, rc); return 0; } @@ -1117,8 +1098,10 @@ iscsi_xmit(struct iscsi_conn *conn) while (1) { rc = iscsi_tcp_xmit_segment(tcp_conn, segment); - if (rc < 0) + if (rc < 0) { + rc = ISCSI_ERR_XMIT_FAILED; goto error; + } if (rc == 0) break; @@ -1127,7 +1110,7 @@ iscsi_xmit(struct iscsi_conn *conn) if (segment->total_copied >= segment->total_size) { if (segment->done != NULL) { rc = segment->done(tcp_conn, segment); - if (rc < 0) + if (rc != 0) goto error; } } @@ -1142,8 +1125,8 @@ error: /* Transmit error. We could initiate error recovery * here. */ debug_tcp("Error sending PDU, errno=%d\n", rc); - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - return rc; + iscsi_conn_failure(conn, rc); + return -EIO; } /** @@ -1904,6 +1887,7 @@ static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session) struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); iscsi_r2tpool_free(cls_session->dd_data); + iscsi_session_teardown(cls_session); iscsi_host_remove(shost); iscsi_host_free(shost); @@ -1927,7 +1911,7 @@ static struct scsi_host_template iscsi_sht = { .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, .eh_abort_handler = iscsi_eh_abort, .eh_device_reset_handler= iscsi_eh_device_reset, - .eh_host_reset_handler = iscsi_eh_host_reset, + .eh_target_reset_handler= iscsi_eh_target_reset, .use_clustering = DISABLE_CLUSTERING, .slave_configure = iscsi_tcp_slave_configure, .proc_name = "iscsi_tcp", diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index da7b67d30d9..801c7cf54d2 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -404,11 +404,6 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task, conn->session->queued_cmdsn--; else conn->session->tt->cleanup_task(conn, task); - /* - * Check if cleanup_task dropped the lock and the command completed, - */ - if (!task->sc) - return; sc->result = err; if (!scsi_bidi_cmnd(sc)) @@ -633,6 +628,40 @@ out: __iscsi_put_task(task); } +/** + * iscsi_data_in_rsp - SCSI Data-In Response processing + * @conn: iscsi connection + * @hdr: iscsi pdu + * @task: scsi command task + **/ +static void +iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, + struct iscsi_task *task) +{ + struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)hdr; + struct scsi_cmnd *sc = task->sc; + + if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS)) + return; + + sc->result = (DID_OK << 16) | rhdr->cmd_status; + conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; + if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW | + ISCSI_FLAG_DATA_OVERFLOW)) { + int res_count = be32_to_cpu(rhdr->residual_count); + + if (res_count > 0 && + (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || + res_count <= scsi_in(sc)->length)) + scsi_in(sc)->resid = res_count; + else + sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; + } + + conn->scsirsp_pdus_cnt++; + __iscsi_put_task(task); +} + static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) { struct iscsi_tm_rsp *tmf = (struct iscsi_tm_rsp *)hdr; @@ -818,12 +847,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, iscsi_scsi_cmd_rsp(conn, hdr, task, data, datalen); break; case ISCSI_OP_SCSI_DATA_IN: - if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { - conn->scsirsp_pdus_cnt++; - iscsi_update_cmdsn(session, - (struct iscsi_nopin*) hdr); - __iscsi_put_task(task); - } + iscsi_data_in_rsp(conn, hdr, task); break; case ISCSI_OP_LOGOUT_RSP: iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); @@ -954,6 +978,38 @@ struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt) } EXPORT_SYMBOL_GPL(iscsi_itt_to_ctask); +void iscsi_session_failure(struct iscsi_cls_session *cls_session, + enum iscsi_err err) +{ + struct iscsi_session *session = cls_session->dd_data; + struct iscsi_conn *conn; + struct device *dev; + unsigned long flags; + + spin_lock_irqsave(&session->lock, flags); + conn = session->leadconn; + if (session->state == ISCSI_STATE_TERMINATE || !conn) { + spin_unlock_irqrestore(&session->lock, flags); + return; + } + + dev = get_device(&conn->cls_conn->dev); + spin_unlock_irqrestore(&session->lock, flags); + if (!dev) + return; + /* + * if the host is being removed bypass the connection + * recovery initialization because we are going to kill + * the session. + */ + if (err == ISCSI_ERR_INVALID_HOST) + iscsi_conn_error_event(conn->cls_conn, err); + else + iscsi_conn_failure(conn, err); + put_device(dev); +} +EXPORT_SYMBOL_GPL(iscsi_session_failure); + void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) { struct iscsi_session *session = conn->session; @@ -968,9 +1024,10 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) if (conn->stop_stage == 0) session->state = ISCSI_STATE_FAILED; spin_unlock_irqrestore(&session->lock, flags); + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); - iscsi_conn_error(conn->cls_conn, err); + iscsi_conn_error_event(conn->cls_conn, err); } EXPORT_SYMBOL_GPL(iscsi_conn_failure); @@ -1194,15 +1251,13 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) switch (session->state) { case ISCSI_STATE_IN_RECOVERY: reason = FAILURE_SESSION_IN_RECOVERY; - sc->result = DID_IMM_RETRY << 16; - break; + goto reject; case ISCSI_STATE_LOGGING_OUT: reason = FAILURE_SESSION_LOGGING_OUT; - sc->result = DID_IMM_RETRY << 16; - break; + goto reject; case ISCSI_STATE_RECOVERY_FAILED: reason = FAILURE_SESSION_RECOVERY_TIMEOUT; - sc->result = DID_NO_CONNECT << 16; + sc->result = DID_TRANSPORT_FAILFAST << 16; break; case ISCSI_STATE_TERMINATE: reason = FAILURE_SESSION_TERMINATE; @@ -1267,7 +1322,7 @@ reject: spin_unlock(&session->lock); debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason); spin_lock(host->host_lock); - return SCSI_MLQUEUE_HOST_BUSY; + return SCSI_MLQUEUE_TARGET_BUSY; fault: spin_unlock(&session->lock); @@ -1307,7 +1362,7 @@ void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) } EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout); -int iscsi_eh_host_reset(struct scsi_cmnd *sc) +int iscsi_eh_target_reset(struct scsi_cmnd *sc) { struct iscsi_cls_session *cls_session; struct iscsi_session *session; @@ -1321,7 +1376,7 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc) spin_lock_bh(&session->lock); if (session->state == ISCSI_STATE_TERMINATE) { failed: - debug_scsi("failing host reset: session terminated " + debug_scsi("failing target reset: session terminated " "[CID %d age %d]\n", conn->id, session->age); spin_unlock_bh(&session->lock); mutex_unlock(&session->eh_mutex); @@ -1336,7 +1391,7 @@ failed: */ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - debug_scsi("iscsi_eh_host_reset wait for relogin\n"); + debug_scsi("iscsi_eh_target_reset wait for relogin\n"); wait_event_interruptible(conn->ehwait, session->state == ISCSI_STATE_TERMINATE || session->state == ISCSI_STATE_LOGGED_IN || @@ -1348,14 +1403,14 @@ failed: spin_lock_bh(&session->lock); if (session->state == ISCSI_STATE_LOGGED_IN) iscsi_session_printk(KERN_INFO, session, - "host reset succeeded\n"); + "target reset succeeded\n"); else goto failed; spin_unlock_bh(&session->lock); mutex_unlock(&session->eh_mutex); return SUCCESS; } -EXPORT_SYMBOL_GPL(iscsi_eh_host_reset); +EXPORT_SYMBOL_GPL(iscsi_eh_target_reset); static void iscsi_tmf_timedout(unsigned long data) { @@ -1769,10 +1824,10 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc) iscsi_suspend_tx(conn); - spin_lock(&session->lock); + spin_lock_bh(&session->lock); fail_all_commands(conn, sc->device->lun, DID_ERROR); conn->tmf_state = TMF_INITIAL; - spin_unlock(&session->lock); + spin_unlock_bh(&session->lock); iscsi_start_tx(conn); goto done; @@ -1878,6 +1933,7 @@ struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht, int dd_data_size, uint16_t qdepth) { struct Scsi_Host *shost; + struct iscsi_host *ihost; shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size); if (!shost) @@ -1892,22 +1948,43 @@ struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht, qdepth = ISCSI_DEF_CMD_PER_LUN; } shost->cmd_per_lun = qdepth; + + ihost = shost_priv(shost); + spin_lock_init(&ihost->lock); + ihost->state = ISCSI_HOST_SETUP; + ihost->num_sessions = 0; + init_waitqueue_head(&ihost->session_removal_wq); return shost; } EXPORT_SYMBOL_GPL(iscsi_host_alloc); +static void iscsi_notify_host_removed(struct iscsi_cls_session *cls_session) +{ + iscsi_session_failure(cls_session, ISCSI_ERR_INVALID_HOST); +} + /** * iscsi_host_remove - remove host and sessions * @shost: scsi host * - * This will also remove any sessions attached to the host, but if userspace - * is managing the session at the same time this will break. TODO: add - * refcounting to the netlink iscsi interface so a rmmod or host hot unplug - * does not remove the memory from under us. + * If there are any sessions left, this will initiate the removal and wait + * for the completion. */ void iscsi_host_remove(struct Scsi_Host *shost) { - iscsi_host_for_each_session(shost, iscsi_session_teardown); + struct iscsi_host *ihost = shost_priv(shost); + unsigned long flags; + + spin_lock_irqsave(&ihost->lock, flags); + ihost->state = ISCSI_HOST_REMOVED; + spin_unlock_irqrestore(&ihost->lock, flags); + + iscsi_host_for_each_session(shost, iscsi_notify_host_removed); + wait_event_interruptible(ihost->session_removal_wq, + ihost->num_sessions == 0); + if (signal_pending(current)) + flush_signals(current); + scsi_remove_host(shost); } EXPORT_SYMBOL_GPL(iscsi_host_remove); @@ -1923,6 +2000,27 @@ void iscsi_host_free(struct Scsi_Host *shost) } EXPORT_SYMBOL_GPL(iscsi_host_free); +static void iscsi_host_dec_session_cnt(struct Scsi_Host *shost) +{ + struct iscsi_host *ihost = shost_priv(shost); + unsigned long flags; + + shost = scsi_host_get(shost); + if (!shost) { + printk(KERN_ERR "Invalid state. Cannot notify host removal " + "of session teardown event because host already " + "removed.\n"); + return; + } + + spin_lock_irqsave(&ihost->lock, flags); + ihost->num_sessions--; + if (ihost->num_sessions == 0) + wake_up(&ihost->session_removal_wq); + spin_unlock_irqrestore(&ihost->lock, flags); + scsi_host_put(shost); +} + /** * iscsi_session_setup - create iscsi cls session and host and session * @iscsit: iscsi transport template @@ -1943,9 +2041,19 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost, uint16_t cmds_max, int cmd_task_size, uint32_t initial_cmdsn, unsigned int id) { + struct iscsi_host *ihost = shost_priv(shost); struct iscsi_session *session; struct iscsi_cls_session *cls_session; int cmd_i, scsi_cmds, total_cmds = cmds_max; + unsigned long flags; + + spin_lock_irqsave(&ihost->lock, flags); + if (ihost->state == ISCSI_HOST_REMOVED) { + spin_unlock_irqrestore(&ihost->lock, flags); + return NULL; + } + ihost->num_sessions++; + spin_unlock_irqrestore(&ihost->lock, flags); if (!total_cmds) total_cmds = ISCSI_DEF_XMIT_CMDS_MAX; @@ -1958,7 +2066,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost, printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue " "must be a power of two that is at least %d.\n", total_cmds, ISCSI_TOTAL_CMDS_MIN); - return NULL; + goto dec_session_count; } if (total_cmds > ISCSI_TOTAL_CMDS_MAX) { @@ -1982,7 +2090,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost, cls_session = iscsi_alloc_session(shost, iscsit, sizeof(struct iscsi_session)); if (!cls_session) - return NULL; + goto dec_session_count; session = cls_session->dd_data; session->cls_session = cls_session; session->host = shost; @@ -2021,6 +2129,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost, if (iscsi_add_session(cls_session, id)) goto cls_session_fail; + return cls_session; cls_session_fail: @@ -2029,6 +2138,8 @@ module_get_fail: iscsi_pool_free(&session->cmdpool); cmdpool_alloc_fail: iscsi_free_session(cls_session); +dec_session_count: + iscsi_host_dec_session_cnt(shost); return NULL; } EXPORT_SYMBOL_GPL(iscsi_session_setup); @@ -2044,6 +2155,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) { struct iscsi_session *session = cls_session->dd_data; struct module *owner = cls_session->transport->owner; + struct Scsi_Host *shost = session->host; iscsi_pool_free(&session->cmdpool); @@ -2056,6 +2168,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) kfree(session->ifacename); iscsi_destroy_session(cls_session); + iscsi_host_dec_session_cnt(shost); module_put(owner); } EXPORT_SYMBOL_GPL(iscsi_session_teardown); @@ -2335,8 +2448,10 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, * flush queues. */ spin_lock_bh(&session->lock); - fail_all_commands(conn, -1, - STOP_CONN_RECOVER ? DID_BUS_BUSY : DID_ERROR); + if (flag == STOP_CONN_RECOVER) + fail_all_commands(conn, -1, DID_TRANSPORT_DISRUPTED); + else + fail_all_commands(conn, -1, DID_ERROR); flush_control_queues(session, conn); spin_unlock_bh(&session->lock); mutex_unlock(&session->eh_mutex); diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index e0e018d1265..60a9e6e9384 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -34,7 +34,14 @@ struct lpfc_sli2_slim; #define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */ #define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */ #define LPFC_VNAME_LEN 100 /* vport symbolic name length */ - +#define LPFC_TGTQ_INTERVAL 40000 /* Min amount of time between tgt + queue depth change in millisecs */ +#define LPFC_TGTQ_RAMPUP_PCENT 5 /* Target queue rampup in percentage */ +#define LPFC_MIN_TGT_QDEPTH 100 +#define LPFC_MAX_TGT_QDEPTH 0xFFFF + +#define LPFC_MAX_BUCKET_COUNT 20 /* Maximum no. of buckets for stat data + collection. */ /* * Following time intervals are used of adjusting SCSI device * queue depths when there are driver resource error or Firmware @@ -49,6 +56,9 @@ struct lpfc_sli2_slim; #define LPFC_HB_MBOX_INTERVAL 5 /* Heart beat interval in seconds. */ #define LPFC_HB_MBOX_TIMEOUT 30 /* Heart beat timeout in seconds. */ +/* Error Attention event polling interval */ +#define LPFC_ERATT_POLL_INTERVAL 5 /* EATT poll interval in seconds */ + /* Define macros for 64 bit support */ #define putPaddrLow(addr) ((uint32_t) (0xffffffff & (u64)(addr))) #define putPaddrHigh(addr) ((uint32_t) (0xffffffff & (((u64)(addr))>>32))) @@ -60,6 +70,9 @@ struct lpfc_sli2_slim; #define MAX_HBAEVT 32 +/* Number of MSI-X vectors the driver uses */ +#define LPFC_MSIX_VECTORS 2 + /* lpfc wait event data ready flag */ #define LPFC_DATA_READY (1<<0) @@ -357,6 +370,7 @@ struct lpfc_vport { uint32_t cfg_log_verbose; uint32_t cfg_max_luns; uint32_t cfg_enable_da_id; + uint32_t cfg_max_scsicmpl_time; uint32_t dev_loss_tmo_changed; @@ -369,6 +383,8 @@ struct lpfc_vpor |