📄 wd33c93.c
字号:
/* Respond to the specific WD3393 interrupt - there are quite a few! */ switch (sr) { case CSR_TIMEOUT:DB(DB_INTR,printk("TIMEOUT")) if (hostdata->state == S_RUNNING_LEVEL2) hostdata->connected = NULL; else { cmd = (Scsi_Cmnd *)hostdata->selecting; /* get a valid cmd */ hostdata->selecting = NULL; } cmd->result = DID_NO_CONNECT << 16; hostdata->busy[cmd->target] &= ~(1 << cmd->lun); hostdata->state = S_UNCONNECTED; cmd->scsi_done(cmd); /* From esp.c: * There is a window of time within the scsi_done() path * of execution where interrupts are turned back on full * blast and left that way. During that time we could * reconnect to a disconnected command, then we'd bomb * out below. We could also end up executing two commands * at _once_. ...just so you know why the restore_flags() * is here... */ restore_flags(flags);/* We are not connected to a target - check to see if there * are commands waiting to be executed. */ wd33c93_execute(instance); break;/* Note: this interrupt should not occur in a LEVEL2 command */ case CSR_SELECT:DB(DB_INTR,printk("SELECT")) hostdata->connected = cmd = (Scsi_Cmnd *)hostdata->selecting; hostdata->selecting = NULL; /* construct an IDENTIFY message with correct disconnect bit */ hostdata->outgoing_msg[0] = (0x80 | 0x00 | cmd->lun); if (cmd->SCp.phase) hostdata->outgoing_msg[0] |= 0x40; if (hostdata->sync_stat[cmd->target] == SS_FIRST) {#ifdef SYNC_DEBUGprintk(" sending SDTR ");#endif hostdata->sync_stat[cmd->target] = SS_WAITING;/* Tack on a 2nd message to ask about synchronous transfers. If we've * been asked to do only asynchronous transfers on this device, we * request a fifo depth of 0, which is equivalent to async - should * solve the problems some people have had with GVP's Guru ROM. */ hostdata->outgoing_msg[1] = EXTENDED_MESSAGE; hostdata->outgoing_msg[2] = 3; hostdata->outgoing_msg[3] = EXTENDED_SDTR; if (hostdata->no_sync & (1 << cmd->target)) { hostdata->outgoing_msg[4] = hostdata->default_sx_per/4; hostdata->outgoing_msg[5] = 0; } else { hostdata->outgoing_msg[4] = OPTIMUM_SX_PER/4; hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF; } hostdata->outgoing_len = 6; } else hostdata->outgoing_len = 1; hostdata->state = S_CONNECTED; break; case CSR_XFER_DONE|PHS_DATA_IN: case CSR_UNEXP |PHS_DATA_IN: case CSR_SRV_REQ |PHS_DATA_IN:DB(DB_INTR,printk("IN-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual)) transfer_bytes(regs, cmd, DATA_IN_DIR); if (hostdata->state != S_RUNNING_LEVEL2) hostdata->state = S_CONNECTED; break; case CSR_XFER_DONE|PHS_DATA_OUT: case CSR_UNEXP |PHS_DATA_OUT: case CSR_SRV_REQ |PHS_DATA_OUT:DB(DB_INTR,printk("OUT-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual)) transfer_bytes(regs, cmd, DATA_OUT_DIR); 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(regs, 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(regs);DB(DB_INTR,printk("%02x",cmd->SCp.Status)) if (hostdata->level2 >= L2_BASIC) { sr = read_wd33c93(regs, WD_SCSI_STATUS); /* clear interrupt */ hostdata->state = S_RUNNING_LEVEL2; write_wd33c93(regs, WD_COMMAND_PHASE, 0x50); write_wd33c93_cmd(regs, 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(regs); sr = read_wd33c93(regs, 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_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); hostdata->state = S_PRE_CMP_DISC; break; case SAVE_POINTERS:DB(DB_INTR,printk("SDP")) write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); hostdata->state = S_CONNECTED; break; case RESTORE_POINTERS:DB(DB_INTR,printk("RDP")) if (hostdata->level2 >= L2_BASIC) { write_wd33c93(regs, WD_COMMAND_PHASE, 0x45); write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER); hostdata->state = S_RUNNING_LEVEL2; } else { write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); hostdata->state = S_CONNECTED; } break; case DISCONNECT:DB(DB_INTR,printk("DIS")) cmd->device->disconnect = 1; write_wd33c93_cmd(regs, 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_wd33c93_cmd(regs, 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_wd33c93_cmd(regs, 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_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); hostdata->state = S_CONNECTED; break; case EXTENDED_WDTR: write_wd33c93_cmd(regs, 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_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); hostdata->state = S_CONNECTED; break; default: write_wd33c93_cmd(regs, 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_wd33c93_cmd(regs, 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_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); hostdata->state = S_CONNECTED; } break; default: printk("Rejecting Unknown Message(%02x) ",msg); write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN); /* want MESS_OUT */ hostdata->outgoing_msg[0] = MESSAGE_REJECT; hostdata->outgoing_len = 1; write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); hostdata->state = S_CONNECTED; } restore_flags(flags); 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_wd33c93(regs, WD_SOURCE_ID, SRCID_ER); if (phs == 0x60) {DB(DB_INTR,printk("SX-DONE-%ld",cmd->pid)) cmd->SCp.Message = COMMAND_COMPLETE; lun = read_wd33c93(regs, 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. */ restore_flags(flags); wd33c93_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_wd33c93(regs, WD_COMMAND_PHASE, 0x41); write_wd33c93_cmd(regs, 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(regs, 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_wd33c93(regs, WD_SOURCE_ID, SRCID_ER); if (cmd == NULL) { printk(" - Already disconnected! "); hostdata->state = S_UNCONNECTED; 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. */ /* look above for comments on scsi_done() */ restore_flags(flags); wd33c93_execute(instance); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -