Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+80 −0
Original line number Original line Diff line number Diff line
@@ -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)
static void arcmsr_remove(struct pci_dev *pdev)
{
{
	struct Scsi_Host *host = pci_get_drvdata(pdev);
	struct Scsi_Host *host = pci_get_drvdata(pdev);
	struct AdapterControlBlock *acb =
	struct AdapterControlBlock *acb =
		(struct AdapterControlBlock *) host->hostdata;
		(struct AdapterControlBlock *) host->hostdata;
	int poll_count = 0;
	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);
	arcmsr_free_sysfs_attr(acb);
	scsi_remove_host(host);
	scsi_remove_host(host);
	flush_work(&acb->arcmsr_do_message_isr_bh);
	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 Scsi_Host *host = pci_get_drvdata(pdev);
	struct AdapterControlBlock *acb =
	struct AdapterControlBlock *acb =
		(struct AdapterControlBlock *)host->hostdata;
		(struct AdapterControlBlock *)host->hostdata;
	if (acb->acb_flags & ACB_F_ADAPTER_REMOVED)
		return;
	del_timer_sync(&acb->eternal_timer);
	del_timer_sync(&acb->eternal_timer);
	if (set_date_time)
	if (set_date_time)
		del_timer_sync(&acb->refresh_timer);
		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 AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
	struct CommandControlBlock *ccb;
	struct CommandControlBlock *ccb;
	int target = cmd->device->id;
	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->scsi_done = done;
	cmd->host_scribble = NULL;
	cmd->host_scribble = NULL;
	cmd->result = 0;
	cmd->result = 0;
@@ -4177,6 +4253,8 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
	int retry_count = 0;
	int retry_count = 0;
	int rtn = FAILED;
	int rtn = FAILED;
	acb = (struct AdapterControlBlock *) cmd->device->host->hostdata;
	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,"
	pr_notice("arcmsr: executing bus reset eh.....num_resets = %d,"
		" num_aborts = %d \n", acb->num_resets, acb->num_aborts);
		" num_aborts = %d \n", acb->num_resets, acb->num_aborts);
	acb->num_resets++;
	acb->num_resets++;
@@ -4243,6 +4321,8 @@ static int arcmsr_abort(struct scsi_cmnd *cmd)
	int rtn = FAILED;
	int rtn = FAILED;
	uint32_t intmask_org;
	uint32_t intmask_org;


	if (acb->acb_flags & ACB_F_ADAPTER_REMOVED)
		return SUCCESS;
	printk(KERN_NOTICE
	printk(KERN_NOTICE
		"arcmsr%d: abort device command of scsi id = %d lun = %d\n",
		"arcmsr%d: abort device command of scsi id = %d lun = %d\n",
		acb->host->host_no, cmd->device->id, (u32)cmd->device->lun);
		acb->host->host_no, cmd->device->id, (u32)cmd->device->lun);