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 + -
显示快捷键?