📄 fas216.c
字号:
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);#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 int fas216_wait_cmd(FAS216_Info *info, int cmd){ int tout; int stat; outb(cmd, REG_CMD(info)); for (tout = 1000; tout; tout -= 1) { stat = inb(REG_STAT(info)); if (stat & STAT_INT) break; udelay(1); } return stat;}static int fas216_get_msg_byte(FAS216_Info *info){ int stat; stat = fas216_wait_cmd(info, CMD_MSGACCEPTED); if ((stat & STAT_INT) == 0) goto timedout; if ((stat & STAT_BUSMASK) != STAT_MESGIN) goto unexpected_phase_change; inb(REG_INST(info)); stat = fas216_wait_cmd(info, CMD_TRANSFERINFO); if ((stat & STAT_INT) == 0) goto timedout; if ((stat & STAT_BUSMASK) != STAT_MESGIN) goto unexpected_phase_change; inb(REG_INST(info)); return inb(REG_FF(info));timedout: printk("scsi%d.%c: timed out waiting for message byte\n", info->host->host_no, fas216_target(info)); return -1;unexpected_phase_change: printk("scsi%d.%c: unexpected phase change: status = %02X\n", info->host->host_no, fas216_target(info), stat); return -2;}/* 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 = info->scsi.message; unsigned int msglen = 1, i; int msgbyte = 0; fas216_checkmagic(info); message[0] = inb(REG_FF(info)); if (message[0] == EXTENDED_MESSAGE) { msgbyte = fas216_get_msg_byte(info); if (msgbyte >= 0) { message[1] = msgbyte; for (msglen = 2; msglen < message[1] + 2; msglen++) { msgbyte = fas216_get_msg_byte(info); if (msgbyte >= 0) message[msglen] = msgbyte; else break; } } } info->scsi.msglen = msglen;#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: if (msglen != 1) goto unrecognised; 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: if (msglen != 1) goto unrecognised; /* * 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: if (msglen != 1) goto unrecognised; /* * 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: if (msglen != 1) goto unrecognised; info->scsi.phase = PHASE_MSGIN_DISCONNECT; break; case MESSAGE_REJECT: if (msglen != 1) goto unrecognised; 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: if (msglen < 2) goto unrecognised; /* handled above - print a warning since this is untested */ printk("scsi%d.%c: reconnect queue tag %02X\n", info->host->host_no, fas216_target(info), message[1]); break; case EXTENDED_MESSAGE: if (msglen < 3) goto unrecognised; 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: goto unrecognised; } break; default: goto unrecognised; } outb(CMD_MSGACCEPTED, REG_CMD(info)); return;unrecognised: printk("scsi%d.%c: unrecognised message, rejecting\n", info->host->host_no, fas216_target(info)); printk("scsi%d.%c: message was", info->host->host_no, fas216_target(info)); for (i = 0; i < msglen; i++) printk("%s%02X", i & 31 ? " " : "\n ", message[i]); printk("\n"); /* * Something strange seems to be happening here - * I can't use SETATN since the chip gives me an * invalid command interrupt when I do. Weird. */outb(CMD_NOP, REG_CMD(info));fas216_dumpstate(info); outb(CMD_SETATN, REG_CMD(info)); msgqueue_flush(&info->scsi.msgs); msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); info->scsi.phase = PHASE_MSGOUT_EXPECT;fas216_dumpstate(info); outb(CMD_MSGACCEPTED, REG_CMD(info));}/* 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); 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, int start) * 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); 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);#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 (info->scsi.phase) { case PHASE_SELECTION: if ((ssr & IS_BITS) != 1) goto bad_is; break; case PHASE_SELSTEPS: switch (ssr & IS_BITS) { case IS_SELARB: case IS_MSGBYTESENT: goto bad_is; case IS_NOTCOMMAND: case IS_EARLYPHASE: if ((stat & STAT_BUSMASK) == STAT_MESGIN) break; goto bad_is; case IS_COMPLETE: break; } default: break; } 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -