📄 fas216.c
字号:
case STATE(STAT_DATAOUT, PHASE_SELSTEPS):/* Sel w/ steps-> Data Out */ case STATE(STAT_DATAOUT, PHASE_MSGOUT): /* Message Out -> Data Out */ case STATE(STAT_DATAOUT, PHASE_COMMAND):/* Command -> Data Out */ case STATE(STAT_DATAOUT, PHASE_MSGIN): /* Message In -> Data Out */ fas216_starttransfer(info, DMA_OUT, 1); return; /* Reselmsgin -> Status */ case STATE(STAT_STATUS, PHASE_RECONNECTED): fas216_finish_reconnect(info); goto status; case STATE(STAT_STATUS, PHASE_DATAOUT): /* Data Out -> Status */ case STATE(STAT_STATUS, PHASE_DATAIN): /* Data In -> Status */ fas216_stoptransfer(info); case STATE(STAT_STATUS, PHASE_SELSTEPS):/* Sel w/ steps -> Status */ case STATE(STAT_STATUS, PHASE_MSGOUT): /* Message Out -> Status */ case STATE(STAT_STATUS, PHASE_COMMAND): /* Command -> Status */ case STATE(STAT_STATUS, PHASE_MSGIN): /* Message In -> Status */ status: outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); info->scsi.phase = PHASE_STATUS; return; case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out -> Message In */ case STATE(STAT_MESGIN, PHASE_DATAIN): /* Data In -> Message In */ fas216_stoptransfer(info); case STATE(STAT_MESGIN, PHASE_COMMAND): /* Command -> Message In */ case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In */ case STATE(STAT_MESGIN, PHASE_MSGOUT): /* Message Out -> Message In */ info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF; outb(CMD_FLUSHFIFO, REG_CMD(info)); outb(CMD_TRANSFERINFO, REG_CMD(info)); info->scsi.phase = PHASE_MSGIN; return; /* Reselmsgin -> Message In */ case STATE(STAT_MESGIN, PHASE_RECONNECTED): case STATE(STAT_MESGIN, PHASE_MSGIN): info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF; outb(CMD_TRANSFERINFO, REG_CMD(info)); return; /* Reselmsgin -> Command */ case STATE(STAT_COMMAND, PHASE_RECONNECTED): fas216_finish_reconnect(info); case STATE(STAT_COMMAND, PHASE_MSGOUT): /* Message Out -> Command */ case STATE(STAT_COMMAND, PHASE_MSGIN): /* Message In -> Command */ fas216_send_command(info); info->scsi.phase = PHASE_COMMAND; return; /* Selection -> Message Out */ case STATE(STAT_MESGOUT, PHASE_SELECTION): fas216_send_messageout(info, 1); return; /* Any -> Message Out */ case STATE(STAT_MESGOUT, PHASE_MSGOUT_EXPECT): fas216_send_messageout(info, 0); return; /* Error recovery rules. * These either attempt to abort or retry the operation. * TODO: we need more of these */ case STATE(STAT_COMMAND, PHASE_COMMAND):/* Command -> Command */ /* error - we've sent out all the command bytes * we have. * NOTE: we need SAVE DATA POINTERS/RESTORE DATA POINTERS * to include the command bytes sent for this to work * correctly. */ printk(KERN_ERR "scsi%d.%c: " "target trying to receive more command bytes\n", info->host->host_no, fas216_target(info)); outb(CMD_SETATN, REG_CMD(info)); outb(15, REG_STCL(info)); outb(0, REG_STCM(info)); outb(0, REG_STCH(info)); outb(CMD_PADBYTES | CMD_WITHDMA, REG_CMD(info)); msgqueue_flush(&info->scsi.msgs); msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); info->scsi.phase = PHASE_MSGOUT_EXPECT; return; /* Selection -> Message Out */ case STATE(STAT_MESGOUT, PHASE_SELSTEPS): case STATE(STAT_MESGOUT, PHASE_MSGOUT): /* Message Out -> Message Out */ /* If we get another message out phase, this * usually means some parity error occurred. * Resend complete set of messages. If we have * more than 1 byte to send, we need to assert * ATN again. */ if (msgqueue_msglength(&info->scsi.msgs) > 1) outb(CMD_SETATN, REG_CMD(info)); fas216_send_messageout(info, 0); return; } if (info->scsi.phase == PHASE_MSGIN_DISCONNECT) { printk(KERN_ERR "scsi%d.%c: disconnect message received, but bus service %s?\n", info->host->host_no, fas216_target(info), fas216_bus_phase(stat)); msgqueue_flush(&info->scsi.msgs); outb(CMD_SETATN, REG_CMD(info)); msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); info->scsi.phase = PHASE_MSGOUT_EXPECT; info->scsi.aborting = 1; outb(CMD_TRANSFERINFO, REG_CMD(info)); return; } printk(KERN_ERR "scsi%d.%c: bus phase %s after %s?\n", info->host->host_no, fas216_target(info), fas216_bus_phase(stat), fas216_drv_phase(info)); print_debug_list(); return;bad_is: printk("scsi%d.%c: bus service at step %d?\n", info->host->host_no, fas216_target(info), ssr & IS_BITS); print_debug_list(); fas216_done(info, DID_ERROR);}/* Function: void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr) * Purpose : handle a function done interrupt from FAS216 chip * Params : info - interface which caused function done interrupt * stat - Status register contents * ssr - SCSI Status register contents */static void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr){ int status, message; fas216_checkmagic(info);#ifdef DEBUG_FUNCTIONDONE printk("scsi%d.%c: function done: stat=%X ssr=%X phase=%02X\n", info->host->host_no, fas216_target(info), stat, ssr, info->scsi.phase);#endif switch (info->scsi.phase) { case PHASE_STATUS: /* status phase - read status and msg */ status = inb(REG_FF(info)); message = inb(REG_FF(info)); info->scsi.SCp.Message = message; info->scsi.SCp.Status = status; info->scsi.phase = PHASE_DONE; outb(CMD_MSGACCEPTED, REG_CMD(info)); break; case PHASE_IDLE: /* reselected? */ case PHASE_MSGIN: /* message in phase */ case PHASE_RECONNECTED: /* reconnected command */ if ((stat & STAT_BUSMASK) == STAT_MESGIN) { info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF; fas216_message(info); break; } default: printk("scsi%d.%c: internal phase %s for function done?" " What do I do with this?\n", info->host->host_no, fas216_target(info), fas216_drv_phase(info)); }}/* Function: void fas216_intr(struct Scsi_Host *instance) * Purpose : handle interrupts from the interface to progress a command * Params : instance - interface to service */void fas216_intr(struct Scsi_Host *instance){ FAS216_Info *info = (FAS216_Info *)instance->hostdata; unsigned char isr, ssr, stat; fas216_checkmagic(info); stat = inb(REG_STAT(info)); ssr = inb(REG_IS(info)); isr = inb(REG_INST(info)); add_debug_list(stat, ssr, isr, info->scsi.phase); if (stat & STAT_INT) { if (isr & INST_BUSRESET) { printk(KERN_DEBUG "scsi%d.H: bus reset detected\n", instance->host_no); scsi_report_bus_reset(instance, 0); } else if (isr & INST_ILLEGALCMD) { printk(KERN_CRIT "scsi%d.H: illegal command given\n", instance->host_no); fas216_dumpstate(info); } else if (isr & INST_DISCONNECT) fas216_disconnect_intr(info); else if (isr & INST_RESELECTED) /* reselected */ fas216_reselected_intr(info); else if (isr & INST_BUSSERVICE) /* bus service request */ fas216_busservice_intr(info, stat, ssr); else if (isr & INST_FUNCDONE) /* function done */ fas216_funcdone_intr(info, stat, ssr); else printk("scsi%d.%c: unknown interrupt received:" " phase %s isr %02X ssr %02X stat %02X\n", instance->host_no, fas216_target(info), fas216_drv_phase(info), isr, ssr, stat); }}/* Function: void fas216_kick(FAS216_Info *info) * Purpose : kick a command to the interface - interface should be idle * Params : info - our host interface to kick * Notes : Interrupts are always disabled! */static void fas216_kick(FAS216_Info *info){ Scsi_Cmnd *SCpnt = NULL; int tot_msglen, from_queue = 0, disconnect_ok; fas216_checkmagic(info); /* * Obtain the next command to process. */ do { if (info->reqSCpnt) { SCpnt = info->reqSCpnt; info->reqSCpnt = NULL; break; } if (info->origSCpnt) { SCpnt = info->origSCpnt; info->origSCpnt = NULL; break; } /* retrieve next command */ if (!SCpnt) { SCpnt = queue_remove_exclude(&info->queues.issue, info->busyluns); from_queue = 1; break; } } while (0); if (!SCpnt) /* no command pending - just exit */ return; if (info->scsi.disconnectable && info->SCpnt) { queue_add_cmd_tail(&info->queues.disconnected, info->SCpnt); info->scsi.disconnectable = 0; info->SCpnt = NULL; printk("scsi%d.%c: moved command to disconnected queue\n", info->host->host_no, fas216_target(info)); } /* * claim host busy */ info->scsi.phase = PHASE_SELECTION; info->SCpnt = SCpnt; info->scsi.SCp = SCpnt->SCp; info->dma.transfer_type = fasdma_none;#ifdef DEBUG_CONNECT printk("scsi%d.%c: starting cmd %02X", info->host->host_no, '0' + SCpnt->target, SCpnt->cmnd[0]);#endif if (from_queue) {#ifdef SCSI2_TAG /* * tagged queuing - allocate a new tag to this command */ if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE && SCpnt->cmnd[0] != INQUIRY) { SCpnt->device->current_tag += 1; if (SCpnt->device->current_tag == 0) SCpnt->device->current_tag = 1; SCpnt->tag = SCpnt->device->current_tag; } else#endif set_bit(SCpnt->target * 8 + SCpnt->lun, info->busyluns); info->stats.removes += 1; switch (SCpnt->cmnd[0]) { case WRITE_6: case WRITE_10: case WRITE_12: info->stats.writes += 1; break; case READ_6: case READ_10: case READ_12: info->stats.reads += 1; break; default: info->stats.miscs += 1; break; } } /* * Don't allow request sense commands to disconnect. */ disconnect_ok = SCpnt->cmnd[0] != REQUEST_SENSE && info->device[SCpnt->target].disconnect_ok; /* * build outgoing message bytes */ msgqueue_flush(&info->scsi.msgs); msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(disconnect_ok, SCpnt->lun)); /* * add tag message if required */ if (SCpnt->tag) msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag); do {#ifdef SCSI2_WIDE if (info->device[SCpnt->target].wide_state == neg_wait) { info->device[SCpnt->target].wide_state = neg_inprogress; msgqueue_addmsg(&info->scsi.msgs, 4, EXTENDED_MESSAGE, 2, EXTENDED_WDTR, info->ifcfg.wide_max_size); break; }#endif#ifdef SCSI2_SYNC if ((info->device[SCpnt->target].sync_state == neg_wait || info->device[SCpnt->target].sync_state == neg_complete) && (SCpnt->cmnd[0] == REQUEST_SENSE || SCpnt->cmnd[0] == INQUIRY)) { info->device[SCpnt->target].sync_state = neg_inprogress; msgqueue_addmsg(&info->scsi.msgs, 5, EXTENDED_MESSAGE, 3, EXTENDED_SDTR, 1000 / info->ifcfg.clockrate, info->ifcfg.sync_max_depth); break; }#endif } while (0); /* following what the ESP driver says */ outb(0, REG_STCL(info)); outb(0, REG_STCM(info)); outb(0, REG_STCH(info)); outb(CMD_NOP | CMD_WITHDMA, REG_CMD(info)); /* flush FIFO */ outb(CMD_FLUSHFIFO, REG_CMD(info)); /* load bus-id and timeout */ outb(BUSID(SCpnt->target), REG_SDID(info)); outb(info->ifcfg.select_timeout, REG_STIM(info)); /* synchronous transfers */ fas216_set_sync(info, SCpnt->target); tot_msglen = msgqueue_msglength(&info->scsi.msgs);#ifdef DEBUG_MESSAGES { struct message *msg; int msgnr = 0, i; printk("scsi%d.%c: message out: ", info->host->host_no, '0' + SCpnt->target); while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) { printk("{ "); for (i = 0; i < msg->length; i++) printk("%02x ", msg->msg[i]); printk("} "); } printk("\n"); }#endif if (tot_msglen == 1 || tot_msglen == 3) { /* * We have an easy message length to send... */ struct message *msg; int msgnr = 0, i; info->scsi.phase = PHASE_SELSTEPS; /* load message bytes */ while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) { for (i = 0; i < msg->length; i++) outb(msg->msg[i], REG_FF(info)); msg->fifo = tot_msglen - (inb(REG_CFIS(info)) & CFIS_CF); } /* load command */ for (i = 0; i < SCpnt->cmd_len; i++) outb(SCpnt->cmnd[i], REG_FF(info)); if (tot_msglen == 1) outb(CMD_SELECTATN, REG_CMD(info)); else outb(CMD_SELECTATN3, REG_CMD(info)); } else { /* * We have an unusual number of message bytes to send. * Load first byte into fifo, and issue SELECT with ATN and * stop steps. */ struct message *msg = msgqueue_getmsg(&info->scsi.msgs, 0); outb(msg->msg[0], REG_FF(info)); msg->fifo = 1; outb(CMD_SELECTATNSTOP, REG_CMD(info)); }#ifdef DEBUG_CONNECT printk(", data pointers [%p, %X]\n", info->scsi.SCp.ptr, info->scsi.SCp.this_residual);#endif /* should now get either DISCONNECT or (FUNCTION DONE with BUS SERVICE) intr */}/* Function: void fas216_rq_sns_done(info, SCpnt, result) * Purpose : Finish processing automatic request sense command * Params : info - interface that completed * SCpnt - command that completed * result - driver byte of result */static voidfas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result){#ifdef DEBUG_CONNECT printk("scsi%d.%c: request sense complete, result=%04X%02X%02X\n", info->host->host_no, '0' + SCpnt->target, result, SCpnt->SCp.Message, SCpnt->SCp.Status);#endif 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)); /* * 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);}/* Function: void fas216_std_done(info, SCpnt, result) * Purpose : Finish processing of standard command * Params : info - interface that completed * SCpnt - command that completed
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -