📄 ahc.c
字号:
regs[SSTAT0] &= ~data; /* clear interrupt status bits */ if (!ahc->intr_scsi_clr_done) /* compute interrupt latency */ { lat = YS__Simtime - ahc->intr_scsi_start; ahc->intr_scsi_clr_avg += lat; if (lat > ahc->intr_scsi_clr_max) ahc->intr_scsi_clr_max = lat; if (lat < ahc->intr_scsi_clr_min) ahc->intr_scsi_clr_min = lat; ahc->intr_scsi_clr_done = 1; } break; /*---------------------------------------------------------------*/ /* clear SCSI interrupt status 1 (write only) */ case CLRSINT1: regs[CLRSINT1] &= ~data; /* clear register */ regs[SSTAT1] &= ~data; /* clear interrupt status bits */ if (!ahc->intr_scsi_clr_done) /* compute interrupt latency */ { lat = YS__Simtime - ahc->intr_scsi_start; ahc->intr_scsi_clr_avg += lat; if (lat > ahc->intr_scsi_clr_max) ahc->intr_scsi_clr_max = lat; if (lat < ahc->intr_scsi_clr_min) ahc->intr_scsi_clr_min = lat; ahc->intr_scsi_clr_done = 1; } break; /*---------------------------------------------------------------*/ /* clear host interrupt (write only) */ case CLRINT: regs[CLRINT] &= ~data; /* clear register */ regs[INTSTAT] &= ~data; /* clear interrupt status bits */ if (!ahc->intr_seq_clr_done) /* compute interrupt latency */ { lat = YS__Simtime - ahc->intr_seq_start; ahc->intr_seq_clr_avg += lat; if (lat > ahc->intr_seq_clr_max) ahc->intr_seq_clr_max = lat; if (lat < ahc->intr_seq_clr_min) ahc->intr_seq_clr_min = lat; ahc->intr_seq_clr_done = 1; } if (!ahc->intr_cmpl_clr_done) /* compute interrupt latency */ { lat = YS__Simtime - ahc->intr_cmpl_start; ahc->intr_cmpl_clr_avg += lat; if (lat > ahc->intr_cmpl_clr_max) ahc->intr_cmpl_clr_max = lat; if (lat < ahc->intr_cmpl_clr_min) ahc->intr_cmpl_clr_min = lat; ahc->intr_cmpl_clr_done = 1; } break; /*---------------------------------------------------------------*/ /* write to SCB input queue: load queue, adjust counter, */ /* start seqencer */ case QINFIFO: ahc_queue_shiftin(ahc->qin_fifo, data); regs[QINCNT] = ahc_queue_size(ahc->qin_fifo);#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, " Load QIN -> %i\n", regs[QINCNT]);#endif if (!(regs[HCNTRL] & PAUSE) && (IsNotScheduled(ahc->sequencer))) schedule_event(ahc->sequencer, YS__Simtime + ahc->seq_cycle_fast); ahc->scbs[data].start_time = YS__Simtime; ahc->request_count++; break; /*---------------------------------------------------------------*/ /* write to any SCB register: copy new byte into current SCB */ /* entry and add SCB index to offset if in auto-increment mode */ case SCB_CONTROL: case SCB_TCL: case SCB_TARGET_STATUS: case SCB_SGCOUNT: case SCB_SGPTR0: case SCB_SGPTR1: case SCB_SGPTR2: case SCB_SGPTR3: case SCB_RESID_SGCNT: case SCB_RESID_DCNT0: case SCB_RESID_DCNT1: case SCB_RESID_DCNT2: case SCB_DATAPTR0: case SCB_DATAPTR1: case SCB_DATAPTR2: case SCB_DATAPTR3: case SCB_DATACNT0: case SCB_DATACNT1: case SCB_DATACNT2: case SCB_CMDPTR0: case SCB_CMDPTR1: case SCB_CMDPTR2: case SCB_CMDPTR3: case SCB_CMDLEN: case SCB_TAG: case SCB_NEXT: case SCB_PREV: { unsigned char *p; p = (unsigned char*)&(ahc->scbs[regs[SCBPTR]]); p += offset - SCBARRAY; if (regs[SCBCNT] & SCBAUTO) p += (regs[SCBCNT] & SCBCNT_MASK); *p = data; break; } /*---------------------------------------------------------------*/ default: break; } } /* end of request per-byte loop */ /*-----------------------------------------------------------------------*/ /* for writes to a SCB register, increment SCB index if auto-increment */ if ((offset >= SCBARRAY) && (offset <= AHC_REG_END) && (regs[SCBCNT] & SCBAUTO)) { memcpy(regs + SCBARRAY, &ahc->scbs[regs[SCBPTR]], AHC_REG_END - SCBARRAY); regs[SCBCNT] = SCBAUTO | (((regs[SCBCNT] & SCBCNT_MASK) + olength) & SCBCNT_MASK); } return(1);}/*=========================================================================*//* PCI Mapping callback routine: called when host writes to PCI address *//* space register. If new value is -1 simply return required address space *//* and flag bits, otherwise map control registers at new base address. *//*=========================================================================*/void ahc_pci_map(void *controller, unsigned address, int node, int module, int function, int reg, unsigned *size, unsigned *flags){ ahc_t *ahc = (ahc_t*)controller; *flags = PCI_MAPREG_TYPE_IO; /* require I/O space */ if (address == 0xFFFFFFFF) /* return size for function 0 */ { /* and register 0, otherwise */ if ((function == 0) && (reg == 0)) /* return 0 (unused) */ *size = AHC_REG_END; else *size = 0; return; } else /* map control registers */ { if (ahc->base_addr != 0) { AddrMap_remove(node, ahc->base_addr, ahc->base_addr + AHC_REG_END, module); PageTable_remove(node, ahc->base_addr); } address = PCI_MAPREG_IO_ADDR(address); AddrMap_insert(node, address, address + AHC_REG_END, module); PageTable_insert(node, address, (char*)ahc->regs); ahc->base_addr = address; }}/*=========================================================================*//* SCSI Controller Sequencer state machine *//* Controls processing of requests, SCSI bus transactions and host bus DMA *//*=========================================================================*/void ahc_sequencer(void){ ahc_t *ahc = (ahc_t*)EventGetArg(NULL); unsigned char *regs = ahc->regs; unsigned char data; ahc_scb_t *scb; double lat; int n; scb = &ahc->scbs[ahc->seq_scb]; switch (ahc->seq_state) { /*===================================================================*/ /* Idle state: return immediately if sequencer is halted, check for */ /* reconnect-SCB, otherwise take SCB off the input queue. Check if */ /* new request is a second non-queued request to a target. */ case SEQ_IDLE: if (ahc->seq_pause) return; if (regs[WAITING_SCBH] != SCB_LIST_NULL) { data = regs[WAITING_SCBH]; ahc->regs[QINCNT] = ahc_queue_size(ahc->qin_fifo); if ((ahc_queue_size(ahc->qin_fifo) == 0) || ((ahc_queue_size(ahc->qin_fifo) > 0) && (ahc_queue_head(ahc->qin_fifo) != data))) { ahc_queue_shiftin_head(ahc->qin_fifo, data); } regs[WAITING_SCBH] = ahc->scbs[data].next;#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] %.0f: AHC Taking entry %i off selection queue; next = %i\n", ahc->scsi_me->mid, YS__Simtime, data, regs[WAITING_SCBH]);#endif } if (ahc_queue_size(ahc->reconnect_scbs) > 0) /* reconnect SCB ? */ { data = ahc_queue_head(ahc->reconnect_scbs); /* take 1. elem. from Q*/ ahc->seq_scb = data; scb = &(ahc->scbs[data]); ahc_queue_shiftout(ahc->reconnect_scbs, data); regs[SCBPTR] = ahc->seq_scb; memcpy(regs + SCBARRAY, scb, AHC_REG_END - SCBARRAY);#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] %.0f: AHC Taking entry %i off reconnect queue; %i waiting\n", ahc->scsi_me->mid, YS__Simtime, data, ahc_queue_size(ahc->reconnect_scbs));#endif ahc->seq_state = SEQ_DATA; schedule_event(ahc->sequencer, YS__Simtime + ahc->seq_cycle_fast); return; } else /* else check input queue */ { if (ahc_queue_size(ahc->qin_fifo) == 0) return; data = ahc_queue_head(ahc->qin_fifo); /* take first elem. from Q*/ ahc->seq_scb = data; scb = &(ahc->scbs[data]);#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] %.0f: AHC Taking entry %i off command queue; %i waiting\n", ahc->scsi_me->mid, YS__Simtime, data, ahc_queue_size(ahc->qin_fifo)-1);#endif if ((ahc->pending[scb->tcl >> 4] != NULL) && (!(scb->control & TAG_ENB))) /* stall second non-queued*/ { /* request to a target */#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] %.0f: AHC Stall additional non-queued request\n", ahc->scsi_me->mid, YS__Simtime);#endif return; } if (regs[WAITING_SCBH] == SCB_LIST_NULL) regs[WAITING_SCBH] = data; else { unsigned char p; p = regs[WAITING_SCBH]; while (ahc->scbs[p].next != SCB_LIST_NULL) p = ahc->scbs[p].next; ahc->scbs[p].next = data; } scb->next = SCB_LIST_NULL; regs[SCBPTR] = ahc->seq_scb; memcpy(regs + SCBARRAY, scb, AHC_REG_END - SCBARRAY); }#ifdef AHC_TRACE YS__logmsg(ahc->scsi_me->nodeid, "[%i] SCB[%i]\n", ahc->scsi_me->mid, data); YS__logmsg(ahc->scsi_me->nodeid, " Control = 0x%02X\n", scb->control); YS__logmsg(ahc->scsi_me->nodeid, " Target = 0x%02X\n", scb->tcl); YS__logmsg(ahc->scsi_me->nodeid, " SegCount = 0x%02X\n", scb->sg_segment_count); YS__logmsg(ahc->scsi_me->nodeid, " Segment = 0x%02X%02X%02X%02X\n", scb->sg_segment_ptr3, scb->sg_segment_ptr2, scb->sg_segment_ptr1, scb->sg_segment_ptr0); YS__logmsg(ahc->scsi_me->nodeid, " Data = 0x%02X%02X%02X%02X\n", scb->data_ptr3, scb->data_ptr2, scb->data_ptr1, scb->data_ptr0); YS__logmsg(ahc->scsi_me->nodeid, " DataLen = 0x00%02X%02X%02X\n", scb->data_count2, scb->data_count1, scb->data_count0); YS__logmsg(ahc->scsi_me->nodeid, " Command = 0x%02X%02X%02X%02X\n", scb->scsi_cmd_ptr3, scb->scsi_cmd_ptr2, scb->scsi_cmd_ptr1, scb->scsi_cmd_ptr0); YS__logmsg(ahc->scsi_me->nodeid, " CmdLen = 0x%02X\n", scb->scsi_cmd_len); YS__logmsg(ahc->scsi_me->nodeid, " Tag = 0x%02X\n", scb->tag); YS__logmsg(ahc->scsi_me->nodeid, " Next = 0x%02X\n", scb->next); YS__logmsg(ahc->scsi_me->nodeid, " Prev = 0x%02X\n", scb->prev);#endif /* prepare for command DMA ------------------------------------------*/ scb->dma_addr = (scb->scsi_cmd_ptr3 << 24) | (scb->scsi_cmd_ptr2 << 16) | (scb->scsi_cmd_ptr1 << 8) | scb->scsi_cmd_ptr0; scb->dma_length = scb->scsi_cmd_len; scb->dma_sg_length = scb->scsi_cmd_len; scb->dma_length_done = scb->scsi_cmd_len; scb->dma_buffer = scb->command; if (scb->dma_length > sizeof(scb->command)) YS__errmsg(ahc->scsi_me->nodeid, "AHC[%i]: SCSI Command too long (0x%02X)", ahc->scsi_me->mid, scb->dma_length); ahc->seq_state = SEQ_COMMAND; scb->status = SCB_ACTIVE; scb->write = 0; /*===================================================================*/ /* read SCSI command into internal buffer via DMA */ /* issue host bus transactions until dma_length is 0, then wait for */ /* all data returns. */ case SEQ_COMMAND: 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: Command DMA Done\n", ahc->scsi_me->mid, YS__Simtime);#endif /* prepare for DMA of S/G vector if it has not been read ------------*/ if ((scb->dma_segments == NULL) && (scb->sg_segment_count > 0)) { scb->dma_segments = malloc(scb->sg_segment_count * sizeof(ahc_dmaseg_t)); if (scb->dma_segments == NULL) YS__errmsg(ahc->scsi_me->nodeid, "Malloc failed in %s:%i", __FILE__, __LINE__); scb->dma_addr = (scb->sg_segment_ptr3 << 24) | (scb->sg_segment_ptr2 << 16) | (scb->sg_segment_ptr1 << 8) | scb->sg_segment_ptr0; scb->dma_length = scb->sg_segment_count * sizeof(ahc_dmaseg_t); scb->dma_sg_length = scb->sg_segment_count * sizeof(ahc_dmaseg_t); scb->dma_length_done = scb->dma_length; scb->dma_buffer = (unsigned char*)scb->dma_segments; } else { scb->dma_length = 0; scb->dma_sg_length = 0; scb->dma_length_done = 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -