From: Ching Huang <ching2...@areca.com.tw>

Handle adapter removed due to thunderbolt cable disconnection.

Signed-off-by: Ching Huang <ching2...@areca.com.tw>
---

diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 75e828b..2f52c53 100755
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -1446,12 +1446,80 @@ static void arcmsr_done4abort_postqueue(struct 
AdapterControlBlock *acb)
        }
 }
 
+static void arcmsr_remove_scsi_devices(struct AdapterControlBlock *acb)
+{
+       char *acb_dev_map = (char *)acb->device_map;
+       int target, lun, i;
+       struct scsi_device *psdev;
+       struct CommandControlBlock *ccb;
+       char temp;
+
+       for (i = 0; i < acb->maxFreeCCB; i++) {
+               ccb = acb->pccb_pool[i];
+               if (ccb->startdone == ARCMSR_CCB_START) {
+                       ccb->pcmd->result = DID_NO_CONNECT << 16;
+                       arcmsr_pci_unmap_dma(ccb);
+                       ccb->pcmd->scsi_done(ccb->pcmd);
+               }
+       }
+       for (target = 0; target < ARCMSR_MAX_TARGETID; target++) {
+               temp = *acb_dev_map;
+               if (temp) {
+                       for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
+                               if (temp & 1) {
+                                       psdev = scsi_device_lookup(acb->host,
+                                               0, target, lun);
+                                       if (psdev != NULL) {
+                                               scsi_remove_device(psdev);
+                                               scsi_device_put(psdev);
+                                       }
+                               }
+                               temp >>= 1;
+                       }
+                       *acb_dev_map = 0;
+               }
+               acb_dev_map++;
+       }
+}
+
+static void arcmsr_free_pcidev(struct AdapterControlBlock *acb)
+{
+       struct pci_dev *pdev;
+       struct Scsi_Host *host;
+
+       host = acb->host;
+       arcmsr_free_sysfs_attr(acb);
+       scsi_remove_host(host);
+       flush_work(&acb->arcmsr_do_message_isr_bh);
+       del_timer_sync(&acb->eternal_timer);
+       if (set_date_time)
+               del_timer_sync(&acb->refresh_timer);
+       pdev = acb->pdev;
+       arcmsr_free_irq(pdev, acb);
+       arcmsr_free_ccb_pool(acb);
+       arcmsr_free_mu(acb);
+       arcmsr_unmap_pciregion(acb);
+       pci_release_regions(pdev);
+       scsi_host_put(host);
+       pci_disable_device(pdev);
+}
+
 static void arcmsr_remove(struct pci_dev *pdev)
 {
        struct Scsi_Host *host = pci_get_drvdata(pdev);
        struct AdapterControlBlock *acb =
                (struct AdapterControlBlock *) host->hostdata;
        int poll_count = 0;
+       uint16_t dev_id;
+
+       pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id);
+       if (dev_id == 0xffff) {
+               acb->acb_flags &= ~ACB_F_IOP_INITED;
+               acb->acb_flags |= ACB_F_ADAPTER_REMOVED;
+               arcmsr_remove_scsi_devices(acb);
+               arcmsr_free_pcidev(acb);
+               return;
+       }
        arcmsr_free_sysfs_attr(acb);
        scsi_remove_host(host);
        flush_work(&acb->arcmsr_do_message_isr_bh);
@@ -1499,6 +1567,8 @@ static void arcmsr_shutdown(struct pci_dev *pdev)
        struct Scsi_Host *host = pci_get_drvdata(pdev);
        struct AdapterControlBlock *acb =
                (struct AdapterControlBlock *)host->hostdata;
+       if (acb->acb_flags & ACB_F_ADAPTER_REMOVED)
+               return;
        del_timer_sync(&acb->eternal_timer);
        if (set_date_time)
                del_timer_sync(&acb->refresh_timer);
@@ -2931,6 +3001,12 @@ static int arcmsr_queue_command_lck(struct scsi_cmnd 
*cmd,
        struct AdapterControlBlock *acb = (struct AdapterControlBlock *) 
host->hostdata;
        struct CommandControlBlock *ccb;
        int target = cmd->device->id;
+
+       if (acb->acb_flags & ACB_F_ADAPTER_REMOVED) {
+               cmd->result = (DID_NO_CONNECT << 16);
+               cmd->scsi_done(cmd);
+               return 0;
+       }
        cmd->scsi_done = done;
        cmd->host_scribble = NULL;
        cmd->result = 0;
@@ -4177,6 +4253,8 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
        int retry_count = 0;
        int rtn = FAILED;
        acb = (struct AdapterControlBlock *) cmd->device->host->hostdata;
+       if (acb->acb_flags & ACB_F_ADAPTER_REMOVED)
+               return SUCCESS;
        pr_notice("arcmsr: executing bus reset eh.....num_resets = %d,"
                " num_aborts = %d \n", acb->num_resets, acb->num_aborts);
        acb->num_resets++;
@@ -4243,6 +4321,8 @@ static int arcmsr_abort(struct scsi_cmnd *cmd)
        int rtn = FAILED;
        uint32_t intmask_org;
 
+       if (acb->acb_flags & ACB_F_ADAPTER_REMOVED)
+               return SUCCESS;
        printk(KERN_NOTICE
                "arcmsr%d: abort device command of scsi id = %d lun = %d\n",
                acb->host->host_no, cmd->device->id, (u32)cmd->device->lun);


Reply via email to