📄 fas216.c
字号:
info->scsi.disconnectable = 0; if (info->SCpnt->device->id == target && info->SCpnt->device->lun == lun && info->SCpnt->tag == tag) { fas216_log(info, LOG_CONNECT, "reconnected previously executing command"); } else { queue_add_cmd_tail(&info->queues.disconnected, info->SCpnt); fas216_log(info, LOG_CONNECT, "had to move command to disconnected queue"); info->SCpnt = NULL; } } if (!info->SCpnt) { info->SCpnt = queue_remove_tgtluntag(&info->queues.disconnected, target, lun, tag); fas216_log(info, LOG_CONNECT, "had to get command"); } if (info->SCpnt) { /* * Restore data pointer from SAVED data pointer */ info->scsi.SCp = info->SCpnt->SCp; fas216_log(info, LOG_CONNECT, "data pointers: [%p, %X]", info->scsi.SCp.ptr, info->scsi.SCp.this_residual); info->scsi.phase = PHASE_MSGIN; } 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. */ fas216_cmd(info, CMD_SETATN);#if 0 if (tag) msgqueue_addmsg(&info->scsi.msgs, 2, ABORT_TAG, tag); else#endif msgqueue_addmsg(&info->scsi.msgs, 1, ABORT); info->scsi.phase = PHASE_MSGOUT_EXPECT; info->scsi.aborting = 1; } fas216_cmd(info, CMD_MSGACCEPTED); return; initiator_error: printk(KERN_ERR "scsi%d.H: error during reselection: bytes", info->host->host_no); for (i = 0; i < cfis; i++) printk(" %02x", msg[i]); printk("\n"); bad_message: fas216_cmd(info, CMD_SETATN); msgqueue_flush(&info->scsi.msgs); msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); info->scsi.phase = PHASE_MSGOUT_EXPECT; fas216_cmd(info, CMD_MSGACCEPTED);}static void fas216_parse_message(FAS216_Info *info, unsigned char *message, int msglen){ int i; 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; fas216_log(info, LOG_CONNECT | LOG_MESSAGES | LOG_BUFFER, "save data pointers: [%p, %X]", info->scsi.SCp.ptr, info->scsi.SCp.this_residual); break; case RESTORE_POINTERS: if (msglen != 1) goto unrecognised; /* * Restore current data pointer from SAVED data pointer */ info->scsi.SCp = info->SCpnt->SCp; fas216_log(info, LOG_CONNECT | LOG_MESSAGES | LOG_BUFFER, "restore data pointers: [%p, 0x%x]", info->scsi.SCp.ptr, info->scsi.SCp.this_residual); 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; default: fas216_log(info, 0, "reject, last message 0x%04x", fas216_get_last_msg(info, info->scsi.msgin_fifo)); } break; case NOP: break; case EXTENDED_MESSAGE: if (msglen < 3) goto unrecognised; switch (message[2]) { case EXTENDED_SDTR: /* Sync transfer negotiation request/reply */ fas216_handlesync(info, message); break; default: goto unrecognised; } break; default: goto unrecognised; } return;unrecognised: fas216_log(info, 0, "unrecognised message, rejecting"); 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. */fas216_cmd(info, CMD_NOP);fas216_dumpstate(info); fas216_cmd(info, CMD_SETATN); msgqueue_flush(&info->scsi.msgs); msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); info->scsi.phase = PHASE_MSGOUT_EXPECT;fas216_dumpstate(info);}static int fas216_wait_cmd(FAS216_Info *info, int cmd){ int tout; int stat; fas216_cmd(info, cmd); for (tout = 1000; tout; tout -= 1) { stat = fas216_readb(info, REG_STAT); if (stat & (STAT_INT|STAT_PARITYERROR)) break; udelay(1); } return stat;}static int fas216_get_msg_byte(FAS216_Info *info){ unsigned int stat = fas216_wait_cmd(info, CMD_MSGACCEPTED); if ((stat & STAT_INT) == 0) goto timedout; if ((stat & STAT_BUSMASK) != STAT_MESGIN) goto unexpected_phase_change; fas216_readb(info, REG_INST); stat = fas216_wait_cmd(info, CMD_TRANSFERINFO); if ((stat & STAT_INT) == 0) goto timedout; if (stat & STAT_PARITYERROR) goto parity_error; if ((stat & STAT_BUSMASK) != STAT_MESGIN) goto unexpected_phase_change; fas216_readb(info, REG_INST); return fas216_readb(info, REG_FF);timedout: fas216_log(info, LOG_ERROR, "timed out waiting for message byte"); return -1;unexpected_phase_change: fas216_log(info, LOG_ERROR, "unexpected phase change: status = %02x", stat); return -2;parity_error: fas216_log(info, LOG_ERROR, "parity error during message in phase"); return -3;}/** * fas216_message - handle a function done interrupt from FAS216 chip * @info: interface which caused function done interrupt * * Handle a function done interrupt from FAS216 chip */static void fas216_message(FAS216_Info *info){ unsigned char *message = info->scsi.message; unsigned int msglen = 1; int msgbyte = 0; fas216_checkmagic(info); message[0] = fas216_readb(info, REG_FF); 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; } } } if (msgbyte == -3) goto parity_error;#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 fas216_parse_message(info, message, msglen); fas216_cmd(info, CMD_MSGACCEPTED); return;parity_error: fas216_cmd(info, CMD_SETATN); msgqueue_flush(&info->scsi.msgs); msgqueue_addmsg(&info->scsi.msgs, 1, MSG_PARITY_ERROR); info->scsi.phase = PHASE_MSGOUT_EXPECT; fas216_cmd(info, CMD_MSGACCEPTED); return;}/** * fas216_send_command - send command after all message bytes have been sent * @info: interface which caused bus service * * Send a command to a target after all message bytes have been sent */static void fas216_send_command(FAS216_Info *info){ int i; fas216_checkmagic(info); fas216_cmd(info, CMD_NOP|CMD_WITHDMA); fas216_cmd(info, CMD_FLUSHFIFO); /* load command */ for (i = info->scsi.SCp.sent_command; i < info->SCpnt->cmd_len; i++) fas216_writeb(info, REG_FF, info->SCpnt->cmnd[i]); fas216_cmd(info, CMD_TRANSFERINFO); info->scsi.phase = PHASE_COMMAND;}/** * fas216_send_messageout - handle bus service to send a message * @info: interface which caused bus service * * Handle bus service to send a message. * 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_cmd(info, CMD_FLUSHFIFO); 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++) fas216_writeb(info, REG_FF, msg->msg[i]); msg->fifo = tot_msglen - (fas216_readb(info, REG_CFIS) & CFIS_CF); start = 0; } } else fas216_writeb(info, REG_FF, NOP); fas216_cmd(info, CMD_TRANSFERINFO); info->scsi.phase = PHASE_MSGOUT;}/** * fas216_busservice_intr - handle bus service interrupt from FAS216 chip * @info: interface which caused bus service interrupt * @stat: Status register contents * @is: SCSI Status register contents * * Handle a bus service interrupt from FAS216 chip */static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int is){ fas216_checkmagic(info); fas216_log(info, LOG_BUSSERVICE, "bus service: stat=%02x is=%02x phase=%02x", stat, is, info->scsi.phase); switch (info->scsi.phase) { case PHASE_SELECTION: if ((is & IS_BITS) != IS_MSGBYTESENT) goto bad_is; break; case PHASE_SELSTEPS: switch (is & 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; } fas216_cmd(info, CMD_NOP);#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)) { case STATE(STAT_DATAIN, PHASE_SELSTEPS):/* Sel w/ steps -> 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 */ info->scsi.phase = PHASE_DATAIN; fas216_transfer(info); return; case STATE(STAT_DATAIN, PHASE_DATAIN): /* Data In -> Data In */ case STATE(STAT_DATAOUT, PHASE_DATAOUT):/* Data Out -> Data Out */ fas216_cleanuptransfer(info); fas216_transfer(info); return; 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_cmd(info, CMD_FLUSHFIFO); info->scsi.phase = PHASE_DATAOUT; fas216_transfer(info); return; 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 */ fas216_cmd(info, CMD_INITCMDCOMPLETE); 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 = fas216_readb(info, REG_CFIS) & CFIS_CF; fas216_cmd(info, CMD_FLUSHFIFO); fas216_cmd(info, CMD_TRANSFERINFO); info->scsi.phase = PHASE_MSGIN; return; case STATE(STAT_MESGIN, PHASE_MSGIN): info->scsi.msgin_fifo = fas216_readb(info, REG_CFIS) & CFIS_CF; fas216_cmd(info, CMD_TRANSFERINFO); return; 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; /* * Message Out -> Message Out */ case STATE(STAT_MESGOUT, PHASE_SELSTEPS): case STATE(STAT_MESGOUT, PHASE_MSGOUT): /* * If we get another message out phase, this usually * means some parity error occurred. Resend complete * set of messages. If we have more than one byte to * send, we need to assert ATN again. */ if (info->device[info->SCpnt->device->id].parity_check) { /* * We were testing... good, the device * supports parity checking. */ info->device[info->SCpnt->device->id].parity_check = 0; info->device[info->SCpnt->device->id].parity_enabled = 1; fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]); } if (msgqueue_msglength(&info->scsi.msgs) > 1) fas216_cmd(info, CMD_SETATN); /*FALLTHROUGH*/ /* * Any -> Message Out */ case STATE(STAT_MESGOUT, PHASE_MSGOUT_EXPECT): fas216_send_messageout(info, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -