Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 4 Aug 2009 22:38:10 +0000 (15:38 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 4 Aug 2009 22:38:10 +0000 (15:38 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6: (23 commits)
  [SCSI] sd: Avoid sending extended inquiry to legacy devices
  [SCSI] libsas: fix wide port hotplug issues
  [SCSI] libfc: fix a circular locking warning during sending RRQ
  [SCSI] qla4xxx: Remove hiwat code so scsi eh does not get escalated when we can make progress
  [SCSI] qla4xxx: Fix srb lookup in qla4xxx_eh_device_reset
  [SCSI] qla4xxx: Fix Driver Fault Recovery Completion
  [SCSI] qla4xxx: add timeout handler
  [SCSI] qla4xxx: Correct Extended Sense Data Errors
  [SCSI] libiscsi: disable bh in and abort handler.
  [SCSI] zfcp: Fix tracing of request id for abort requests
  [SCSI] zfcp: Fix wka port processing
  [SCSI] zfcp: avoid double notify in lowmem scenario
  [SCSI] zfcp: Add port only once to FC transport class
  [SCSI] zfcp: Recover from stalled outbound queue
  [SCSI] zfcp: Fix erp escalation procedure
  [SCSI] zfcp: Fix logic for physical port close
  [SCSI] zfcp: Use -EIO for SBAL allocation failures
  [SCSI] zfcp: Use unchained mode for small ct and els requests
  [SCSI] zfcp: Use correct flags for zfcp_erp_notify
  [SCSI] zfcp: Return -ENOMEM for allocation failures in zfcp_fsf
  ...

18 files changed:
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_fc.c
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_scsi.c
drivers/s390/scsi/zfcp_sysfs.c
drivers/scsi/libfc/fc_exch.c
drivers/scsi/libiscsi.c
drivers/scsi/libsas/sas_expander.c
drivers/scsi/libsas/sas_port.c
drivers/scsi/qla4xxx/ql4_dbg.c
drivers/scsi/qla4xxx/ql4_def.h
drivers/scsi/qla4xxx/ql4_fw.h
drivers/scsi/qla4xxx/ql4_iocb.c
drivers/scsi/qla4xxx/ql4_isr.c
drivers/scsi/qla4xxx/ql4_mbx.c
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/qla4xxx/ql4_version.h
drivers/scsi/sd.c

index 8030e25152fb90e1f4f389c0494f31b82b1d9592..c75d6f35cb5f64d05e88ac8b423d7cb03e2977e6 100644 (file)
@@ -553,40 +553,35 @@ static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,
                _zfcp_erp_unit_reopen(unit, clear, id, ref);
 }
 
-static void zfcp_erp_strategy_followup_actions(struct zfcp_erp_action *act)
+static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
 {
-       struct zfcp_adapter *adapter = act->adapter;
-       struct zfcp_port *port = act->port;
-       struct zfcp_unit *unit = act->unit;
-       u32 status = act->status;
-
-       /* initiate follow-up actions depending on success of finished action */
        switch (act->action) {
-
        case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
-               if (status == ZFCP_ERP_SUCCEEDED)
-                       _zfcp_erp_port_reopen_all(adapter, 0, "ersfa_1", NULL);
-               else
-                       _zfcp_erp_adapter_reopen(adapter, 0, "ersfa_2", NULL);
+               _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL);
                break;
-
        case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
-               if (status == ZFCP_ERP_SUCCEEDED)
-                       _zfcp_erp_port_reopen(port, 0, "ersfa_3", NULL);
-               else
-                       _zfcp_erp_adapter_reopen(adapter, 0, "ersfa_4", NULL);
+               _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL);
                break;
-
        case ZFCP_ERP_ACTION_REOPEN_PORT:
-               if (status == ZFCP_ERP_SUCCEEDED)
-                       _zfcp_erp_unit_reopen_all(port, 0, "ersfa_5", NULL);
-               else
-                       _zfcp_erp_port_forced_reopen(port, 0, "ersfa_6", NULL);
+               _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL);
                break;
-
        case ZFCP_ERP_ACTION_REOPEN_UNIT:
-               if (status != ZFCP_ERP_SUCCEEDED)
-                       _zfcp_erp_port_reopen(unit->port, 0, "ersfa_7", NULL);
+               _zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL);
+               break;
+       }
+}
+
+static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act)
+{
+       switch (act->action) {
+       case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
+               _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL);
+               break;
+       case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
+               _zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL);
+               break;
+       case ZFCP_ERP_ACTION_REOPEN_PORT:
+               _zfcp_erp_unit_reopen_all(act->port, 0, "ersfs_3", NULL);
                break;
        }
 }
@@ -801,7 +796,7 @@ static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
                        return ZFCP_ERP_FAILED;
 
        case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
-               if (status & ZFCP_STATUS_PORT_PHYS_OPEN)
+               if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN))
                        return ZFCP_ERP_SUCCEEDED;
        }
        return ZFCP_ERP_FAILED;
@@ -853,11 +848,17 @@ void zfcp_erp_port_strategy_open_lookup(struct work_struct *work)
                                              gid_pn_work);
 
        retval = zfcp_fc_ns_gid_pn(&port->erp_action);
-       if (retval == -ENOMEM)
-               zfcp_erp_notify(&port->erp_action, ZFCP_ERP_NOMEM);
-       port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP;
-       if (retval)
-               zfcp_erp_notify(&port->erp_action, ZFCP_ERP_FAILED);
+       if (!retval) {
+               port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP;
+               goto out;
+       }
+       if (retval == -ENOMEM) {
+               zfcp_erp_notify(&port->erp_action, ZFCP_STATUS_ERP_LOWMEM);
+               goto out;
+       }
+       /* all other error condtions */
+       zfcp_erp_notify(&port->erp_action, 0);
+out:
        zfcp_port_put(port);
 }
 
@@ -1289,7 +1290,10 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
        retval = zfcp_erp_strategy_statechange(erp_action, retval);
        if (retval == ZFCP_ERP_EXIT)
                goto unlock;
-       zfcp_erp_strategy_followup_actions(erp_action);
+       if (retval == ZFCP_ERP_SUCCEEDED)
+               zfcp_erp_strategy_followup_success(erp_action);
+       if (retval == ZFCP_ERP_FAILED)
+               zfcp_erp_strategy_followup_failed(erp_action);
 
  unlock:
        write_unlock(&adapter->erp_lock);
index 2f0705d76b7202095066be064232205b0373fb4e..47daebfa7e59af2f7b17e91184182199ed7bb26f 100644 (file)
@@ -79,11 +79,9 @@ static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port)
 
        mutex_unlock(&wka_port->mutex);
 
-       wait_event_timeout(
-               wka_port->completion_wq,
-               wka_port->status == ZFCP_WKA_PORT_ONLINE ||
-               wka_port->status == ZFCP_WKA_PORT_OFFLINE,
-               HZ >> 1);
+       wait_event(wka_port->completion_wq,
+                  wka_port->status == ZFCP_WKA_PORT_ONLINE ||
+                  wka_port->status == ZFCP_WKA_PORT_OFFLINE);
 
        if (wka_port->status == ZFCP_WKA_PORT_ONLINE) {
                atomic_inc(&wka_port->refcount);
index c57658f3d34f60a9f8c49bb57ccb7c157b9ddb8b..47795fbf081fdc823ec92dc35e00aaee84aec218 100644 (file)
@@ -670,8 +670,11 @@ static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter)
                               zfcp_fsf_sbal_check(adapter), 5 * HZ);
        if (ret > 0)
                return 0;
-       if (!ret)
+       if (!ret) {
                atomic_inc(&adapter->qdio_outb_full);
+               /* assume hanging outbound queue, try queue recovery */
+               zfcp_erp_adapter_reopen(adapter, 0, "fsrsg_1", NULL);
+       }
 
        spin_lock_bh(&adapter->req_q_lock);
        return -EIO;
@@ -722,7 +725,7 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter,
                req = zfcp_fsf_alloc_qtcb(pool);
 
        if (unlikely(!req))
-               return ERR_PTR(-EIO);
+               return ERR_PTR(-ENOMEM);
 
        if (adapter->req_no == 0)
                adapter->req_no++;
@@ -1010,6 +1013,23 @@ skip_fsfstatus:
                send_ct->handler(send_ct->handler_data);
 }
 
+static void zfcp_fsf_setup_ct_els_unchained(struct qdio_buffer_element *sbale,
+                                           struct scatterlist *sg_req,
+                                           struct scatterlist *sg_resp)
+{
+       sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
+       sbale[2].addr   = sg_virt(sg_req);
+       sbale[2].length = sg_req->length;
+       sbale[3].addr   = sg_virt(sg_resp);
+       sbale[3].length = sg_resp->length;
+       sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
+}
+
+static int zfcp_fsf_one_sbal(struct scatterlist *sg)
+{
+       return sg_is_last(sg) && sg->length <= PAGE_SIZE;
+}
+
 static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
                                       struct scatterlist *sg_req,
                                       struct scatterlist *sg_resp,
@@ -1020,30 +1040,30 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
        int bytes;
 
        if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) {
-               if (sg_req->length > PAGE_SIZE || sg_resp->length > PAGE_SIZE ||
-                   !sg_is_last(sg_req) || !sg_is_last(sg_resp))
+               if (!zfcp_fsf_one_sbal(sg_req) || !zfcp_fsf_one_sbal(sg_resp))
                        return -EOPNOTSUPP;
 
-               sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
-               sbale[2].addr   = sg_virt(sg_req);
-               sbale[2].length = sg_req->length;
-               sbale[3].addr   = sg_virt(sg_resp);
-               sbale[3].length = sg_resp->length;
-               sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
+               zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp);
+               return 0;
+       }
+
+       /* use single, unchained SBAL if it can hold the request */
+       if (zfcp_fsf_one_sbal(sg_req) && zfcp_fsf_one_sbal(sg_resp)) {
+               zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp);
                return 0;
        }
 
        bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,
                                        sg_req, max_sbals);
        if (bytes <= 0)
-               return -ENOMEM;
+               return -EIO;
        req->qtcb->bottom.support.req_buf_length = bytes;
        req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
 
        bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,
                                        sg_resp, max_sbals);
        if (bytes <= 0)
-               return -ENOMEM;
+               return -EIO;
        req->qtcb->bottom.support.resp_buf_length = bytes;
 
        return 0;
@@ -1607,10 +1627,10 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)
        case FSF_ACCESS_DENIED:
                wka_port->status = ZFCP_WKA_PORT_OFFLINE;
                break;
-       case FSF_PORT_ALREADY_OPEN:
-               break;
        case FSF_GOOD:
                wka_port->handle = header->port_handle;
+               /* fall through */
+       case FSF_PORT_ALREADY_OPEN:
                wka_port->status = ZFCP_WKA_PORT_ONLINE;
        }
 out:
@@ -1731,15 +1751,16 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
                zfcp_fsf_access_denied_port(req, port);
                break;
        case FSF_PORT_BOXED:
-               zfcp_erp_port_boxed(port, "fscpph2", req);
-               req->status |= ZFCP_STATUS_FSFREQ_ERROR |
-                              ZFCP_STATUS_FSFREQ_RETRY;
                /* can't use generic zfcp_erp_modify_port_status because
                 * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */
                atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
                list_for_each_entry(unit, &port->unit_list_head, list)
                        atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN,
                                          &unit->status);
+               zfcp_erp_port_boxed(port, "fscpph2", req);
+               req->status |= ZFCP_STATUS_FSFREQ_ERROR |
+                              ZFCP_STATUS_FSFREQ_RETRY;
+
                break;
        case FSF_ADAPTER_STATUS_AVAILABLE:
                switch (header->fsf_status_qual.word[0]) {
@@ -2541,7 +2562,6 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
        bytes = zfcp_qdio_sbals_from_sg(req, direction, fsf_cfdc->sg,
                                        FSF_MAX_SBALS_PER_REQ);
        if (bytes != ZFCP_CFDC_MAX_SIZE) {
-               retval = -ENOMEM;
                zfcp_fsf_req_free(req);
                goto out;
        }
index 967ede73f4c57c3ffcbbc12455dd851c7638d744..6925a17846825109225e7530705505b5151cc477 100644 (file)
@@ -167,20 +167,21 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
        struct zfcp_unit *unit = scpnt->device->hostdata;
        struct zfcp_fsf_req *old_req, *abrt_req;
        unsigned long flags;
-       unsigned long old_req_id = (unsigned long) scpnt->host_scribble;
+       unsigned long old_reqid = (unsigned long) scpnt->host_scribble;
        int retval = SUCCESS;
        int retry = 3;
+       char *dbf_tag;
 
        /* avoid race condition between late normal completion and abort */
        write_lock_irqsave(&adapter->abort_lock, flags);
 
        spin_lock(&adapter->req_list_lock);
-       old_req = zfcp_reqlist_find(adapter, old_req_id);
+       old_req = zfcp_reqlist_find(adapter, old_reqid);
        spin_unlock(&adapter->req_list_lock);
        if (!old_req) {
                write_unlock_irqrestore(&adapter->abort_lock, flags);
                zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL,
-                                         old_req_id);
+                                         old_reqid);
                return FAILED; /* completion could be in progress */
        }
        old_req->data = NULL;
@@ -189,7 +190,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
        write_unlock_irqrestore(&adapter->abort_lock, flags);
 
        while (retry--) {
-               abrt_req = zfcp_fsf_abort_fcp_command(old_req_id, unit);
+               abrt_req = zfcp_fsf_abort_fcp_command(old_reqid, unit);
                if (abrt_req)
                        break;
 
@@ -197,7 +198,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
                if (!(atomic_read(&adapter->status) &
                      ZFCP_STATUS_COMMON_RUNNING)) {
                        zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL,
-                                                 old_req_id);
+                                                 old_reqid);
                        return SUCCESS;
                }
        }
@@ -208,13 +209,14 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
                   abrt_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
 
        if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED)
-               zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, abrt_req, 0);
+               dbf_tag = "okay";
        else if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED)
-               zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, abrt_req, 0);
+               dbf_tag = "lte2";
        else {
-               zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, abrt_req, 0);
+               dbf_tag = "fail";
                retval = FAILED;
        }
+       zfcp_scsi_dbf_event_abort(dbf_tag, adapter, scpnt, abrt_req, old_reqid);
        zfcp_fsf_req_free(abrt_req);
        return retval;
 }
@@ -534,6 +536,9 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port)
        struct fc_rport_identifiers ids;
        struct fc_rport *rport;
 
+       if (port->rport)
+               return;
+
        ids.node_name = port->wwnn;
        ids.port_name = port->wwpn;
        ids.port_id = port->d_id;
@@ -557,8 +562,10 @@ static void zfcp_scsi_rport_block(struct zfcp_port *port)
 {
        struct fc_rport *rport = port->rport;
 
-       if (rport)
+       if (rport) {
                fc_remote_port_delete(rport);
+               port->rport = NULL;
+       }
 }
 
 void zfcp_scsi_schedule_rport_register(struct zfcp_port *port)
index 3e51e64d11081393fe62c849cc7af3ffe7fd6394..0fe5cce818cb48ce69968734f2a90c64267ab5f6 100644 (file)
@@ -494,9 +494,14 @@ static ssize_t zfcp_sysfs_adapter_q_full_show(struct device *dev,
        struct Scsi_Host *scsi_host = class_to_shost(dev);
        struct zfcp_adapter *adapter =
                (struct zfcp_adapter *) scsi_host->hostdata[0];
+       u64 util;
+
+       spin_lock_bh(&adapter->qdio_stat_lock);
+       util = adapter->req_q_util;
+       spin_unlock_bh(&adapter->qdio_stat_lock);
 
        return sprintf(buf, "%d %llu\n", atomic_read(&adapter->qdio_outb_full),
-                      (unsigned long long)adapter->req_q_util);
+                      (unsigned long long)util);
 }
 static DEVICE_ATTR(queue_full, S_IRUGO, zfcp_sysfs_adapter_q_full_show, NULL);
 
index 2bc22be5f84944277edc2d7c8b3248a74a4d76e9..145ab9ba55ea0804a3b6c061f9f090c0670b1d6a 100644 (file)
@@ -415,9 +415,9 @@ static void fc_exch_timeout(struct work_struct *work)
        e_stat = ep->esb_stat;
        if (e_stat & ESB_ST_COMPLETE) {
                ep->esb_stat = e_stat & ~ESB_ST_REC_QUAL;
+               spin_unlock_bh(&ep->ex_lock);
                if (e_stat & ESB_ST_REC_QUAL)
                        fc_exch_rrq(ep);
-               spin_unlock_bh(&ep->ex_lock);
                goto done;
        } else {
                resp = ep->resp;
@@ -1624,14 +1624,14 @@ static void fc_exch_rrq(struct fc_exch *ep)
        struct fc_lport *lp;
        struct fc_els_rrq *rrq;
        struct fc_frame *fp;
-       struct fc_seq *rrq_sp;
        u32 did;
 
        lp = ep->lp;
 
        fp = fc_frame_alloc(lp, sizeof(*rrq));
        if (!fp)
-               return;
+               goto retry;
+
        rrq = fc_frame_payload_get(fp, sizeof(*rrq));
        memset(rrq, 0, sizeof(*rrq));
        rrq->rrq_cmd = ELS_RRQ;
@@ -1647,13 +1647,20 @@ static void fc_exch_rrq(struct fc_exch *ep)
                       fc_host_port_id(lp->host), FC_TYPE_ELS,
                       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
 
-       rrq_sp = fc_exch_seq_send(lp, fp, fc_exch_rrq_resp, NULL, ep,
-                                 lp->e_d_tov);
-       if (!rrq_sp) {
-               ep->esb_stat |= ESB_ST_REC_QUAL;
-               fc_exch_timer_set_locked(ep, ep->r_a_tov);
+       if (fc_exch_seq_send(lp, fp, fc_exch_rrq_resp, NULL, ep, lp->e_d_tov))
+               return;
+
+retry:
+       spin_lock_bh(&ep->ex_lock);
+       if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) {
+               spin_unlock_bh(&ep->ex_lock);
+               /* drop hold for rec qual */
+               fc_exch_release(ep);
                return;
        }
+       ep->esb_stat |= ESB_ST_REC_QUAL;
+       fc_exch_timer_set_locked(ep, ep->r_a_tov);
+       spin_unlock_bh(&ep->ex_lock);
 }
 
 
index 716cc344c5dfb5253eb5436cd0e19e5fbaa82b66..a751f6230c2258f4e7870391b96330d08e209e5a 100644 (file)
@@ -1974,10 +1974,10 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
                 * good and have never sent us a successful tmf response
                 * then sent more data for the cmd.
                 */
-               spin_lock(&session->lock);
+               spin_lock_bh(&session->lock);
                fail_scsi_task(task, DID_ABORT);
                conn->tmf_state = TMF_INITIAL;
-               spin_unlock(&session->lock);
+               spin_unlock_bh(&session->lock);
                iscsi_start_tx(conn);
                goto success_unlocked;
        case TMF_TIMEDOUT:
index 54fa1e42dc4d2dfba29cdf52afd52d909af67139..b3381959acce19ee167c183ccd7b2b9354203c1b 100644 (file)
@@ -766,6 +766,7 @@ static int sas_ex_join_wide_port(struct domain_device *parent, int phy_id)
                if (!memcmp(phy->attached_sas_addr, ephy->attached_sas_addr,
                            SAS_ADDR_SIZE) && ephy->port) {
                        sas_port_add_phy(ephy->port, phy->phy);
+                       phy->port = ephy->port;
                        phy->phy_state = PHY_DEVICE_DISCOVERED;
                        return 0;
                }
@@ -945,11 +946,21 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
                        if (ex->ex_phy[i].phy_state == PHY_VACANT ||
                            ex->ex_phy[i].phy_state == PHY_NOT_PRESENT)
                                continue;
-
+                       /*
+                        * Due to races, the phy might not get added to the
+                        * wide port, so we add the phy to the wide port here.
+                        */
                        if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) ==
-                           SAS_ADDR(child->sas_addr))
+                           SAS_ADDR(child->sas_addr)) {
                                ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED;
+                               res = sas_ex_join_wide_port(dev, i);
+                               if (!res)
+                                       SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n",
+                                                   i, SAS_ADDR(ex->ex_phy[i].attached_sas_addr));
+
+                       }
                }
+               res = 0;
        }
 
        return res;
@@ -1598,7 +1609,7 @@ static int sas_get_phy_attached_sas_addr(struct domain_device *dev,
 }
 
 static int sas_find_bcast_phy(struct domain_device *dev, int *phy_id,
-                             int from_phy)
+                             int from_phy, bool update)
 {
        struct expander_device *ex = &dev->ex_dev;
        int res = 0;
@@ -1611,7 +1622,9 @@ static int sas_find_bcast_phy(struct domain_device *dev, int *phy_id,
                if (res)
                        goto out;
                else if (phy_change_count != ex->ex_phy[i].phy_change_count) {
-                       ex->ex_phy[i].phy_change_count = phy_change_count;
+                       if (update)
+                               ex->ex_phy[i].phy_change_count =
+                                       phy_change_count;
                        *phy_id = i;
                        return 0;
                }
@@ -1653,31 +1666,52 @@ out:
        kfree(rg_req);
        return res;
 }
+/**
+ * sas_find_bcast_dev -  find the device issue BROADCAST(CHANGE).
+ * @dev:domain device to be detect.
+ * @src_dev: the device which originated BROADCAST(CHANGE).
+ *
+ * Add self-configuration expander suport. Suppose two expander cascading,
+ * when the first level expander is self-configuring, hotplug the disks in
+ * second level expander, BROADCAST(CHANGE) will not only be originated
+ * in the second level expander, but also be originated in the first level
+ * expander (see SAS protocol SAS 2r-14, 7.11 for detail), it is to say,
+ * expander changed count in two level expanders will all increment at least
+ * once, but the phy which chang count has changed is the source device which
+ * we concerned.
+ */
 
 static int sas_find_bcast_dev(struct domain_device *dev,
                              struct domain_device **src_dev)
 {
        struct expander_device *ex = &dev->ex_dev;
        int ex_change_count = -1;
+       int phy_id = -1;
        int res;
+       struct domain_device *ch;
 
        res = sas_get_ex_change_count(dev, &ex_change_count);
        if (res)
                goto out;
-       if (ex_change_count != -1 &&
-           ex_change_count != ex->ex_change_count) {
-               *src_dev = dev;
-               ex->ex_change_count = ex_change_count;
-       } else {
-               struct domain_device *ch;
-
-               list_for_each_entry(ch, &ex->children, siblings) {
-                       if (ch->dev_type == EDGE_DEV ||
-                           ch->dev_type == FANOUT_DEV) {
-                               res = sas_find_bcast_dev(ch, src_dev);
-                               if (src_dev)
-                                       return res;
-                       }
+       if (ex_change_count != -1 && ex_change_count != ex->ex_change_count) {
+               /* Just detect if this expander phys phy change count changed,
+               * in order to determine if this expander originate BROADCAST,
+               * and do not update phy change count field in our structure.
+               */
+               res = sas_find_bcast_phy(dev, &phy_id, 0, false);
+               if (phy_id != -1) {
+                       *src_dev = dev;
+                       ex->ex_change_count = ex_change_count;
+                       SAS_DPRINTK("Expander phy change count has changed\n");
+                       return res;
+               } else
+                       SAS_DPRINTK("Expander phys DID NOT change\n");
+       }
+       list_for_each_entry(ch, &ex->children, siblings) {
+               if (ch->dev_type == EDGE_DEV || ch->dev_type == FANOUT_DEV) {
+                       res = sas_find_bcast_dev(ch, src_dev);
+                       if (src_dev)
+                               return res;
                }
        }
 out:
@@ -1700,24 +1734,26 @@ static void sas_unregister_ex_tree(struct domain_device *dev)
 }
 
 static void sas_unregister_devs_sas_addr(struct domain_device *parent,
-                                        int phy_id)
+                                        int phy_id, bool last)
 {
        struct expander_device *ex_dev = &parent->ex_dev;
        struct ex_phy *phy = &ex_dev->ex_phy[phy_id];
        struct domain_device *child, *n;
-
-       list_for_each_entry_safe(child, n, &ex_dev->children, siblings) {
-               if (SAS_ADDR(child->sas_addr) ==
-                   SAS_ADDR(phy->attached_sas_addr)) {
-                       if (child->dev_type == EDGE_DEV ||
-                           child->dev_type == FANOUT_DEV)
-                               sas_unregister_ex_tree(child);
-                       else
-                               sas_unregister_dev(child);
-                       break;
+       if (last) {
+               list_for_each_entry_safe(child, n,
+                       &ex_dev->children, siblings) {
+                       if (SAS_ADDR(child->sas_addr) ==
+                           SAS_ADDR(phy->attached_sas_addr)) {
+                               if (child->dev_type == EDGE_DEV ||
+                                   child->dev_type == FANOUT_DEV)
+                                       sas_unregister_ex_tree(child);
+                               else
+                                       sas_unregister_dev(child);
+                               break;
+                       }
                }
+               sas_disable_routing(parent, phy->attached_sas_addr);
        }
-       sas_disable_routing(parent, phy->attached_sas_addr);
        memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
        sas_port_delete_phy(phy->port, phy->phy);
        if (phy->port->num_phys == 0)
@@ -1770,15 +1806,31 @@ static int sas_discover_new(struct domain_device *dev, int phy_id)
 {
        struct ex_phy *ex_phy = &dev->ex_dev.ex_phy[phy_id];
        struct domain_device *child;
-       int res;
+       bool found = false;
+       int res, i;
 
        SAS_DPRINTK("ex %016llx phy%d new device attached\n",
                    SAS_ADDR(dev->sas_addr), phy_id);
        res = sas_ex_phy_discover(dev, phy_id);
        if (res)
                goto out;
+       /* to support the wide port inserted */
+       for (i = 0; i < dev->ex_dev.num_phys; i++) {
+               struct ex_phy *ex_phy_temp = &dev->ex_dev.ex_phy[i];
+               if (i == phy_id)
+                       continue;
+               if (SAS_ADDR(ex_phy_temp->attached_sas_addr) ==
+                   SAS_ADDR(ex_phy->attached_sas_addr)) {
+                       found = true;
+                       break;
+               }
+       }
+       if (found) {
+               sas_ex_join_wide_port(dev, phy_id);
+               return 0;
+       }
        res = sas_ex_discover_devices(dev, phy_id);
-       if (res)
+       if (!res)
                goto out;
        list_for_each_entry(child, &dev->ex_dev.children, siblings) {
                if (SAS_ADDR(child->sas_addr) ==
@@ -1793,7 +1845,7 @@ out:
        return res;
 }
 
-static int sas_rediscover_dev(struct domain_device *dev, int phy_id)
+static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last)
 {
        struct expander_device *ex = &dev->ex_dev;
        struct ex_phy *phy = &ex->ex_phy[phy_id];
@@ -1804,11 +1856,11 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id)
        switch (res) {
        case SMP_RESP_NO_PHY:
                phy->phy_state = PHY_NOT_PRESENT;
-               sas_unregister_devs_sas_addr(dev, phy_id);
+               sas_unregister_devs_sas_addr(dev, phy_id, last);
                goto out; break;
        case SMP_RESP_PHY_VACANT:
                phy->phy_state = PHY_VACANT;
-               sas_unregister_devs_sas_addr(dev, phy_id);
+               sas_unregister_devs_sas_addr(dev, phy_id, last);
                goto out; break;
        case SMP_RESP_FUNC_ACC:
                break;
@@ -1816,7 +1868,7 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id)
 
        if (SAS_ADDR(attached_sas_addr) == 0) {
                phy->phy_state = PHY_EMPTY;
-               sas_unregister_devs_sas_addr(dev, phy_id);
+               sas_unregister_devs_sas_addr(dev, phy_id, last);
        } else if (SAS_ADDR(attached_sas_addr) ==
                   SAS_ADDR(phy->attached_sas_addr)) {
                SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter\n",
@@ -1828,12 +1880,27 @@ out:
        return res;
 }
 
+/**
+ * sas_rediscover - revalidate the domain.
+ * @dev:domain device to be detect.
+ * @phy_id: the phy id will be detected.
+ *
+ * NOTE: this process _must_ quit (return) as soon as any connection
+ * errors are encountered.  Connection recovery is done elsewhere.
+ * Discover process only interrogates devices in order to discover the
+ * domain.For plugging out, we un-register the device only when it is
+ * the last phy in the port, for other phys in this port, we just delete it
+ * from the port.For inserting, we do discovery when it is the
+ * first phy,for other phys in this port, we add it to the port to
+ * forming the wide-port.
+ */
 static int sas_rediscover(struct domain_device *dev, const int phy_id)
 {
        struct expander_device *ex = &dev->ex_dev;
        struct ex_phy *changed_phy = &ex->ex_phy[phy_id];
        int res = 0;
        int i;
+       bool last = true;       /* is this the last phy of the port */
 
        SAS_DPRINTK("ex %016llx phy%d originated BROADCAST(CHANGE)\n",
                    SAS_ADDR(dev->sas_addr), phy_id);
@@ -1848,13 +1915,13 @@ static int sas_rediscover(struct domain_device *dev, const int phy_id)
                            SAS_ADDR(changed_phy->attached_sas_addr)) {
                                SAS_DPRINTK("phy%d part of wide port with "
                                            "phy%d\n", phy_id, i);
-                               goto out;
+                               last = false;
+                               break;
                        }
                }
-               res = sas_rediscover_dev(dev, phy_id);
+               res = sas_rediscover_dev(dev, phy_id, last);
        } else
                res = sas_discover_new(dev, phy_id);
-out:
        return res;
 }
 
@@ -1881,7 +1948,7 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev)
 
                do {
                        phy_id = -1;
-                       res = sas_find_bcast_phy(dev, &phy_id, i);
+                       res = sas_find_bcast_phy(dev, &phy_id, i, true);
                        if (phy_id == -1)
                                break;
                        res = sas_rediscover(dev, phy_id);
index e6ac59c023f199393b10eed05bb086f34a12fee4..fe8b74c706d21d4449887070133db3294d1b50ac 100644 (file)
@@ -56,7 +56,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
                }
        }
 
-       /* find a port */
+       /* see if the phy should be part of a wide port */
        spin_lock_irqsave(&sas_ha->phy_port_lock, flags);
        for (i = 0; i < sas_ha->num_phys; i++) {
                port = sas_ha->sas_port[i];
@@ -69,12 +69,23 @@ static void sas_form_port(struct asd_sas_phy *phy)
                        SAS_DPRINTK("phy%d matched wide port%d\n", phy->id,
                                    port->id);
                        break;
-               } else if (*(u64 *) port->sas_addr == 0 && port->num_phys==0) {
-                       memcpy(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE);
-                       break;
                }
                spin_unlock(&port->phy_list_lock);
        }
+       /* The phy does not match any existing port, create a new one */
+       if (i == sas_ha->num_phys) {
+               for (i = 0; i < sas_ha->num_phys; i++) {
+                       port = sas_ha->sas_port[i];
+                       spin_lock(&port->phy_list_lock);
+                       if (*(u64 *)port->sas_addr == 0
+                               && port->num_phys == 0) {
+                               memcpy(port->sas_addr, phy->sas_addr,
+                                       SAS_ADDR_SIZE);
+                               break;
+                       }
+                       spin_unlock(&port->phy_list_lock);
+               }
+       }
 
        if (i >= sas_ha->num_phys) {
                printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n",
index fcc184cd066d505d09f12b61a6d16be30a9761b4..cbceb0ebabf7c41888ec091ab77f61e1c9b20f48 100644 (file)
@@ -15,19 +15,18 @@ void qla4xxx_dump_buffer(void *b, uint32_t size)
        uint32_t cnt;
        uint8_t *c = b;
 
-       printk(" 0   1   2   3   4   5   6   7   8   9  Ah  Bh  Ch  Dh  Eh  "
+       printk(" 0   1   2   3   4   5   6   7   8   9  Ah  Bh  Ch  Dh  Eh  "
               "Fh\n");
        printk("------------------------------------------------------------"
               "--\n");
-       for (cnt = 0; cnt < size; cnt++, c++) {
-               printk(KERN_DEBUG "%02x", *c);
-               if (!(cnt % 16))
-                       printk(KERN_DEBUG "\n");
+       for (cnt = 0; cnt < size; c++) {
+               printk(KERN_INFO "%02x", *c);
+               if (!(++cnt % 16))
+                       printk(KERN_INFO "\n");
 
                else
-                       printk(KERN_DEBUG "  ");
+                       printk(KERN_INFO "  ");
        }
-       if (cnt % 16)
-               printk(KERN_DEBUG "\n");
+       printk(KERN_INFO "\n");
 }
 
index b586f27c3bd4a32f0baa1e629eccbde2eb7ec32b..81b5f29254e296ba68db569df740021fba8113db 100644 (file)
 #define MAX_SRBS               MAX_CMDS_TO_RISC
 #define MBOX_AEN_REG_COUNT     5
 #define MAX_INIT_RETRIES       5
-#define IOCB_HIWAT_CUSHION     16
 
 /*
  * Buffer sizes
@@ -184,6 +183,11 @@ struct srb {
        uint16_t cc_stat;
        u_long r_start;         /* Time we recieve a cmd from OS */
        u_long u_start;         /* Time when we handed the cmd to F/W */
+
+       /* Used for extended sense / status continuation */
+       uint8_t *req_sense_ptr;
+       uint16_t req_sense_len;
+       uint16_t reserved2;
 };
 
 /*
@@ -302,7 +306,6 @@ struct scsi_qla_host {
        uint32_t tot_ddbs;
 
        uint16_t        iocb_cnt;
-       uint16_t        iocb_hiwat;
 
        /* SRB cache. */
 #define SRB_MIN_REQ    128
@@ -436,6 +439,8 @@ struct scsi_qla_host {
        /* Map ddb_list entry by FW ddb index */
        struct ddb_entry *fw_ddb_index_map[MAX_DDB_ENTRIES];
 
+       /* Saved srb for status continuation entry processing */
+       struct srb *status_srb;
 };
 
 static inline int is_qla4010(struct scsi_qla_host *ha)
index 1b667a70cffaac586c33f0781ad77569fc22e527..9cd7a608df389455c7ada50263c68a4ac090e2bc 100644 (file)
@@ -572,6 +572,7 @@ struct conn_event_log_entry {
  *************************************************************************/
 #define IOCB_MAX_CDB_LEN           16  /* Bytes in a CBD */
 #define IOCB_MAX_SENSEDATA_LEN     32  /* Bytes of sense data */
+#define IOCB_MAX_EXT_SENSEDATA_LEN  60  /* Bytes of extended sense data */
 
 /* IOCB header structure */
 struct qla4_header {
@@ -733,6 +734,12 @@ struct status_entry {
 
 };
 
+/* Status Continuation entry */
+struct status_cont_entry {
+       struct qla4_header hdr; /* 00-03 */
+       uint8_t ext_sense_data[IOCB_MAX_EXT_SENSEDATA_LEN]; /* 04-63 */
+};
+
 struct passthru0 {
        struct qla4_header hdr;                /* 00-03 */
        uint32_t handle;        /* 04-07 */
index 912a67494adff6928cc52f760d34b2da89149e6e..e0c32159749c5b61aa5d57abe1050212d0e6fc40 100644 (file)
 #include "ql4_dbg.h"
 #include "ql4_inline.h"
 
-
 #include <scsi/scsi_tcq.h>
 
+static int
+qla4xxx_space_in_req_ring(struct scsi_qla_host *ha, uint16_t req_cnt)
+{
+       uint16_t cnt;
+
+       /* Calculate number of free request entries. */
+       if ((req_cnt + 2) >= ha->req_q_count) {
+               cnt = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out);
+               if (ha->request_in < cnt)
+                       ha->req_q_count = cnt - ha->request_in;
+               else
+                       ha->req_q_count = REQUEST_QUEUE_DEPTH -
+                                               (ha->request_in - cnt);
+       }
+
+       /* Check if room for request in request ring. */
+       if ((req_cnt + 2) < ha->req_q_count)
+               return 1;
+       else
+               return 0;
+}
+
+static void qla4xxx_advance_req_ring_ptr(struct scsi_qla_host *ha)
+{
+       /* Advance request queue pointer */
+       if (ha->request_in == (REQUEST_QUEUE_DEPTH - 1)) {
+               ha->request_in = 0;
+               ha->request_ptr = ha->request_ring;
+       } else {
+               ha->request_in++;
+               ha->request_ptr++;
+       }
+}
+
 /**
  * qla4xxx_get_req_pkt - returns a valid entry in request queue.
  * @ha: Pointer to host adapter structure.
 static int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
                               struct queue_entry **queue_entry)
 {
-       uint16_t request_in;
-       uint8_t status = QLA_SUCCESS;
-
-       *queue_entry = ha->request_ptr;
+       uint16_t req_cnt = 1;
 
-       /* get the latest request_in and request_out index */
-       request_in = ha->request_in;
-       ha->request_out = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out);
-
-       /* Advance request queue pointer and check for queue full */
-       if (request_in == (REQUEST_QUEUE_DEPTH - 1)) {
-               request_in = 0;
-               ha->request_ptr = ha->request_ring;
-       } else {
-               request_in++;
-               ha->request_ptr++;
-       }
-
-       /* request queue is full, try again later */
-       if ((ha->iocb_cnt + 1) >= ha->iocb_hiwat) {
-               /* restore request pointer */
-               ha->request_ptr = *queue_entry;
-               status = QLA_ERROR;
-       } else {
-               ha->request_in = request_in;
+       if (qla4xxx_space_in_req_ring(ha, req_cnt)) {
+               *queue_entry = ha->request_ptr;
                memset(*queue_entry, 0, sizeof(**queue_entry));
+
+               qla4xxx_advance_req_ring_ptr(ha);
+               ha->req_q_count -= req_cnt;
+               return QLA_SUCCESS;
        }
 
-       return status;
+       return QLA_ERROR;
 }
 
 /**
@@ -100,21 +116,14 @@ exit_send_marker:
        return status;
 }
 
-static struct continuation_t1_entry* qla4xxx_alloc_cont_entry(
-       struct scsi_qla_host *ha)
+static struct continuation_t1_entry *
+qla4xxx_alloc_cont_entry(struct scsi_qla_host *ha)
 {
        struct continuation_t1_entry *cont_entry;
 
        cont_entry = (struct continuation_t1_entry *)ha->request_ptr;
 
-       /* Advance request queue pointer */
-       if (ha->request_in == (REQUEST_QUEUE_DEPTH - 1)) {
-               ha->request_in = 0;
-               ha->request_ptr = ha->request_ring;
-       } else {
-               ha->request_in++;
-               ha->request_ptr++;
-       }
+       qla4xxx_advance_req_ring_ptr(ha);
 
        /* Load packet defaults */
        cont_entry->hdr.entryType = ET_CONTINUE;
@@ -197,13 +206,10 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
        struct scsi_cmnd *cmd = srb->cmd;
        struct ddb_entry *ddb_entry;
        struct command_t3_entry *cmd_entry;
-
        int nseg;
        uint16_t tot_dsds;
        uint16_t req_cnt;
-
        unsigned long flags;
-       uint16_t cnt;
        uint32_t index;
        char tag[2];
 
@@ -217,6 +223,19 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
 
        index = (uint32_t)cmd->request->tag;
 
+       /*
+        * Check to see if adapter is online before placing request on
+        * request queue.  If a reset occurs and a request is in the queue,
+        * the firmware will still attempt to process the request, retrieving
+        * garbage for pointers.
+        */
+       if (!test_bit(AF_ONLINE, &ha->flags)) {
+               DEBUG2(printk("scsi%ld: %s: Adapter OFFLINE! "
+                             "Do not issue command.\n",
+                             ha->host_no, __func__));
+               goto queuing_error;
+       }
+
        /* Calculate the number of request entries needed. */
        nseg = scsi_dma_map(cmd);
        if (nseg < 0)
@@ -224,17 +243,7 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
        tot_dsds = nseg;
 
        req_cnt = qla4xxx_calc_request_entries(tot_dsds);
-
-       if (ha->req_q_count < (req_cnt + 2)) {
-               cnt = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out);
-               if (ha->request_in < cnt)
-                       ha->req_q_count = cnt - ha->request_in;
-               else
-                       ha->req_q_count = REQUEST_QUEUE_DEPTH -
-                               (ha->request_in - cnt);
-       }
-
-       if (ha->req_q_count < (req_cnt + 2))
+       if (!qla4xxx_space_in_req_ring(ha, req_cnt))
                goto queuing_error;
 
        /* total iocbs active */
@@ -286,32 +295,10 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
                        break;
                }
 
-
-       /* Advance request queue pointer */
-       ha->request_in++;
-       if (ha->request_in == REQUEST_QUEUE_DEPTH) {
-               ha->request_in = 0;
-               ha->request_ptr = ha->request_ring;
-       } else
-               ha->request_ptr++;
-
-
+       qla4xxx_advance_req_ring_ptr(ha);
        qla4xxx_build_scsi_iocbs(srb, cmd_entry, tot_dsds);
        wmb();
 
-       /*
-        * Check to see if adapter is online before placing request on
-        * request queue.  If a reset occurs and a request is in the queue,
-        * the firmware will still attempt to process the request, retrieving
-        * garbage for pointers.
-        */
-       if (!test_bit(AF_ONLINE, &ha->flags)) {
-               DEBUG2(printk("scsi%ld: %s: Adapter OFFLINE! "
-                             "Do not issue command.\n",
-                             ha->host_no, __func__));
-               goto queuing_error;
-       }
-
        srb->cmd->host_scribble = (unsigned char *)srb;
 
        /* update counters */
index 799120fcb9be20a43901482781afd7dfbbd29884..8025ee16588e5a9f7104cf82fc80d4531fe01b70 100644 (file)
 #include "ql4_dbg.h"
 #include "ql4_inline.h"
 
+/**
+ * qla4xxx_copy_sense - copy sense data        into cmd sense buffer
+ * @ha: Pointer to host adapter structure.
+ * @sts_entry: Pointer to status entry structure.
+ * @srb: Pointer to srb structure.
+ **/
+static void qla4xxx_copy_sense(struct scsi_qla_host *ha,
+                               struct status_entry *sts_entry,
+                               struct srb *srb)
+{
+       struct scsi_cmnd *cmd = srb->cmd;
+       uint16_t sense_len;
+
+       memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+       sense_len = le16_to_cpu(sts_entry->senseDataByteCnt);
+       if (sense_len == 0)
+               return;
+
+       /* Save total available sense length,
+        * not to exceed cmd's sense buffer size */
+       sense_len = min_t(uint16_t, sense_len, SCSI_SENSE_BUFFERSIZE);
+       srb->req_sense_ptr = cmd->sense_buffer;
+       srb->req_sense_len = sense_len;
+
+       /* Copy sense from sts_entry pkt */
+       sense_len = min_t(uint16_t, sense_len, IOCB_MAX_SENSEDATA_LEN);
+       memcpy(cmd->sense_buffer, sts_entry->senseData, sense_len);
+
+       DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%d: %s: sense key = %x, "
+               "ASL= %02x, ASC/ASCQ = %02x/%02x\n", ha->host_no,
+               cmd->device->channel, cmd->device->id,
+               cmd->device->lun, __func__,
+               sts_entry->senseData[2] & 0x0f,
+               sts_entry->senseData[7],
+               sts_entry->senseData[12],
+               sts_entry->senseData[13]));
+
+       DEBUG5(qla4xxx_dump_buffer(cmd->sense_buffer, sense_len));
+       srb->flags |= SRB_GOT_SENSE;
+
+       /* Update srb, in case a sts_cont pkt follows */
+       srb->req_sense_ptr += sense_len;
+       srb->req_sense_len -= sense_len;
+       if (srb->req_sense_len != 0)
+               ha->status_srb = srb;
+       else
+               ha->status_srb = NULL;
+}
+
+/**
+ * qla4xxx_status_cont_entry - Process a Status Continuations entry.
+ * @ha: SCSI driver HA context
+ * @sts_cont: Entry pointer
+ *
+ * Extended sense data.
+ */
+static void
+qla4xxx_status_cont_entry(struct scsi_qla_host *ha,
+                         struct status_cont_entry *sts_cont)
+{
+       struct srb *srb = ha->status_srb;
+       struct scsi_cmnd *cmd;
+       uint8_t sense_len;
+
+       if (srb == NULL)
+               return;
+
+       cmd = srb->cmd;
+       if (cmd == NULL) {
+               DEBUG2(printk(KERN_INFO "scsi%ld: %s: Cmd already returned "
+                       "back to OS srb=%p srb->state:%d\n", ha->host_no,
+                       __func__, srb, srb->state));
+               ha->status_srb = NULL;
+               return;
+       }
+
+       /* Copy sense data. */
+       sense_len = min_t(uint16_t, srb->req_sense_len,
+                         IOCB_MAX_EXT_SENSEDATA_LEN);
+       memcpy(srb->req_sense_ptr, sts_cont->ext_sense_data, sense_len);
+       DEBUG5(qla4xxx_dump_buffer(srb->req_sense_ptr, sense_len));
+
+       srb->req_sense_ptr += sense_len;
+       srb->req_sense_len -= sense_len;
+
+       /* Place command on done queue. */
+       if (srb->req_sense_len == 0) {
+               qla4xxx_srb_compl(ha, srb);
+               ha->status_srb = NULL;
+       }
+}
+
 /**
  * qla4xxx_status_entry - processes status IOCBs
  * @ha: Pointer to host adapter structure.
@@ -23,7 +115,6 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
        struct srb *srb;
        struct ddb_entry *ddb_entry;
        uint32_t residual;
-       uint16_t sensebytecnt;
 
        srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle));
        if (!srb) {
@@ -92,24 +183,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
                        break;
 
                /* Copy Sense Data into sense buffer. */
-               memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
-
-               sensebytecnt = le16_to_cpu(sts_entry->senseDataByteCnt);
-               if (sensebytecnt == 0)
-                       break;
-
-               memcpy(cmd->sense_buffer, sts_entry->senseData,
-                      min_t(uint16_t, sensebytecnt, SCSI_SENSE_BUFFERSIZE));
-
-               DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
-                             "ASC/ASCQ = %02x/%02x\n", ha->host_no,
-                             cmd->device->channel, cmd->device->id,
-                             cmd->device->lun, __func__,
-                             sts_entry->senseData[2] & 0x0f,
-                             sts_entry->senseData[12],
-                             sts_entry->senseData[13]));
-
-               srb->flags |= SRB_GOT_SENSE;
+               qla4xxx_copy_sense(ha, sts_entry, srb);
                break;
 
        case SCS_INCOMPLETE:
@@ -176,23 +250,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
                                break;
 
                        /* Copy Sense Data into sense buffer. */
-                       memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
-
-                       sensebytecnt =
-                               le16_to_cpu(sts_entry->senseDataByteCnt);
-                       if (sensebytecnt == 0)
-                               break;
-
-                       memcpy(cmd->sense_buffer, sts_entry->senseData,
-                              min_t(uint16_t, sensebytecnt, SCSI_SENSE_BUFFERSIZE));
-
-                       DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
-                                     "ASC/ASCQ = %02x/%02x\n", ha->host_no,
-                                     cmd->device->channel, cmd->device->id,
-                                     cmd->device->lun, __func__,
-                                     sts_entry->senseData[2] & 0x0f,
-                                     sts_entry->senseData[12],
-                                     sts_entry->senseData[13]));
+                       qla4xxx_copy_sense(ha, sts_entry, srb);
                } else {
                        /*
                         * If RISC reports underrun and target does not
@@ -268,9 +326,10 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
 
 status_entry_exit:
 
-       /* complete the request */
+       /* complete the request, if not waiting for status_continuation pkt */
        srb->cc_stat = sts_entry->completionStatus;
-       qla4xxx_srb_compl(ha, srb);
+       if (ha->status_srb == NULL)
+               qla4xxx_srb_compl(ha, srb);
 }
 
 /**
@@ -305,10 +364,7 @@ static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)
                /* process entry */
                switch (sts_entry->hdr.entryType) {
                case ET_STATUS:
-                       /*
-                        * Common status - Single completion posted in single
-                        * IOSB.
-                        */
+                       /* Common status */
                        qla4xxx_status_entry(ha, sts_entry);
                        break;
 
@@ -316,9 +372,8 @@ static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)
                        break;
 
                case ET_STATUS_CONTINUATION:
-                       /* Just throw away the status continuation entries */
-                       DEBUG2(printk("scsi%ld: %s: Status Continuation entry "
-                                     "- ignoring\n", ha->host_no, __func__));
+                       qla4xxx_status_cont_entry(ha,
+                               (struct status_cont_entry *) sts_entry);
                        break;
 
                case ET_COMMAND:
index 051b0f5e8c8e88cc53494ac9d1922af9e2150541..09d6d4b76f39536512b3578142b26a1a0f27bcf8 100644 (file)
@@ -385,16 +385,6 @@ int qla4xxx_get_firmware_status(struct scsi_qla_host * ha)
                              mbox_sts[0]));
                return QLA_ERROR;
        }
-
-       /* High-water mark of IOCBs */
-       ha->iocb_hiwat = mbox_sts[2];
-       if (ha->iocb_hiwat > IOCB_HIWAT_CUSHION)
-               ha->iocb_hiwat -= IOCB_HIWAT_CUSHION;
-       else
-               dev_info(&ha->pdev->dev, "WARNING!!!  You have less than %d "
-                          "firmware IOCBs available (%d).\n",
-                          IOCB_HIWAT_CUSHION, ha->iocb_hiwat);
-
        return QLA_SUCCESS;
 }
 
index ec9da6ce8489ceedf36ab7efe8bd59c56cebfc45..40e3cafb3a9c54e44e813f738a01eec9c060498a 100644 (file)
@@ -66,6 +66,7 @@ static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess,
 static int qla4xxx_host_get_param(struct Scsi_Host *shost,
                                  enum iscsi_host_param param, char *buf);
 static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session);
+static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc);
 
 /*
  * SCSI host template entry points
@@ -89,6 +90,7 @@ static struct scsi_host_template qla4xxx_driver_template = {
        .eh_device_reset_handler = qla4xxx_eh_device_reset,
        .eh_target_reset_handler = qla4xxx_eh_target_reset,
        .eh_host_reset_handler  = qla4xxx_eh_host_reset,
+       .eh_timed_out           = qla4xxx_eh_cmd_timed_out,
 
        .slave_configure        = qla4xxx_slave_configure,
        .slave_alloc            = qla4xxx_slave_alloc,
@@ -124,6 +126,21 @@ static struct iscsi_transport qla4xxx_iscsi_transport = {
 
 static struct scsi_transport_template *qla4xxx_scsi_transport;
 
+static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc)
+{
+       struct iscsi_cls_session *session;
+       struct ddb_entry *ddb_entry;
+
+       session = starget_to_session(scsi_target(sc->device));
+       ddb_entry = session->dd_data;
+
+       /* if we are not logged in then the LLD is going to clean up the cmd */
+       if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE)
+               return BLK_EH_RESET_TIMER;
+       else
+               return BLK_EH_NOT_HANDLED;
+}
+
 static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session)
 {
        struct ddb_entry *ddb_entry = session->dd_data;
@@ -904,18 +921,17 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha,
        /* Flush any pending ddb changed AENs */
        qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
 
+       qla4xxx_flush_active_srbs(ha);
+
        /* Reset the firmware.  If successful, function
         * returns with ISP interrupts enabled.
         */
-       if (status == QLA_SUCCESS) {
-               DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n",
-                             ha->host_no, __func__));
-               qla4xxx_flush_active_srbs(ha);
-               if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS)
-                       status = qla4xxx_soft_reset(ha);
-               else
-                       status = QLA_ERROR;
-       }
+       DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n",
+                     ha->host_no, __func__));
+       if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS)
+               status = qla4xxx_soft_reset(ha);
+       else
+               status = QLA_ERROR;
 
        /* Flush any pending ddb changed AENs */
        qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
@@ -1527,11 +1543,9 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
 {
        struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
        struct ddb_entry *ddb_entry = cmd->device->hostdata;
-       struct srb *sp;
        int ret = FAILED, stat;
 
-       sp = (struct srb *) cmd->SCp.ptr;
-       if (!sp || !ddb_entry)
+       if (!ddb_entry)
                return ret;
 
        dev_info(&ha->pdev->dev,
@@ -1644,7 +1658,7 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
        ha = (struct scsi_qla_host *) cmd->device->host->hostdata;
 
        dev_info(&ha->pdev->dev,
-                  "scsi(%ld:%d:%d:%d): ADAPTER RESET ISSUED.\n", ha->host_no,
+                  "scsi(%ld:%d:%d:%d): HOST RESET ISSUED.\n", ha->host_no,
                   cmd->device->channel, cmd->device->id, cmd->device->lun);
 
        if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) {
index ab984cb89cea53f14ee4c0cf6ab34dce1c48b82f..6980cb279c81cead66de9339bfb4f5fe4c23a289 100644 (file)
@@ -5,5 +5,5 @@
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
 
-#define QLA4XXX_DRIVER_VERSION "5.01.00-k8"
+#define QLA4XXX_DRIVER_VERSION "5.01.00-k9"
 
index 5616cd780ff3504420363d0c42b24af0274218c6..b7b9fec67a98fc4f130bf2a1e0c51a2d0c66c445 100644 (file)
@@ -1840,6 +1840,18 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
        kfree(buffer);
 }
 
+static int sd_try_extended_inquiry(struct scsi_device *sdp)
+{
+       /*
+        * Although VPD inquiries can go to SCSI-2 type devices,
+        * some USB ones crash on receiving them, and the pages
+        * we currently ask for are for SPC-3 and beyond
+        */
+       if (sdp->scsi_level > SCSI_SPC_2)
+               return 1;
+       return 0;
+}
+
 /**
  *     sd_revalidate_disk - called the first time a new disk is seen,
  *     performs disk spin up, read_capacity, etc.
@@ -1877,8 +1889,12 @@ static int sd_revalidate_disk(struct gendisk *disk)
         */
        if (sdkp->media_present) {
                sd_read_capacity(sdkp, buffer);
-               sd_read_block_limits(sdkp);
-               sd_read_block_characteristics(sdkp);
+
+               if (sd_try_extended_inquiry(sdp)) {
+                       sd_read_block_limits(sdkp);
+                       sd_read_block_characteristics(sdkp);
+               }
+
                sd_read_write_protect_flag(sdkp, buffer);
                sd_read_cache_type(sdkp, buffer);
                sd_read_app_tag_own(sdkp, buffer);