diff options
Diffstat (limited to 'drivers/scsi/aacraid/linit.c')
-rw-r--r-- | drivers/scsi/aacraid/linit.c | 232 |
1 files changed, 142 insertions, 90 deletions
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 372a07533026..0f277df73af0 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -405,17 +405,23 @@ static int aac_slave_configure(struct scsi_device *sdev) int chn, tid; unsigned int depth = 0; unsigned int set_timeout = 0; + bool set_qd_dev_type = false; + u8 devtype = 0; chn = aac_logical_to_phys(sdev_channel(sdev)); tid = sdev_id(sdev); - if (chn < AAC_MAX_BUSES && tid < AAC_MAX_TARGETS && - aac->hba_map[chn][tid].devtype == AAC_DEVTYPE_NATIVE_RAW) { - depth = aac->hba_map[chn][tid].qd_limit; + if (chn < AAC_MAX_BUSES && tid < AAC_MAX_TARGETS && aac->sa_firmware) { + devtype = aac->hba_map[chn][tid].devtype; + + if (devtype == AAC_DEVTYPE_NATIVE_RAW) + depth = aac->hba_map[chn][tid].qd_limit; + else if (devtype == AAC_DEVTYPE_ARC_RAW) + set_qd_dev_type = true; + set_timeout = 1; goto common_config; } - if (aac->jbod && (sdev->type == TYPE_DISK)) sdev->removable = 1; @@ -466,9 +472,26 @@ static int aac_slave_configure(struct scsi_device *sdev) ++num_lsu; depth = (host->can_queue - num_one) / num_lsu; + + if (sdev_channel(sdev) != NATIVE_CHANNEL) + goto common_config; + + set_qd_dev_type = true; + } common_config: + + /* + * Check if SATA drive + */ + if (set_qd_dev_type) { + if (strncmp(sdev->vendor, "ATA", 3) == 0) + depth = 32; + else + depth = 64; + } + /* * Firmware has an individual device recovery time typically * of 35 seconds, give us a margin. @@ -601,6 +624,56 @@ static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg) return aac_do_ioctl(dev, cmd, arg); } +static int get_num_of_incomplete_fibs(struct aac_dev *aac) +{ + + unsigned long flags; + struct scsi_device *sdev = NULL; + struct Scsi_Host *shost = aac->scsi_host_ptr; + struct scsi_cmnd *scmnd = NULL; + struct device *ctrl_dev; + + int mlcnt = 0; + int llcnt = 0; + int ehcnt = 0; + int fwcnt = 0; + int krlcnt = 0; + + __shost_for_each_device(sdev, shost) { + spin_lock_irqsave(&sdev->list_lock, flags); + list_for_each_entry(scmnd, &sdev->cmd_list, list) { + switch (scmnd->SCp.phase) { + case AAC_OWNER_FIRMWARE: + fwcnt++; + break; + case AAC_OWNER_ERROR_HANDLER: + ehcnt++; + break; + case AAC_OWNER_LOWLEVEL: + llcnt++; + break; + case AAC_OWNER_MIDLEVEL: + mlcnt++; + break; + default: + krlcnt++; + break; + } + } + spin_unlock_irqrestore(&sdev->list_lock, flags); + } + + ctrl_dev = &aac->pdev->dev; + + dev_info(ctrl_dev, "outstanding cmd: midlevel-%d\n", mlcnt); + dev_info(ctrl_dev, "outstanding cmd: lowlevel-%d\n", llcnt); + dev_info(ctrl_dev, "outstanding cmd: error handler-%d\n", ehcnt); + dev_info(ctrl_dev, "outstanding cmd: firmware-%d\n", fwcnt); + dev_info(ctrl_dev, "outstanding cmd: kernel-%d\n", krlcnt); + + return mlcnt + llcnt + ehcnt + fwcnt; +} + static int aac_eh_abort(struct scsi_cmnd* cmd) { struct scsi_device * dev = cmd->device; @@ -661,8 +734,8 @@ static int aac_eh_abort(struct scsi_cmnd* cmd) (fib_callback) aac_hba_callback, (void *) cmd); - /* Wait up to 2 minutes for completion */ - for (count = 0; count < 120; ++count) { + /* Wait up to 15 secs for completion */ + for (count = 0; count < 15; ++count) { if (cmd->SCp.sent_command) { ret = SUCCESS; break; @@ -754,6 +827,12 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) int count; u32 bus, cid; int ret = FAILED; + int status = 0; + __le32 supported_options2 = 0; + bool is_mu_reset; + bool is_ignore_reset; + bool is_doorbell_reset; + bus = aac_logical_to_phys(scmd_channel(cmd)); cid = scmd_id(cmd); @@ -817,8 +896,8 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) (fib_callback) aac_hba_callback, (void *) cmd); - /* Wait up to 2 minutes for completion */ - for (count = 0; count < 120; ++count) { + /* Wait up to 15 seconds for completion */ + for (count = 0; count < 15; ++count) { if (cmd->SCp.sent_command) { ret = SUCCESS; break; @@ -826,12 +905,10 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) msleep(1000); } - if (ret != SUCCESS) - pr_err("%s: Host adapter reset request timed out\n", - AAC_DRIVERNAME); + if (ret == SUCCESS) + goto out; + } else { - struct scsi_cmnd *command; - unsigned long flags; /* Mark the assoc. FIB to not complete, eh handler does this */ for (count = 0; @@ -846,68 +923,42 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER; } } + } - pr_err("%s: Host adapter reset request. SCSI hang ?\n", - AAC_DRIVERNAME); - - count = aac_check_health(aac); - if (count) - return count; - /* - * Wait for all commands to complete to this specific - * target (block maximum 60 seconds). - */ - for (count = 60; count; --count) { - int active = aac->in_reset; - - if (active == 0) - __shost_for_each_device(dev, host) { - spin_lock_irqsave(&dev->list_lock, flags); - list_for_each_entry(command, &dev->cmd_list, - list) { - if ((command != cmd) && - (command->SCp.phase == - AAC_OWNER_FIRMWARE)) { - active++; - break; - } - } - spin_unlock_irqrestore(&dev->list_lock, flags); - if (active) - break; + pr_err("%s: Host adapter reset request. SCSI hang ?\n", AAC_DRIVERNAME); - } - /* - * We can exit If all the commands are complete - */ - if (active == 0) - return SUCCESS; - ssleep(1); - } - pr_err("%s: SCSI bus appears hung\n", AAC_DRIVERNAME); + /* + * Check the health of the controller + */ + status = aac_adapter_check_health(aac); + if (status) + dev_err(&aac->pdev->dev, "Adapter health - %d\n", status); - /* - * This adapter needs a blind reset, only do so for - * Adapters that support a register, instead of a commanded, - * reset. - */ - if (((aac->supplement_adapter_info.supported_options2 & - AAC_OPTION_MU_RESET) || - (aac->supplement_adapter_info.supported_options2 & - AAC_OPTION_DOORBELL_RESET)) && - aac_check_reset && - ((aac_check_reset != 1) || - !(aac->supplement_adapter_info.supported_options2 & - AAC_OPTION_IGNORE_RESET))) { - /* Bypass wait for command quiesce */ - aac_reset_adapter(aac, 2, IOP_HWSOFT_RESET); - } - ret = SUCCESS; - } + count = get_num_of_incomplete_fibs(aac); + if (count == 0) + return SUCCESS; + + /* + * Check if reset is supported by the firmware + */ + supported_options2 = aac->supplement_adapter_info.supported_options2; + is_mu_reset = supported_options2 & AAC_OPTION_MU_RESET; + is_doorbell_reset = supported_options2 & AAC_OPTION_DOORBELL_RESET; + is_ignore_reset = supported_options2 & AAC_OPTION_IGNORE_RESET; /* - * Cause an immediate retry of the command with a ten second delay - * after successful tur + * This adapter needs a blind reset, only do so for + * Adapters that support a register, instead of a commanded, + * reset. */ + if ((is_mu_reset || is_doorbell_reset) + && aac_check_reset + && (aac_check_reset != -1 || !is_ignore_reset)) { + /* Bypass wait for command quiesce */ + aac_reset_adapter(aac, 2, IOP_HWSOFT_RESET); + } + ret = SUCCESS; + +out: return ret; } @@ -1365,10 +1416,7 @@ static void __aac_shutdown(struct aac_dev * aac) kthread_stop(aac->thread); } aac_adapter_disable_int(aac); - if (aac->pdev->device == PMC_DEVICE_S6 || - aac->pdev->device == PMC_DEVICE_S7 || - aac->pdev->device == PMC_DEVICE_S8 || - aac->pdev->device == PMC_DEVICE_S9) { + if (aac_is_src(aac)) { if (aac->max_msix > 1) { for (i = 0; i < aac->max_msix; i++) { free_irq(pci_irq_vector(aac->pdev, i), @@ -1403,6 +1451,7 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) int error = -ENODEV; int unique_id = 0; u64 dmamask; + int mask_bits = 0; extern int aac_sync_mode; /* @@ -1426,18 +1475,32 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) goto out; error = -ENODEV; + if (!(aac_drivers[index].quirks & AAC_QUIRK_SRC)) { + error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (error) { + dev_err(&pdev->dev, "PCI 32 BIT dma mask set failed"); + goto out_disable_pdev; + } + } + /* * If the quirk31 bit is set, the adapter needs adapter * to driver communication memory to be allocated below 2gig */ - if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) + if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) { dmamask = DMA_BIT_MASK(31); - else + mask_bits = 31; + } else { dmamask = DMA_BIT_MASK(32); + mask_bits = 32; + } - if (pci_set_dma_mask(pdev, dmamask) || - pci_set_consistent_dma_mask(pdev, dmamask)) + error = pci_set_consistent_dma_mask(pdev, dmamask); + if (error) { + dev_err(&pdev->dev, "PCI %d B consistent dma mask set failed\n" + , mask_bits); goto out_disable_pdev; + } pci_set_master(pdev); @@ -1501,15 +1564,6 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) goto out_deinit; } - /* - * If we had set a smaller DMA mask earlier, set it to 4gig - * now since the adapter can dma data to at least a 4gig - * address space. - */ - if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) - goto out_deinit; - aac->maximum_num_channels = aac_drivers[index].channels; error = aac_get_adapter_info(aac); if (error < 0) @@ -1627,9 +1681,7 @@ static int aac_acquire_resources(struct aac_dev *dev) aac_adapter_enable_int(dev); - if ((dev->pdev->device == PMC_DEVICE_S7 || - dev->pdev->device == PMC_DEVICE_S8 || - dev->pdev->device == PMC_DEVICE_S9)) + if (aac_is_src(dev)) aac_define_int_mode(dev); if (dev->msi_enabled) |