📄 in2000.c
字号:
if (hostdata->state != S_RUNNING_LEVEL2) hostdata->state = S_CONNECTED; break;/* Note: this interrupt should not occur in a LEVEL2 command */ case CSR_XFER_DONE|PHS_COMMAND: case CSR_UNEXP |PHS_COMMAND: case CSR_SRV_REQ |PHS_COMMAND:DB(DB_INTR,printk("CMND-%02x,%ld",cmd->cmnd[0],cmd->pid)) transfer_pio(cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata); hostdata->state = S_CONNECTED; break; case CSR_XFER_DONE|PHS_STATUS: case CSR_UNEXP |PHS_STATUS: case CSR_SRV_REQ |PHS_STATUS:DB(DB_INTR,printk("STATUS=")) cmd->SCp.Status = read_1_byte(hostdata);DB(DB_INTR,printk("%02x",cmd->SCp.Status)) if (hostdata->level2 >= L2_BASIC) { sr = read_3393(hostdata,WD_SCSI_STATUS); /* clear interrupt */ hostdata->state = S_RUNNING_LEVEL2; write_3393(hostdata,WD_COMMAND_PHASE, 0x50); write_3393_cmd(hostdata,WD_CMD_SEL_ATN_XFER); } else { hostdata->state = S_CONNECTED; } break; case CSR_XFER_DONE|PHS_MESS_IN: case CSR_UNEXP |PHS_MESS_IN: case CSR_SRV_REQ |PHS_MESS_IN:DB(DB_INTR,printk("MSG_IN=")) msg = read_1_byte(hostdata); sr = read_3393(hostdata,WD_SCSI_STATUS); /* clear interrupt */ hostdata->incoming_msg[hostdata->incoming_ptr] = msg; if (hostdata->incoming_msg[0] == EXTENDED_MESSAGE) msg = EXTENDED_MESSAGE; else hostdata->incoming_ptr = 0; cmd->SCp.Message = msg; switch (msg) { case COMMAND_COMPLETE:DB(DB_INTR,printk("CCMP-%ld",cmd->pid)) write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK); hostdata->state = S_PRE_CMP_DISC; break; case SAVE_POINTERS:DB(DB_INTR,printk("SDP")) write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK); hostdata->state = S_CONNECTED; break; case RESTORE_POINTERS:DB(DB_INTR,printk("RDP")) if (hostdata->level2 >= L2_BASIC) { write_3393(hostdata,WD_COMMAND_PHASE, 0x45); write_3393_cmd(hostdata,WD_CMD_SEL_ATN_XFER); hostdata->state = S_RUNNING_LEVEL2; } else { write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK); hostdata->state = S_CONNECTED; } break; case DISCONNECT:DB(DB_INTR,printk("DIS")) cmd->device->disconnect = 1; write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK); hostdata->state = S_PRE_TMP_DISC; break; case MESSAGE_REJECT:DB(DB_INTR,printk("REJ"))#ifdef SYNC_DEBUGprintk("-REJ-");#endif if (hostdata->sync_stat[cmd->target] == SS_WAITING) hostdata->sync_stat[cmd->target] = SS_SET; write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK); hostdata->state = S_CONNECTED; break; case EXTENDED_MESSAGE:DB(DB_INTR,printk("EXT")) ucp = hostdata->incoming_msg;#ifdef SYNC_DEBUGprintk("%02x",ucp[hostdata->incoming_ptr]);#endif /* Is this the last byte of the extended message? */ if ((hostdata->incoming_ptr >= 2) && (hostdata->incoming_ptr == (ucp[1] + 1))) { switch (ucp[2]) { /* what's the EXTENDED code? */ case EXTENDED_SDTR: id = calc_sync_xfer(ucp[3],ucp[4]); if (hostdata->sync_stat[cmd->target] != SS_WAITING) {/* A device has sent an unsolicited SDTR message; rather than go * through the effort of decoding it and then figuring out what * our reply should be, we're just gonna say that we have a * synchronous fifo depth of 0. This will result in asynchronous * transfers - not ideal but so much easier. * Actually, this is OK because it assures us that if we don't * specifically ask for sync transfers, we won't do any. */ write_3393_cmd(hostdata,WD_CMD_ASSERT_ATN); /* want MESS_OUT */ hostdata->outgoing_msg[0] = EXTENDED_MESSAGE; hostdata->outgoing_msg[1] = 3; hostdata->outgoing_msg[2] = EXTENDED_SDTR; hostdata->outgoing_msg[3] = hostdata->default_sx_per/4; hostdata->outgoing_msg[4] = 0; hostdata->outgoing_len = 5; hostdata->sync_xfer[cmd->target] = calc_sync_xfer(hostdata->default_sx_per/4,0); } else { hostdata->sync_xfer[cmd->target] = id; }#ifdef SYNC_DEBUGprintk("sync_xfer=%02x",hostdata->sync_xfer[cmd->target]);#endif hostdata->sync_stat[cmd->target] = SS_SET; write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK); hostdata->state = S_CONNECTED; break; case EXTENDED_WDTR: write_3393_cmd(hostdata,WD_CMD_ASSERT_ATN); /* want MESS_OUT */ printk("sending WDTR "); hostdata->outgoing_msg[0] = EXTENDED_MESSAGE; hostdata->outgoing_msg[1] = 2; hostdata->outgoing_msg[2] = EXTENDED_WDTR; hostdata->outgoing_msg[3] = 0; /* 8 bit transfer width */ hostdata->outgoing_len = 4; write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK); hostdata->state = S_CONNECTED; break; default: write_3393_cmd(hostdata,WD_CMD_ASSERT_ATN); /* want MESS_OUT */ printk("Rejecting Unknown Extended Message(%02x). ",ucp[2]); hostdata->outgoing_msg[0] = MESSAGE_REJECT; hostdata->outgoing_len = 1; write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK); hostdata->state = S_CONNECTED; break; } hostdata->incoming_ptr = 0; } /* We need to read more MESS_IN bytes for the extended message */ else { hostdata->incoming_ptr++; write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK); hostdata->state = S_CONNECTED; } break; default: printk("Rejecting Unknown Message(%02x) ",msg); write_3393_cmd(hostdata,WD_CMD_ASSERT_ATN); /* want MESS_OUT */ hostdata->outgoing_msg[0] = MESSAGE_REJECT; hostdata->outgoing_len = 1; write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK); hostdata->state = S_CONNECTED; } break;/* Note: this interrupt will occur only after a LEVEL2 command */ case CSR_SEL_XFER_DONE:/* Make sure that reselection is enabled at this point - it may * have been turned off for the command that just completed. */ write_3393(hostdata,WD_SOURCE_ID, SRCID_ER); if (phs == 0x60) {DB(DB_INTR,printk("SX-DONE-%ld",cmd->pid)) cmd->SCp.Message = COMMAND_COMPLETE; lun = read_3393(hostdata,WD_TARGET_LUN);DB(DB_INTR,printk(":%d.%d",cmd->SCp.Status,lun)) hostdata->connected = NULL; hostdata->busy[cmd->target] &= ~(1 << cmd->lun); hostdata->state = S_UNCONNECTED; if (cmd->SCp.Status == ILLEGAL_STATUS_BYTE) cmd->SCp.Status = lun; if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD) cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); else cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); cmd->scsi_done(cmd);/* We are no longer connected to a target - check to see if * there are commands waiting to be executed. */ in2000_execute(instance); } else { printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---",asr,sr,phs,cmd->pid); } break;/* Note: this interrupt will occur only after a LEVEL2 command */ case CSR_SDP:DB(DB_INTR,printk("SDP")) hostdata->state = S_RUNNING_LEVEL2; write_3393(hostdata,WD_COMMAND_PHASE, 0x41); write_3393_cmd(hostdata,WD_CMD_SEL_ATN_XFER); break; case CSR_XFER_DONE|PHS_MESS_OUT: case CSR_UNEXP |PHS_MESS_OUT: case CSR_SRV_REQ |PHS_MESS_OUT:DB(DB_INTR,printk("MSG_OUT="))/* To get here, we've probably requested MESSAGE_OUT and have * already put the correct bytes in outgoing_msg[] and filled * in outgoing_len. We simply send them out to the SCSI bus. * Sometimes we get MESSAGE_OUT phase when we're not expecting * it - like when our SDTR message is rejected by a target. Some * targets send the REJECT before receiving all of the extended * message, and then seem to go back to MESSAGE_OUT for a byte * or two. Not sure why, or if I'm doing something wrong to * cause this to happen. Regardless, it seems that sending * NOP messages in these situations results in no harm and * makes everyone happy. */ if (hostdata->outgoing_len == 0) { hostdata->outgoing_len = 1; hostdata->outgoing_msg[0] = NOP; } transfer_pio(hostdata->outgoing_msg, hostdata->outgoing_len, DATA_OUT_DIR, hostdata);DB(DB_INTR,printk("%02x",hostdata->outgoing_msg[0])) hostdata->outgoing_len = 0; hostdata->state = S_CONNECTED; break; case CSR_UNEXP_DISC:/* I think I've seen this after a request-sense that was in response * to an error condition, but not sure. We certainly need to do * something when we get this interrupt - the question is 'what?'. * Let's think positively, and assume some command has finished * in a legal manner (like a command that provokes a request-sense), * so we treat it as a normal command-complete-disconnect. *//* Make sure that reselection is enabled at this point - it may * have been turned off for the command that just completed. */ write_3393(hostdata,WD_SOURCE_ID, SRCID_ER); if (cmd == NULL) { printk(" - Already disconnected! "); hostdata->state = S_UNCONNECTED;/* release the SMP spin_lock and restore irq state */ CLISPIN_UNLOCK(flags); return; }DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid)) hostdata->connected = NULL; hostdata->busy[cmd->target] &= ~(1 << cmd->lun); hostdata->state = S_UNCONNECTED; if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD) cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); else cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); cmd->scsi_done(cmd);/* We are no longer connected to a target - check to see if * there are commands waiting to be executed. */ in2000_execute(instance); break; case CSR_DISC:/* Make sure that reselection is enabled at this point - it may * have been turned off for the command that just completed. */ write_3393(hostdata,WD_SOURCE_ID, SRCID_ER);DB(DB_INTR,printk("DISC-%ld",cmd->pid)) if (cmd == NULL) { printk(" - Already disconnected! "); hostdata->state = S_UNCONNECTED; } switch (hostdata->state) { case S_PRE_CMP_DISC: hostdata->connected = NULL; hostdata->busy[cmd->target] &= ~(1 << cmd->lun); hostdata->state = S_UNCONNECTED;DB(DB_INTR,printk(":%d",cmd->SCp.Status)) if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD) cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); else cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); cmd->scsi_done(cmd); break; case S_PRE_TMP_DISC: case S_RUNNING_LEVEL2: cmd->host_scribble = (uchar *)hostdata->disconnected_Q; hostdata->disconnected_Q = cmd; hostdata->connected = NULL; hostdata->state = S_UNCONNECTED;#ifdef PROC_STATISTICS hostdata->disc_done_cnt[cmd->target]++;#endif break; default: printk("*** Unexpected DISCONNECT interrupt! ***"); hostdata->state = S_UNCONNECTED; }/* We are no longer connected to a target - check to see if * there are commands waiting to be executed. */ in2000_execute(instance); break; case CSR_RESEL_AM:DB(DB_INTR,printk("RESEL")) /* First we have to make sure this reselection didn't */ /* happen during Arbitration/Selection of some other device. */ /* If yes, put losing command back on top of input_Q. */ if (hostdata->level2 <= L2_NONE) { if (hostdata->selecting) { cmd = (Scsi_Cmnd *)hostdata->selecting; hostdata->selecting = NULL; hostdata->busy[cmd->target] &= ~(1 << cmd->lun); cmd->host_scribble = (uchar *)hostdata->input_Q; hostdata->input_Q = cmd; } } else { if (cmd) { if (phs == 0x00) { hostdata->busy[cmd->target] &= ~(1 << cmd->lun); cmd->host_scribble = (uchar *)hostdata->input_Q; hostdata->input_Q = cmd; } else { printk("---%02x:%02x:%02x-TROUBLE: Intrusive ReSelect!---",asr,sr,phs); while (1) printk("\r"); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -