📄 qla_os.c
字号:
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 intqla2x00_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) || 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){ scsi_qla_host_t *ha = to_qla_host(cmd->device->host); srb_t *sp; int ret, i; unsigned int id, lun; unsigned long serial; unsigned long flags; if (!CMD_SP(cmd)) return FAILED; ret = FAILED; id = cmd->device->id; lun = cmd->device->lun; serial = cmd->serial_number; /* Check active list for command command. */ spin_lock_irqsave(&ha->hardware_lock, flags); for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) { sp = ha->outstanding_cmds[i]; if (sp == NULL) continue; if (sp->cmd != cmd) continue; DEBUG2(printk("%s(%ld): aborting sp %p from RISC. pid=%ld " "sp->state=%x\n", __func__, ha->host_no, sp, serial, sp->state)); DEBUG3(qla2x00_print_scsi_cmd(cmd);) spin_unlock_irqrestore(&ha->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)); ret = SUCCESS; } spin_lock_irqsave(&ha->hardware_lock, flags); break; } spin_unlock_irqrestore(&ha->hardware_lock, flags); /* Wait for the command to be returned. */ if (ret == SUCCESS) { 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); } } qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): Abort command issued -- %lx %x.\n", ha->host_no, id, lun, 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; 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(&ha->hardware_lock, flags); sp = ha->outstanding_cmds[cnt]; if (sp) { cmd = sp->cmd; spin_unlock_irqrestore(&ha->hardware_lock, flags); if (cmd->device->id == t) { if (!qla2x00_eh_wait_on_command(ha, cmd)) { status = 1; break; } } } else { spin_unlock_irqrestore(&ha->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).***************************************************************************/intqla2xxx_eh_device_reset(struct scsi_cmnd *cmd){ scsi_qla_host_t *ha = to_qla_host(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; srb_t *sp; int ret; unsigned int id, lun; unsigned long serial; ret = FAILED; id = cmd->device->id; lun = cmd->device->lun; serial = cmd->serial_number; sp = (srb_t *) CMD_SP(cmd); if (!sp || !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); } }#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).***************************************************************************/intqla2xxx_eh_bus_reset(struct scsi_cmnd *cmd){ scsi_qla_host_t *ha = to_qla_host(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; srb_t *sp; int ret; unsigned int id, lun; unsigned long serial; ret = FAILED; id = cmd->device->id; lun = cmd->device->lun; serial = cmd->serial_number; sp = (srb_t *) CMD_SP(cmd); if (!sp || !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(ha)) 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:**************************************************************************/intqla2xxx_eh_host_reset(struct scsi_cmnd *cmd){ scsi_qla_host_t *ha = to_qla_host(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; srb_t *sp; int ret; unsigned int id, lun; unsigned long serial; ret = FAILED; id = cmd->device->id; lun = cmd->device->lun; serial = cmd->serial_number; sp = (srb_t *) CMD_SP(cmd); if (!sp || !fcport) return ret; qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): ADAPTER RESET ISSUED.\n", ha->host_no, id, lun); if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) goto eh_host_reset_lock; /* * Fixme-may be dpc thread is active and processing * loop_resync,so wait a while for it to * be completed and then issue big hammer.Otherwise * it may cause I/O failure as big hammer marks the * devices as lost kicking of the port_down_timer * while dpc is stuck for the mailbox to complete. */ qla2x00_wait_for_loop_ready(ha); set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); if (qla2x00_abort_isp(ha)) { clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); /* failed. schedule dpc to try */ set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) goto eh_host_reset_lock; } clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); /* Waiting for our command in done_queue to be returned to OS.*/ if (qla2x00_eh_wait_for_pending_commands(ha)) ret = SUCCESS;eh_host_reset_lock: qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__, (ret == FAILED) ? "failed" : "succeded"); return ret;}/** qla2x00_loop_reset* Issue loop reset.** Input:* ha = adapter block pointer.** Returns:* 0 = success*/static intqla2x00_loop_reset(scsi_qla_host_t *ha){ int status = QLA_SUCCESS; struct fc_port *fcport; if (ha->flags.enable_lip_reset) { status = qla2x00_lip_reset(ha); } if (status == QLA_SUCCESS && ha->flags.enable_target_reset) { list_for_each_entry(fcport, &ha->fcports, list) { if (fcport->port_type != FCT_TARGET) continue; status = qla2x00_device_reset(ha, fcport); if (status != QLA_SUCCESS) break; } } if (status == QLA_SUCCESS && ((!ha->flags.enable_target_reset && !ha->flags.enable_lip_reset) || ha->flags.enable_lip_full_login)) { status = qla2x00_full_login_lip(ha); } /* Issue marker command only when we are going to start the I/O */ ha->marker_needed = 1; if (status) { /* Empty */ DEBUG2_3(printk("%s(%ld): **** FAILED ****\n", __func__, ha->host_no);) } else { /* Empty */ DEBUG3(printk("%s(%ld): exiting normally.\n", __func__, ha->host_no);) } return(status);}/* * qla2x00_device_reset * Issue bus device reset message to the target. * * Input: * ha = adapter block pointer. * t = SCSI ID. * TARGET_QUEUE_LOCK must be released. * ADAPTER_STATE_LOCK must be released. * * Context: * Kernel context. */static intqla2x00_device_reset(scsi_qla_host_t *ha, fc_port_t *reset_fcport){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -