⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qla_os.c

📁 h内核
💻 C
📖 第 1 页 / 共 5 页
字号:
    loff_t off, size_t count){	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,	    struct device, kobj)));	uint16_t	*witer;	unsigned long	flags;	uint16_t	cnt;	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != sizeof(nvram_t))		return 0;	/* Read NVRAM. */	spin_lock_irqsave(&ha->hardware_lock, flags);	qla2x00_lock_nvram_access(ha); 	witer = (uint16_t *)buf; 	for (cnt = 0; cnt < count / 2; cnt++) {		*witer = cpu_to_le16(qla2x00_get_nvram_word(ha,		    cnt+ha->nvram_base));		witer++; 	}	qla2x00_unlock_nvram_access(ha);	spin_unlock_irqrestore(&ha->hardware_lock, flags);	return (count);}static ssize_t qla2x00_sysfs_write_nvram(struct kobject *kobj, char *buf,    loff_t off, size_t count){	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,	    struct device, kobj)));	uint8_t		*iter;	uint16_t	*witer;	unsigned long	flags;	uint16_t	cnt;	uint8_t		chksum;	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != sizeof(nvram_t))		return 0;	/* Checksum NVRAM. */	iter = (uint8_t *)buf;	chksum = 0;	for (cnt = 0; cnt < count - 1; cnt++)		chksum += *iter++;	chksum = ~chksum + 1;	*iter = chksum;	/* Write NVRAM. */	spin_lock_irqsave(&ha->hardware_lock, flags);	qla2x00_lock_nvram_access(ha);	qla2x00_release_nvram_protection(ha); 	witer = (uint16_t *)buf;	for (cnt = 0; cnt < count / 2; cnt++) {		qla2x00_write_nvram_word(ha, cnt+ha->nvram_base,		    cpu_to_le16(*witer));		witer++;	}	qla2x00_unlock_nvram_access(ha);	spin_unlock_irqrestore(&ha->hardware_lock, flags);	return (count);}/* -------------------------------------------------------------------------- */static char *qla2x00_get_pci_info_str(struct scsi_qla_host *ha, char *str){	static char *pci_bus_modes[] = {		"33", "66", "100", "133",	};	uint16_t pci_bus;	strcpy(str, "PCI");	pci_bus = (ha->pci_attr & (BIT_9 | BIT_10)) >> 9;	if (pci_bus) {		strcat(str, "-X (");		strcat(str, pci_bus_modes[pci_bus]);	} else {		pci_bus = (ha->pci_attr & BIT_8) >> 8;		strcat(str, " (");		strcat(str, pci_bus_modes[pci_bus]);	}	strcat(str, " MHz)");	return (str);}char *qla2x00_get_fw_version_str(struct scsi_qla_host *ha, char *str){	char un_str[10];		sprintf(str, "%d.%02d.%02d ", ha->fw_major_version,	    ha->fw_minor_version,	    ha->fw_subminor_version);	if (ha->fw_attributes & BIT_9) {		strcat(str, "FLX");		return (str);	}	switch (ha->fw_attributes & 0xFF) {	case 0x7:		strcat(str, "EF");		break;	case 0x17:		strcat(str, "TP");		break;	case 0x37:		strcat(str, "IP");		break;	case 0x77:		strcat(str, "VI");		break;	default:		sprintf(un_str, "(%x)", ha->fw_attributes);		strcat(str, un_str);		break;	}	if (ha->fw_attributes & 0x100)		strcat(str, "X");	return (str);}/*************************************************************************** qla2x00_queuecommand** Description:*     Queue a command to the controller.** Input:*     cmd - pointer to Scsi cmd structure*     fn - pointer to Scsi done function** Returns:*   0 - Always** Note:* The mid-level driver tries to ensures 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).**************************************************************************/static intqla2x00_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *)){	fc_port_t	*fcport;	os_lun_t	*lq;	os_tgt_t	*tq;	scsi_qla_host_t	*ha, *ha2;	srb_t		*sp;	struct Scsi_Host *host;	unsigned int	b, t, l;	unsigned long	handle;	int		was_empty;	host = cmd->device->host;	ha = (scsi_qla_host_t *) host->hostdata;	was_empty = 1;	cmd->scsi_done = fn;	spin_unlock_irq(ha->host->host_lock);	/*	 * Allocate a command packet from the "sp" pool.  If we cant get back	 * one then let scsi layer come back later.	 */	if ((sp = qla2x00_get_new_sp(ha)) == NULL) {		qla_printk(KERN_WARNING, ha,		    "Couldn't allocate memory for sp - retried.\n");		spin_lock_irq(ha->host->host_lock);		return (1);	}	sp->cmd = cmd;	CMD_SP(cmd) = (void *)sp;	sp->flags = 0;	if (CMD_RESID_LEN(cmd) & SRB_IOCTL) {		/* Need to set sp->flags */		sp->flags |= SRB_IOCTL;		CMD_RESID_LEN(cmd) = 0; /* Clear it since no more use. */	}	sp->fo_retry_cnt = 0;	sp->err_id = 0;	/* Generate LU queue on bus, target, LUN */	b = cmd->device->channel;	t = cmd->device->id;	l = cmd->device->lun;	/*	 * Start Command Timer. Typically it will be 2 seconds less than what	 * is requested by the Host such that we can return the IO before	 * aborts are called.	 */	if ((cmd->timeout_per_command / HZ) > QLA_CMD_TIMER_DELTA)		qla2x00_add_timer_to_cmd(sp,		    (cmd->timeout_per_command / HZ) - QLA_CMD_TIMER_DELTA);	else		qla2x00_add_timer_to_cmd(sp, cmd->timeout_per_command / HZ);	if (l >= ha->max_luns) {		cmd->result = DID_NO_CONNECT << 16;		sp->err_id = SRB_ERR_PORT;		spin_lock_irq(ha->host->host_lock);		sp_put(ha, sp);		return (0);	}	if ((tq = (os_tgt_t *) TGT_Q(ha, t)) != NULL &&	    (lq = (os_lun_t *) LUN_Q(ha, t, l)) != NULL) {		fcport = lq->fclun->fcport;		ha2 = fcport->ha;	} else {		lq = NULL;		fcport = NULL;		ha2 = ha;	}	/* Set an invalid handle until we issue the command to ISP */	/* then we will set the real handle value.                 */	handle = INVALID_HANDLE;	cmd->host_scribble = (unsigned char *)handle;	/* Bookkeeping information */	sp->r_start = jiffies;		/* Time the request was recieved. */	sp->u_start = 0;	/* Setup device queue pointers. */	sp->tgt_queue = tq;	sp->lun_queue = lq;	/*	 * NOTE : q is NULL	 *	 * 1. When device is added from persistent binding but has not been	 *    discovered yet.The state of loopid == PORT_AVAIL.	 * 2. When device is never found on the bus.(loopid == UNUSED)	 *	 * IF Device Queue is not created, or device is not in a valid state	 * and link down error reporting is enabled, reject IO.	 */	if (fcport == NULL) {		DEBUG3(printk("scsi(%ld:%2d:%2d): port unavailable\n",		    ha->host_no,t,l));		cmd->result = DID_NO_CONNECT << 16;		sp->err_id = SRB_ERR_PORT;		spin_lock_irq(ha->host->host_lock);		sp_put(ha, sp);		return (0);	}	/* Only modify the allowed count if the target is a *non* tape device */	if ((fcport->flags & FCF_TAPE_PRESENT) == 0) {		sp->flags &= ~SRB_TAPE;		if (cmd->allowed < ql2xretrycount) {			cmd->allowed = ql2xretrycount;		}	} else		sp->flags |= SRB_TAPE;	DEBUG5(printk("scsi(%ld:%2d:%2d): (queuecmd) queue sp = %p, "	    "flags=0x%x fo retry=%d, pid=%ld\n",	    ha->host_no, t, l, sp, sp->flags, sp->fo_retry_cnt,	    cmd->serial_number));	DEBUG5(qla2x00_print_scsi_cmd(cmd));	sp->fclun = lq->fclun;	sp->ha = ha2;	if (cmd->sc_data_direction == DMA_BIDIRECTIONAL &&	    cmd->request_bufflen != 0) {		DEBUG2(printk(KERN_WARNING		    "scsi(%ld): Incorrect data direction - transfer "		    "length=%d, direction=%d, pid=%ld, opcode=%x\n",		    ha->host_no, cmd->request_bufflen, cmd->sc_data_direction,		    cmd->serial_number, cmd->cmnd[0]));	}	/* Final pre-check :	 *	 *	Either PORT_DOWN_TIMER OR LINK_DOWN_TIMER Expired.	 */	if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||	    atomic_read(&ha2->loop_state) == LOOP_DEAD) {		/*		 * Add the command to the done-queue for later failover		 * processing.		 */		cmd->result = DID_NO_CONNECT << 16;		if (atomic_read(&ha2->loop_state) == LOOP_DOWN) 			sp->err_id = SRB_ERR_LOOP;		else			sp->err_id = SRB_ERR_PORT;		add_to_done_queue(ha, sp);		qla2x00_done(ha);		spin_lock_irq(ha->host->host_lock);		return (0);	}	if (tq && test_bit(TQF_SUSPENDED, &tq->flags) &&	    (sp->flags & SRB_TAPE) == 0) {		/* If target suspended put incoming I/O in retry_q. */		qla2x00_extend_timeout(sp->cmd, 10);		add_to_scsi_retry_queue(ha, sp);	} else		was_empty = add_to_pending_queue(ha, sp);	if ((IS_QLA2100(ha) || IS_QLA2200(ha)) && ha->flags.online) {		if (ha->response_ring_ptr->signature != RESPONSE_PROCESSED) {			unsigned long flags;			spin_lock_irqsave(&ha->hardware_lock, flags);				qla2x00_process_response_queue(ha);			spin_unlock_irqrestore(&ha->hardware_lock, flags);		}	}	/* We submit to the hardware if:	 *	 *	1) we're on the cpu the irq's arrive on or	 *	2) there are very few io's outstanding.	 *	 * In all other cases we'll let an irq pick up our IO and submit it	 * to the controller to improve affinity.	 */	if (_smp_processor_id() == ha->last_irq_cpu || was_empty)		qla2x00_next(ha);	spin_lock_irq(ha->host->host_lock);	return (0);}/* * qla2x00_eh_wait_on_command *    Waits for the command to be returned by the Firmware for some *    max time. * * Input: *    ha = actual ha whose done queue will contain the command *	      returned by firmware. *    cmd = Scsi Command to wait on. *    flag = Abort/Reset(Bus or Device Reset) * * Return: *    Not Found : 0 *    Found : 1 */static intqla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd){#define ABORT_POLLING_PERIOD	HZ#define ABORT_WAIT_TIME		((10 * HZ) / (ABORT_POLLING_PERIOD))	int		found = 0;	int		done = 0;	srb_t		*rp = NULL;	struct list_head *list, *temp;	u_long		max_wait_time = ABORT_WAIT_TIME;	do {		/* Check on done queue */		spin_lock(&ha->list_lock);		list_for_each_safe(list, temp, &ha->done_queue) {			rp = list_entry(list, srb_t, list);			/*			 * Found command. Just exit and wait for the cmd sent			 * to OS.			*/			if (cmd == rp->cmd) {				found++;				DEBUG3(printk("%s: found in done queue.\n",				    __func__);)				break;			}		}		spin_unlock(&ha->list_lock);		/* Complete the cmd right away. */		if (found) { 			qla2x00_delete_from_done_queue(ha, rp);			sp_put(ha, rp);			done++;			break;		}		spin_unlock_irq(ha->host->host_lock);		set_current_state(TASK_UNINTERRUPTIBLE);		schedule_timeout(ABORT_POLLING_PERIOD);		spin_lock_irq(ha->host->host_lock);	} while ((max_wait_time--));	if (done)		DEBUG2(printk(KERN_INFO "%s: found cmd=%p.\n", __func__, cmd));	return (done);}/* * qla2x00_wait_for_hba_online *    Wait till the HBA is online after going through  *    <= MAX_RETRIES_OF_ISP_ABORT  or *    finally HBA is disabled ie marked offline * * Input: *     ha - pointer to host adapter structure *  * Note:     *    Does context switching-Release SPIN_LOCK *    (if any) before calling this routine. * * Return: *    Success (Adapter is online) : 0 *    Failed  (Adapter is offline/disabled) : 1 */static int qla2x00_wait_for_hba_online(scsi_qla_host_t *ha){	int 	 return_status;	unsigned long wait_online;	wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ); 	while (((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) ||	    test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||	    test_bit(ISP_ABORT_RETRY, &ha->dpc_flags) ||	    ha->dpc_active) && time_before(jiffies, wait_online)) {		msleep(1000);	}	if (ha->flags.online) 		return_status = QLA_SUCCESS; 	else		return_status = QLA_FUNCTION_FAILED;	DEBUG2(printk("%s return_status=%d\n",__func__,return_status));	return (return_status);}/* * qla2x00_wait_for_loop_ready *    Wait for MAX_LOOP_TIMEOUT(5 min) value for loop *    to be in LOOP_READY state.	  * Input: *     ha - pointer to host adapter structure *  * Note:     *    Does context switching-Release SPIN_LOCK *    (if any) before calling this routine. *     * * Return: *    Success (LOOP_READY) : 0 *    Failed  (LOOP_NOT_READY) : 1 */static inline int qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha){	int 	 return_status = QLA_SUCCESS;	unsigned long loop_timeout ;	/* wait for 5 min at the max for loop to be ready */	loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ); 	while ((!atomic_read(&ha->loop_down_timer) &&	    atomic_read(&ha->loop_state) == LOOP_DOWN) ||	    test_bit(CFG_ACTIVE, &ha->cfg_flags) ||	    atomic_read(&ha->loop_state) != LOOP_READY) {		msleep(1000);		if (time_after_eq(jiffies, loop_timeout)) {			return_status = QLA_FUNCTION_FAILED;			break;		}	}	return (return_status);	}/*************************************************************************** qla2xxx_eh_abort** Description:*    The abort function will abort the specified command.** Input:*    cmd = Linux SCSI command packet to be aborted.** Returns:*    Either SUCCESS or FAILED.** Note:**************************************************************************/intqla2xxx_eh_abort(struct scsi_cmnd *cmd){

⌨️ 快捷键说明

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