Commit c4c1adb3 authored by Ching Huang's avatar Ching Huang Committed by Martin K. Petersen

scsi: arcmsr: Handle adapter removed due to thunderbolt cable disconnection.

Handle adapter removed due to thunderbolt cable disconnection.
Signed-off-by: default avatarChing Huang <ching2048@areca.com.tw>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 50b08240
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment