📄 fas216.c
字号:
/* * Something went wrong - send an initiator error to * the target. */ outb(CMD_SETATN, REG_CMD(info)); outb(CMD_MSGACCEPTED, REG_CMD(info)); msgqueue_flush(&info->scsi.msgs); msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); info->scsi.phase = PHASE_MSGOUT_EXPECT; return; } target &= ~(1 << info->host->this_id); switch (target) { case 1: target = 0; break; case 2: target = 1; break; case 4: target = 2; break; case 8: target = 3; break; case 16: target = 4; break; case 32: target = 5; break; case 64: target = 6; break; case 128: target = 7; break; default: target = info->host->this_id; break; } identify_msg &= 7; info->scsi.reconnected.target = target; info->scsi.reconnected.lun = identify_msg; info->scsi.reconnected.tag = 0; ok = 0; if (info->scsi.disconnectable && info->SCpnt && info->SCpnt->target == target && info->SCpnt->lun == identify_msg) ok = 1; if (!ok && queue_probetgtlun(&info->queues.disconnected, target, identify_msg)) ok = 1; msgqueue_flush(&info->scsi.msgs); if (ok) { info->scsi.phase = PHASE_RECONNECTED; outb(target, REG_SDID(info)); } else { /* * Our command structure not found - abort the * command on the target. Since we have no * record of this command, we can't send * an INITIATOR DETECTED ERROR message. */ outb(CMD_SETATN, REG_CMD(info)); msgqueue_addmsg(&info->scsi.msgs, 1, ABORT); info->scsi.phase = PHASE_MSGOUT_EXPECT; } outb(CMD_MSGACCEPTED, REG_CMD(info));}/* Function: void fas216_finish_reconnect(FAS216_Info *info) * Purpose : finish reconnection sequence for device * Params : info - interface which caused function done interrupt */static voidfas216_finish_reconnect(FAS216_Info *info){ fas216_checkmagic(info, "fas216_reconnect");#ifdef DEBUG_CONNECT printk("Connected: %1X %1X %02X, reconnected: %1X %1X %02X\n", info->SCpnt->target, info->SCpnt->lun, info->SCpnt->tag, info->scsi.reconnected.target, info->scsi.reconnected.lun, info->scsi.reconnected.tag);#endif if (info->scsi.disconnectable && info->SCpnt) { info->scsi.disconnectable = 0; if (info->SCpnt->target == info->scsi.reconnected.target && info->SCpnt->lun == info->scsi.reconnected.lun && info->SCpnt->tag == info->scsi.reconnected.tag) {#ifdef DEBUG_CONNECT printk("scsi%d.%c: reconnected", info->host->host_no, fas216_target(info));#endif } else { queue_add_cmd_tail(&info->queues.disconnected, info->SCpnt);#ifdef DEBUG_CONNECT printk("scsi%d.%c: had to move command to disconnected queue\n", info->host->host_no, fas216_target(info));#endif info->SCpnt = NULL; } } if (!info->SCpnt) { info->SCpnt = queue_remove_tgtluntag(&info->queues.disconnected, info->scsi.reconnected.target, info->scsi.reconnected.lun, info->scsi.reconnected.tag);#ifdef DEBUG_CONNECT printk("scsi%d.%c: had to get command", info->host->host_no, fas216_target(info));#endif } if (!info->SCpnt) { outb(CMD_SETATN, REG_CMD(info)); msgqueue_flush(&info->scsi.msgs);#if 0 if (info->scsi.reconnected.tag) msgqueue_addmsg(&info->scsi.msgs, 2, ABORT_TAG, info->scsi.reconnected.tag); else#endif msgqueue_addmsg(&info->scsi.msgs, 1, ABORT); info->scsi.phase = PHASE_MSGOUT_EXPECT; info->scsi.aborting = 1; } else { /* * Restore data pointer from SAVED data pointer */ info->scsi.SCp = info->SCpnt->SCp;#ifdef DEBUG_CONNECT printk(", data pointers: [%p, %X]", info->scsi.SCp.ptr, info->scsi.SCp.this_residual);#endif }#ifdef DEBUG_CONNECT printk("\n");#endif}static unsigned char fas216_get_msg_byte(FAS216_Info *info){ int tout; outb(CMD_MSGACCEPTED, REG_CMD(info)); for (tout = 1000000; tout; tout --) if (inb(REG_STAT(info)) & STAT_INT) break; inb(REG_INST(info)); outb(CMD_TRANSFERINFO, REG_CMD(info)); for (tout = 1000000; tout; tout --) if (inb(REG_STAT(info)) & STAT_INT) break; inb(REG_INST(info)); return inb(REG_FF(info));}/* Function: void fas216_message(FAS216_Info *info) * Purpose : handle a function done interrupt from FAS216 chip * Params : info - interface which caused function done interrupt */static void fas216_message(FAS216_Info *info){ unsigned char message[16]; unsigned int msglen = 1; fas216_checkmagic(info, "fas216_message"); message[0] = inb(REG_FF(info)); if (message[0] == EXTENDED_MESSAGE) { message[1] = fas216_get_msg_byte(info); for (msglen = 2; msglen < message[1] + 2; msglen++) message[msglen] = fas216_get_msg_byte(info); }#ifdef DEBUG_MESSAGES { int i; printk("scsi%d.%c: message in: ", info->host->host_no, fas216_target(info)); for (i = 0; i < msglen; i++) printk("%02X ", message[i]); printk("\n"); }#endif if (info->scsi.phase == PHASE_RECONNECTED) { if (message[0] == SIMPLE_QUEUE_TAG) info->scsi.reconnected.tag = message[1]; fas216_finish_reconnect(info); info->scsi.phase = PHASE_MSGIN; } switch (message[0]) { case COMMAND_COMPLETE: printk(KERN_ERR "scsi%d.%c: command complete with no " "status in MESSAGE_IN?\n", info->host->host_no, fas216_target(info)); break; case SAVE_POINTERS: /* * Save current data pointer to SAVED data pointer * SCSI II standard says that we must not acknowledge * this until we have really saved pointers. * NOTE: we DO NOT save the command nor status pointers * as required by the SCSI II standard. These always * point to the start of their respective areas. */ info->SCpnt->SCp = info->scsi.SCp; info->SCpnt->SCp.sent_command = 0;#if defined (DEBUG_MESSAGES) || defined (DEBUG_CONNECT) printk("scsi%d.%c: save data pointers: [%p, %X]\n", info->host->host_no, fas216_target(info), info->scsi.SCp.ptr, info->scsi.SCp.this_residual);#endif break; case RESTORE_POINTERS: /* * Restore current data pointer from SAVED data pointer */ info->scsi.SCp = info->SCpnt->SCp;#if defined (DEBUG_MESSAGES) || defined (DEBUG_CONNECT) printk("scsi%d.%c: restore data pointers: [%p, %X]\n", info->host->host_no, fas216_target(info), info->scsi.SCp.ptr, info->scsi.SCp.this_residual);#endif break; case DISCONNECT: info->scsi.phase = PHASE_MSGIN_DISCONNECT; break; case MESSAGE_REJECT:printk("scsi%d.%c: message reject at %02X (%X)\n", info->host->host_no, fas216_target(info), info->scsi.msgin_fifo, fas216_get_last_msg(info, info->scsi.msgin_fifo)); switch(fas216_get_last_msg(info, info->scsi.msgin_fifo)) { case EXTENDED_MESSAGE | EXTENDED_SDTR << 8: fas216_handlesync(info, message); break; case EXTENDED_MESSAGE | EXTENDED_WDTR << 8: fas216_handlewide(info, message); break; default: printk("scsi%d.%c: reject, last message %04X\n", info->host->host_no, fas216_target(info), fas216_get_last_msg(info, info->scsi.msgin_fifo)); } break; case NOP: break; case SIMPLE_QUEUE_TAG: /* handled above */ printk("scsi%d.%c: reconnect queue tag %02X\n", info->host->host_no, fas216_target(info), message[1]); break; case EXTENDED_MESSAGE: switch (message[2]) { case EXTENDED_SDTR: /* Sync transfer negociation request/reply */ fas216_handlesync(info, message); break; case EXTENDED_WDTR: /* Wide transfer negociation request/reply */ fas216_handlewide(info, message); break; default: printk("scsi%d.%c: unrecognised extended message %02X, rejecting\n", info->host->host_no, fas216_target(info), message[2]); goto reject_message; } break; default: printk("scsi%d.%c: unrecognised message %02X, rejecting\n", info->host->host_no, fas216_target(info), message[0]); goto reject_message; } outb(CMD_MSGACCEPTED, REG_CMD(info)); return;reject_message: outb(CMD_SETATN, REG_CMD(info)); outb(CMD_MSGACCEPTED, REG_CMD(info)); msgqueue_flush(&info->scsi.msgs); msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); info->scsi.phase = PHASE_MSGOUT_EXPECT;}/* Function: void fas216_send_command(FAS216_Info *info) * Purpose : send a command to a target after all message bytes have been sent * Params : info - interface which caused bus service */static void fas216_send_command(FAS216_Info *info){ int i; fas216_checkmagic(info, "fas216_send_command"); outb(CMD_NOP|CMD_WITHDMA, REG_CMD(info)); outb(CMD_FLUSHFIFO, REG_CMD(info)); /* load command */ for (i = info->scsi.SCp.sent_command; i < info->SCpnt->cmd_len; i++) outb(info->SCpnt->cmnd[i], REG_FF(info)); outb(CMD_TRANSFERINFO, REG_CMD(info)); info->scsi.phase = PHASE_COMMAND;}/* Function: void fas216_send_messageout(FAS216_Info *info) * Purpose : handle bus service to send a message * Params : info - interface which caused bus service * Note : We do not allow the device to change the data direction! */static void fas216_send_messageout(FAS216_Info *info, int start){ unsigned int tot_msglen = msgqueue_msglength(&info->scsi.msgs); fas216_checkmagic(info, "fas216_send_messageout"); outb(CMD_FLUSHFIFO, REG_CMD(info)); if (tot_msglen) { struct message *msg; int msgnr = 0; while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) { int i; for (i = start; i < msg->length; i++) outb(msg->msg[i], REG_FF(info)); msg->fifo = tot_msglen - (inb(REG_CFIS(info)) & CFIS_CF); start = 0; } } else outb(NOP, REG_FF(info)); outb(CMD_TRANSFERINFO, REG_CMD(info)); info->scsi.phase = PHASE_MSGOUT;}/* Function: void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr) * Purpose : handle a bus service interrupt from FAS216 chip * Params : info - interface which caused bus service interrupt * stat - Status register contents * ssr - SCSI Status register contents */static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr){ fas216_checkmagic(info, "fas216_busservice_intr");#ifdef DEBUG_BUSSERVICE printk("scsi%d.%c: bus service: stat=%02X ssr=%02X phase=%02X\n", info->host->host_no, fas216_target(info), stat, ssr, info->scsi.phase);#endif switch (ssr & IS_BITS) { case IS_MSGBYTESENT: /* select with ATN and stop steps completed */ case IS_COMPLETE: /* last action completed */ outb(CMD_NOP, REG_CMD(info));#define STATE(st,ph) ((ph) << 3 | (st)) /* This table describes the legal SCSI state transitions, * as described by the SCSI II spec. */ switch (STATE(stat & STAT_BUSMASK, info->scsi.phase)) { /* Reselmsgin -> Data In */ case STATE(STAT_DATAIN, PHASE_RECONNECTED): fas216_finish_reconnect(info); case STATE(STAT_DATAIN, PHASE_SELSTEPS):/* Sel w/ steps -> Data In */ case STATE(STAT_DATAIN, PHASE_DATAIN): /* Data In -> Data In */ case STATE(STAT_DATAIN, PHASE_MSGOUT): /* Message Out -> Data In */ case STATE(STAT_DATAIN, PHASE_COMMAND): /* Command -> Data In */ case STATE(STAT_DATAIN, PHASE_MSGIN): /* Message In -> Data In */ fas216_starttransfer(info, DMA_IN, 0); return; case STATE(STAT_DATAOUT, PHASE_DATAOUT):/* Data Out -> Data Out */ fas216_starttransfer(info, DMA_OUT, 0); return; /* Reselmsgin -> Data Out */ case STATE(STAT_DATAOUT, PHASE_RECONNECTED): fas216_finish_reconnect(info); 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_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_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: "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -