ql4_os.c

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

C
1,732
字号
 *	that the command has been processed. * * Remarks: * This routine is invoked by Linux to send a SCSI command to the driver. * The mid-level driver tries to ensure that queuecommand never gets * invoked concurrently with itself or the interrupt handler (although * the interrupt handler may call this routine as part of request- * completion handling).   Unfortunely, it sometimes calls the scheduler * in interrupt context which is a big NO! NO!. **/static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,				void (*done)(struct scsi_cmnd *)){	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);	struct ddb_entry *ddb_entry = cmd->device->hostdata;	struct srb *srb;	int rval;	if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) {		if (atomic_read(&ddb_entry->state) == DDB_STATE_DEAD) {			cmd->result = DID_NO_CONNECT << 16;			goto qc_fail_command;		}		goto qc_host_busy;	}	if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags))		goto qc_host_busy;	spin_unlock_irq(ha->host->host_lock);	srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd, done);	if (!srb)		goto qc_host_busy_lock;	rval = qla4xxx_send_command_to_isp(ha, srb);	if (rval != QLA_SUCCESS)		goto qc_host_busy_free_sp;	spin_lock_irq(ha->host->host_lock);	return 0;qc_host_busy_free_sp:	qla4xxx_srb_free_dma(ha, srb);	mempool_free(srb, ha->srb_mempool);qc_host_busy_lock:	spin_lock_irq(ha->host->host_lock);qc_host_busy:	return SCSI_MLQUEUE_HOST_BUSY;qc_fail_command:	done(cmd);	return 0;}/** * qla4xxx_mem_free - frees memory allocated to adapter * @ha: Pointer to host adapter structure. * * Frees memory previously allocated by qla4xxx_mem_alloc **/static void qla4xxx_mem_free(struct scsi_qla_host *ha){	if (ha->queues)		dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues,				  ha->queues_dma);	ha->queues_len = 0;	ha->queues = NULL;	ha->queues_dma = 0;	ha->request_ring = NULL;	ha->request_dma = 0;	ha->response_ring = NULL;	ha->response_dma = 0;	ha->shadow_regs = NULL;	ha->shadow_regs_dma = 0;	/* Free srb pool. */	if (ha->srb_mempool)		mempool_destroy(ha->srb_mempool);	ha->srb_mempool = NULL;	/* release io space registers  */	if (ha->reg)		iounmap(ha->reg);	pci_release_regions(ha->pdev);}/** * qla4xxx_mem_alloc - allocates memory for use by adapter. * @ha: Pointer to host adapter structure * * Allocates DMA memory for request and response queues. Also allocates memory * for srbs. **/static int qla4xxx_mem_alloc(struct scsi_qla_host *ha){	unsigned long align;	/* Allocate contiguous block of DMA memory for queues. */	ha->queues_len = ((REQUEST_QUEUE_DEPTH * QUEUE_SIZE) +			  (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE) +			  sizeof(struct shadow_regs) +			  MEM_ALIGN_VALUE +			  (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);	ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len,					&ha->queues_dma, GFP_KERNEL);	if (ha->queues == NULL) {		dev_warn(&ha->pdev->dev,			"Memory Allocation failed - queues.\n");		goto mem_alloc_error_exit;	}	memset(ha->queues, 0, ha->queues_len);	/*	 * As per RISC alignment requirements -- the bus-address must be a	 * multiple of the request-ring size (in bytes).	 */	align = 0;	if ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1))		align = MEM_ALIGN_VALUE - ((unsigned long)ha->queues_dma &					   (MEM_ALIGN_VALUE - 1));	/* Update request and response queue pointers. */	ha->request_dma = ha->queues_dma + align;	ha->request_ring = (struct queue_entry *) (ha->queues + align);	ha->response_dma = ha->queues_dma + align +		(REQUEST_QUEUE_DEPTH * QUEUE_SIZE);	ha->response_ring = (struct queue_entry *) (ha->queues + align +						    (REQUEST_QUEUE_DEPTH *						     QUEUE_SIZE));	ha->shadow_regs_dma = ha->queues_dma + align +		(REQUEST_QUEUE_DEPTH * QUEUE_SIZE) +		(RESPONSE_QUEUE_DEPTH * QUEUE_SIZE);	ha->shadow_regs = (struct shadow_regs *) (ha->queues + align +						  (REQUEST_QUEUE_DEPTH *						   QUEUE_SIZE) +						  (RESPONSE_QUEUE_DEPTH *						   QUEUE_SIZE));	/* Allocate memory for srb pool. */	ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab,					 mempool_free_slab, srb_cachep);	if (ha->srb_mempool == NULL) {		dev_warn(&ha->pdev->dev,			"Memory Allocation failed - SRB Pool.\n");		goto mem_alloc_error_exit;	}	return QLA_SUCCESS;mem_alloc_error_exit:	qla4xxx_mem_free(ha);	return QLA_ERROR;}/** * qla4xxx_timer - checks every second for work to do. * @ha: Pointer to host adapter structure. **/static void qla4xxx_timer(struct scsi_qla_host *ha){	struct ddb_entry *ddb_entry, *dtemp;	int start_dpc = 0;	/* Search for relogin's to time-out and port down retry. */	list_for_each_entry_safe(ddb_entry, dtemp, &ha->ddb_list, list) {		/* Count down time between sending relogins */		if (adapter_up(ha) &&		    !test_bit(DF_RELOGIN, &ddb_entry->flags) &&		    atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) {			if (atomic_read(&ddb_entry->retry_relogin_timer) !=			    INVALID_ENTRY) {				if (atomic_read(&ddb_entry->retry_relogin_timer)				    		== 0) {					atomic_set(&ddb_entry->						retry_relogin_timer,						INVALID_ENTRY);					set_bit(DPC_RELOGIN_DEVICE,						&ha->dpc_flags);					set_bit(DF_RELOGIN, &ddb_entry->flags);					DEBUG2(printk("scsi%ld: %s: index [%d]"						      " login device\n",						      ha->host_no, __func__,						      ddb_entry->fw_ddb_index));				} else					atomic_dec(&ddb_entry->							retry_relogin_timer);			}		}		/* Wait for relogin to timeout */		if (atomic_read(&ddb_entry->relogin_timer) &&		    (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) {			/*			 * If the relogin times out and the device is			 * still NOT ONLINE then try and relogin again.			 */			if (atomic_read(&ddb_entry->state) !=			    DDB_STATE_ONLINE &&			    ddb_entry->fw_ddb_device_state ==			    DDB_DS_SESSION_FAILED) {				/* Reset retry relogin timer */				atomic_inc(&ddb_entry->relogin_retry_count);				DEBUG2(printk("scsi%ld: index[%d] relogin"					      " timed out-retrying"					      " relogin (%d)\n",					      ha->host_no,					      ddb_entry->fw_ddb_index,					      atomic_read(&ddb_entry->							  relogin_retry_count))					);				start_dpc++;				DEBUG(printk("scsi%ld:%d:%d: index [%d] "					     "initate relogin after"					     " %d seconds\n",					     ha->host_no, ddb_entry->bus,					     ddb_entry->target,					     ddb_entry->fw_ddb_index,					     ddb_entry->default_time2wait + 4)					);				atomic_set(&ddb_entry->retry_relogin_timer,					   ddb_entry->default_time2wait + 4);			}		}	}	/* Check for heartbeat interval. */	if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE &&	    ha->heartbeat_interval != 0) {		ha->seconds_since_last_heartbeat++;		if (ha->seconds_since_last_heartbeat >		    ha->heartbeat_interval + 2)			set_bit(DPC_RESET_HA, &ha->dpc_flags);	}	/* Wakeup the dpc routine for this adapter, if needed. */	if ((start_dpc ||	     test_bit(DPC_RESET_HA, &ha->dpc_flags) ||	     test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) ||	     test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) ||	     test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) ||	     test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||	     test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) ||	     test_bit(DPC_AEN, &ha->dpc_flags)) &&	     ha->dpc_thread) {		DEBUG2(printk("scsi%ld: %s: scheduling dpc routine"			      " - dpc flags = 0x%lx\n",			      ha->host_no, __func__, ha->dpc_flags));		queue_work(ha->dpc_thread, &ha->dpc_work);	}	/* Reschedule timer thread to call us back in one second */	mod_timer(&ha->timer, jiffies + HZ);	DEBUG2(ha->seconds_since_last_intr++);}/** * qla4xxx_cmd_wait - waits for all outstanding commands to complete * @ha: Pointer to host adapter structure. * * This routine stalls the driver until all outstanding commands are returned. * Caller must release the Hardware Lock prior to calling this routine. **/static int qla4xxx_cmd_wait(struct scsi_qla_host *ha){	uint32_t index = 0;	int stat = QLA_SUCCESS;	unsigned long flags;	struct scsi_cmnd *cmd;	int wait_cnt = WAIT_CMD_TOV;	/*					 * Initialized for 30 seconds as we					 * expect all commands to retuned					 * ASAP.					 */	while (wait_cnt) {		spin_lock_irqsave(&ha->hardware_lock, flags);		/* Find a command that hasn't completed. */		for (index = 0; index < ha->host->can_queue; index++) {			cmd = scsi_host_find_tag(ha->host, index);			if (cmd != NULL)				break;		}		spin_unlock_irqrestore(&ha->hardware_lock, flags);		/* If No Commands are pending, wait is complete */		if (index == ha->host->can_queue) {			break;		}		/* If we timed out on waiting for commands to come back		 * return ERROR.		 */		wait_cnt--;		if (wait_cnt == 0)			stat = QLA_ERROR;		else {			msleep(1000);		}	}			/* End of While (wait_cnt) */	return stat;}void qla4xxx_hw_reset(struct scsi_qla_host *ha){	uint32_t ctrl_status;	unsigned long flags = 0;	DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__));	spin_lock_irqsave(&ha->hardware_lock, flags);	/*	 * If the SCSI Reset Interrupt bit is set, clear it.	 * Otherwise, the Soft Reset won't work.	 */	ctrl_status = readw(&ha->reg->ctrl_status);	if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0)		writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status);	/* Issue Soft Reset */	writel(set_rmask(CSR_SOFT_RESET), &ha->reg->ctrl_status);	readl(&ha->reg->ctrl_status);	spin_unlock_irqrestore(&ha->hardware_lock, flags);}/** * qla4xxx_soft_reset - performs soft reset. * @ha: Pointer to host adapter structure. **/int qla4xxx_soft_reset(struct scsi_qla_host *ha){	uint32_t max_wait_time;	unsigned long flags = 0;	int status = QLA_ERROR;	uint32_t ctrl_status;	qla4xxx_hw_reset(ha);	/* Wait until the Network Reset Intr bit is cleared */	max_wait_time = RESET_INTR_TOV;	do {		spin_lock_irqsave(&ha->hardware_lock, flags);		ctrl_status = readw(&ha->reg->ctrl_status);		spin_unlock_irqrestore(&ha->hardware_lock, flags);		if ((ctrl_status & CSR_NET_RESET_INTR) == 0)			break;		msleep(1000);	} while ((--max_wait_time));	if ((ctrl_status & CSR_NET_RESET_INTR) != 0) {		DEBUG2(printk(KERN_WARNING			      "scsi%ld: Network Reset Intr not cleared by "			      "Network function, clearing it now!\n",			      ha->host_no));		spin_lock_irqsave(&ha->hardware_lock, flags);		writel(set_rmask(CSR_NET_RESET_INTR), &ha->reg->ctrl_status);		readl(&ha->reg->ctrl_status);		spin_unlock_irqrestore(&ha->hardware_lock, flags);	}	/* Wait until the firmware tells us the Soft Reset is done */	max_wait_time = SOFT_RESET_TOV;	do {		spin_lock_irqsave(&ha->hardware_lock, flags);		ctrl_status = readw(&ha->reg->ctrl_status);		spin_unlock_irqrestore(&ha->hardware_lock, flags);		if ((ctrl_status & CSR_SOFT_RESET) == 0) {			status = QLA_SUCCESS;			break;		}		msleep(1000);	} while ((--max_wait_time));	/*	 * Also, make sure that the SCSI Reset Interrupt bit has been cleared	 * after the soft reset has taken place.	 */	spin_lock_irqsave(&ha->hardware_lock, flags);	ctrl_status = readw(&ha->reg->ctrl_status);	if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) {		writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status);		readl(&ha->reg->ctrl_status);	}	spin_unlock_irqrestore(&ha->hardware_lock, flags);	/* If soft reset fails then most probably the bios on other	 * function is also enabled.	 * Since the initialization is sequential the other fn	 * wont be able to acknowledge the soft reset.	 * Issue a force soft reset to workaround this scenario.	 */	if (max_wait_time == 0) {		/* Issue Force Soft Reset */		spin_lock_irqsave(&ha->hardware_lock, flags);		writel(set_rmask(CSR_FORCE_SOFT_RESET), &ha->reg->ctrl_status);		readl(&ha->reg->ctrl_status);		spin_unlock_irqrestore(&ha->hardware_lock, flags);		/* Wait until the firmware tells us the Soft Reset is done */		max_wait_time = SOFT_RESET_TOV;		do {			spin_lock_irqsave(&ha->hardware_lock, flags);			ctrl_status = readw(&ha->reg->ctrl_status);			spin_unlock_irqrestore(&ha->hardware_lock, flags);			if ((ctrl_status & CSR_FORCE_SOFT_RESET) == 0) {				status = QLA_SUCCESS;				break;			}			msleep(1000);		} while ((--max_wait_time));	}	return status;}

⌨️ 快捷键说明

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