📄 am53c974.c
字号:
/* 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; hostdata->disconnecting = 0; hostdata->dma_busy = 0; hostdata->busy[cmd->target] &= ~(1 << cmd->lun); AM53C974_write_8(CMDREG, CMDREG_CFIFO); DEB(printk("disconnect; issue_queue: 0x%lx, disconnected_queue: 0x%lx\n", (long) hostdata->issue_queue, (long) hostdata->disconnected_queue)); cmd->scsi_done(cmd); if (!hostdata->selecting) { AM53C974_set_async(instance, cmd->target); AM53C974_write_8(CMDREG, CMDREG_ESR); } /* allow reselect */ return; EXIT_UNFINISHED: hostdata->msgout[0] = NOP; hostdata->sel_cmd = NULL; hostdata->connected = NULL; hostdata->aborted = 0; hostdata->selecting = 0; hostdata->disconnecting = 0; hostdata->dma_busy = 0; DEB(printk("disconnect; issue_queue: 0x%lx, disconnected_queue: 0x%lx\n", (long) hostdata->issue_queue, (long) hostdata->disconnected_queue)); if (!hostdata->selecting) { AM53C974_set_async(instance, cmd->target); AM53C974_write_8(CMDREG, CMDREG_ESR); } /* allow reselect */ return;}/************************************************************************** * Function : int AM53C974_sync_neg(struct Scsi_Host *instance, int target, unsigned char *msg)** Purpose : setup message string for sync. negotiation** Inputs : instance -- which AM53C974* target -- which SCSI target to deal with* msg -- input message string* * Returns : 0 if parameters accepted or 1 if not accepted** Side effects: hostdata is changed** Note: we assume here that fastclk is enabled**************************************************************************/static int AM53C974_sync_neg(struct Scsi_Host *instance, int target, unsigned char *msg){ AM53C974_local_declare(); struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; int period, offset, i, rate, rate_rem; AM53C974_setio(instance); period = (DEF_CLK * msg[3] * 8 + 1000) / 2000; if (period < MIN_PERIOD) { period = MIN_PERIOD; hostdata->msgout[3] = period / 4; } else if (period > MAX_PERIOD) { period = MAX_PERIOD; hostdata->msgout[3] = period / 4; } else hostdata->msgout[3] = msg[3]; offset = msg[4]; if (offset > MAX_OFFSET) offset = MAX_OFFSET; hostdata->msgout[4] = offset; hostdata->sync_per[target] = period; hostdata->sync_off[target] = offset; for (i = 0; i < 3; i++) hostdata->msgout[i] = msg[i]; if ((hostdata->msgout[3] != msg[3]) || (msg[4] != offset)) return (1); rate = DEF_CLK / period; rate_rem = 10 * (DEF_CLK - period * rate) / period; if (offset) printk("\ntarget %d: rate=%d.%d Mhz, synchronous, sync offset=%d bytes\n", target, rate, rate_rem, offset); else printk("\ntarget %d: rate=%d.%d Mhz, asynchronous\n", target, rate, rate_rem); return (0);}/************************************************************************** * Function : AM53C974_set_async(struct Scsi_Host *instance, int target)** Purpose : put controller into async. mode** Inputs : instance -- which AM53C974* target -- which SCSI target to deal with* * Returns : nothing**************************************************************************/static __inline__ void AM53C974_set_async(struct Scsi_Host *instance, int target){ AM53C974_local_declare(); struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; AM53C974_setio(instance); AM53C974_write_8(STPREG, hostdata->sync_per[target]); AM53C974_write_8(SOFREG, (DEF_SOF_RAD << 6) | (DEF_SOF_RAA << 4));}/************************************************************************** * Function : AM53C974_set_sync(struct Scsi_Host *instance, int target)** Purpose : put controller into sync. mode** Inputs : instance -- which AM53C974* target -- which SCSI target to deal with* * Returns : nothing**************************************************************************/static __inline__ void AM53C974_set_sync(struct Scsi_Host *instance, int target){ AM53C974_local_declare(); struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; AM53C974_setio(instance); AM53C974_write_8(STPREG, hostdata->sync_per[target]); AM53C974_write_8(SOFREG, (SOFREG_SO & hostdata->sync_off[target]) | (DEF_SOF_RAD << 6) | (DEF_SOF_RAA << 4));}/************************************************************************ Function : AM53C974_information_transfer(struct Scsi_Host *instance, ** unsigned char statreg, unsigned char isreg, ** unsigned char instreg, unsigned char cfifo, ** unsigned char dmastatus) ** ** Purpose : handle phase changes ** ** Inputs : instance - which AM53C974 ** statreg - status register ** isreg - internal state register ** instreg - interrupt status register ** cfifo - number of bytes in FIFO ** dmastatus - dma status register ** ** Returns : nothing *************************************************************************/static void AM53C974_information_transfer(struct Scsi_Host *instance, unsigned char statreg, unsigned char isreg, unsigned char instreg, unsigned char cfifo, unsigned char dmastatus){ AM53C974_local_declare(); struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; int ret, i, len, residual = -1; AM53C974_setio(instance); DEB_INFO(printk(SEPARATOR_LINE)); switch (statreg & STATREG_PHASE) { /* scsi phase */ case PHASE_DATAOUT: DEB_INFO(printk("Dataout phase; cmd=0x%lx, sel_cmd=0x%lx, this_residual=%d, buffers_residual=%d\n", (long) hostdata->connected, (long) hostdata->sel_cmd, cmd->SCp.this_residual, cmd->SCp.buffers_residual)); cmd->SCp.phase = PHASE_DATAOUT; goto PHASE_DATA_IO; case PHASE_DATAIN: DEB_INFO(printk("Datain phase; cmd=0x%lx, sel_cmd=0x%lx, this_residual=%d, buffers_residual=%d\n", (long) hostdata->connected, (long) hostdata->sel_cmd, cmd->SCp.this_residual, cmd->SCp.buffers_residual)); cmd->SCp.phase = PHASE_DATAIN; PHASE_DATA_IO: if (hostdata->aborted) { AM53C974_write_8(DMACMD, DMACMD_IDLE); AM53C974_write_8(CMDREG, CMDREG_CFIFO); AM53C974_write_8(CMDREG, CMDREG_SATN); return; } if ((!cmd->SCp.this_residual) && cmd->SCp.buffers_residual) { cmd->SCp.buffer++; cmd->SCp.buffers_residual--; cmd->SCp.ptr = (unsigned char *) cmd->SCp.buffer->address; cmd->SCp.this_residual = cmd->SCp.buffer->length; } if (cmd->SCp.this_residual) { if (!(AM53C974_read_8(DMACMD) & DMACMD_START)) { hostdata->dma_busy = 0; AM53C974_transfer_dma(instance, statreg & STATREG_IO, (unsigned long) cmd->SCp.this_residual, cmd->SCp.ptr); } else hostdata->dma_busy = 1; } return; case PHASE_MSGIN: DEB_INFO(printk("Message-In phase; cmd=0x%lx, sel_cmd=0x%lx\n", (long) hostdata->connected, (long) hostdata->sel_cmd)); AM53C974_set_async(instance, cmd->target); if (cmd->SCp.phase == PHASE_DATAIN) AM53C974_dma_blast(instance, dmastatus, statreg); if ((cmd->SCp.phase == PHASE_DATAOUT) && (AM53C974_read_8(DMACMD) & DMACMD_START)) { AM53C974_write_8(DMACMD, DMACMD_IDLE); residual = cfifo + (AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) | (AM53C974_read_8(CTCHREG) << 16)); cmd->SCp.ptr += cmd->SCp.this_residual - residual; cmd->SCp.this_residual = residual; if (cfifo) { AM53C974_write_8(CMDREG, CMDREG_CFIFO); cfifo = 0; } } if (cmd->SCp.phase == PHASE_STATIN) { while ((AM53C974_read_8(CFIREG) & CFIREG_CF) < 2); cmd->SCp.Status = AM53C974_read_8(FFREG); cmd->SCp.Message = AM53C974_read_8(FFREG); DEB_INFO(printk("Message-In phase; status=0x%02x, message=0x%02x\n", cmd->SCp.Status, cmd->SCp.Message)); ret = AM53C974_message(instance, cmd, cmd->SCp.Message); } else { if (!cfifo) { AM53C974_write_8(CMDREG, CMDREG_IT); AM53C974_poll_int(); cmd->SCp.Message = AM53C974_read_8(FFREG); } ret = AM53C974_message(instance, cmd, cmd->SCp.Message); } cmd->SCp.phase = PHASE_MSGIN; AM53C974_set_sync(instance, cmd->target); break; case PHASE_MSGOUT: DEB_INFO(printk("Message-Out phase; cfifo=%d; msgout[0]=0x%02x\n", AM53C974_read_8(CFIREG) & CFIREG_CF, hostdata->msgout[0])); AM53C974_write_8(DMACMD, DMACMD_IDLE); AM53C974_set_async(instance, cmd->target); for (i = 0; i < sizeof(hostdata->last_message); i++) hostdata->last_message[i] = hostdata->msgout[i]; if ((hostdata->msgout[0] == 0) || INSIDE(hostdata->msgout[0], 0x02, 0x1F) || INSIDE(hostdata->msgout[0], 0x80, 0xFF)) len = 1; else { if (hostdata->msgout[0] == EXTENDED_MESSAGE) {#ifdef AM53C974_DEBUG_INFO printk("Extended message dump:\n"); for (i = 0; i < hostdata->msgout[1] + 2; i++) { printk("%02x ", hostdata->msgout[i]); if (i && !(i % 16)) printk("\n"); } printk("\n");#endif len = hostdata->msgout[1] + 2; } else len = 2; } for (i = 0; i < len; i++) AM53C974_write_8(FFREG, hostdata->msgout[i]); AM53C974_write_8(CMDREG, CMDREG_IT); cmd->SCp.phase = PHASE_MSGOUT; hostdata->msgout[0] = NOP; AM53C974_set_sync(instance, cmd->target); break; case PHASE_CMDOUT: DEB_INFO(printk("Command-Out phase\n")); AM53C974_set_async(instance, cmd->target); for (i = 0; i < cmd->cmd_len; i++) AM53C974_write_8(FFREG, cmd->cmnd[i]); AM53C974_write_8(CMDREG, CMDREG_IT); cmd->SCp.phase = PHASE_CMDOUT; AM53C974_set_sync(instance, cmd->target); break; case PHASE_STATIN: DEB_INFO(printk("Status phase\n")); if (cmd->SCp.phase == PHASE_DATAIN) AM53C974_dma_blast(instance, dmastatus, statreg); AM53C974_set_async(instance, cmd->target); if (cmd->SCp.phase == PHASE_DATAOUT) { unsigned long residual; if (AM53C974_read_8(DMACMD) & DMACMD_START) { AM53C974_write_8(DMACMD, DMACMD_IDLE); residual = cfifo + (AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) | (AM53C974_read_8(CTCHREG) << 16)); cmd->SCp.ptr += cmd->SCp.this_residual - residual; cmd->SCp.this_residual = residual; } if (cfifo) { AM53C974_write_8(CMDREG, CMDREG_CFIFO); cfifo = 0; } } cm
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -