ql4_os.c

来自「linux 内核源代码」· C语言 代码 · 共 1,732 行 · 第 1/4 页

C
1,732
字号
		ret = -ENODEV;		goto probe_failed;	}	INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc);	ret = request_irq(pdev->irq, qla4xxx_intr_handler,			  IRQF_DISABLED | IRQF_SHARED, "qla4xxx", ha);	if (ret) {		dev_warn(&ha->pdev->dev, "Failed to reserve interrupt %d"			" already in use.\n", pdev->irq);		goto probe_failed;	}	set_bit(AF_IRQ_ATTACHED, &ha->flags);	host->irq = pdev->irq;	DEBUG(printk("scsi%d: irq %d attached\n", ha->host_no, ha->pdev->irq));	qla4xxx_enable_intrs(ha);	/* Start timer thread. */	qla4xxx_start_timer(ha, qla4xxx_timer, 1);	set_bit(AF_INIT_DONE, &ha->flags);	pci_set_drvdata(pdev, ha);	ret = scsi_add_host(host, &pdev->dev);	if (ret)		goto probe_failed;	/* Update transport device information for all devices. */	list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) {		if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE)			if (qla4xxx_add_sess(ddb_entry))				goto remove_host;	}	printk(KERN_INFO	       " QLogic iSCSI HBA Driver version: %s\n"	       "  QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n",	       qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev),	       ha->host_no, ha->firmware_version[0], ha->firmware_version[1],	       ha->patch_number, ha->build_number);	return 0;remove_host:	qla4xxx_free_ddb_list(ha);	scsi_remove_host(host);probe_failed:	qla4xxx_free_adapter(ha);	scsi_host_put(ha->host);probe_disable_device:	pci_disable_device(pdev);	return ret;}/** * qla4xxx_remove_adapter - calback function to remove adapter. * @pci_dev: PCI device pointer **/static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev){	struct scsi_qla_host *ha;	ha = pci_get_drvdata(pdev);	qla4xxx_disable_intrs(ha);	while (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags))		ssleep(1);	/* remove devs from iscsi_sessions to scsi_devices */	qla4xxx_free_ddb_list(ha);	scsi_remove_host(ha->host);	qla4xxx_free_adapter(ha);	scsi_host_put(ha->host);	pci_set_drvdata(pdev, NULL);}/** * qla4xxx_config_dma_addressing() - Configure OS DMA addressing method. * @ha: HA context * * At exit, the @ha's flags.enable_64bit_addressing set to indicated * supported addressing method. */static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha){	int retval;	/* Update our PCI device dma_mask for full 64 bit mask */	if (pci_set_dma_mask(ha->pdev, DMA_64BIT_MASK) == 0) {		if (pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) {			dev_dbg(&ha->pdev->dev,				  "Failed to set 64 bit PCI consistent mask; "				   "using 32 bit.\n");			retval = pci_set_consistent_dma_mask(ha->pdev,							     DMA_32BIT_MASK);		}	} else		retval = pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK);}static int qla4xxx_slave_alloc(struct scsi_device *sdev){	struct iscsi_cls_session *sess = starget_to_session(sdev->sdev_target);	struct ddb_entry *ddb = sess->dd_data;	sdev->hostdata = ddb;	sdev->tagged_supported = 1;	scsi_activate_tcq(sdev, sdev->host->can_queue);	return 0;}static int qla4xxx_slave_configure(struct scsi_device *sdev){	sdev->tagged_supported = 1;	return 0;}static void qla4xxx_slave_destroy(struct scsi_device *sdev){	scsi_deactivate_tcq(sdev, 1);}/** * qla4xxx_del_from_active_array - returns an active srb * @ha: Pointer to host adapter structure. * @index: index into to the active_array * * This routine removes and returns the srb at the specified index **/struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index){	struct srb *srb = NULL;	struct scsi_cmnd *cmd;	if (!(cmd = scsi_host_find_tag(ha->host, index)))		return srb;	if (!(srb = (struct srb *)cmd->host_scribble))		return srb;	/* update counters */	if (srb->flags & SRB_DMA_VALID) {		ha->req_q_count += srb->iocb_cnt;		ha->iocb_cnt -= srb->iocb_cnt;		if (srb->cmd)			srb->cmd->host_scribble = NULL;	}	return srb;}/** * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware * @ha: actual ha whose done queue will contain the comd returned by firmware. * @cmd: Scsi Command to wait on. * * This routine waits for the command to be returned by the Firmware * for some max time. **/static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha,				      struct scsi_cmnd *cmd){	int done = 0;	struct srb *rp;	uint32_t max_wait_time = EH_WAIT_CMD_TOV;	do {		/* Checking to see if its returned to OS */		rp = (struct srb *) cmd->SCp.ptr;		if (rp == NULL) {			done++;			break;		}		msleep(2000);	} while (max_wait_time--);	return done;}/** * qla4xxx_wait_for_hba_online - waits for HBA to come online * @ha: Pointer to host adapter structure **/static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha){	unsigned long wait_online;	wait_online = jiffies + (30 * HZ);	while (time_before(jiffies, wait_online)) {		if (adapter_up(ha))			return QLA_SUCCESS;		else if (ha->retry_reset_ha_cnt == 0)			return QLA_ERROR;		msleep(2000);	}	return QLA_ERROR;}/** * qla4xxx_eh_wait_for_active_target_commands - wait for active cmds to finish. * @ha: pointer to to HBA * @t: target id * @l: lun id * * This function waits for all outstanding commands to a lun to complete. It * returns 0 if all pending commands are returned and 1 otherwise. **/static int qla4xxx_eh_wait_for_active_target_commands(struct scsi_qla_host *ha,						 int t, int l){	int cnt;	int status = 0;	struct scsi_cmnd *cmd;	/*	 * Waiting for all commands for the designated target in the active	 * array	 */	for (cnt = 0; cnt < ha->host->can_queue; cnt++) {		cmd = scsi_host_find_tag(ha->host, cnt);		if (cmd && cmd->device->id == t && cmd->device->lun == l) {			if (!qla4xxx_eh_wait_on_command(ha, cmd)) {				status++;				break;			}		}	}	return status;}/** * qla4xxx_eh_device_reset - callback for target reset. * @cmd: Pointer to Linux's SCSI command structure * * This routine is called by the Linux OS to reset all luns on the * specified target. **/static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd){	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);	struct ddb_entry *ddb_entry = cmd->device->hostdata;	struct srb *sp;	int ret = FAILED, stat;	sp = (struct srb *) cmd->SCp.ptr;	if (!sp || !ddb_entry)		return ret;	dev_info(&ha->pdev->dev,		   "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no,		   cmd->device->channel, cmd->device->id, cmd->device->lun);	DEBUG2(printk(KERN_INFO		      "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"		      "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,		      cmd, jiffies, cmd->timeout_per_command / HZ,		      ha->dpc_flags, cmd->result, cmd->allowed));	/* FIXME: wait for hba to go online */	stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun);	if (stat != QLA_SUCCESS) {		dev_info(&ha->pdev->dev, "DEVICE RESET FAILED. %d\n", stat);		goto eh_dev_reset_done;	}	/* Send marker. */	ha->marker_needed = 1;	/*	 * If we are coming down the EH path, wait for all commands to complete	 * for the device.	 */	if (cmd->device->host->shost_state == SHOST_RECOVERY) {		if (qla4xxx_eh_wait_for_active_target_commands(ha,							  cmd->device->id,							  cmd->device->lun)){			dev_info(&ha->pdev->dev,				   "DEVICE RESET FAILED - waiting for "				   "commands.\n");			goto eh_dev_reset_done;		}	}	dev_info(&ha->pdev->dev,		   "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n",		   ha->host_no, cmd->device->channel, cmd->device->id,		   cmd->device->lun);	ret = SUCCESS;eh_dev_reset_done:	return ret;}/** * qla4xxx_eh_host_reset - kernel callback * @cmd: Pointer to Linux's SCSI command structure * * This routine is invoked by the Linux kernel to perform fatal error * recovery on the specified adapter. **/static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd){	int return_status = FAILED;	struct scsi_qla_host *ha;	ha = (struct scsi_qla_host *) cmd->device->host->hostdata;	dev_info(&ha->pdev->dev,		   "scsi(%ld:%d:%d:%d): ADAPTER RESET ISSUED.\n", ha->host_no,		   cmd->device->channel, cmd->device->id, cmd->device->lun);	if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) {		DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host.  Adapter "			      "DEAD.\n", ha->host_no, cmd->device->channel,			      __func__));		return FAILED;	}	if (qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST) == QLA_SUCCESS) {		return_status = SUCCESS;	}	dev_info(&ha->pdev->dev, "HOST RESET %s.\n",		   return_status == FAILED ? "FAILED" : "SUCCEDED");	return return_status;}static struct pci_device_id qla4xxx_pci_tbl[] = {	{		.vendor		= PCI_VENDOR_ID_QLOGIC,		.device		= PCI_DEVICE_ID_QLOGIC_ISP4010,		.subvendor	= PCI_ANY_ID,		.subdevice	= PCI_ANY_ID,	},	{		.vendor		= PCI_VENDOR_ID_QLOGIC,		.device		= PCI_DEVICE_ID_QLOGIC_ISP4022,		.subvendor	= PCI_ANY_ID,		.subdevice	= PCI_ANY_ID,	},	{		.vendor		= PCI_VENDOR_ID_QLOGIC,		.device		= PCI_DEVICE_ID_QLOGIC_ISP4032,		.subvendor	= PCI_ANY_ID,		.subdevice	= PCI_ANY_ID,	},	{0, 0},};MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);static struct pci_driver qla4xxx_pci_driver = {	.name		= DRIVER_NAME,	.id_table	= qla4xxx_pci_tbl,	.probe		= qla4xxx_probe_adapter,	.remove		= qla4xxx_remove_adapter,};static int __init qla4xxx_module_init(void){	int ret;	/* Allocate cache for SRBs. */	srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0,				       SLAB_HWCACHE_ALIGN, NULL);	if (srb_cachep == NULL) {		printk(KERN_ERR		       "%s: Unable to allocate SRB cache..."		       "Failing load!\n", DRIVER_NAME);		ret = -ENOMEM;		goto no_srp_cache;	}	/* Derive version string. */	strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION);	if (ql4xextended_error_logging)		strcat(qla4xxx_version_str, "-debug");	qla4xxx_scsi_transport =		iscsi_register_transport(&qla4xxx_iscsi_transport);	if (!qla4xxx_scsi_transport){		ret = -ENODEV;		goto release_srb_cache;	}	ret = pci_register_driver(&qla4xxx_pci_driver);	if (ret)		goto unregister_transport;	printk(KERN_INFO "QLogic iSCSI HBA Driver\n");	return 0;unregister_transport:	iscsi_unregister_transport(&qla4xxx_iscsi_transport);release_srb_cache:	kmem_cache_destroy(srb_cachep);no_srp_cache:	return ret;}static void __exit qla4xxx_module_exit(void){	ql4_mod_unload = 1;	pci_unregister_driver(&qla4xxx_pci_driver);	iscsi_unregister_transport(&qla4xxx_iscsi_transport);	kmem_cache_destroy(srb_cachep);}module_init(qla4xxx_module_init);module_exit(qla4xxx_module_exit);MODULE_AUTHOR("QLogic Corporation");MODULE_DESCRIPTION("QLogic iSCSI HBA Driver");MODULE_LICENSE("GPL");MODULE_VERSION(QLA4XXX_DRIVER_VERSION);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?