📄 fas216.c
字号:
break; case reject: outb(CMD_SETATN, REG_CMD(info)); msgqueue_flush(&info->scsi.msgs); msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); info->scsi.phase = PHASE_MSGOUT_EXPECT; case async: dev->period = info->ifcfg.asyncperiod / 4; dev->sof = 0; dev->stp = info->scsi.async_stp; fas216_set_sync(info, info->SCpnt->target); break; case none: break; }}/* Function: void fas216_handlewide(FAS216_Info *info, char *msg) * Purpose : Handle a wide transfer message from the target * Params : info - state structure for interface * : msg - message from target */static voidfas216_handlewide(FAS216_Info *info, char *msg){ struct fas216_device *dev = &info->device[info->SCpnt->target]; enum { wide, bit8, none, reject } res = none;#ifdef SCSI2_WIDE switch (msg[0]) { case MESSAGE_REJECT: /* Wide transfer request failed. * Note: SCSI II r10: * * SCSI devices that are capable of wide * data transfers shall not respond to a * WDTR message with a MESSAGE REJECT message. * * Hence, if we get this condition, we never * reattempt negociation for this device. */ if (dev->wide_state == neg_inprogress) { dev->wide_state = neg_invalid; res = bit8; } break; case EXTENDED_MESSAGE: switch (dev->wide_state) { /* We don't accept wide data transfer requests. * Respond with a MESSAGE REJECT to prevent a * wide data transfer agreement from being reached. */ case neg_invalid: res = reject; break; /* We were not negociating a wide data transfer, * but the device sent is a negociation request. * Honour the request by sending back a WDTR * message containing our capability, limited by * the targets capability. */ default: outb(CMD_SETATN, REG_CMD(info)); if (msg[3] > info->ifcfg.wide_max_size) msg[3] = info->ifcfg.wide_max_size; msgqueue_flush(&info->scsi.msgs); msgqueue_addmsg(&info->scsi.msgs, 4, EXTENDED_MESSAGE, 2, EXTENDED_WDTR, msg[3]); info->scsi.phase = PHASE_MSGOUT_EXPECT; res = wide; break; /* We initiated the wide data transfer negociation, * and have successfully received a response from the * target. The synchronous transfer agreement has been * reached. Note: if the values returned are out of our * bounds, we must reject the message. */ case neg_inprogress: res = reject; if (msg[3] <= info->ifcfg.wide_max_size) { dev->wide_state = neg_complete; res = wide; } break; } }#else res = reject;#endif switch (res) { case wide: dev->wide_xfer = msg[3]; break; case reject: outb(CMD_SETATN, REG_CMD(info)); msgqueue_flush(&info->scsi.msgs); msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); info->scsi.phase = PHASE_MSGOUT_EXPECT; case bit8: dev->wide_xfer = 0; break; case none: break; }}/* Function: void fas216_updateptrs(FAS216_Info *info, int bytes_transferred) * Purpose : update data pointers after transfer suspended/paused * Params : info - interface's local pointer to update * bytes_transferred - number of bytes transferred */static voidfas216_updateptrs(FAS216_Info *info, int bytes_transferred){ unsigned char *ptr; unsigned int residual; fas216_checkmagic(info); ptr = info->scsi.SCp.ptr; residual = info->scsi.SCp.this_residual; info->SCpnt->request_bufflen -= bytes_transferred; while (residual <= bytes_transferred && bytes_transferred) { /* We have used up this buffer */ bytes_transferred -= residual; if (info->scsi.SCp.buffers_residual) { info->scsi.SCp.buffer++; info->scsi.SCp.buffers_residual--; ptr = (unsigned char *)info->scsi.SCp.buffer->address; residual = info->scsi.SCp.buffer->length; } else { ptr = NULL; residual = 0; } } residual -= bytes_transferred; ptr += bytes_transferred; if (residual == 0) ptr = NULL; info->scsi.SCp.ptr = ptr; info->scsi.SCp.this_residual = residual;}/* Function: void fas216_pio(FAS216_Info *info, fasdmadir_t direction) * Purpose : transfer data off of/on to card using programmed IO * Params : info - interface to transfer data to/from * direction - direction to transfer data (DMA_OUT/DMA_IN) * Notes : this is incredibly slow */static voidfas216_pio(FAS216_Info *info, fasdmadir_t direction){ unsigned int residual; char *ptr; fas216_checkmagic(info); residual = info->scsi.SCp.this_residual; ptr = info->scsi.SCp.ptr; if (direction == DMA_OUT) outb(*ptr++, REG_FF(info)); else *ptr++ = inb(REG_FF(info)); residual -= 1; if (residual == 0) { if (info->scsi.SCp.buffers_residual) { info->scsi.SCp.buffer++; info->scsi.SCp.buffers_residual--; ptr = (unsigned char *)info->scsi.SCp.buffer->address; residual = info->scsi.SCp.buffer->length; } else { ptr = NULL; residual = 0; } } info->scsi.SCp.ptr = ptr; info->scsi.SCp.this_residual = residual;}/* Function: void fas216_starttransfer(FAS216_Info *info, * fasdmadir_t direction) * Purpose : Start a DMA/PIO transfer off of/on to card * Params : info - interface from which device disconnected from * direction - transfer direction (DMA_OUT/DMA_IN) */static voidfas216_starttransfer(FAS216_Info *info, fasdmadir_t direction, int flush_fifo){ fasdmatype_t dmatype; fas216_checkmagic(info); info->scsi.phase = (direction == DMA_OUT) ? PHASE_DATAOUT : PHASE_DATAIN; if (info->dma.transfer_type != fasdma_none && info->dma.transfer_type != fasdma_pio) { unsigned long total, residual; if (info->dma.transfer_type == fasdma_real_all) total = info->SCpnt->request_bufflen; else total = info->scsi.SCp.this_residual; residual = (inb(REG_CFIS(info)) & CFIS_CF) + inb(REG_CTCL(info)) + (inb(REG_CTCM(info)) << 8) + (inb(REG_CTCH(info)) << 16); fas216_updateptrs(info, total - residual); } info->dma.transfer_type = fasdma_none; if (!info->scsi.SCp.ptr) { printk("scsi%d.%c: null buffer passed to " "fas216_starttransfer\n", info->host->host_no, fas216_target(info)); return; } /* flush FIFO */ if (flush_fifo) outb(CMD_FLUSHFIFO, REG_CMD(info)); /* * Default to PIO mode or DMA mode if we have a synchronous * transfer agreement. */ if (info->device[info->SCpnt->target].sof && info->dma.setup) dmatype = fasdma_real_all; else dmatype = fasdma_pio; if (info->dma.setup) dmatype = info->dma.setup(info->host, &info->scsi.SCp, direction, dmatype); info->dma.transfer_type = dmatype; switch (dmatype) { case fasdma_pio: outb(0, REG_SOF(info)); outb(info->scsi.async_stp, REG_STP(info)); outb(info->scsi.SCp.this_residual, REG_STCL(info)); outb(info->scsi.SCp.this_residual >> 8, REG_STCM(info)); outb(info->scsi.SCp.this_residual >> 16, REG_STCH(info)); outb(CMD_TRANSFERINFO, REG_CMD(info)); fas216_pio(info, direction); break; case fasdma_pseudo: outb(info->scsi.SCp.this_residual, REG_STCL(info)); outb(info->scsi.SCp.this_residual >> 8, REG_STCM(info)); outb(info->scsi.SCp.this_residual >> 16, REG_STCH(info)); outb(CMD_TRANSFERINFO | CMD_WITHDMA, REG_CMD(info)); info->dma.pseudo(info->host, &info->scsi.SCp, direction, info->SCpnt->transfersize); break; case fasdma_real_block: outb(info->scsi.SCp.this_residual, REG_STCL(info)); outb(info->scsi.SCp.this_residual >> 8, REG_STCM(info)); outb(info->scsi.SCp.this_residual >> 16, REG_STCH(info)); outb(CMD_TRANSFERINFO | CMD_WITHDMA, REG_CMD(info)); break; case fasdma_real_all: outb(info->SCpnt->request_bufflen, REG_STCL(info)); outb(info->SCpnt->request_bufflen >> 8, REG_STCM(info)); outb(info->SCpnt->request_bufflen >> 16, REG_STCH(info)); outb(CMD_TRANSFERINFO | CMD_WITHDMA, REG_CMD(info)); break; default: printk(KERN_ERR "scsi%d.%d: invalid FAS216 DMA type\n", info->host->host_no, fas216_target(info)); break; }}/* Function: void fas216_stoptransfer(FAS216_Info *info) * Purpose : Stop a DMA transfer onto / off of the card * Params : info - interface from which device disconnected from */static voidfas216_stoptransfer(FAS216_Info *info){ fas216_checkmagic(info); if (info->dma.transfer_type != fasdma_none && info->dma.transfer_type != fasdma_pio) { unsigned long total, residual; if ((info->dma.transfer_type == fasdma_real_all || info->dma.transfer_type == fasdma_real_block) && info->dma.stop) info->dma.stop(info->host, &info->scsi.SCp); if (info->dma.transfer_type == fasdma_real_all) total = info->SCpnt->request_bufflen; else total = info->scsi.SCp.this_residual; residual = (inb(REG_CFIS(info)) & CFIS_CF) + inb(REG_CTCL(info)) + (inb(REG_CTCM(info)) << 8) + (inb(REG_CTCH(info)) << 16); fas216_updateptrs(info, total - residual); info->dma.transfer_type = fasdma_none; } if (info->scsi.phase == PHASE_DATAOUT) outb(CMD_FLUSHFIFO, REG_CMD(info));}/* Function: void fas216_disconnected_intr(FAS216_Info *info) * Purpose : handle device disconnection * Params : info - interface from which device disconnected from */static voidfas216_disconnect_intr(FAS216_Info *info){ fas216_checkmagic(info);#ifdef DEBUG_CONNECT printk("scsi%d.%c: disconnect phase=%02X\n", info->host->host_no, fas216_target(info), info->scsi.phase);#endif msgqueue_flush(&info->scsi.msgs); switch (info->scsi.phase) { case PHASE_SELECTION: /* while selecting - no target */ case PHASE_SELSTEPS: fas216_done(info, DID_NO_CONNECT); break; case PHASE_MSGIN_DISCONNECT: /* message in - disconnecting */ outb(CMD_ENABLESEL, REG_CMD(info)); info->scsi.disconnectable = 1; info->scsi.reconnected.tag = 0; info->scsi.phase = PHASE_IDLE; info->stats.disconnects += 1; break; case PHASE_DONE: /* at end of command - complete */ fas216_done(info, DID_OK); break; case PHASE_MSGOUT: /* message out - possible ABORT message */ if (fas216_get_last_msg(info, info->scsi.msgin_fifo) == ABORT) { info->scsi.aborting = 0; fas216_done(info, DID_ABORT); break; } default: /* huh? */ printk(KERN_ERR "scsi%d.%c: unexpected disconnect in phase %s\n", info->host->host_no, fas216_target(info), fas216_drv_phase(info)); print_debug_list(); fas216_stoptransfer(info); fas216_done(info, DID_ERROR); break; }}/* Function: void fas216_reselected_intr(FAS216_Info *info) * Purpose : Start reconnection of a device * Params : info - interface which was reselected */static voidfas216_reselected_intr(FAS216_Info *info){ unsigned char target, identify_msg, ok; fas216_checkmagic(info); if ((info->scsi.phase == PHASE_SELECTION || info->scsi.phase == PHASE_SELSTEPS) && info->SCpnt) { Scsi_Cmnd *SCpnt = info->SCpnt; info->origSCpnt = SCpnt; info->SCpnt = NULL; if (info->device[SCpnt->target].wide_state == neg_inprogress) info->device[SCpnt->target].wide_state = neg_wait; if (info->device[SCpnt->target].sync_state == neg_inprogress) info->device[SCpnt->target].sync_state = neg_wait; }#ifdef DEBUG_CONNECT printk("scsi%d.%c: reconnect phase=%02X\n", info->host->host_no, fas216_target(info), info->scsi.phase);#endif if ((inb(REG_CFIS(info)) & CFIS_CF) != 2) { printk(KERN_ERR "scsi%d.H: incorrect number of bytes after reselect\n", info->host->host_no); outb(CMD_SETATN, REG_CMD(info)); outb(CMD_MSGACCEPTED, REG_CMD(info)); msgqueue_flush(&info->scsi.msgs); msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); info->scsi.phase = PHASE_MSGOUT_EXPECT; return; } target = inb(REG_FF(info)); identify_msg = inb(REG_FF(info)); ok = 1; if (!(target & (1 << info->host->this_id))) { printk(KERN_ERR "scsi%d.H: invalid host id on reselect\n", info->host->host_no); ok = 0; } if (!(identify_msg & 0x80)) { printk(KERN_ERR "scsi%d.H: no IDENTIFY message on reselect, got msg %02X\n", info->host->host_no, identify_msg); ok = 0; } if (!ok) { /* * Something went wrong - send an initiator error to * the target. */ outb(CMD_SETATN, REG_CMD(info)); outb(CMD_MSGACCEPTED, REG_CMD(info)); msgqueue_flush(&info->scsi.msgs); msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); info->scsi.phase = PHASE_MSGOUT_EXPECT; return; } target &= ~(1 << info->host->this_id); switch (target) { case 1: target = 0; break; case 2: target = 1; break; case 4: target = 2; break; case 8: target = 3; break; case 16: target = 4; break; case 32: target = 5; break; case 64: target = 6; break; case 128: target = 7; break; default: target = info->host->this_id; break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -