📄 sdc.c
字号:
if(sdstart()) goto loop; /* return keeping the 16K shared buffer */ return(VS_KEEP);bad: bp->b_flags |= B_ERROR; if(sd_st.sd_flags[unit] & DEV_EOM) bp->b_error = ENOSPC; dp = &sdutab[unit]; dp->b_actf = bp->av_forw; iodone(bp); goto loop;}/* This routine gets called after 700 m.sec timeout for RX23 motor to speed up */sd_rx23wakeup(bp)register struct buf *bp;{ register int unit,maxsize,sz,xunit; struct buf *dp; unit = dkunit(bp); sz = (bp->b_bcount+511) >> 9; xunit = minor(bp->b_dev) & 07; dsket_type = rx23_type(); /* find out the diskette type */ if(dsket_type == DT_RX23H) sd_rx23htype(unit); else sd_rx23dtype(unit); if(sdst[dsket_type].sizes[xunit].nblocks == -1) maxsize = sd_st.ucb[unit].hostsize - sdst[dsket_type].sizes[xunit].blkoffs; else maxsize = sdst[dsket_type].sizes[xunit].nblocks; if (bp->b_blkno < 0 || (dkblock(bp)+sz) > maxsize){ if(sddebug) cprintf("%s%d:%s: Accessing beyond block %d\n",DEV_ID,unit,SOFT_ERR,maxsize); sd_st.sd_flags[unit] |= DEV_EOM; bp->b_flags |= B_ERROR; if(sd_st.sd_flags[unit] & DEV_EOM) bp->b_error = ENOSPC; dp = &sdutab[unit]; dp->b_actf = bp->av_forw; iodone(bp); sdustart(); } else { sd_st.sd_blkno = bp->b_blkno + sd_st.ucb[unit].lbnbase + sdst[dsket_type].sizes[xunit].blkoffs; if(sdstart()) sdustart(); } return;}/* This routine checks if a diskette is in the drive and ready */sd_diskette(){ register struct nb1_regs *sdaddr = (struct nb1_regs *)qmem; u_char cmd; sdaddr->dkc_cmd = (SD_SETREG | UDC_DHEAD); sdc_delay(); sdaddr->dkc_reg = 1; /* assume RX33: head 1 valid only for RX33/RX23 */ sdc_delay(); sdaddr->dkc_reg = 0; /* UDC_DCYL */ sdc_delay(); sdaddr->dkc_cmd = (SD_SETREG | UDC_RTCNT); sdc_delay(); sdaddr->dkc_reg = (RT_CNT | RT_INVRDY |RT_MOTOR ); /* UDC_RTCNT */ sdc_delay(); sdaddr->dkc_reg = (MOD_HD | MOD_CHKCRC | MOD_SRTRXH); /* UDC_MODE */ sdc_delay(); sdaddr->dkc_cmd = (SD_SETREG | UDC_TERM); sdc_delay(); sdaddr->dkc_reg = (TERM_CRC | TERM_INT | TERM_DEL | TERM_WRPR | TERM_WRFL); cmd = (SD_SELECT | DTRT_RX33 | (0377&DRV_NUM2)); rx_reselect = 0; if(sd_select(cmd,1)) { mprintf("%s%d:%s: Drive Select failed\n",DEV_ID,sd_st.sd_drno,HARD_ERR); return(1); } if(rx_reselect == 1) { /* The drive is not shown to be ready. So SELECT the * * drive with INVRDY 0 in UDC_RTCNT. */ sdaddr->dkc_cmd = (SD_SETREG | UDC_DHEAD); sdc_delay(); sdaddr->dkc_reg = 1; /* assume RX33: head 1 valid only for RX33 */ sdc_delay(); sdaddr->dkc_reg = 0; /* UDC_DCYL */ sdc_delay(); sdaddr->dkc_cmd = (SD_SETREG | UDC_RTCNT); sdc_delay(); sdaddr->dkc_reg = (RT_CNT |RT_MOTOR ); /*UDC_RTCNT */ cmd = (SD_SELECT | DTRT_RX33 | (0377&DRV_NUM2)); if(sd_select(cmd,1)) { mprintf("%s%d:%s: Drive Select failed\n",DEV_ID,sd_st.sd_drno,HARD_ERR); return(1); } /* The previous SELECT succeeded. Issue STEP command. * * The READY bit in UDC_DSTAT should now be 0. */ if(sd_rxcyl == 0) cmd = SD_STEP; else cmd = (SD_STEP | STEP_OUT); if(sd_step(cmd)) { return(1); } /* Since STEP succeeded, there is a diskette in the * * drive. But the drive has to be selected again * * with INVRDY as 1 in UDC_RTCNT !! I GIVE UP!! */ sdaddr->dkc_cmd = (SD_SETREG | UDC_DHEAD); sdc_delay(); sdaddr->dkc_reg = 1; /* assume RX33: head 1 valid only for RX33 */ sdc_delay(); sdaddr->dkc_reg = 0; /* UDC_DCYL */ sdc_delay(); sdaddr->dkc_cmd = (SD_SETREG | UDC_RTCNT); sdc_delay(); sdaddr->dkc_reg = (RT_CNT | RT_INVRDY |RT_MOTOR ); /*UDC_RTCNT */ sdc_delay(); sdaddr->dkc_reg = (MOD_HD | MOD_CHKCRC | MOD_SRTRXH); /* UDC_MODE */ rx_reselect = 0; cmd = (SD_SELECT | DTRT_RX33 | (0377&DRV_NUM2)); if(sd_select(cmd,1)) { mprintf("%s%d:%s: Drive Select failed\n",DEV_ID,sd_st.sd_drno,HARD_ERR); return(1); } } return(0);}/* This routine returns the RX23 diskette type */rx23_type(){ register struct nb1_regs *sdaddr = (struct nb1_regs *)qmem; register struct nb_regs *sdiaddr = (struct nb_regs *)nexus; register count = 0; u_char status,udc_cstat,udc_dstat; u_char udc_dhead,udc_dcyl,udc_scnt,udc_dsect,cmd; int retry; /* Reset and restore the chip and drive, in order to ensure that the following density test is reliable */ if (sd_diskette()) { if (sddebug) cprintf ("drive is not ready\n"); } else if (sddebug) cprintf ("drive is ready\n"); if (sd_restore(1)) { if (sddebug) cprintf ("Restore failed\n"); } else if (sddebug) cprintf ("Restore Success\n"); /* read sector no. 18 to check if high density RX23 */ udc_dhead = 0; udc_dcyl = 0; udc_scnt = 1; udc_dsect = 18; /* High density */ cmd = (SD_RDLOG | RD_XFER); for(retry=0; retry< 10; retry++) { count = 0; sd_poll = 1; sdiaddr->nb_int_msk &= ~SINT_DC; if(sd_rdwr(udc_dsect,udc_dhead,udc_dcyl,udc_scnt,cmd,0) ) { if (sdiaddr->nb_int_reqclr & SINT_DC) sdiaddr->nb_int_reqclr = SINT_DC; continue; } while(!(sdiaddr->nb_int_reqclr & SINT_DC)) { DELAY(10); if(++count >= LOOP_DELAY) break; } if(count >= LOOP_DELAY) { if (sdiaddr->nb_int_reqclr & SINT_DC) sdiaddr->nb_int_reqclr = SINT_DC; continue; } sdc_delay(); /* to make sure status is correct */ status = sdaddr->dkc_stat; if( (status & DKC_TERMCOD) != DKC_SUCCESS) { sdaddr->dkc_cmd = (SD_SETREG | UDC_CSTAT); sdc_delay(); udc_cstat = sdaddr->dkc_reg; /* read UDC_CSTAT */ sdc_delay(); sdaddr->dkc_cmd = (SD_SETREG | UDC_DSTAT); sdc_delay(); udc_dstat = sdaddr->dkc_reg; cprintf("rx23_type: status = %o, udc_cstat = %o, udc_dstat = %o\n",status,udc_cstat,udc_dstat); if (sdiaddr->nb_int_reqclr & SINT_DC) sdiaddr->nb_int_reqclr = SINT_DC; continue; } break; } if(count >= LOOP_DELAY) { sd_st.sd_cmd = SD_RESET; /* This should take care if the * * cancelled command finishes later */ } if (sdiaddr->nb_int_reqclr & SINT_DC) sdiaddr->nb_int_reqclr = SINT_DC; DELAY(1); sdiaddr->nb_int_msk |= SINT_DC; if(retry >=10) { if(udc_cstat & CST_CMPER) cprintf("%s%d:%s: compare error\n",DEV_ID,sd_st.sd_drno,HARD_ERR); else if(udc_cstat & CST_ECCER) cprintf("%s%d:%s: eccerror\n",DEV_ID,sd_st.sd_drno,HARD_ERR); else if (udc_cstat & CST_SYNER) { cprintf("%s%d:%s: syncerr\n",DEV_ID,sd_st.sd_drno,HARD_ERR); } cprintf("RX23 Double Density\n"); return(DT_RX23D); } /*cprintf("RX23 High Density\n");*/ return(DT_RX23H); }/* This routine selects the drive (coded in cmd) before doing any I/O */sd_select(cmd,diskette) u_char cmd; int diskette;{ register struct nb1_regs *sdaddr = (struct nb1_regs *)qmem; register struct nb_regs *sdiaddr = (struct nb_regs *)nexus; register count = 0; register fail_count=0; u_char status,udc_dstat; while(fail_count++ < 2) { sdiaddr->nb_int_msk &= ~SINT_DC; count = 0; sdaddr->dkc_cmd = cmd; if(diskette){ DELAY(75); /* for diskette max. of 64 microseconds */ } else { DELAY(30); } while(!(sdaddr->dkc_stat & DKC_DONE)) { if(++count >= LOOP_DELAY) break; } status = sdaddr->dkc_stat; if(count >= LOOP_DELAY) { sd_deselect(); DELAY(10); } else break; } if(count >= LOOP_DELAY) { cprintf("sd_select: SELECT not done within count = %d\n",count); sd_reset(); if (sdiaddr->nb_int_reqclr & SINT_DC) sdiaddr->nb_int_reqclr = SINT_DC; DELAY(1); sdiaddr->nb_int_msk |= SINT_DC; return(1); } if(diskette) { DELAY(70); sdaddr->dkc_cmd = (SD_SETREG | UDC_DSTAT); sdc_delay(); udc_dstat = sdaddr->dkc_reg; /* read UDC_DSTAT */ if(sddebug >= 2) cprintf("sd_select: udc_dstat = %o,rx_reselect = %d\n",udc_dstat,rx_reselect); if ((udc_dstat & DST_READY) != DST_READY) { if(sddebug>=2) cprintf("sd_select: udc_dstat not ready\n"); if(rx_reselect == 0) { rx_reselect = 1; } else { rx_reselect = 0; if (sdiaddr->nb_int_reqclr & SINT_DC) sdiaddr->nb_int_reqclr = SINT_DC; DELAY(1); sdiaddr->nb_int_msk |= SINT_DC; return(1); } } } else { if ((status & DKC_DATERR) == DKC_DATERR) { if(sddebug) cprintf("sd_select: dkc_stat = %o\n",status); if (sdiaddr->nb_int_reqclr & SINT_DC) sdiaddr->nb_int_reqclr = SINT_DC; DELAY(1); sdiaddr->nb_int_msk |= SINT_DC; return(1); } } if (sdiaddr->nb_int_reqclr & SINT_DC) sdiaddr->nb_int_reqclr = SINT_DC; DELAY(1); sdiaddr->nb_int_msk |= SINT_DC; return(0);}/* This routine deselcts all the drives */sd_deselect(){ register struct nb1_regs *sdaddr = (struct nb1_regs *)qmem; register struct nb_regs *sdiaddr = (struct nb_regs *)nexus; register count = 0; sdiaddr->nb_int_msk &= ~SINT_DC; sdaddr->dkc_cmd = SD_DESEL; DELAY(64); while(!(sdaddr->dkc_stat & DKC_DONE)) { if(++count >= LOOP_DELAY) break; ; } if(count >= LOOP_DELAY) { if(sddebug) cprintf("sd_deselect: DESELECT not done within count = %d, dkc_stat = %o\n",count,sdaddr->dkc_stat); /* Reset the controller to cancel the DESELCT command in case it finishes */ sd_reset(); if (sdiaddr->nb_int_reqclr & SINT_DC) sdiaddr->nb_int_reqclr = SINT_DC; DELAY(1); sdiaddr->nb_int_msk |= SINT_DC; return(1); } if (sdiaddr->nb_int_reqclr & SINT_DC) sdiaddr->nb_int_reqclr = SINT_DC; DELAY(1); sdiaddr->nb_int_msk |= SINT_DC; return(0);}/* This routine issues the RESTORE command to the controller */sd_restore(diskette){ register struct nb1_regs *sdaddr = (struct nb1_regs *)qmem; register struct nb_regs *sdiaddr = (struct nb_regs *)nexus; register count = 0; u_char status; sdiaddr->nb_int_msk &= ~SINT_DC; if(diskette) sdaddr->dkc_cmd = SD_RESTOR; else sdaddr->dkc_cmd = (SD_RESTOR | REST_WAIT); if(diskette){ DELAY(64); /* for diskette max. of 64 microseconds */ } else { DELAY(30); } while(!(sdaddr->dkc_stat & DKC_DONE)) { if(++count >= LOOP_DELAY) break; } if(count >= LOOP_DELAY) { if(sddebug) cprintf("sd_restore: RESTORE not done within count = %d\n",count); /* Reset the controller to cancel the RESTORE command in case it finishes */ sd_reset(); if (sdiaddr->nb_int_reqclr & SINT_DC) sdiaddr->nb_int_reqclr = SINT_DC; DELAY(1); sdiaddr->nb_int_msk |= SINT_DC; return(1); } status = sdaddr->dkc_stat; if(diskette) { if( (status & DKC_TERMCOD) == DKC_VERERR) { if(sddebug) cprintf("sd_restore: Diskette Not restored\n"); if (sdiaddr->nb_int_reqclr & SINT_DC) sdiaddr->nb_int_reqclr = SINT_DC; DELAY(1); sdiaddr->nb_int_msk |= SINT_DC; return(1); } } if (sdiaddr->nb_int_reqclr & SINT_DC) sdiaddr->nb_int_reqclr = SINT_DC; DELAY(1); sdiaddr->nb_int_msk |= SINT_DC; return(0);}sd_step(cmd) u_char cmd;{ register struct nb1_regs *sdaddr = (struct nb1_regs *)qmem; register struct nb_regs *sdiaddr = (struct nb_regs *)nexus; register count = 0; u_char udc_dstat; sdiaddr->nb_int_msk &= ~SINT_DC; sdaddr->dkc_cmd = cmd; DELAY(64); while(!(sdiaddr->nb_int_reqclr & SINT_DC)) { DELAY(10); if(++count >= LOOP_DELAY) break; ; } if(count >= LOOP_DELAY) { if(sddebug) cprintf("sd_step: STEP not done within count = %d\n",count); /* Reset the controller to cancel the STEP command in case it finishes */ sd_reset(); if (sdiaddr->nb_int_reqclr & SINT_DC) sdiaddr->nb_int_reqclr = SINT_DC; DELAY(1); sdiaddr->nb_int_msk |= SINT_DC; return(1); } sdaddr->dkc_cmd = (SD_SETREG | UDC_DSTAT); sdc_delay(); udc_dstat = sdaddr->dkc_reg; /* read UDC_DSTAT */ if(sddebug) cprintf("sd_step: udc_dstat = %o\n",udc_dstat); if(rx_reselect == 1) { rx_reselect = 0; if( (udc_dstat & DST_READY) == DST_READY) { mprintf("%s%d: Diskette Drive not ready\n",DEV_ID,sd_st.sd_drno); if (sdiaddr->nb_int_reqclr & SINT_DC) sdiaddr->nb_int_reqclr = SINT_DC; DELAY(1); sdiaddr->nb_int_msk |= SINT_DC; return(1); } } if (sdiaddr->nb_int_reqclr & SINT_DC) sdiaddr->nb_int_reqclr = SINT_DC; DELAY(1); sdiaddr->nb_int_msk |= SINT_DC; return(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -