📄 am53c974.c
字号:
* Purpose : interrupt handler ** ** Inputs : irq - interrupt line, regs - ? ** ** Returns : nothing *************************************************************************/static void AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs){AM53C974_local_declare(); struct Scsi_Host *instance;struct AM53C974_hostdata *hostdata;unsigned char cmdreg, dmastatus, statreg, isreg, instreg, cfifo;/* find AM53C974 hostadapter responsible for this interrupt */for (instance = first_instance; instance; instance = instance->next) if ((instance->irq == irq) && (instance->hostt == the_template)) goto FOUND;sti();return;/* found; now decode and process */FOUND:hostdata = (struct AM53C974_hostdata *)instance->hostdata;AM53C974_setio(instance);dmastatus = AM53C974_read_8(DMASTATUS);DEB_INTR(printk(SEPARATOR_LINE));DEB_INTR(printk("AM53C974 interrupt; dmastatus=0x%02x\n", dmastatus));KEYWAIT();/*** DMA related interrupts ***/if (hostdata->connected && (dmastatus & (DMASTATUS_ERROR | DMASTATUS_PWDN | DMASTATUS_ABORT))) { /* DMA error or POWERDOWN */ printk("scsi%d: DMA error or powerdown; dmastatus: 0x%02x\n", instance->host_no, dmastatus);#ifdef AM53C974_DEBUG deb_stop = 1;#endif panic("scsi%d: cannot recover\n", instance->host_no); }if (hostdata->connected && (dmastatus & DMASTATUS_DONE)) { /* DMA transfer done */ unsigned long residual; cli(); if (!(AM53C974_read_8(DMACMD) & DMACMD_DIR)) { do { dmastatus = AM53C974_read_8(DMASTATUS); residual = AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) | (AM53C974_read_8(CTCHREG) << 16); residual += AM53C974_read_8(CFIREG) & CFIREG_CF; } while (!(dmastatus & DMASTATUS_SCSIINT) && residual); residual = AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) | (AM53C974_read_8(CTCHREG) << 16); residual += AM53C974_read_8(CFIREG) & CFIREG_CF; } else residual = 0; hostdata->connected->SCp.ptr += hostdata->connected->SCp.this_residual - residual; hostdata->connected->SCp.this_residual = residual; AM53C974_write_8(DMACMD, DMACMD_IDLE); /* if service request missed before, process it now (ugly) */ if (hostdata->dma_busy) { hostdata->dma_busy = 0; cmdreg = AM53C974_read_8(CMDREG); statreg = AM53C974_read_8(STATREG); isreg = AM53C974_read_8(ISREG); instreg = AM53C974_read_8(INSTREG); cfifo = AM53C974_cfifo(); AM53C974_information_transfer(instance, statreg, isreg, instreg, cfifo, dmastatus); } sti(); } if (!(dmastatus & DMASTATUS_SCSIINT)) { sti(); return; }/*** SCSI related interrupts ***/cmdreg = AM53C974_read_8(CMDREG);statreg = AM53C974_read_8(STATREG);isreg = AM53C974_read_8(ISREG);instreg = AM53C974_read_8(INSTREG);cfifo = AM53C974_cfifo();DEB_INTR(printk("scsi%d: statreg: 0x%02x; isreg: 0x%02x; instreg: 0x%02x; cfifo: 0x%02x\n", instance->host_no, statreg, isreg, instreg, cfifo));if (statreg & STATREG_PE) { /* parity error */#ifdef AM53C974_DEBUG deb_stop = 1;#endif printk("scsi%d : PARITY error\n", instance->host_no); if (hostdata->connected) hostdata->sync_off[hostdata->connected->target] = 0; /* setup asynchronous transfer */ hostdata->aborted = 1; }if (statreg & STATREG_IOE) { /* illegal operation error */#ifdef AM53C974_DEBUG deb_stop = 1;#endif printk("scsi%d : ILLEGAL OPERATION error\n", instance->host_no); printk("cmdreg: 0x%02x; dmacmd: 0x%02x; statreg: 0x%02x; \n" "isreg: 0x%02x; instreg: 0x%02x; cfifo: 0x%02x\n", cmdreg, AM53C974_read_8(DMACMD), statreg, isreg, instreg, cfifo); }if (hostdata->in_reset && (instreg & INSTREG_SRST)) { /* RESET INTERRUPT */#ifdef AM53C974_DEBUG deb_stop = 1;#endif DEB(printk("Bus reset interrupt received\n")); AM53C974_intr_bus_reset(instance); cli(); if (hostdata->connected) { hostdata->connected->result = DID_RESET << 16; hostdata->connected->scsi_done((Scsi_Cmnd *)hostdata->connected); hostdata->connected = NULL; } else { if (hostdata->sel_cmd) { hostdata->sel_cmd->result = DID_RESET << 16; hostdata->sel_cmd->scsi_done((Scsi_Cmnd *)hostdata->sel_cmd); hostdata->sel_cmd = NULL; } } sti(); if (hostdata->in_reset == 1) goto EXIT; else return; }if (instreg & INSTREG_ICMD) { /* INVALID COMMAND INTERRUPT */#ifdef AM53C974_DEBUG deb_stop = 1;#endif printk("scsi%d: Invalid command interrupt\n", instance->host_no); printk("cmdreg: 0x%02x; dmacmd: 0x%02x; statreg: 0x%02x; dmastatus: 0x%02x; \n" "isreg: 0x%02x; instreg: 0x%02x; cfifo: 0x%02x\n", cmdreg, AM53C974_read_8(DMACMD), statreg, dmastatus, isreg, instreg, cfifo); panic("scsi%d: cannot recover\n", instance->host_no); }if (instreg & INSTREG_DIS) { /* DISCONNECT INTERRUPT */ DEB_INTR(printk("Disconnect interrupt received; ")); cli(); AM53C974_intr_disconnect(instance); sti(); goto EXIT; }if (instreg & INSTREG_RESEL) { /* RESELECTION INTERRUPT */ DEB_INTR(printk("Reselection interrupt received\n")); cli(); AM53C974_intr_reselect(instance, statreg); sti(); goto EXIT; }if (instreg & INSTREG_SO) { DEB_INTR(printk("Successful operation interrupt received\n")); if (hostdata->selecting) { DEB_INTR(printk("DSR completed, starting select\n")); cli(); AM53C974_select(instance, (Scsi_Cmnd *)hostdata->sel_cmd, (hostdata->sel_cmd->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT); hostdata->selecting = 0; AM53C974_set_sync(instance, hostdata->sel_cmd->target); sti(); return; } if (hostdata->sel_cmd != NULL) { if ( ((isreg & ISREG_IS) != ISREG_OK_NO_STOP) && ((isreg & ISREG_IS) != ISREG_OK_STOP) ) { /* UNSUCCESSFUL SELECTION */ DEB_INTR(printk("unsuccessful selection\n")); cli(); hostdata->dma_busy = 0; LIST(hostdata->sel_cmd, hostdata->issue_queue); hostdata->sel_cmd->host_scribble = (unsigned char *)hostdata->issue_queue; hostdata->issue_queue = hostdata->sel_cmd; hostdata->sel_cmd = NULL; hostdata->selecting = 0; sti(); goto EXIT; } else { /* SUCCESSFUL SELECTION */ DEB(printk("successful selection; cmd=0x%02lx\n", (long)hostdata->sel_cmd)); cli(); hostdata->dma_busy = 0; hostdata->disconnecting = 0; hostdata->connected = hostdata->sel_cmd; hostdata->sel_cmd = NULL; hostdata->selecting = 0;#ifdef SCSI2 if (!hostdata->connected->device->tagged_queue)#endif hostdata->busy[hostdata->connected->target] |= (1 << hostdata->connected->lun); /* very strange -- use_sg is sometimes nonzero for request sense commands !! */ if ((hostdata->connected->cmnd[0] == REQUEST_SENSE) && hostdata->connected->use_sg) { DEB(printk("scsi%d: REQUEST_SENSE command with nonzero use_sg\n", instance->host_no)); KEYWAIT(); hostdata->connected->use_sg = 0; } initialize_SCp((Scsi_Cmnd *)hostdata->connected); hostdata->connected->SCp.phase = PHASE_CMDOUT; AM53C974_information_transfer(instance, statreg, isreg, instreg, cfifo, dmastatus); sti(); return; } } else { cli(); AM53C974_information_transfer(instance, statreg, isreg, instreg, cfifo, dmastatus); sti(); return; } } if (instreg & INSTREG_SR) { DEB_INTR(printk("Service request interrupt received, ")); if (hostdata->connected) { DEB_INTR(printk("calling information_transfer\n")); cli(); AM53C974_information_transfer(instance, statreg, isreg, instreg, cfifo, dmastatus); sti(); } else { printk("scsi%d: weird: service request when no command connected\n", instance->host_no); AM53C974_write_8(CMDREG, CMDREG_CFIFO); } /* clear FIFO */ return; }EXIT: DEB_INTR(printk("intr: starting main\n")); run_main(); DEB_INTR(printk("end of intr\n"));}/************************************************************************** * Function : AM53C974_intr_disconnect(struct Scsi_Host *instance)** Purpose : manage target disconnection** Inputs : instance -- which AM53C974* * Returns : nothing**************************************************************************/static void AM53C974_intr_disconnect(struct Scsi_Host *instance) {AM53C974_local_declare(); struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata;Scsi_Cmnd *cmd;AM53C974_setio(instance);if (hostdata->sel_cmd != NULL) { /* normal selection timeout, typical for nonexisting targets */ cmd = (Scsi_Cmnd *)hostdata->sel_cmd; DEB_INTR(printk("bad target\n")); cmd->result = DID_BAD_TARGET << 16; goto EXIT_FINISHED; }if (!hostdata->connected) { /* can happen if controller was reset, a device tried to reconnect, failed and disconnects now */ AM53C974_write_8(CMDREG, CMDREG_CFIFO); return; }if (hostdata->disconnecting) { /* target sent disconnect message, so we are prepared */ cmd = (Scsi_Cmnd *)hostdata->connected; AM53C974_set_async(instance, cmd->target); DEB_INTR(printk("scsi%d : disc. from cmnd %d for ta %d, lun %d\n", instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun)); if (cmd->device->disconnect) { /* target wants to reselect later */ DEB_INTR(printk("ok, re-enabling selection\n")); LIST(cmd,hostdata->disconnected_queue); cmd->host_scribble = (unsigned char *)hostdata->disconnected_queue; hostdata->disconnected_queue = cmd; DEB_QUEUE(printk("scsi%d : command for target %d lun %d this %d was moved from connected to" " the disconnected_queue\n", instance->host_no, cmd->target, cmd->lun, hostdata->disconnected_queue->SCp.this_residual)); DEB_QUEUE(AM53C974_print_queues(instance)); goto EXIT_UNFINISHED; } else { /* target does not want to reselect later, we are really finished */#ifdef AM53C974_DEBUG if (cmd->cmnd[0] == REQUEST_SENSE) { int i; printk("Request sense data dump:\n"); for (i = 0; i < cmd->request_bufflen; i++) { printk("%02x ", *((char *)(cmd->request_buffer) + i)); if (i && !(i % 16)) printk("\n"); } printk("\n"); }#endif goto EXIT_FINISHED; } /* !cmd->device->disconnect */ } /* if (hostdata->disconnecting) *//* no disconnect message received; unexpected disconnection */cmd = (Scsi_Cmnd *)hostdata->connected;if (cmd) {#ifdef AM53C974_DEBUG deb_stop = 1;#endif AM53C974_set_async(instance, cmd->target); printk("scsi%d: Unexpected disconnect; phase: %d; target: %d; this_residual: %d; buffers_residual: %d; message: %d\n", instance->host_no, cmd->SCp.phase, cmd->target, cmd->SCp.this_residual, cmd->SCp.buffers_residual, cmd->SCp.Message); printk("cmdreg: 0x%02x; statreg: 0x%02x; isreg: 0x%02x; cfifo: 0x%02x\n", AM53C974_read_8(CMDREG), AM53C974_read_8(STATREG), AM53C974_read_8(ISREG), AM53C974_read_8(CFIREG) & CFIREG_CF); if ((hostdata->last_message[0] == EXTENDED_MESSAGE) && (hostdata->last_message[2] == EXTENDED_SDTR)) { /* sync. negotiation was aborted, setup asynchronous transfer with target */ hostdata->sync_off[cmd->target] = 0; } if (hostdata->aborted || hostdata->msgout[0] == ABORT) cmd->result = DID_ABORT << 16; else cmd->result = DID_ERROR << 16; goto EXIT_FINISHED; }EXIT_FINISHED:hostdata->aborted = 0;hostdata->msgout[0] = NOP;hostdata->sel_cmd = NULL;hostdata->connected = NULL;hostdata->selecting = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -