in2000.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,042 行 · 第 1/5 页
C
2,042 行
hostdata->sync_stat[cmd->device->id] = 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_DEBUG printk("%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->device->id] != 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->device->id] = calc_sync_xfer(hostdata->default_sx_per / 4, 0); } else { hostdata->sync_xfer[cmd->device->id] = id; }#ifdef SYNC_DEBUG printk("sync_xfer=%02x", hostdata->sync_xfer[cmd->device->id]);#endif hostdata->sync_stat[cmd->device->id] = 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->device->id] &= ~(1 << cmd->device->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 */ spin_unlock_irqrestore(instance->host_lock, flags); return IRQ_HANDLED; } DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->pid)) hostdata->connected = NULL; hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->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->device->id] &= ~(1 << cmd->device->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->device->id]++;#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->device->id] &= ~(1 << cmd->device->lun); cmd->host_scribble = (uchar *) hostdata->input_Q; hostdata->input_Q = cmd; } } else { if (cmd) { if (phs == 0x00) { hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->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"); } } } /* OK - find out which device reselected us. */ id = read_3393(hostdata, WD_SOURCE_ID); id &= SRCID_MASK; /* and extract the lun from the ID message. (Note that we don't * bother to check for a valid message here - I guess this is * not the right way to go, but....) */ lun = read_3393(hostdata, WD_DATA); if (hostdata->level2 < L2_RESELECT) write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK); lun &= 7; /* Now we look for the command that's reconnecting. */ cmd = (Scsi_Cmnd *) hostdata->disconnected_Q; patch = NULL; while (cmd) { if (id == cmd->device->id && lun == cmd->device->lun) break; patch = cmd; cmd = (Scsi_Cmnd *) cmd->host_scribble; } /* Hmm. Couldn't find a valid command.... What to do? */ if (!cmd) { printk("---TROUBLE: target %d.%d not in disconnect queue---", id, lun); break; } /* Ok, found the command - now start it up again. */ if (patch) patch->host_scribble = cmd->host_scribble; else hostdata->disconnected_Q = (Scsi_Cmnd *) cmd->host_scribble; hostdata->connected = cmd; /* We don't need to worry about 'initialize_SCp()' or 'hostdata->busy[]' * because these things are preserved over a disconnect. * But we DO need to fix the DPD bit so it's correct for this command. */ if (is_dir_out(cmd)) write_3393(hostdata, WD_DESTINATION_ID, cmd->device->id); else write_3393(hostdata, WD_DESTINATION_ID, cmd->device->id | DSTID_DPD); if (hostdata->level2 >= L2_RESELECT) { write_3393_count(hostdata, 0); /* we want a DATA_PHASE interrupt */ write_3393(hostdata, WD_COMMAND_PHASE, 0x45); write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER); hostdata->state = S_RUNNING_LEVEL2; } else hostdata->state = S_CONNECTED; DB(DB_INTR, printk("-%ld", cmd->pid)) break; default: printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--", asr, sr, phs); } write1_io(0, IO_LED_OFF); DB(DB_INTR, printk("} "))/* release the SMP spin_lock and restore irq state */ spin_unlock_irqrestore(instance->host_lock, flags); return IRQ_HANDLED;}#define RESET_CARD 0#define RESET_CARD_AND_BUS 1#define B_FLAG 0x80/* * Caller must hold instance lock! */static int reset_hardware(struct Scsi_Host *instance, int type){ struct IN2000_hostdata *hostdata; int qt, x; hostdata = (struct IN2000_hostdata *) instance->hostdata; write1_io(0, IO_LED_ON); if (type == RESET_CARD_AND_BUS) { write1_io(0, IO_CARD_RESET); x = read1_io(IO_HARDWARE); } x = read_3393(hostdata, WD_SCSI_STATUS); /* clear any WD intrpt */ write_3393(hostdata, WD_OWN_ID, instance->this_id | OWNID_EAF | OWNID_RAF | OWNID_FS_8); write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); write_3393(hostdata, WD_SYNCHRONOUS_TRANSFER, calc_sync_xfer(hostdata->default_sx_per / 4, DEFAULT_SX_OFF)); write1_io(0, IO_FIFO_WRITE); /* clear fifo counter */ write1_io(0, IO_FIFO_READ); /* start fifo out in read mode */ write_3393(hostdata, WD_COMMAND, WD_CMD_RESET); /* FIXME: timeout ?? */ while (!(READ_AUX_STAT() & ASR_INT)) cpu_relax(); /* wait for RESET to complete */ x = read_3393(hostdata, WD_SCSI_STATUS); /* clear interrupt */ write_3393(hostdata, WD_QUEUE_TAG, 0xa5); /* any random number */ qt = read_3393(hostdata, WD_QUEUE_TAG); if (qt == 0xa5) { x |= B_FLAG; write_3393(hostdata, WD_QUEUE_TAG, 0); } write_3393(hostdata, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE); write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); write1_io(0, IO_LED_OFF);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?