📄 ahc.c
字号:
ahc->seq_state = SEQ_DMA_VECTOR; /*===================================================================*/ /* read DMA S/G vector via DMA */ /* issue host bus transactions until remaining length is 0, then */ /* wait for all data returns. If a reconnect request arrived in the */ /* meantime drop current request and return to idle, otherwise */ /* issue request on SCSI bus and remove from input queue. */ case SEQ_DMA_VECTOR: if (scb->dma_length > 0) /* need more data */ ahc_dma(ahc, scb); if (scb->dma_length_done > 0) /* wait for data returns */ { if (IsNotScheduled(ahc->sequencer)) schedule_event(ahc->sequencer, YS__Simtime + ahc->seq_cycle_fast); return; }#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] %.0f: Vector DMA Done\n", ahc->scsi_me->mid, YS__Simtime); for (n = 0; n < scb->sg_segment_count; n++) YS__logmsg(ahc->scsi_me->nodeid, "[%i] Segment %i: 0x%02X%02X%02X%02X 0x%02X%02X%02X%02X\n", ahc->scsi_me->mid, n, scb->dma_segments[n].addr3, scb->dma_segments[n].addr2, scb->dma_segments[n].addr1, scb->dma_segments[n].addr0, scb->dma_segments[n].length3, scb->dma_segments[n].length2, scb->dma_segments[n].length1, scb->dma_segments[n].length0);#endif /* reconnect request arrived: drop current request and return to idle*/ if (ahc_queue_size(ahc->reconnect_scbs) > 0) {#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] %.0f: Reconnect while processing command\n", ahc->scsi_me->mid, YS__Simtime);#endif if (IsNotScheduled(ahc->sequencer)) schedule_event(ahc->sequencer, YS__Simtime + ahc->seq_cycle_fast); ahc->seq_state = SEQ_IDLE; return; } /* otherwise: issue request on SCSI bus and remove from input queue */ if (!ahc_scsi_command(ahc, scb)) YS__errmsg(ahc->scsi_me->nodeid, "AHC[%i]: SCSI Command failed", ahc->scsi_me->mid); if ((ahc_queue_size(ahc->qin_fifo) > 0) && (ahc_queue_head(ahc->qin_fifo) == ahc->seq_scb)) { ahc_queue_shiftout(ahc->qin_fifo, data); ahc->regs[QINCNT] = ahc_queue_size(ahc->qin_fifo); memcpy(regs + SCBARRAY, &ahc->scbs[data], AHC_REG_END - SCBARRAY); if (!(scb->control & TAG_ENB)) ahc->pending[scb->tcl >> 4] = scb; scb->queue_time = YS__Simtime - scb->start_time; } scb->current_segment = 0; scb->dma_length = scb->dma_length_done = 0; regs[SCSIID] |= (scb->tcl & 0xF0); /* prepare for data transfer, start at current S/G segment ----------*/ ahc->seq_state = SEQ_RESPONSE; if (scb->sg_segment_count > 0) { scb->dma_addr = (scb->dma_segments[scb->current_segment].addr3 << 24) | (scb->dma_segments[scb->current_segment].addr2 << 16) | (scb->dma_segments[scb->current_segment].addr1 << 8) | scb->dma_segments[scb->current_segment].addr0; scb->dma_sg_length = (scb->dma_segments[scb->current_segment].length3 << 24) | (scb->dma_segments[scb->current_segment].length2 << 16) | (scb->dma_segments[scb->current_segment].length1 << 8) | scb->dma_segments[scb->current_segment].length0; scb->dma_buffer = scb->data; } else { scb->data = NULL; scb->dma_buffer = NULL; scb->dma_addr = 0; scb->dma_sg_length = 0; } /*===================================================================*/ /* Wait for SCSI device response. */ case SEQ_RESPONSE: if (scb->status == SCB_ACTIVE) /* keep polling while no response */ { if (IsNotScheduled(ahc->sequencer)) schedule_event(ahc->sequencer, YS__Simtime + ahc->seq_cycle_fast); return; } lat = YS__Simtime - scb->start_time; if (lat > ahc->request_connect_time_max) ahc->request_connect_time_max = lat; if (lat < ahc->request_connect_time_min) ahc->request_connect_time_min = lat; ahc->request_connect_time_avg += lat; regs[WAITING_SCBH] = ahc->scbs[regs[WAITING_SCBH]].next; if (scb->status == SCB_ERROR) /* SCSI error (timeout): finish */ { /* request and return to idle */#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] %.0f: AHC Command Error\n", ahc->scsi_me->mid, YS__Simtime);#endif ahc_scsi_complete(ahc, scb); ahc->seq_state = SEQ_IDLE; if (IsNotScheduled(ahc->sequencer)) schedule_event(ahc->sequencer, YS__Simtime + ahc->seq_cycle_fast); return; } if (scb->status == SCB_BUSY) /* device busy: finish request */ { /* and return to idle */#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] %.0f: AHC Command Busy\n", ahc->scsi_me->mid, YS__Simtime);#endif ahc_scsi_complete(ahc, scb); ahc->seq_state = SEQ_IDLE; if (IsNotScheduled(ahc->sequencer)) schedule_event(ahc->sequencer, YS__Simtime + ahc->seq_cycle_read * 50); return; } if (scb->status == SCB_DISCONNECT) /* SCSI disconnect: return to idle*/ {#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] %.0f: AHC Command Disconnect\n", ahc->scsi_me->mid, YS__Simtime);#endif ahc->seq_state = SEQ_IDLE; scb->control |= 0x04; if (IsNotScheduled(ahc->sequencer)) schedule_event(ahc->sequencer, YS__Simtime + ahc->seq_cycle_fast); ahc->request_disconnect_count++; return; } if (scb->status == SCB_CONNECT) /* SCSI connect: start data xfer */ { ahc->seq_state = SEQ_DATA; if (IsNotScheduled(ahc->sequencer)) schedule_event(ahc->sequencer, YS__Simtime + (scb->write ? ahc->seq_cycle_read : ahc->seq_cycle_write)); return; } if (scb->status == SCB_COMPLETE) /* request complete: finish it and */ { /* return to idle */#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "%.0f: AHC Command Complete %i (no DMA)\n", YS__Simtime, scb->status);#endif ahc_scsi_complete(ahc, scb); if (IsNotScheduled(ahc->sequencer)) schedule_event(ahc->sequencer, YS__Simtime + (scb->write ? ahc->seq_cycle_read : ahc->seq_cycle_write)); ahc->seq_state = SEQ_IDLE; return; } /*===================================================================*/ /* data transfer: dma_length is set by connect/reconnect request, */ /* issue host transactions until length is 0, if at end of current */ /* segment move to next segment, check status at end of transfer. */ case SEQ_DATA: if (scb->dma_length > 0) ahc_dma(ahc, scb); /* at end of segment, more data and more segments: go to next segment*/ if ((scb->dma_sg_length <= 0) && (scb->current_segment + 1 < scb->sg_segment_count)) { scb->current_segment++; scb->dma_sg_length = (scb->dma_segments[scb->current_segment].length3 << 24) | (scb->dma_segments[scb->current_segment].length2 << 16) | (scb->dma_segments[scb->current_segment].length1 << 8) | scb->dma_segments[scb->current_segment].length0; scb->dma_addr = (scb->dma_segments[scb->current_segment].addr3 << 24) | (scb->dma_segments[scb->current_segment].addr2 << 16) | (scb->dma_segments[scb->current_segment].addr1 << 8) | scb->dma_segments[scb->current_segment].addr0;#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] %.0f: AHC Next Segment %i of %i -> 0x%08X 0x%08X\n", ahc->scsi_me->mid, YS__Simtime, scb->current_segment, scb->sg_segment_count, scb->dma_addr, scb->dma_sg_length);#endif } if (scb->dma_length_done > 0) /* wait for completion */ { if (IsNotScheduled(ahc->sequencer)) schedule_event(ahc->sequencer, YS__Simtime + (scb->write ? ahc->seq_cycle_read : ahc->seq_cycle_write)); return; } /* request is complete: finish it and return to idle ----------------*/ if (scb->status == SCB_COMPLETE) {#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] %.0f: AHC Command Complete %i %i\n", ahc->scsi_me->mid, YS__Simtime, scb->status, ahc_queue_size(ahc->reconnect_scbs));#endif ahc_scsi_complete(ahc, scb); if (IsNotScheduled(ahc->sequencer)) schedule_event(ahc->sequencer, YS__Simtime + (scb->write ? ahc->seq_cycle_read : ahc->seq_cycle_write)); ahc->seq_state = SEQ_IDLE; return; } if (scb->status == SCB_DISCONNECT) { ahc->seq_state = SEQ_IDLE; if (IsNotScheduled(ahc->sequencer)) schedule_event(ahc->sequencer, YS__Simtime + ahc->seq_cycle_fast); return; } /* no request status (neither complete nor save_data_ptr): poll -----*/ if (scb->status == SCB_CONNECT) { if (IsNotScheduled(ahc->sequencer)) schedule_event(ahc->sequencer, YS__Simtime + ahc->seq_cycle_fast); return; } break; /*-------------------------------------------------------------------*/ default: YS__errmsg(ahc->scsi_me->nodeid, "AHC[%i]: Unknown SCSI Sequencer State %i\n", ahc->scsi_me->mid, ahc->seq_state); }}/*=========================================================================*//* Perform a pending DMA transaction *//* copy data between internal buffer and main memory. *//* Called when request is completed at caches/memory. *//*=========================================================================*/static void ahc_perform(REQ *req){ ahc_scb_t *scb = (ahc_scb_t*)req->d.mem.aux; char *addr; int n; addr = PageTable_lookup(req->node, req->paddr); if (addr == NULL) YS__errmsg(req->node, "AHC: DMA to/from non-existing memory location 0x%08X\n", req->paddr); if (req->prcr_req_type == WRITE) memcpy(addr, req->d.mem.buf, req->d.mem.count); else memcpy(req->d.mem.buf, addr, req->d.mem.count); scb->dma_length_done -= req->d.mem.count;}void ahc_complete(REQ *req, HIT_TYPE ht){}/*=========================================================================*//* Issue a host bus DMA transaction: Determine size based on remaining *//* length and address aligmnent, determine read/write, set physical address*//* and completion callback routines. Issue to generic SCSI controller. *//* Adjust DMA address, buffer pointer and length before returning. *//*=========================================================================*/void ahc_dma(ahc_t *ahc, ahc_scb_t *scb){ REQ *req; req = (REQ*)YS__PoolGetObj(&YS__ReqPool); memset(req, 0, sizeof(REQ)); req->vaddr = scb->dma_addr; req->paddr = scb->dma_addr; req->size = ARCH_linesz2; req->perform = ahc_perform; req->complete = ahc_complete; req->d.mem.buf = scb->dma_buffer; req->d.mem.aux = scb; req->d.mem.count = min(min(scb->dma_length, scb->dma_sg_length), ARCH_linesz2 - (scb->dma_addr % ARCH_linesz2)); if (scb->write) req->prcr_req_type = WRITE; else req->prcr_req_type = READ; if (!SCSI_cntl_host_issue(ahc->scsi_me, req)) { YS__PoolReturnObj(&YS__ReqPool, req); return; } scb->dma_addr += req->d.mem.count; scb->dma_buffer += req->d.mem.count; scb->dma_length -= req->d.mem.count; scb->dma_sg_length -= req->d.mem.count; if (req->d.mem.count <= 0) YS__errmsg(ahc->scsi_me->nodeid, "AHC[%i]: Invalid DMA Transaction size %i 0x%08X in state %i\n", ahc->scsi_me->mid, req->d.mem.count, req->paddr, ahc->seq_state); #ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] %.0f: DMA %s (%s) 0x%08X %i bytes -> %i %i %p\n", ahc->scsi_me->mid, YS__Simtime, scb->write ? "Write" : "Read", req->type == WRITEPURGE ? "WRITE_PURGE" : ReqName[req->req_type], req->paddr, req->d.mem.count, scb->dma_length, scb->dma_sg_length, req->d.mem.buf);#endif}/*=========================================================================*//* Assemble and issue SCSI request based on command vector. Allocate *//* request structure, fill in initiator, target and lun, set queue tags *//* and decode command, including length and block size. Also set DMA *//* direction and allocate data buffer. *//*=========================================================================*/int ahc_scsi_command(ahc_t *ahc, ahc_scb_t *scb)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -