qla_os.c

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

C
2,525
字号
qc24_fail_command:	done(cmd);	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	1000#define ABORT_WAIT_ITER		((10 * 1000) / (ABORT_POLLING_PERIOD))	unsigned long wait_iter = ABORT_WAIT_ITER;	int ret = QLA_SUCCESS;	while (CMD_SP(cmd)) {		msleep(ABORT_POLLING_PERIOD);		if (--wait_iter)			break;	}	if (CMD_SP(cmd))		ret = QLA_FUNCTION_FAILED;	return ret;}/* * 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 */intqla2x00_wait_for_hba_online(scsi_qla_host_t *ha){	int		return_status;	unsigned long	wait_online;	scsi_qla_host_t *pha = to_qla_parent(ha);	wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ);	while (((test_bit(ISP_ABORT_NEEDED, &pha->dpc_flags)) ||	    test_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags) ||	    test_bit(ISP_ABORT_RETRY, &pha->dpc_flags) ||	    pha->dpc_active) && time_before(jiffies, wait_online)) {		msleep(1000);	}	if (pha->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 intqla2x00_wait_for_loop_ready(scsi_qla_host_t *ha){	int 	 return_status = QLA_SUCCESS;	unsigned long loop_timeout ;	scsi_qla_host_t *pha = to_qla_parent(ha);	/* wait for 5 min at the max for loop to be ready */	loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ);	while ((!atomic_read(&pha->loop_down_timer) &&	    atomic_read(&pha->loop_state) == LOOP_DOWN) ||	    atomic_read(&pha->loop_state) != LOOP_READY) {		if (atomic_read(&pha->loop_state) == LOOP_DEAD) {			return_status = QLA_FUNCTION_FAILED;			break;		}		msleep(1000);		if (time_after_eq(jiffies, loop_timeout)) {			return_status = QLA_FUNCTION_FAILED;			break;		}	}	return (return_status);}static voidqla2x00_block_error_handler(struct scsi_cmnd *cmnd){	struct Scsi_Host *shost = cmnd->device->host;	struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));	unsigned long flags;	spin_lock_irqsave(shost->host_lock, flags);	while (rport->port_state == FC_PORTSTATE_BLOCKED) {		spin_unlock_irqrestore(shost->host_lock, flags);		msleep(1000);		spin_lock_irqsave(shost->host_lock, flags);	}	spin_unlock_irqrestore(shost->host_lock, flags);	return;}/*************************************************************************** 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:*    Only return FAILED if command not returned by firmware.**************************************************************************/static intqla2xxx_eh_abort(struct scsi_cmnd *cmd){	scsi_qla_host_t *ha = shost_priv(cmd->device->host);	srb_t *sp;	int ret, i;	unsigned int id, lun;	unsigned long serial;	unsigned long flags;	int wait = 0;	scsi_qla_host_t *pha = to_qla_parent(ha);	qla2x00_block_error_handler(cmd);	if (!CMD_SP(cmd))		return SUCCESS;	ret = SUCCESS;	id = cmd->device->id;	lun = cmd->device->lun;	serial = cmd->serial_number;	/* Check active list for command command. */	spin_lock_irqsave(&pha->hardware_lock, flags);	for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {		sp = pha->outstanding_cmds[i];		if (sp == NULL)			continue;		if (sp->cmd != cmd)			continue;		DEBUG2(printk("%s(%ld): aborting sp %p from RISC. pid=%ld.\n",		    __func__, ha->host_no, sp, serial));		DEBUG3(qla2x00_print_scsi_cmd(cmd));		spin_unlock_irqrestore(&pha->hardware_lock, flags);		if (ha->isp_ops->abort_command(ha, sp)) {			DEBUG2(printk("%s(%ld): abort_command "			    "mbx failed.\n", __func__, ha->host_no));		} else {			DEBUG3(printk("%s(%ld): abort_command "			    "mbx success.\n", __func__, ha->host_no));			wait = 1;		}		spin_lock_irqsave(&pha->hardware_lock, flags);		break;	}	spin_unlock_irqrestore(&pha->hardware_lock, flags);	/* Wait for the command to be returned. */	if (wait) {		if (qla2x00_eh_wait_on_command(ha, cmd) != QLA_SUCCESS) {			qla_printk(KERN_ERR, ha,			    "scsi(%ld:%d:%d): Abort handler timed out -- %lx "			    "%x.\n", ha->host_no, id, lun, serial, ret);			ret = FAILED;		}	}	qla_printk(KERN_INFO, ha,	    "scsi(%ld:%d:%d): Abort command issued -- %d %lx %x.\n",	    ha->host_no, id, lun, wait, serial, ret);	return ret;}/*************************************************************************** qla2x00_eh_wait_for_pending_target_commands** Description:*    Waits for all the commands to come back from the specified target.** Input:*    ha - pointer to scsi_qla_host structure.*    t  - target* Returns:*    Either SUCCESS or FAILED.** Note:**************************************************************************/static intqla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t){	int	cnt;	int	status;	srb_t		*sp;	struct scsi_cmnd *cmd;	unsigned long flags;	scsi_qla_host_t *pha = to_qla_parent(ha);	status = 0;	/*	 * Waiting for all commands for the designated target in the active	 * array	 */	for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {		spin_lock_irqsave(&pha->hardware_lock, flags);		sp = pha->outstanding_cmds[cnt];		if (sp) {			cmd = sp->cmd;			spin_unlock_irqrestore(&pha->hardware_lock, flags);			if (cmd->device->id == t &&			    ha->vp_idx == sp->ha->vp_idx) {				if (!qla2x00_eh_wait_on_command(ha, cmd)) {					status = 1;					break;				}			}		} else {			spin_unlock_irqrestore(&pha->hardware_lock, flags);		}	}	return (status);}/*************************************************************************** qla2xxx_eh_device_reset** Description:*    The device reset function will reset the target and abort any*    executing commands.**    NOTE: The use of SP is undefined within this context.  Do *NOT**          attempt to use this value, even if you determine it is*          non-null.** Input:*    cmd = Linux SCSI command packet of the command that cause the*          bus device reset.** Returns:*    SUCCESS/FAILURE (defined as macro in scsi.h).***************************************************************************/static intqla2xxx_eh_device_reset(struct scsi_cmnd *cmd){	scsi_qla_host_t *ha = shost_priv(cmd->device->host);	fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;	int ret = FAILED;	unsigned int id, lun;	unsigned long serial;	qla2x00_block_error_handler(cmd);	id = cmd->device->id;	lun = cmd->device->lun;	serial = cmd->serial_number;	if (!fcport)		return ret;	qla_printk(KERN_INFO, ha,	    "scsi(%ld:%d:%d): DEVICE RESET ISSUED.\n", ha->host_no, id, lun);	if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)		goto eh_dev_reset_done;	if (qla2x00_wait_for_loop_ready(ha) == QLA_SUCCESS) {		if (qla2x00_device_reset(ha, fcport) == 0)			ret = SUCCESS;#if defined(LOGOUT_AFTER_DEVICE_RESET)		if (ret == SUCCESS) {			if (fcport->flags & FC_FABRIC_DEVICE) {				ha->isp_ops->fabric_logout(ha, fcport->loop_id);				qla2x00_mark_device_lost(ha, fcport, 0, 0);			}		}#endif	} else {		DEBUG2(printk(KERN_INFO		    "%s failed: loop not ready\n",__func__));	}	if (ret == FAILED) {		DEBUG3(printk("%s(%ld): device reset failed\n",		    __func__, ha->host_no));		qla_printk(KERN_INFO, ha, "%s: device reset failed\n",		    __func__);		goto eh_dev_reset_done;	}	/* Flush outstanding commands. */	if (qla2x00_eh_wait_for_pending_target_commands(ha, id))		ret = FAILED;	if (ret == FAILED) {		DEBUG3(printk("%s(%ld): failed while waiting for commands\n",		    __func__, ha->host_no));		qla_printk(KERN_INFO, ha,		    "%s: failed while waiting for commands\n", __func__);	} else		qla_printk(KERN_INFO, ha,		    "scsi(%ld:%d:%d): DEVICE RESET SUCCEEDED.\n", ha->host_no,		    id, lun); eh_dev_reset_done:	return ret;}/*************************************************************************** qla2x00_eh_wait_for_pending_commands** Description:*    Waits for all the commands to come back from the specified host.** Input:*    ha - pointer to scsi_qla_host structure.** Returns:*    1 : SUCCESS*    0 : FAILED** Note:**************************************************************************/static intqla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha){	int	cnt;	int	status;	srb_t		*sp;	struct scsi_cmnd *cmd;	unsigned long flags;	status = 1;	/*	 * Waiting for all commands for the designated target in the active	 * array	 */	for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {		spin_lock_irqsave(&ha->hardware_lock, flags);		sp = ha->outstanding_cmds[cnt];		if (sp) {			cmd = sp->cmd;			spin_unlock_irqrestore(&ha->hardware_lock, flags);			status = qla2x00_eh_wait_on_command(ha, cmd);			if (status == 0)				break;		}		else {			spin_unlock_irqrestore(&ha->hardware_lock, flags);		}	}	return (status);}/*************************************************************************** qla2xxx_eh_bus_reset** Description:*    The bus reset function will reset the bus and abort any executing*    commands.** Input:*    cmd = Linux SCSI command packet of the command that cause the*          bus reset.** Returns:*    SUCCESS/FAILURE (defined as macro in scsi.h).***************************************************************************/static intqla2xxx_eh_bus_reset(struct scsi_cmnd *cmd){	scsi_qla_host_t *ha = shost_priv(cmd->device->host);	scsi_qla_host_t *pha = to_qla_parent(ha);	fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;	int ret = FAILED;	unsigned int id, lun;	unsigned long serial;	qla2x00_block_error_handler(cmd);	id = cmd->device->id;	lun = cmd->device->lun;	serial = cmd->serial_number;	if (!fcport)		return ret;	qla_printk(KERN_INFO, ha,	    "scsi(%ld:%d:%d): LOOP RESET ISSUED.\n", ha->host_no, id, lun);	if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) {		DEBUG2(printk("%s failed:board disabled\n",__func__));		goto eh_bus_reset_done;	}	if (qla2x00_wait_for_loop_ready(ha) == QLA_SUCCESS) {		if (qla2x00_loop_reset(ha) == QLA_SUCCESS)			ret = SUCCESS;	}	if (ret == FAILED)		goto eh_bus_reset_done;	/* Flush outstanding commands. */	if (!qla2x00_eh_wait_for_pending_commands(pha))		ret = FAILED;eh_bus_reset_done:	qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,	    (ret == FAILED) ? "failed" : "succeded");	return ret;}/*************************************************************************** qla2xxx_eh_host_reset** Description:*    The reset function will reset the Adapter.** Input:*      cmd = Linux SCSI command packet of the command that cause the*            adapter reset.** Returns:*      Either SUCCESS or FAILED.** Note:**************************************************************************/static intqla2xxx_eh_host_reset(struct scsi_cmnd *cmd){	scsi_qla_host_t *ha = shost_priv(cmd->device->host);	fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;	int ret = FAILED;	unsigned int id, lun;	unsigned long serial;	scsi_qla_host_t *pha = to_qla_parent(ha);	qla2x00_block_error_handler(cmd);	id = cmd->device->id;	lun = cmd->device->lun;	serial = cmd->serial_number;	if (!fcport)

⌨️ 快捷键说明

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