]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/qla2xxx/qla_os.c
Merge branch 'linus' of master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa
[linux-2.6-omap-h63xx.git] / drivers / scsi / qla2xxx / qla_os.c
index 93c0c7e4f08f0c2a98e20e5121b5b2eb422d722f..0351d380c2d7b1790c93d5655ff856b66d59cb74 100644 (file)
@@ -132,6 +132,7 @@ struct scsi_host_template qla2x00_driver_template = {
        .this_id                = -1,
        .cmd_per_lun            = 3,
        .use_clustering         = ENABLE_CLUSTERING,
+       .use_sg_chaining        = ENABLE_SG_CHAINING,
        .sg_tablesize           = SG_ALL,
 
        /*
@@ -163,6 +164,7 @@ struct scsi_host_template qla24xx_driver_template = {
        .this_id                = -1,
        .cmd_per_lun            = 3,
        .use_clustering         = ENABLE_CLUSTERING,
+       .use_sg_chaining        = ENABLE_SG_CHAINING,
        .sg_tablesize           = SG_ALL,
 
        .max_sectors            = 0xFFFF,
@@ -379,12 +381,17 @@ qla2x00_get_new_sp(scsi_qla_host_t *ha, fc_port_t *fcport,
 static int
 qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
-       scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+       scsi_qla_host_t *ha = shost_priv(cmd->device->host);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
        struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
        srb_t *sp;
        int rval;
 
+       if (unlikely(pci_channel_offline(ha->pdev))) {
+               cmd->result = DID_REQUEUE << 16;
+               goto qc_fail_command;
+       }
+
        rval = fc_remote_port_chkready(rport);
        if (rval) {
                cmd->result = rval;
@@ -440,13 +447,18 @@ qc_fail_command:
 static int
 qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
-       scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+       scsi_qla_host_t *ha = shost_priv(cmd->device->host);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
        struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
        srb_t *sp;
        int rval;
        scsi_qla_host_t *pha = to_qla_parent(ha);
 
+       if (unlikely(pci_channel_offline(ha->pdev))) {
+               cmd->result = DID_REQUEUE << 16;
+               goto qc24_fail_command;
+       }
+
        rval = fc_remote_port_chkready(rport);
        if (rval) {
                cmd->result = rval;
@@ -653,7 +665,7 @@ qla2x00_block_error_handler(struct scsi_cmnd *cmnd)
 static int
 qla2xxx_eh_abort(struct scsi_cmnd *cmd)
 {
-       scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+       scsi_qla_host_t *ha = shost_priv(cmd->device->host);
        srb_t *sp;
        int ret, i;
        unsigned int id, lun;
@@ -793,7 +805,7 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
 static int
 qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
 {
-       scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+       scsi_qla_host_t *ha = shost_priv(cmd->device->host);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
        int ret = FAILED;
        unsigned int id, lun;
@@ -922,7 +934,7 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha)
 static int
 qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
 {
-       scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+       scsi_qla_host_t *ha = shost_priv(cmd->device->host);
        scsi_qla_host_t *pha = to_qla_parent(ha);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
        int ret = FAILED;
@@ -982,7 +994,7 @@ eh_bus_reset_done:
 static int
 qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
 {
-       scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+       scsi_qla_host_t *ha = shost_priv(cmd->device->host);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
        int ret = FAILED;
        unsigned int id, lun;
@@ -1132,7 +1144,7 @@ qla2xxx_slave_alloc(struct scsi_device *sdev)
 static int
 qla2xxx_slave_configure(struct scsi_device *sdev)
 {
-       scsi_qla_host_t *ha = to_qla_host(sdev->host);
+       scsi_qla_host_t *ha = shost_priv(sdev->host);
        struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
 
        if (sdev->tagged_supported)
@@ -1384,7 +1396,7 @@ static struct isp_operations qla25xx_isp_ops = {
        .beacon_on              = qla24xx_beacon_on,
        .beacon_off             = qla24xx_beacon_off,
        .beacon_blink           = qla24xx_beacon_blink,
-       .read_optrom            = qla24xx_read_optrom_data,
+       .read_optrom            = qla25xx_read_optrom_data,
        .write_optrom           = qla24xx_write_optrom_data,
        .get_flash_version      = qla24xx_get_flash_version,
 };
@@ -1533,7 +1545,7 @@ iospace_error_exit:
 static void
 qla2xxx_scan_start(struct Scsi_Host *shost)
 {
-       scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
+       scsi_qla_host_t *ha = shost_priv(shost);
 
        set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
        set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
@@ -1543,7 +1555,7 @@ qla2xxx_scan_start(struct Scsi_Host *shost)
 static int
 qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
 {
-       scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
+       scsi_qla_host_t *ha = shost_priv(shost);
 
        if (!ha->host)
                return 1;
@@ -1564,13 +1576,17 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        struct Scsi_Host *host;
        scsi_qla_host_t *ha;
        unsigned long   flags = 0;
-       char pci_info[20];
+       char pci_info[30];
        char fw_str[30];
        struct scsi_host_template *sht;
 
        if (pci_enable_device(pdev))
                goto probe_out;
 
+       if (pci_find_aer_capability(pdev))
+               if (pci_enable_pcie_error_reporting(pdev))
+                       goto probe_out;
+
        sht = &qla2x00_driver_template;
        if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
            pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 ||
@@ -1586,7 +1602,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        }
 
        /* Clear our data area */
-       ha = (scsi_qla_host_t *)host->hostdata;
+       ha = shost_priv(host);
        memset(ha, 0, sizeof(scsi_qla_host_t));
 
        ha->pdev = pdev;
@@ -2423,7 +2439,6 @@ qla2x00_do_dpc(void *data)
                                if (atomic_read(&fcport->state) != FCS_ONLINE &&
                                    fcport->login_retry) {
 
-                                       fcport->login_retry--;
                                        if (fcport->flags & FCF_FABRIC_DEVICE) {
                                                if (fcport->flags &
                                                    FCF_TAPE_PRESENT)
@@ -2439,6 +2454,7 @@ qla2x00_do_dpc(void *data)
                                                    qla2x00_local_device_login(
                                                        ha, fcport);
 
+                                       fcport->login_retry--;
                                        if (status == QLA_SUCCESS) {
                                                fcport->old_loop_id = fcport->loop_id;
 
@@ -2456,6 +2472,8 @@ qla2x00_do_dpc(void *data)
                                        } else {
                                                fcport->login_retry = 0;
                                        }
+                                       if (fcport->login_retry == 0)
+                                               fcport->loop_id = FC_NO_LOOP_ID;
                                }
                                if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
                                        break;
@@ -2814,6 +2832,105 @@ qla2x00_release_firmware(void)
        up(&qla_fw_lock);
 }
 
+static pci_ers_result_t
+qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+{
+       switch (state) {
+       case pci_channel_io_normal:
+               return PCI_ERS_RESULT_CAN_RECOVER;
+       case pci_channel_io_frozen:
+               pci_disable_device(pdev);
+               return PCI_ERS_RESULT_NEED_RESET;
+       case pci_channel_io_perm_failure:
+               qla2x00_remove_one(pdev);
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t
+qla2xxx_pci_mmio_enabled(struct pci_dev *pdev)
+{
+       int risc_paused = 0;
+       uint32_t stat;
+       unsigned long flags;
+       scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+       struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+       struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
+
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+       if (IS_QLA2100(ha) || IS_QLA2200(ha)){
+               stat = RD_REG_DWORD(&reg->hccr);
+               if (stat & HCCR_RISC_PAUSE)
+                       risc_paused = 1;
+       } else if (IS_QLA23XX(ha)) {
+               stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
+               if (stat & HSR_RISC_PAUSED)
+                       risc_paused = 1;
+       } else if (IS_FWI2_CAPABLE(ha)) {
+               stat = RD_REG_DWORD(&reg24->host_status);
+               if (stat & HSRX_RISC_PAUSED)
+                       risc_paused = 1;
+       }
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+       if (risc_paused) {
+               qla_printk(KERN_INFO, ha, "RISC paused -- mmio_enabled, "
+                   "Dumping firmware!\n");
+               ha->isp_ops->fw_dump(ha, 0);
+
+               return PCI_ERS_RESULT_NEED_RESET;
+       } else
+               return PCI_ERS_RESULT_RECOVERED;
+}
+
+static pci_ers_result_t
+qla2xxx_pci_slot_reset(struct pci_dev *pdev)
+{
+       pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
+       scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+
+       if (pci_enable_device(pdev)) {
+               qla_printk(KERN_WARNING, ha,
+                   "Can't re-enable PCI device after reset.\n");
+
+               return ret;
+       }
+       pci_set_master(pdev);
+
+       if (ha->isp_ops->pci_config(ha))
+               return ret;
+
+       set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+       if (qla2x00_abort_isp(ha)== QLA_SUCCESS)
+               ret =  PCI_ERS_RESULT_RECOVERED;
+       clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+
+       return ret;
+}
+
+static void
+qla2xxx_pci_resume(struct pci_dev *pdev)
+{
+       scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+       int ret;
+
+       ret = qla2x00_wait_for_hba_online(ha);
+       if (ret != QLA_SUCCESS) {
+               qla_printk(KERN_ERR, ha,
+                   "the device failed to resume I/O "
+                   "from slot/link_reset");
+       }
+       pci_cleanup_aer_uncorrect_error_status(pdev);
+}
+
+static struct pci_error_handlers qla2xxx_err_handler = {
+       .error_detected = qla2xxx_pci_error_detected,
+       .mmio_enabled = qla2xxx_pci_mmio_enabled,
+       .slot_reset = qla2xxx_pci_slot_reset,
+       .resume = qla2xxx_pci_resume,
+};
+
 static struct pci_device_id qla2xxx_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100) },
        { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200) },
@@ -2839,6 +2956,7 @@ static struct pci_driver qla2xxx_pci_driver = {
        .id_table       = qla2xxx_pci_tbl,
        .probe          = qla2x00_probe_one,
        .remove         = __devexit_p(qla2x00_remove_one),
+       .err_handler    = &qla2xxx_err_handler,
 };
 
 /**