📄 am53c974.c
字号:
break; } /* if target/lun is not busy */ } /* for */ } /* if (!hostdata->connected) */ else { DEB(printk("main: connected; cmd = 0x%lx, sel_cmd = 0x%lx\n", (long) hostdata->connected, (long) hostdata->sel_cmd)); } } /* for instance */ } while (!done); main_running = 0; restore_flags(flags);}/************************************************************************* Function : AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs) ** ** Purpose : interrupt handler ** ** Inputs : irq - interrupt line, regs - ? ** ** Returns : nothing *************************************************************************/static void do_AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs){ unsigned long flags; spin_lock_irqsave(&io_request_lock, flags); AM53C974_intr(irq, dev_id, regs); spin_unlock_irqrestore(&io_request_lock, flags);}/************************************************************************* Function : AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs) ** ** 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; 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; unsigned long flags; save_flags(flags); 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); } restore_flags(flags); } if (!(dmastatus & DMASTATUS_SCSIINT)) { 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)) { unsigned long flags; /* RESET INTERRUPT */#ifdef AM53C974_DEBUG deb_stop = 1;#endif DEB(printk("Bus reset interrupt received\n")); AM53C974_intr_bus_reset(instance); save_flags(flags); 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; } } restore_flags(flags); 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) { unsigned long flags; /* DISCONNECT INTERRUPT */ DEB_INTR(printk("Disconnect interrupt received; ")); save_flags(flags); cli(); AM53C974_intr_disconnect(instance); restore_flags(flags); goto EXIT; } if (instreg & INSTREG_RESEL) { unsigned long flags; /* RESELECTION INTERRUPT */ DEB_INTR(printk("Reselection interrupt received\n")); save_flags(flags); cli(); AM53C974_intr_reselect(instance, statreg); restore_flags(flags); goto EXIT; } if (instreg & INSTREG_SO) { DEB_INTR(printk("Successful operation interrupt received\n")); if (hostdata->selecting) { unsigned long flags; DEB_INTR(printk("DSR completed, starting select\n")); save_flags(flags); 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); restore_flags(flags); return; } if (hostdata->sel_cmd != NULL) { if (((isreg & ISREG_IS) != ISREG_OK_NO_STOP) && ((isreg & ISREG_IS) != ISREG_OK_STOP)) { unsigned long flags; /* UNSUCCESSFUL SELECTION */ DEB_INTR(printk("unsuccessful selection\n")); save_flags(flags); 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; restore_flags(flags); goto EXIT; } else { unsigned long flags; /* SUCCESSFUL SELECTION */ DEB(printk("successful selection; cmd=0x%02lx\n", (long) hostdata->sel_cmd)); save_flags(flags); 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); restore_flags(flags); return; } } else { unsigned long flags; save_flags(flags); cli(); AM53C974_information_transfer(instance, statreg, isreg, instreg, cfifo, dmastatus); restore_flags(flags); return; } } if (instreg & INSTREG_SR) { DEB_INTR(printk("Service request interrupt received, ")); if (hostdata->connected) { unsigned long flags; DEB_INTR(printk("calling information_transfer\n")); save_flags(flags); cli(); AM53C974_information_transfer(instance, statreg, isreg, instreg, cfifo, dmastatus); restore_flags(flags); } 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 {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -