📄 qla_os.c
字号:
int i; int return_status = FAILED; os_lun_t *q; scsi_qla_host_t *ha; scsi_qla_host_t *vis_ha; srb_t *sp; srb_t *rp; struct list_head *list, *temp; struct Scsi_Host *host; uint8_t found = 0; unsigned int b, t, l; /* Get the SCSI request ptr */ sp = (srb_t *) CMD_SP(cmd); /* * If sp is NULL, command is already returned. * sp is NULLED just before we call back scsi_done * */ if ((sp == NULL)) { /* no action - we don't have command */ qla_printk(KERN_INFO, to_qla_host(cmd->device->host), "qla2xxx_eh_abort: cmd already done sp=%p\n", sp); DEBUG(printk("qla2xxx_eh_abort: cmd already done sp=%p\n", sp);) return SUCCESS; } if (sp) { DEBUG(printk("qla2xxx_eh_abort: refcount %i \n", atomic_read(&sp->ref_count));) } vis_ha = (scsi_qla_host_t *) cmd->device->host->hostdata; ha = (scsi_qla_host_t *)cmd->device->host->hostdata; host = ha->host; /* Generate LU queue on bus, target, LUN */ b = cmd->device->channel; t = cmd->device->id; l = cmd->device->lun; q = GET_LU_Q(vis_ha, t, l); qla_printk(KERN_INFO, ha, "%s scsi(%ld:%d:%d:%d): cmd_timeout_in_sec=0x%x.\n", __func__, ha->host_no, (int)b, (int)t, (int)l, cmd->timeout_per_command / HZ); /* * if no LUN queue then something is very wrong!!! */ if (q == NULL) { qla_printk(KERN_WARNING, ha, "qla2x00: (%x:%x:%x) No LUN queue.\n", b, t, l); /* no action - we don't have command */ return FAILED; } DEBUG2(printk("scsi(%ld): ABORTing cmd=%p sp=%p jiffies = 0x%lx, " "timeout=%x, dpc_flags=%lx, vis_ha->dpc_flags=%lx q->flag=%lx\n", ha->host_no, cmd, sp, jiffies, cmd->timeout_per_command / HZ, ha->dpc_flags, vis_ha->dpc_flags, q->q_flag)); DEBUG2(qla2x00_print_scsi_cmd(cmd)); spin_unlock_irq(ha->host->host_lock); if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) { DEBUG2(printk("%s failed:board disabled\n", __func__);) spin_lock_irq(ha->host->host_lock); return FAILED; } spin_lock_irq(ha->host->host_lock); /* Search done queue */ spin_lock(&ha->list_lock); list_for_each_safe(list, temp, &ha->done_queue) { rp = list_entry(list, srb_t, list); if (cmd != rp->cmd) continue; /* * Found command.Remove it from done list. * And proceed to post completion to scsi mid layer. */ return_status = SUCCESS; found++; qla2x00_delete_from_done_queue(ha, sp); break; } /* list_for_each_safe() */ spin_unlock(&ha->list_lock); /* * Return immediately if the aborted command was already in the done * queue */ if (found) { qla_printk(KERN_INFO, ha, "qla2xxx_eh_abort: Returning completed command=%p sp=%p\n", cmd, sp); sp_put(ha, sp); return (return_status); } /* * See if this command is in the retry queue */ DEBUG3(printk("qla2xxx_eh_abort: searching sp %p in retry " "queue.\n", sp);) spin_lock(&ha->list_lock); list_for_each_safe(list, temp, &ha->retry_queue) { rp = list_entry(list, srb_t, list); if (cmd != rp->cmd) continue; DEBUG2(printk("qla2xxx_eh_abort: found " "in retry queue. SP=%p\n", sp);) __del_from_retry_queue(ha, rp); cmd->result = DID_ABORT << 16; __add_to_done_queue(ha, rp); return_status = SUCCESS; found++; break; } spin_unlock(&ha->list_lock); /* * Our SP pointer points at the command we want to remove from the * pending queue providing we haven't already sent it to the adapter. */ if (!found) { DEBUG3(printk("qla2xxx_eh_abort: searching sp %p " "in pending queue.\n", sp);) spin_lock(&vis_ha->list_lock); list_for_each_safe(list, temp, &vis_ha->pending_queue) { rp = list_entry(list, srb_t, list); if (rp->cmd != cmd) continue; /* Remove srb from LUN queue. */ rp->flags |= SRB_ABORTED; DEBUG2(printk("qla2xxx_eh_abort: Cmd in pending queue." " serial_number %ld.\n", sp->cmd->serial_number);) __del_from_pending_queue(vis_ha, rp); cmd->result = DID_ABORT << 16; __add_to_done_queue(vis_ha, rp); return_status = SUCCESS; found++; break; } /* list_for_each_safe() */ spin_unlock(&vis_ha->list_lock); } /*End of if !found */ if (!found) { /* find the command in our active list */ DEBUG3(printk("qla2xxx_eh_abort: searching sp %p " "in outstanding queue.\n", sp);) spin_lock(&ha->hardware_lock); for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) { sp = ha->outstanding_cmds[i]; if (sp == NULL) continue; if (sp->cmd != cmd) continue; DEBUG2(printk("qla2xxx_eh_abort(%ld): aborting sp %p " "from RISC. pid=%ld sp->state=%x q->q_flag=%lx\n", ha->host_no, sp, sp->cmd->serial_number, sp->state, q->q_flag);) DEBUG(qla2x00_print_scsi_cmd(cmd);) /* Get a reference to the sp and drop the lock.*/ sp_get(ha, sp); spin_unlock(&ha->hardware_lock); spin_unlock_irq(ha->host->host_lock); if (qla2x00_abort_command(ha, sp)) { DEBUG2(printk("qla2xxx_eh_abort: abort_command " "mbx failed.\n");) return_status = FAILED; } else { DEBUG3(printk("qla2xxx_eh_abort: abort_command " " mbx success.\n");) return_status = SUCCESS; } sp_put(ha,sp); spin_lock_irq(ha->host->host_lock); spin_lock(&ha->hardware_lock); /* * Regardless of mailbox command status, go check on * done queue just in case the sp is already done. */ break; }/*End of for loop */ spin_unlock(&ha->hardware_lock); } /*End of if !found */ /* Waiting for our command in done_queue to be returned to OS.*/ if (qla2x00_eh_wait_on_command(ha, cmd) != 0) { DEBUG2(printk("qla2xxx_eh_abort: cmd returned back to OS.\n");) return_status = SUCCESS; } if (return_status == FAILED) { qla_printk(KERN_INFO, ha, "qla2xxx_eh_abort Exiting: status=Failed\n"); return FAILED; } DEBUG2(printk("qla2xxx_eh_abort: Exiting. return_status=0x%x.\n", return_status)); return return_status;}/*************************************************************************** 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; status = 0; /* * Waiting for all commands for the designated target in the active * array */ for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { spin_lock(&ha->hardware_lock); sp = ha->outstanding_cmds[cnt]; if (sp) { cmd = sp->cmd; spin_unlock(&ha->hardware_lock); if (cmd->device->id == t) { if (!qla2x00_eh_wait_on_command(ha, cmd)) { status = 1; break; } } } else { spin_unlock(&ha->hardware_lock); } } 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){ int return_status; unsigned int b, t, l; scsi_qla_host_t *ha; os_tgt_t *tq; os_lun_t *lq; fc_port_t *fcport_to_reset; srb_t *rp; struct list_head *list, *temp; return_status = FAILED; if (cmd == NULL) { printk(KERN_INFO "%s(): **** SCSI mid-layer passing in NULL cmd\n", __func__); return (return_status); } b = cmd->device->channel; t = cmd->device->id; l = cmd->device->lun; ha = (scsi_qla_host_t *)cmd->device->host->hostdata; tq = TGT_Q(ha, t); if (tq == NULL) { qla_printk(KERN_INFO, ha, "%s(): **** CMD derives a NULL TGT_Q\n", __func__); return (return_status); } lq = (os_lun_t *)LUN_Q(ha, t, l); if (lq == NULL) { printk(KERN_INFO "%s(): **** CMD derives a NULL LUN_Q\n", __func__); return (return_status); } fcport_to_reset = lq->fclun->fcport; /* If we are coming in from the back-door, stall I/O until complete. */ if (!cmd->device->host->eh_active) set_bit(TQF_SUSPENDED, &tq->flags); qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d:%d): DEVICE RESET ISSUED.\n", ha->host_no, b, t, l); DEBUG2(printk(KERN_INFO "scsi(%ld): DEVICE_RESET cmd=%p jiffies = 0x%lx, timeout=%x, " "dpc_flags=%lx, status=%x allowed=%d cmd.state=%x\n", ha->host_no, cmd, jiffies, cmd->timeout_per_command / HZ, ha->dpc_flags, cmd->result, cmd->allowed, cmd->state)); /* Clear commands from the retry queue. */ spin_lock(&ha->list_lock); list_for_each_safe(list, temp, &ha->retry_queue) { rp = list_entry(list, srb_t, list); if (t != rp->cmd->device->id) continue; DEBUG2(printk(KERN_INFO "qla2xxx_eh_reset: found in retry queue. SP=%p\n", rp)); __del_from_retry_queue(ha, rp); rp->cmd->result = DID_RESET << 16; __add_to_done_queue(ha, rp); } spin_unlock(&ha->list_lock); spin_unlock_irq(ha->host->host_lock); if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) { DEBUG2(printk(KERN_INFO "%s failed:board disabled\n",__func__)); spin_lock_irq(ha->host->host_lock); goto eh_dev_reset_done; } if (qla2x00_wait_for_loop_ready(ha) == QLA_SUCCESS) { if (qla2x00_device_reset(ha, fcport_to_reset) == 0) { return_status = SUCCESS; }#if defined(LOGOUT_AFTER_DEVICE_RESET) if (return_status == SUCCESS) { if (fcport_to_reset->flags & FC_FABRIC_DEVICE) { qla2x00_fabric_logout(ha, fcport_to_reset->loop_id); qla2x00_mark_device_lost(ha, fcport_to_reset); } }#endif } else { DEBUG2(printk(KERN_INFO "%s failed: loop not ready\n",__func__);) } spin_lock_irq(ha->host->host_lock); if (return_status == 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; } /* * If we are coming down the EH path, wait for all commands to * complete for the device. */ if (cmd->device->host->eh_active) { if (qla2x00_eh_wait_for_pending_target_commands(ha, t)) return_status = FAILED; if (return_status == 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__); goto eh_dev_reset_done; } } qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", ha->host_no, b, t, l);eh_dev_reset_done: if (!cmd->device->host->eh_active) clear_bit(TQF_SUSPENDED, &tq->flags); return (return_status);}/*************************************************************************** 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; status = 1; /* * Waiting for all commands for the designated target in the active * array */ for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { spin_lock(&ha->hardware_lock); sp = ha->outstanding_cmds[cnt]; if (sp) { cmd = sp->cmd; spin_unlock(&ha->hardware_lock); status = qla2x00_eh_wait_on_command(ha, cmd); if (status == 0) break; } else { spin_unlock(&ha->hardware_lock); } } 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){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -