📄 fas216.c
字号:
static voidfas216_devicereset_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result){ fas216_log(info, LOG_ERROR, "fas216 device reset complete"); info->rstSCpnt = NULL; info->rst_dev_status = 1; wake_up(&info->eh_wait);}/** * fas216_rq_sns_done - Finish processing automatic request sense command * @info: interface that completed * @SCpnt: command that completed * @result: driver byte of result * * Finish processing automatic request sense command */static voidfas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result){ fas216_log_target(info, LOG_CONNECT, SCpnt->device->id, "request sense complete, result=0x%04x%02x%02x", result, SCpnt->SCp.Message, SCpnt->SCp.Status); if (result != DID_OK || SCpnt->SCp.Status != GOOD) /* * Something went wrong. Make sure that we don't * have valid data in the sense buffer that could * confuse the higher levels. */ memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));//printk("scsi%d.%c: sense buffer: ", info->host->host_no, '0' + SCpnt->device->id);//{ int i; for (i = 0; i < 32; i++) printk("%02x ", SCpnt->sense_buffer[i]); printk("\n"); } /* * Note that we don't set SCpnt->result, since that should * reflect the status of the command that we were asked by * the upper layers to process. This would have been set * correctly by fas216_std_done. */ SCpnt->scsi_done(SCpnt);}/** * fas216_std_done - finish processing of standard command * @info: interface that completed * @SCpnt: command that completed * @result: driver byte of result * * Finish processing of standard command */static voidfas216_std_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result){ info->stats.fins += 1; SCpnt->result = result << 16 | info->scsi.SCp.Message << 8 | info->scsi.SCp.Status; fas216_log_command(info, LOG_CONNECT, SCpnt, "command complete, result=0x%08x", SCpnt->result); /* * If the driver detected an error, we're all done. */ if (host_byte(SCpnt->result) != DID_OK || msg_byte(SCpnt->result) != COMMAND_COMPLETE) goto done; /* * If the command returned CHECK_CONDITION or COMMAND_TERMINATED * status, request the sense information. */ if (status_byte(SCpnt->result) == CHECK_CONDITION || status_byte(SCpnt->result) == COMMAND_TERMINATED) goto request_sense; /* * If the command did not complete with GOOD status, * we are all done here. */ if (status_byte(SCpnt->result) != GOOD) goto done; /* * We have successfully completed a command. Make sure that * we do not have any buffers left to transfer. The world * is not perfect, and we seem to occasionally hit this. * It can be indicative of a buggy driver, target or the upper * levels of the SCSI code. */ if (info->scsi.SCp.ptr) { switch (SCpnt->cmnd[0]) { case INQUIRY: case START_STOP: case MODE_SENSE: break; default: printk(KERN_ERR "scsi%d.%c: incomplete data transfer " "detected: res=%08X ptr=%p len=%X CDB: ", info->host->host_no, '0' + SCpnt->device->id, SCpnt->result, info->scsi.SCp.ptr, info->scsi.SCp.this_residual); __scsi_print_command(SCpnt->cmnd); SCpnt->result &= ~(255 << 16); SCpnt->result |= DID_BAD_TARGET << 16; goto request_sense; } }done: if (SCpnt->scsi_done) { SCpnt->scsi_done(SCpnt); return; } panic("scsi%d.H: null scsi_done function in fas216_done", info->host->host_no);request_sense: if (SCpnt->cmnd[0] == REQUEST_SENSE) goto done; fas216_log_target(info, LOG_CONNECT, SCpnt->device->id, "requesting sense"); memset(SCpnt->cmnd, 0, sizeof (SCpnt->cmnd)); SCpnt->cmnd[0] = REQUEST_SENSE; SCpnt->cmnd[1] = SCpnt->device->lun << 5; SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer); SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); SCpnt->SCp.buffer = NULL; SCpnt->SCp.buffers_residual = 0; SCpnt->SCp.ptr = (char *)SCpnt->sense_buffer; SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer); SCpnt->SCp.Message = 0; SCpnt->SCp.Status = 0; SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer); SCpnt->sc_data_direction = DMA_FROM_DEVICE; SCpnt->use_sg = 0; SCpnt->tag = 0; SCpnt->host_scribble = (void *)fas216_rq_sns_done; /* * Place this command into the high priority "request * sense" slot. This will be the very next command * executed, unless a target connects to us. */ if (info->reqSCpnt) printk(KERN_WARNING "scsi%d.%c: loosing request command\n", info->host->host_no, '0' + SCpnt->device->id); info->reqSCpnt = SCpnt;}/** * fas216_done - complete processing for current command * @info: interface that completed * @result: driver byte of result * * Complete processing for current command */static void fas216_done(FAS216_Info *info, unsigned int result){ void (*fn)(FAS216_Info *, Scsi_Cmnd *, unsigned int); Scsi_Cmnd *SCpnt; unsigned long flags; fas216_checkmagic(info); if (!info->SCpnt) goto no_command; SCpnt = info->SCpnt; info->SCpnt = NULL; info->scsi.phase = PHASE_IDLE; if (info->scsi.aborting) { fas216_log(info, 0, "uncaught abort - returning DID_ABORT"); result = DID_ABORT; info->scsi.aborting = 0; } /* * Sanity check the completion - if we have zero bytes left * to transfer, we should not have a valid pointer. */ if (info->scsi.SCp.ptr && info->scsi.SCp.this_residual == 0) { printk("scsi%d.%c: zero bytes left to transfer, but " "buffer pointer still valid: ptr=%p len=%08x CDB: ", info->host->host_no, '0' + SCpnt->device->id, info->scsi.SCp.ptr, info->scsi.SCp.this_residual); info->scsi.SCp.ptr = NULL; __scsi_print_command(SCpnt->cmnd); } /* * Clear down this command as completed. If we need to request * the sense information, fas216_kick will re-assert the busy * status. */ info->device[SCpnt->device->id].parity_check = 0; clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns); fn = (void (*)(FAS216_Info *, Scsi_Cmnd *, unsigned int))SCpnt->host_scribble; fn(info, SCpnt, result); if (info->scsi.irq != NO_IRQ) { spin_lock_irqsave(&info->host_lock, flags); if (info->scsi.phase == PHASE_IDLE) fas216_kick(info); spin_unlock_irqrestore(&info->host_lock, flags); } return;no_command: panic("scsi%d.H: null command in fas216_done", info->host->host_no);}/** * fas216_queue_command - queue a command for adapter to process. * @SCpnt: Command to queue * @done: done function to call once command is complete * * Queue a command for adapter to process. * Returns: 0 on success, else error. * Notes: io_request_lock is held, interrupts are disabled. */int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)){ FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; int result; fas216_checkmagic(info); fas216_log_command(info, LOG_CONNECT, SCpnt, "received command (%p)", SCpnt); SCpnt->scsi_done = done; SCpnt->host_scribble = (void *)fas216_std_done; SCpnt->result = 0; init_SCp(SCpnt); info->stats.queues += 1; SCpnt->tag = 0; spin_lock(&info->host_lock); /* * Add command into execute queue and let it complete under * whatever scheme we're using. */ result = !queue_add_cmd_ordered(&info->queues.issue, SCpnt); /* * If we successfully added the command, * kick the interface to get it moving. */ if (result == 0 && info->scsi.phase == PHASE_IDLE) fas216_kick(info); spin_unlock(&info->host_lock); fas216_log_target(info, LOG_CONNECT, -1, "queue %s", result ? "failure" : "success"); return result;}/** * fas216_internal_done - trigger restart of a waiting thread in fas216_noqueue_command * @SCpnt: Command to wake * * Trigger restart of a waiting thread in fas216_command */static void fas216_internal_done(Scsi_Cmnd *SCpnt){ FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; fas216_checkmagic(info); info->internal_done = 1;}/** * fas216_noqueue_command - process a command for the adapter. * @SCpnt: Command to queue * * Queue a command for adapter to process. * Returns: scsi result code. * Notes: io_request_lock is held, interrupts are disabled. */int fas216_noqueue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)){ FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; fas216_checkmagic(info); /* * We should only be using this if we don't have an interrupt. * Provide some "incentive" to use the queueing code. */ BUG_ON(info->scsi.irq != NO_IRQ); info->internal_done = 0; fas216_queue_command(SCpnt, fas216_internal_done); /* * This wastes time, since we can't return until the command is * complete. We can't sleep either since we may get re-entered! * However, we must re-enable interrupts, or else we'll be * waiting forever. */ spin_unlock_irq(info->host->host_lock); while (!info->internal_done) { /* * If we don't have an IRQ, then we must poll the card for * it's interrupt, and use that to call this driver's * interrupt routine. That way, we keep the command * progressing. Maybe we can add some inteligence here * and go to sleep if we know that the device is going * to be some time (eg, disconnected). */ if (fas216_readb(info, REG_STAT) & STAT_INT) { spin_lock_irq(info->host->host_lock); fas216_intr(info); spin_unlock_irq(info->host->host_lock); } } spin_lock_irq(info->host->host_lock); done(SCpnt); return 0;}/* * Error handler timeout function. Indicate that we timed out, * and wake up any error handler process so it can continue. */static void fas216_eh_timer(unsigned long data){ FAS216_Info *info = (FAS216_Info *)data; fas216_log(info, LOG_ERROR, "error handling timed out\n"); del_timer(&info->eh_timer); if (info->rst_bus_status == 0) info->rst_bus_status = -1; if (info->rst_dev_status == 0) info->rst_dev_status = -1; wake_up(&info->eh_wait);}enum res_find { res_failed, /* not found */ res_success, /* command on issue queue */ res_hw_abort /* command on disconnected dev */};/** * fas216_do_abort - decide how to abort a command * @SCpnt: command to abort * * Decide how to abort a command. * Returns: abort status */static enum res_find fas216_find_command(FAS216_Info *info, Scsi_Cmnd *SCpnt){ enum res_find res = res_failed; if (queue_remove_cmd(&info->queues.issue, SCpnt)) { /* * The command was on the issue queue, and has not been * issued yet. We can remove the command from the queue, * and acknowledge the abort. Neither the device nor the * interface know about the command. */ printk("on issue queue "); res = res_success; } else if (queue_remove_cmd(&info->queues.disconnected, SCpnt)) { /* * The command was on the disconnected queue. We must * reconnect with the device if possible, and send it * an abort message. */ printk("on disconnected queue "); res = res_hw_abort; } else if (info->SCpnt == SCpnt) { printk("executing "); switch (info->scsi.phase) { /* * If the interface is idle, and the command is 'disconnectable', * then it is the same as on the disconnected queue. */ case PHASE_IDLE: if (info->scsi.disconnectable) { info->scsi.disconnectable = 0; info->SCpnt = NULL; res = res_hw_abort; } break; default: break; } } else if (info->origSCpnt == SCpnt) { /* * The command will be executed next, but a command * is currently using the interface. This is similar to * being on the issue queue, except the busylun bit has * been set. */ info->origSCpnt = NULL; clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns); printk("waiting for execution "); res = res_success; } else printk("unknown "); return res;}/** * fas216_eh_abort - abort this command * @SCpnt: command to abort * * Abort this command. * Returns: FAILED if unable to abort * Notes: io_request_lock is taken, and irqs are disabled */int fas216_eh_abort(Scsi_Cmnd *SCpnt){ FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; int result = FAILED; fas216_checkmagic(info); info->stats.aborts += 1; printk(KERN_WARNING "scsi%d: abort command ", info->host->host_no); __scsi_print_command(SCpnt->data_cmnd); print_debug_list(); fas216_dumpstate(info); printk(KERN_WARNING "scsi%d: abort %p ", info->host->host_no, SCpnt); switch (fas216_find_command(info, SCpnt)) { /* * We found the command, and cleared it out. Either * the command is still known to be executing on the * target, or the busylun bit is not set. */ case res_success: printk("success\n"); result = SUCCESS; break; /* * We need to reconnect to the target and send it an * ABORT or ABORT_TAG message. We can only do this * if the bus is free. */ case res_hw_abort: /* * We are unable to abort the command for some reason. */ default: case res_failed: printk("failed\n"); break; } return result;}/** * fas216_eh_device_reset - Reset the device associated with this command * @SCpnt: command specifing device to reset * * Reset the device associated with this command. * Returns: FAILED if unable to reset. * Notes: We won't be re-entered, so we'll only
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -