📄 stc.c
字号:
* is active. Once REQ and BSY are asserted, the appropiate action * is taken. */ complete = 0; do { STWAIT_WHILE((((staddr->scs_curstat & SCS_REQ) != SCS_REQ) || ((staddr->scs_curstat & SCS_BSY) != SCS_BSY)),1000000,retval); if (retval >= 1000000) {#ifdef STDEBUG printd("\t\tstintr: SCS_REQ or SCS_BSY failed to set\n"); stdumpregs();#endif STDEBUG#ifdef STDEBUG ST_TRACK('H');#endif STDEBUG goto abort; } if (staddr->scs_status & SCS_PARERR) { mprintf ("st0: parity error\n");#ifdef STDEBUG printd("st0: parity error\n");#endif STDEBUG#ifdef STDEBUG ST_TRACK('I');#endif STDEBUG goto abort; } else if (staddr->scs_curstat & SCS_RST) { mprintf ("st0: bus reset\n");#ifdef STDEBUG printd("st0: bus reset\n");#endif STDEBUG#ifdef STDEBUG ST_TRACK('J');#endif STDEBUG goto abort; } i = staddr->scs_reset; stiaddr->nb_int_reqclr = SCS_INT_TAPE; /* * Zero the scs_mode register to clear all * DMA status bits from the last DMA transfer */ staddr->scs_mode = 0; /* * Turn off the SCS_INI_ENOUT driver */ inicmd_tmp &= ~SCS_INI_ENOUT; staddr->scs_inicmd = inicmd_tmp; /* * Read the bus phase, set the phase to match. */ staddr->scs_tarcmd = ((staddr->scs_curstat & SCS_PHA_MSK) >> 2); switch (staddr->scs_curstat & SCS_PHA_MSK) { case SCS_DATAO:#ifdef STDEBUG printd2("stintr: SCS_DATAO:\n");#endif STDEBUG sc->sc_prevpha = sc->sc_fstate; sc->sc_fstate = ST_DATAO_PHA; if (sc->st_opcode != ST_WRITE) { byteptr = (u_char *)&sc->sc_dat[0]; if (sc->st_opcode == ST_MODSEL) { cmdcnt = ST_MODSEL_LEN; } else { if (sc->st_opcode == ST_INQ) { cmdcnt = ST_CMD_LEN; } else {#ifdef STDEBUG printd ("stintr: SCS_DATAO: unknown command 0x%x\n", sc->st_opcode);#endif STDEBUG#ifdef STDEBUG ST_TRACK('K');#endif STDEBUG goto abort; } } inicmd_tmp = SCS_INI_ENOUT; staddr->scs_inicmd = inicmd_tmp; /* * Send the command packet */#ifdef STDEBUG printd2("Data Output Packet: \n"); /* 1 of 3 */#endif STDEBUG for ( ; (cmdcnt > 0); cmdcnt--) { STWAIT_UNTIL(((staddr->scs_curstat & SCS_REQ) == SCS_REQ),10000,retval); if (retval >= 10000) {#ifdef STDEBUG printd("stintr: SCS_DATAO: REQ not set\n");#endif STDEBUG#ifdef STDEBUG ST_TRACK('L');#endif STDEBUG goto abort; }#ifdef STDEBUG printd2 (" %x", *byteptr); /* 2 of 3 */#endif STDEBUG staddr->scs_outdata = *byteptr++; inicmd_tmp |= SCS_INI_ACK; staddr->scs_inicmd = inicmd_tmp; STWAIT_UNTIL(((staddr->scs_curstat & SCS_REQ) != SCS_REQ),10000,retval); if (retval >= 10000) {#ifdef STDEBUG printd("stintr: SCS_DATAO: REQ didn't go false\n");#endif STDEBUG#ifdef STDEBUG ST_TRACK('N');#endif STDEBUG goto abort; } inicmd_tmp &= ~SCS_INI_ACK; staddr->scs_inicmd = inicmd_tmp; }#ifdef STDEBUG printd2 ("\n"); /* 3 of 3 */#endif STDEBUG break; } /* Copy the data from the 16K buffer to memory * (user space or kernel space). Will have to * set up own page table entries when copying to * user space. */ /* * If bytecount is too large, throw out the transfer */ if (bp->b_bcount > 16384) { mprintf("st0: buffer too large\n"); DEV_UGH(sc->sc_device,0,"buffer too large"); bp->b_flags |= B_ERROR;#ifdef STDEBUG ST_TRACK('P');#endif STDEBUG goto abort; break; } /* * set up the count; */ if ((sc->sc_stflags & ST_WAS_DISCON) && (sc->sc_savcnt != 0)) { sc->sc_bcount = -(sc->sc_savcnt); staddr->scd_cnt = sc->sc_savcnt ;#ifdef STDEBUG printd1("stintr#1: scd_cnt = 0x%x, sc_savcnt = 0x%x\n", staddr->scd_cnt, sc->sc_savcnt);#endif STDEBUG } else { sc->sc_bcount = (short)bp->b_bcount; staddr->scd_cnt = (short)-(bp->b_bcount); } /* * Map the user page tables to my page tables (mpte) */ if ((cpu == C_VAXSTAR) && cvs_exmode_on) stv = (char *)cvseddbmem + 0x10000; else stv = (char *)&staddr->nb_ddb[0]; if ((bp->b_flags & B_PHYS) == 0) { bufp = (char *)bp->b_un.b_addr; } else { /* * Map to user space */ v = btop(bp->b_un.b_addr); o = (int)bp->b_un.b_addr & PGOFSET; npf = btoc(bp->b_bcount + o); rp = (bp->b_flags&B_DIRTY) ? &proc[2] : bp->b_proc; if (bp->b_flags & B_UAREA) { pte = &rp->p_addr[v]; } else if (bp->b_flags & B_PAGET) { pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; } else { pte = vtopte(rp, v); } bufp = (char *)ST_bufmap + o; mpte = (struct pte *)stbufmap; for (i = 0; i < npf; i++) { if (pte->pg_pfnum == 0) panic("st0: zero pfn in pte"); *(int *)mpte++ = pte++->pg_pfnum | PG_V | PG_KW; mtpr(TBIS, (char *) ST_bufmap + (i * NBPG)); } *(int *)mpte = 0; mtpr(TBIS, (char *) ST_bufmap + (i * NBPG)); } sc->sc_stflags |= ST_MAPPED; sc->sc_savstv = (long)stv; sc->sc_savbufp = (long)bufp; /* * If the DMA transfer was interrupted by a disconnect * the remaining data to be transfered needs to be * reloaded into the 16K buffer, and then another * DMA transfer started. This only needs to be done * on a write DMA transfer. */ if ((sc->sc_stflags & ST_WAS_DISCON) && (sc->sc_savcnt != 0)) { /* * This is a quick way to subtract the the number of * bytes not transfered before the disconnect, from * the total number of bytes to transfer. The result * is the number of bytes that need to be transfered. * sc->sc_savcnt is in two's complement form. The * number of bytes to be transfered is used as an offset * and added to bufp to get the address of where to start * transfering data from. */ sc->sc_stflags &= ~ST_WAS_DISCON; bufp = bufp + (((short)bp->b_bcount + sc->sc_savcnt) & 0xffff); bcopy (bufp, stv, -(sc->sc_savcnt));#ifdef STDEBUG printd1("stintr: bufp offset = 0x%x, count = 0x%x\n", (((short)bp->b_bcount + sc->sc_savcnt) & 0xffff), -(sc->sc_savcnt));#endif STDEBUG } else { bcopy (bufp, stv, bp->b_bcount); } /* * Enable interrupts, and DMA mode. */ staddr->scs_mode = (SCS_DMA | SCS_INTEOP | SCS_PARCK | SCS_INTPAR); inicmd_tmp = SCS_INI_ENOUT; staddr->scs_inicmd = inicmd_tmp; staddr->scd_dir = SCD_DMA_OUT; /* * Set the starting address in the 16K buffer. This * is really an offset into the buffer. It needs to * be written twice. Whatever is in bits <7:0> gets * moved into bits <15:8> with the bits <15:14> zeroed, * and what ever you write into this register get put * into bits <7:0>. Therefore, the first write contains * the bits destined for <15:8>, and the second write * contains the bits for <7:0>. */ if ((cpu == C_VAXSTAR) && cvs_exmode_on) staddr->nb_scd_adr.l = 0x10000; else { staddr->nb_scd_adr.c[0] = 0; staddr->nb_scd_adr.c[0] = 0; } /* * Start the DMA transfer */ staddr->scs_dmasend = 1; sc->sc_stflags |= (ST_DID_DMA | ST_RETD_KEEP); return(VS_KEEP); break; case SCS_DATAI:#ifdef STDEBUG printd2("stintr: SCS_DATAI:\n");#endif STDEBUG sc->sc_prevpha = sc->sc_fstate; sc->sc_fstate = ST_DATAI_PHA; if (sc->st_opcode != ST_READ) { byteptr = (u_char *)&sc->sc_sns; switch (sc->st_opcode) { case ST_RQSNS: num_expected = ST_RQSNS_LEN; break; case ST_INQ: num_expected = ST_INQ_LEN; byteptr = (u_char *)&sc->st_dat; break; case ST_MODSNS: num_expected = ST_MODSNS_LEN; byteptr = (u_char *)&sc->st_dat; break; case ST_RECDIAG: num_expected = ST_RECDIAG_LEN; byteptr = (u_char *)&sc->st_dat; break; default:#ifdef STDEBUG printd("stintr: SCS_DATAI: unexpected command = %x\n", sc->st_opcode);#endif STDEBUG break; } inicmd_tmp = 0; staddr->scs_inicmd = inicmd_tmp; /* * Receive the command packet */#ifdef STDEBUG printd2("Data In Packet:"); /* 1 of 3 */#endif STDEBUG for ( ; (num_expected > 0); num_expected--) { STWAIT_UNTIL(((staddr->scs_curstat & SCS_REQ) == SCS_REQ),10000,retval); if (retval >= 10000) {#ifdef STDEBUG printd("stintr: SCS_DATAI: REQ not set\n");#endif STDEBUG#ifdef STDEBUG ST_TRACK('Q');#endif STDEBUG goto abort; } *byteptr++ = staddr->scs_curdata;#ifdef STDEBUG printd2(" %x", staddr->scs_curdata); /* 2 of 3 */#endif STDEBUG inicmd_tmp |= SCS_INI_ACK; staddr->scs_inicmd = inicmd_tmp; STWAIT_UNTIL(((staddr->scs_curstat & SCS_REQ) != SCS_REQ),10000,retval); if (retval >= 10000) {#ifdef STDEBUG printd("stintr: SCS_DATAO: REQ didn't go false\n");#endif STDEBUG#ifdef STDEBUG ST_TRACK('R');#endif STDEBUG goto abort; } inicmd_tmp &= ~SCS_INI_ACK; staddr->scs_inicmd = inicmd_tmp; }#ifdef STDEBUG printd2("\n"); /* 3 of 3 */#endif STDEBUG break; } /* * Start of DMA code. * * set up the count; */ if ((sc->sc_stflags & ST_WAS_DISCON) && (sc->sc_savcnt != 0)) { sc->sc_bcount = -(sc->sc_savcnt); staddr->scd_cnt = sc->sc_savcnt ;#ifdef STDEBUG printd1("stintr#2: scd_cnt = 0x%x, sc_savcnt = 0x%x\n", staddr->scd_cnt, sc->sc_savcnt);#endif STDEBUG } else { sc->sc_bcount = (short)bp->b_bcount; staddr->scd_cnt = (short)-(bp->b_bcount); } /* * Enable interrupts, and DMA mode. */ staddr->scs_mode = (SCS_DMA | SCS_INTEOP | SCS_PARCK | SCS_INTPAR); staddr->scs_inicmd = 0; staddr->scd_dir = SCD_DMA_IN; /* * Set the starting address in the 16K buffer. This * is really an offset into the buffer. It needs to * be written twice. Whatever is in bits <7:0> gets * moved into bits <15:8> with the bits <15:14> zeroed, * and what ever you write into this register get put * into bits <7:0>. Therefore, the first write contains * the bits destined for <15:8>, and the second write * contains the bits for <7:0>. */ if ((cpu == C_VAXSTAR) && cvs_exmode_on) staddr->nb_scd_adr.l = 0x10000; else { staddr->nb_scd_adr.c[0] = 0; staddr->nb_scd_adr.c[0] = 0; } /* * Start the DMA transfer */ staddr->scs_dmaircv = 1; sc->sc_stflags |= (ST_DID_DMA | ST_RETD_KEEP); return(VS_KEEP); break; case SCS_CMD:#ifdef STDEBUG printd2("stintr: SCS_CMD:\n");#endif STDEBUG sc->sc_prevpha = sc->sc_fstate; sc->sc_fstate = ST_CMD_PHA; /* * clear savecnt and stflags */ sc->sc_stflags = 0; sc->sc_savcnt = 0; inicmd_tmp = SCS_INI_ENOUT; staddr->scs_inicmd = inicmd_tmp; byteptr = (u_char *)&sc->st_command;#ifdef STDEBUG if ((st_prev_cmd == ST_WFM) && (*byteptr != ST_SPACE)) { printd1("Didn't space back over second filemark\n"); } st_prev_cmd = *byteptr; printd2("cmd pkt: %x %x %x %x %x\n", *byteptr, *(byteptr + 1), *(byteptr + 2), *(byteptr + 3), *(byteptr + 4), *(byteptr + 5));#endif STDEBUG /* * Send the command packet */ for (cmdcnt = ST_CMD_LEN; (cmdcnt > 0); cmdcnt--) { STWAIT_UNTIL(((staddr->scs_curstat & SCS_REQ) == SCS_REQ),10000,retval); if (retval >= 10000) {#ifdef STDEBUG printd("stintr: SCS_CMD: REQ not set\n");#endif STDEBUG#ifdef STDEBUG ST_TRACK('S');#endif STDEBUG goto abort; }#ifdef STDEBUG ST_CMDTRACK(*byteptr); #endif STDEBUG staddr->scs_outdata = *byteptr++; inicmd_tmp |= SCS_INI_ACK; staddr->scs_inicmd = inicmd_tmp; STWAIT_UNTIL(((staddr->scs_curstat & SCS_REQ) != SCS_REQ),10000,retval); if (retval >= 10000) {#ifdef STDEBUG printd("stintr: SCS_CMD: REQ didn't go false\n");#endif STDEBUG#ifdef STDEBUG ST_TRACK('U');#endif STDEBUG goto abort; } inicmd_tmp &= ~SCS_INI_ACK; staddr->scs_inicmd = inicmd_tmp; } break; case SCS_STATUS:#ifdef STDEBUG printd2("stintr: SCS_STATUS:\n");#endif STDEBUG sc->sc_prevpha = sc->sc_fstate; sc->sc_fstate = ST_STATUS_PHA; /* * Save the residual count if the command is a read * or a write. */ if((sc->st_opcode==ST_READ)||(sc->st_opcode==ST_WRITE)) {/* Fix for rev 45 TZK50 *//* if ((sc->sc_prevpha == ST_DATAI_PHA) || (sc->sc_prevpha == ST_DATAO_PHA)) {*/ stiaddr->nb_hltcod = 0; sc->sc_resid = -(staddr->scd_cnt);/* } else { sc->sc_resid = bp->b_bcount; }*/ } STWAIT_UNTIL(((staddr->scs_curstat & SCS_REQ) == SCS_REQ),10000,retval); if (retval >= 10000) {#ifdef STDEBUG printd("stintr: SCS_STATUS: REQ didn't set\n");#endif STDEBUG#ifdef STDEBUG ST_TRACK('V');#endif STDEBUG goto abort; } sc->sc_status = staddr->scs_curdata; inicmd_tmp = SCS_INI_ACK; staddr->scs_inicmd = inicmd_tmp;#ifdef STDEBUG printd2("stintr: SCS_STATUS: ppha = 0x%x, status = 0x%x, scd_cnt = 0x%x\n", sc->sc_prevpha, sc->sc_status, staddr->scd_cnt);#endif STDEBUG STWAIT_WHILE(((staddr->scs_curstat & SCS_REQ) == SCS_REQ),50000,retval); if (retval >= 50000) {#ifdef STDEBUG printd("stintr: SCS_STATUS: REQ didn't go false\n");#endif STDEBUG#ifdef STDEBUG ST_TRACK('W');#endif STDEBUG goto abort; } inicmd_tmp = 0; staddr->scs_inicmd = inicmd_tmp; /* * Check the status */ if (sc->sc_status != ST_GOOD) { sc->sc_stflags |= ST_NEED_SENSE; } break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -