scsi: qla2xxx: Enable type checking for the SRB free and done callback functions
[linux-2.6-block.git] / drivers / scsi / qla2xxx / qla_os.c
index 2e58cff9d2005b0cab783ab22653cb27e8333ecd..9ef59995f5d6e5315fcc2057a5c394467006d76c 100644 (file)
@@ -69,7 +69,7 @@ MODULE_PARM_DESC(ql2xplogiabsentdevice,
                "a Fabric scan.  This is needed for several broken switches. "
                "Default is 0 - no PLOGI. 1 - perform PLOGI.");
 
-int ql2xloginretrycount = 0;
+int ql2xloginretrycount;
 module_param(ql2xloginretrycount, int, S_IRUGO);
 MODULE_PARM_DESC(ql2xloginretrycount,
                "Specify an alternate value for the NVRAM login retry count.");
@@ -234,7 +234,7 @@ MODULE_PARM_DESC(ql2xmdenable,
                "0 - MiniDump disabled. "
                "1 (Default) - MiniDump enabled.");
 
-int ql2xexlogins = 0;
+int ql2xexlogins;
 module_param(ql2xexlogins, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(ql2xexlogins,
                 "Number of extended Logins. "
@@ -250,7 +250,7 @@ module_param(ql2xiniexchg, uint, 0644);
 MODULE_PARM_DESC(ql2xiniexchg,
        "Number of initiator exchanges.");
 
-int ql2xfwholdabts = 0;
+int ql2xfwholdabts;
 module_param(ql2xfwholdabts, int, S_IRUGO);
 MODULE_PARM_DESC(ql2xfwholdabts,
                "Allow FW to hold status IOCB until ABTS rsp received. "
@@ -536,80 +536,70 @@ static void qla2x00_free_queues(struct qla_hw_data *ha)
 }
 
 static char *
-qla2x00_pci_info_str(struct scsi_qla_host *vha, char *str)
+qla2x00_pci_info_str(struct scsi_qla_host *vha, char *str, size_t str_len)
 {
        struct qla_hw_data *ha = vha->hw;
-       static char *pci_bus_modes[] = {
+       static const char *const pci_bus_modes[] = {
                "33", "66", "100", "133",
        };
        uint16_t pci_bus;
 
-       strcpy(str, "PCI");
        pci_bus = (ha->pci_attr & (BIT_9 | BIT_10)) >> 9;
        if (pci_bus) {
-               strcat(str, "-X (");
-               strcat(str, pci_bus_modes[pci_bus]);
+               snprintf(str, str_len, "PCI-X (%s MHz)",
+                        pci_bus_modes[pci_bus]);
        } else {
                pci_bus = (ha->pci_attr & BIT_8) >> 8;
-               strcat(str, " (");
-               strcat(str, pci_bus_modes[pci_bus]);
+               snprintf(str, str_len, "PCI (%s MHz)", pci_bus_modes[pci_bus]);
        }
-       strcat(str, " MHz)");
 
-       return (str);
+       return str;
 }
 
 static char *
-qla24xx_pci_info_str(struct scsi_qla_host *vha, char *str)
+qla24xx_pci_info_str(struct scsi_qla_host *vha, char *str, size_t str_len)
 {
-       static char *pci_bus_modes[] = { "33", "66", "100", "133", };
+       static const char *const pci_bus_modes[] = {
+               "33", "66", "100", "133",
+       };
        struct qla_hw_data *ha = vha->hw;
        uint32_t pci_bus;
 
        if (pci_is_pcie(ha->pdev)) {
-               char lwstr[6];
                uint32_t lstat, lspeed, lwidth;
+               const char *speed_str;
 
                pcie_capability_read_dword(ha->pdev, PCI_EXP_LNKCAP, &lstat);
                lspeed = lstat & PCI_EXP_LNKCAP_SLS;
                lwidth = (lstat & PCI_EXP_LNKCAP_MLW) >> 4;
 
-               strcpy(str, "PCIe (");
                switch (lspeed) {
                case 1:
-                       strcat(str, "2.5GT/s ");
+                       speed_str = "2.5GT/s";
                        break;
                case 2:
-                       strcat(str, "5.0GT/s ");
+                       speed_str = "5.0GT/s";
                        break;
                case 3:
-                       strcat(str, "8.0GT/s ");
+                       speed_str = "8.0GT/s";
                        break;
                default:
-                       strcat(str, "<unknown> ");
+                       speed_str = "<unknown>";
                        break;
                }
-               snprintf(lwstr, sizeof(lwstr), "x%d)", lwidth);
-               strcat(str, lwstr);
+               snprintf(str, str_len, "PCIe (%s x%d)", speed_str, lwidth);
 
                return str;
        }
 
-       strcpy(str, "PCI");
        pci_bus = (ha->pci_attr & CSRX_PCIX_BUS_MODE_MASK) >> 8;
-       if (pci_bus == 0 || pci_bus == 8) {
-               strcat(str, " (");
-               strcat(str, pci_bus_modes[pci_bus >> 3]);
-       } else {
-               strcat(str, "-X ");
-               if (pci_bus & BIT_2)
-                       strcat(str, "Mode 2");
-               else
-                       strcat(str, "Mode 1");
-               strcat(str, " (");
-               strcat(str, pci_bus_modes[pci_bus & ~BIT_2]);
-       }
-       strcat(str, " MHz)");
+       if (pci_bus == 0 || pci_bus == 8)
+               snprintf(str, str_len, "PCI (%s MHz)",
+                        pci_bus_modes[pci_bus >> 3]);
+       else
+               snprintf(str, str_len, "PCI-X Mode %d (%s MHz)",
+                        pci_bus & 4 ? 2 : 1,
+                        pci_bus_modes[pci_bus & 3]);
 
        return str;
 }
@@ -662,10 +652,8 @@ qla24xx_fw_version_str(struct scsi_qla_host *vha, char *str, size_t size)
        return str;
 }
 
-void
-qla2x00_sp_free_dma(void *ptr)
+void qla2x00_sp_free_dma(srb_t *sp)
 {
-       srb_t *sp = ptr;
        struct qla_hw_data *ha = sp->vha->hw;
        struct scsi_cmnd *cmd = GET_CMD_SP(sp);
        void *ctx = GET_CMD_CTX_SP(sp);
@@ -709,10 +697,8 @@ qla2x00_sp_free_dma(void *ptr)
        }
 }
 
-void
-qla2x00_sp_compl(void *ptr, int res)
+void qla2x00_sp_compl(srb_t *sp, int res)
 {
-       srb_t *sp = ptr;
        struct scsi_cmnd *cmd = GET_CMD_SP(sp);
        struct completion *comp = sp->comp;
 
@@ -730,10 +716,8 @@ qla2x00_sp_compl(void *ptr, int res)
        qla2x00_rel_sp(sp);
 }
 
-void
-qla2xxx_qpair_sp_free_dma(void *ptr)
+void qla2xxx_qpair_sp_free_dma(srb_t *sp)
 {
-       srb_t *sp = (srb_t *)ptr;
        struct scsi_cmnd *cmd = GET_CMD_SP(sp);
        struct qla_hw_data *ha = sp->fcport->vha->hw;
        void *ctx = GET_CMD_CTX_SP(sp);
@@ -814,10 +798,8 @@ qla2xxx_qpair_sp_free_dma(void *ptr)
        }
 }
 
-void
-qla2xxx_qpair_sp_compl(void *ptr, int res)
+void qla2xxx_qpair_sp_compl(srb_t *sp, int res)
 {
-       srb_t *sp = ptr;
        struct scsi_cmnd *cmd = GET_CMD_SP(sp);
        struct completion *comp = sp->comp;
 
@@ -845,9 +827,6 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
        struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
        srb_t *sp;
        int rval;
-       struct qla_qpair *qpair = NULL;
-       uint32_t tag;
-       uint16_t hwq;
 
        if (unlikely(test_bit(UNLOADING, &base_vha->dpc_flags)) ||
            WARN_ON_ONCE(!rport)) {
@@ -856,6 +835,10 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
        }
 
        if (ha->mqenable) {
+               uint32_t tag;
+               uint16_t hwq;
+               struct qla_qpair *qpair = NULL;
+
                tag = blk_mq_unique_tag(cmd->request);
                hwq = blk_mq_unique_tag_to_hwq(tag);
                qpair = ha->queue_pair_map[hwq];
@@ -1058,8 +1041,8 @@ qc24_fail_command:
  *    cmd = Scsi Command to wait on.
  *
  * Return:
- *    Not Found : 0
- *    Found : 1
+ *    Completed in time : QLA_SUCCESS
+ *    Did not complete in time : QLA_FUNCTION_FAILED
  */
 static int
 qla2x00_eh_wait_on_command(struct scsi_cmnd *cmd)
@@ -1269,6 +1252,7 @@ static int
 qla2xxx_eh_abort(struct scsi_cmnd *cmd)
 {
        scsi_qla_host_t *vha = shost_priv(cmd->device->host);
+       DECLARE_COMPLETION_ONSTACK(comp);
        srb_t *sp;
        int ret;
        unsigned int id;
@@ -1296,6 +1280,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
        if (!qpair)
                return SUCCESS;
 
+       if (sp->fcport && sp->fcport->deleted)
+               return SUCCESS;
+
        spin_lock_irqsave(qpair->qp_lock_ptr, flags);
        if (sp->type != SRB_SCSI_CMD || GET_CMD_SP(sp) != cmd) {
                /* there's a chance an interrupt could clear
@@ -1304,6 +1291,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
                return SUCCESS;
        }
 
+       /* Get a reference to the sp and drop the lock. */
        if (sp_get(sp)){
                /* ref_count is already 0 */
                spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
@@ -1331,6 +1319,23 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
                sp->done(sp, DID_ABORT << 16);
                ret = SUCCESS;
                break;
+       case QLA_FUNCTION_PARAMETER_ERROR: {
+               /* Wait for the command completion. */
+               uint32_t ratov = ha->r_a_tov/10;
+               uint32_t ratov_j = msecs_to_jiffies(4 * ratov * 1000);
+
+               WARN_ON_ONCE(sp->comp);
+               sp->comp = &comp;
+               if (!wait_for_completion_timeout(&comp, ratov_j)) {
+                       ql_dbg(ql_dbg_taskm, vha, 0xffff,
+                           "%s: Abort wait timer (4 * R_A_TOV[%d]) expired\n",
+                           __func__, ha->r_a_tov);
+                       ret = FAILED;
+               } else {
+                       ret = SUCCESS;
+               }
+               break;
+       }
        default:
                /*
                 * Either abort failed or abort and completion raced. Let
@@ -1340,6 +1345,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
                break;
        }
 
+       sp->comp = NULL;
+       atomic_dec(&sp->ref_count);
        ql_log(ql_log_info, vha, 0x801c,
            "Abort command issued nexus=%ld:%d:%llu -- %x.\n",
            vha->host_no, id, lun, ret);
@@ -1347,6 +1354,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
        return ret;
 }
 
+/*
+ * Returns: QLA_SUCCESS or QLA_FUNCTION_FAILED.
+ */
 int
 qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t,
        uint64_t l, enum nexus_wait_type type)
@@ -1420,6 +1430,9 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type,
        if (err != 0)
                return err;
 
+       if (fcport->deleted)
+               return SUCCESS;
+
        ql_log(ql_log_info, vha, 0x8009,
            "%s RESET ISSUED nexus=%ld:%d:%llu cmd=%p.\n", name, vha->host_no,
            cmd->device->id, cmd->device->lun, cmd);
@@ -1534,6 +1547,9 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
                return ret;
        ret = FAILED;
 
+       if (qla2x00_chip_is_down(vha))
+               return ret;
+
        ql_log(ql_log_info, vha, 0x8012,
            "BUS RESET ISSUED nexus=%ld:%d:%llu.\n", vha->host_no, id, lun);
 
@@ -1746,6 +1762,8 @@ static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res,
                spin_lock_irqsave(qp->qp_lock_ptr, *flags);
                sp->comp = NULL;
        }
+
+       atomic_dec(&sp->ref_count);
 }
 
 static void
@@ -1800,8 +1818,13 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
        int que;
        struct qla_hw_data *ha = vha->hw;
 
+       /* Continue only if initialization complete. */
+       if (!ha->base_qpair)
+               return;
        __qla2x00_abort_all_cmds(ha->base_qpair, res);
 
+       if (!ha->queue_pair_map)
+               return;
        for (que = 0; que < ha->max_qpairs; que++) {
                if (!ha->queue_pair_map[que])
                        continue;
@@ -2477,7 +2500,7 @@ static struct isp_operations qla27xx_isp_ops = {
        .config_rings           = qla24xx_config_rings,
        .reset_adapter          = qla24xx_reset_adapter,
        .nvram_config           = qla81xx_nvram_config,
-       .update_fw_options      = qla81xx_update_fw_options,
+       .update_fw_options      = qla24xx_update_fw_options,
        .load_risc              = qla81xx_load_risc,
        .pci_info_str           = qla24xx_pci_info_str,
        .fw_version_str         = qla24xx_fw_version_str,
@@ -3154,6 +3177,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ql_log(ql_log_fatal, base_vha, 0x003d,
                    "Failed to allocate memory for queue pointers..."
                    "aborting.\n");
+               ret = -ENODEV;
                goto probe_failed;
        }
 
@@ -3418,7 +3442,8 @@ skip_dpc:
            "QLogic %s - %s.\n", ha->model_number, ha->model_desc);
        ql_log(ql_log_info, base_vha, 0x00fc,
            "ISP%04X: %s @ %s hdma%c host#=%ld fw=%s.\n",
-           pdev->device, ha->isp_ops->pci_info_str(base_vha, pci_info),
+           pdev->device, ha->isp_ops->pci_info_str(base_vha, pci_info,
+                                                      sizeof(pci_info)),
            pci_name(pdev), ha->flags.enable_64bit_addressing ? '+' : '-',
            base_vha->host_no,
            ha->isp_ops->fw_version_str(base_vha, fw_str, sizeof(fw_str)));
@@ -4708,7 +4733,7 @@ qla2x00_mem_free(struct qla_hw_data *ha)
        mempool_destroy(ha->ctx_mempool);
        ha->ctx_mempool = NULL;
 
-       if (ql2xenabledif) {
+       if (ql2xenabledif && ha->dif_bundl_pool) {
                struct dsd_dma *dsd, *nxt;
 
                list_for_each_entry_safe(dsd, nxt, &ha->pool.unusable.head,
@@ -4731,8 +4756,7 @@ qla2x00_mem_free(struct qla_hw_data *ha)
                }
        }
 
-       if (ha->dif_bundl_pool)
-               dma_pool_destroy(ha->dif_bundl_pool);
+       dma_pool_destroy(ha->dif_bundl_pool);
        ha->dif_bundl_pool = NULL;
 
        qlt_mem_free(ha);
@@ -4804,7 +4828,7 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
        if (!vha->gnl.l) {
                ql_log(ql_log_fatal, vha, 0xd04a,
                    "Alloc failed for name list.\n");
-               scsi_remove_host(vha->host);
+               scsi_host_put(vha->host);
                return NULL;
        }
 
@@ -4816,7 +4840,7 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
                    "Alloc failed for scan database.\n");
                dma_free_coherent(&ha->pdev->dev, vha->gnl.size,
                    vha->gnl.l, vha->gnl.ldma);
-               scsi_remove_host(vha->host);
+               scsi_host_put(vha->host);
                return NULL;
        }
        INIT_DELAYED_WORK(&vha->scan.scan_work, qla_scan_work_fn);
@@ -5045,8 +5069,10 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
                                   "%s %8phC mem alloc fail.\n",
                                   __func__, e->u.new_sess.port_name);
 
-                       if (pla)
+                       if (pla) {
+                               list_del(&pla->list);
                                kmem_cache_free(qla_tgt_plogi_cachep, pla);
+                       }
                        return;
                }
 
@@ -5077,6 +5103,7 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
        if (fcport) {
                fcport->id_changed = 1;
                fcport->scan_state = QLA_FCPORT_FOUND;
+               fcport->chip_reset = vha->hw->base_qpair->chip_reset;
                memcpy(fcport->node_name, e->u.new_sess.node_name, WWN_SIZE);
 
                if (pla) {
@@ -5156,8 +5183,10 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
 
        if (free_fcport) {
                qla2x00_free_fcport(fcport);
-               if (pla)
+               if (pla) {
+                       list_del(&pla->list);
                        kmem_cache_free(qla_tgt_plogi_cachep, pla);
+               }
        }
 }
 
@@ -5677,7 +5706,6 @@ exit:
 void
 qla83xx_idc_lock(scsi_qla_host_t *base_vha, uint16_t requester_id)
 {
-       uint16_t options = (requester_id << 15) | BIT_6;
        uint32_t data;
        uint32_t lock_owner;
        struct qla_hw_data *ha = base_vha->hw;
@@ -5710,22 +5738,6 @@ retry_lock:
        }
 
        return;
-
-       /* XXX: IDC-lock implementation using access-control mbx */
-retry_lock2:
-       if (qla83xx_access_control(base_vha, options, 0, 0, NULL)) {
-               ql_dbg(ql_dbg_p3p, base_vha, 0xb072,
-                   "Failed to acquire IDC lock. retrying...\n");
-               /* Retry/Perform IDC-Lock recovery */
-               if (qla83xx_idc_lock_recovery(base_vha) == QLA_SUCCESS) {
-                       qla83xx_wait_logic();
-                       goto retry_lock2;
-               } else
-                       ql_log(ql_log_warn, base_vha, 0xb076,
-                           "IDC Lock recovery FAILED.\n");
-       }
-
-       return;
 }
 
 void