📄 scsi_disk.c
字号:
/* * TODO: this is a temporary fix! * If rsblk returns an error, revert * back to the default partition table. * * NOTE: the read by rsblk wipes out the current pt. * ABOVE comment wrong. * * Must get pt every time media changed! * RZ are fixed media disks, but..... */ i = rsblk(rzstrategy, dev, &sz_part[unit]); } /* So open nodelay doesn't falsely set on-line! */ if (dev_ready) sz_unit_online[unit] = 1; return (0);}/* * * Name: rzsize -Disk partition size routine * * Abstract: This routine returns the size of the specified * disk partition in 512 byte blocks. The partition * number is the 3 LSB if the minor device number. * * Inputs: * * dev ULTRIX major/minor device number. * * Outputs: None. * * Return Values: * * psize Size of requested partition in 512 byte blocks. * -1 Invalid device. * * Side Effects: * panic: invalid partition table * * */rzsize(dev){ register struct sz_softc *sc = sz_softc; register struct uba_device *ui; int unit = minor(dev) >> 3; int targid; int part; daddr_t psize; /* TODO: check meaning of ui_flags == 0 in udsize???? */ if (unit >= nNSZ || (ui = szdinfo[unit]) == 0 || ui->ui_alive == 0) return(-1); sc += ui->ui_ctlr; targid = ui->ui_slave; /* * Sanity check */ if ( sz_part[unit].pt_valid != PT_VALID ) panic("rzsize: invalid partition table "); part = minor(dev) & 7; if (sz_part[unit].pt_part[part].pi_nblocks != -1) psize = sz_part[unit].pt_part[part].pi_nblocks; else psize = sc->sc_disksize[targid] - sz_part[unit].pt_part[part].pi_blkoff; return(psize);}/* * * Name: rzcommand -Disk command rountine * * Abstract: This routine is called to execute non data transfer * commands (test unit ready, read capacity, etc.). It * sets up the command in cszbuf and calls rzstrategy * to queue the command. * * Inputs: * * dev ULTRIX major/minor device number. * com SCSI command type (see scsivar.h). * count Count argument to some commands. * retry If 1, retry command if it fails. * * Outputs: * B_ERROR can be set in bp->b_flags. * * Return Values: None. * * Side Effects: * iowait() on all commands (all have count >= 1). * sleep() called. * rzstrategy() called. * */rzcommand(dev, com, count, retry) register dev_t dev; register int com; register int count; register int retry;{ int unit = minor(dev) >> 3; register struct buf *bp = &cszbuf[unit]; register int s; int error; register struct uba_device *ui = szdinfo[unit]; int cntlr = ui->ui_ctlr; int targid = ui->ui_slave; register struct sz_softc *sc = &sz_softc[cntlr]; if (error = rziowait (bp, sc->sc_rzspecial[targid])) { return (error); } /* * Load the buffer. The bp field usage is (see scsireg.h): * * b_bcount = The command count. * b_gid = The command mnemonic. * b_bufsize = The retry count. * * These two fields are "known" to be "save" to use for this purpose. * (Most other drivers also use these fields in this way.) */ bp->b_flags = B_BUSY|B_READ; bp->b_dev = dev; bp->b_comand = com; bp->b_bcount = count; bp->b_blkno = 0; bp->b_retry = retry; bp->b_error = 0; bp->b_proc = u.u_procp; rzstrategy(bp); iowait(bp); s = spl5(); if (bp->b_flags & B_WANTED) { wakeup ((caddr_t)bp); } splx(s); bp->b_flags &= ~(B_BUSY | B_WANTED); return (geterror (bp));}/* * rziowait() - Wait For Prior I/O To Complete (if busy). * * Inputs: bp = The buffer to check. * special = Special I/O active flag. * * Return Value: * Return 0 for SUCCESS, or EINTR if sleep interrupted. */static intrziowait (bp, special)register struct buf *bp;register int special;{ register int error = 0; register int s; s = spl5(); while (bp->b_flags & B_BUSY) { bp->b_flags |= B_WANTED; if (special) { if (sleep ((caddr_t)bp, (PCATCH | PZERO + 1))) { error = EINTR; } } else { (void) sleep ((caddr_t)bp, PRIBIO + 1); } } splx (s); return (error);}/* * Name: rzstrategy -Disk strategy routine * * Abstract: This routine is called to queue a command for * execution. The routine validates the command * parameters then places it on the I/O queue * of the specified unit. sz_start() is called * if there is not activity. * * Inputs: * * bp Buffer pointer of command to be queued. * * Outputs: * Possible error messages (unit offline). * * Return Values: None. * * bp->b_error: * ENXIO Unit does not exist. * EROFS Write to a write locked device (CDROM). * ENOSPC End of media. * * Side Effects: * panic: invalid partition table * IPL raised to 15 to queue buffer. * */rzstrategy(bp) register struct buf *bp;{ register struct uba_ctlr *um; register struct buf *dp; register int s; int unit = minor(bp->b_dev) >> 3; int targid; int cntlr; register struct sz_softc *sc; struct uba_device *ui; int bad, err; daddr_t sz, maxsz; int part; struct pt *pt; ui = szdinfo[unit]; targid = ui->ui_slave; cntlr = ui->ui_ctlr; sc = &sz_softc[cntlr]; /* TODO: note - no queue sorting! */ /* * Validate things like block number, * unit number, on-line, etc. */ bad = 0; while(1) { if (unit >= nNSZ) { bad = 1; err = ENXIO; break; } /* * CDROM is read only! */ if ((sc->sc_devtyp[targid] & SZ_CDROM) && ((bp->b_flags & B_READ) == 0)) { bad = 1; err = EROFS; break; } /* * RSP says we must have this check. * It prevents open no delay burning us if the * disk's partition table is not valid. * We only do this check for data transfer commands. * House keeping commands (TUR, RDCAP, MODSEL, etc.) * also call rzstrategy. */ if (bp != &cszbuf[unit]) { if (sz_part[unit].pt_valid != PT_VALID) { if (sc->sc_szflags[targid] & SZ_NODEVICE) { bad = 1; err = ENXIO; break; } else { panic("rzstrategy: invalid partition table "); } } } /* TODO: check ui == 0 || ui->ui_alive == 0 here - someday */ /* TODO: EOM maybe, CSE - don't think so */ /* TODO: don't think this can happen for disks */ if ((sc->sc_flags[targid]&DEV_EOM) && !((sc->sc_flags[targid]&DEV_CSE) || (dis_eot_sz[unit] & DISEOT))) { bad = 1; err = ENOSPC; break; } /* * If SZ_NODEVICE is set, the device was opened * with FNDELAY, but the device didn't respond. * We'll try again to see if the device is here, * if it is not, return an error. */ if (sc->sc_szflags[targid] & SZ_NODEVICE) { DEV_UGH(sc->sc_device[targid], unit, "offline"); bad = 1; err = ENXIO; break; } /* * Check transfer size, * to be sure it does not overflow the * bounds of the partition. * Only check data transfer commands. */ if (bp == &cszbuf[unit]) break; part = minor(bp->b_dev) & 7; sz = (bp->b_bcount + 511) >> 9; pt = &sz_part[unit]; if (pt->pt_part[part].pi_nblocks == -1) maxsz = sc->sc_disksize[targid] - pt->pt_part[part].pi_blkoff; else maxsz = pt->pt_part[part].pi_nblocks; if ((bp->b_blkno < 0) || (bp->b_blkno+sz > maxsz) || (pt->pt_part[part].pi_blkoff >= sc->sc_disksize[targid])) { bad = 1; err = ENXIO; break; } break; } if (bad) { bp->b_flags |= B_ERROR; bp->b_resid = bp->b_bcount; bp->b_error = err; biodone(bp); return; } /* TODO: DISKLOG stuff in uda.c?????? */ s = spl5(); dp = &szutab[unit]; if (dp->b_actf == NULL) dp->b_actf = bp; else dp->b_actl->av_forw = bp; dp->b_actl = bp; bp->av_forw = NULL; if ((dp->b_active == 0) && (sc->sc_active == 0)) { sc->sc_xstate[targid] = SZ_NEXT; sc->sc_xevent[targid] = SZ_BEGIN; sz_start(sc, targid); } splx(s);}/* * * Name: rzread -Disk physio read routine * * Abstract: This routine is called to for RAW I/O reads. * Calls physio() with appropriate arguments. * * Inputs: * * dev ULTRIX major/minor device number. * uio Pointer to user I/O (uio) structure. * * Outputs: None. * * Return Values: * Returns value returned by physio(). * * Side Effects: * physio() and rzstrategy() called. * minphys() limits maximum transfer size. * */rzread(dev, uio) register dev_t dev; register struct uio *uio;{ int unit = minor(dev) >> 3; return (physio(rzstrategy, &rszbuf[unit], dev, B_READ, minphys, uio));}/* * * Name: rzwrite -Disk physio write routine * * Abstract: This routine is called to for RAW I/O writes. * Calls physio() with appropriate arguments. * * Inputs: * * dev ULTRIX major/minor device number. * uio Pointer to user I/O (uio) structure. * * Outputs: None. * * Return Values: * Returns value returned by physio(). * EROFS Returned if write to CDROM attempted. * * Side Effects: * physio() and rzstrategy() called. * minphys() limits maximum transfer size. * */rzwrite(dev, uio) register dev_t dev; register struct uio *uio;{ register struct sz_softc *sc; register struct uba_device *ui; int unit = minor(dev) >> 3; ui = szdinfo[unit]; sc = &sz_softc[ui->ui_ctlr]; /* * CDROM is read only! */ if (sc->sc_devtyp[ui->ui_slave] & SZ_CDROM) return(EROFS); return (physio(rzstrategy, &rszbuf[unit], dev, B_WRITE, minphys, uio));}/* * * Name: rzioctl -Disk ioctl routine * * Abstract: This routine is called via the ioctl system call * to perform various non data transfer functions, * such as get/set disk partition table. * * Inputs: * * dev ULTRIX major/minor device number. * cmd The ioctl to execute. * data Pointer to data bassed with ioctl. * flag Flag passed with ioctl. * * Outputs: * Some ioctls pass data back to the caller. * * Return Values: * * EACCES Must be superuser to access this ioctl. * EROFS Can't set partition table on CDROM. * error Value returned from call to ptcmp(). * ENXIO Non supported ioctl. * 0 Success. * * Side Effects: * Several other routines called. * */rzioctl(dev, cmd, data, flag) dev_t dev; register int cmd; caddr_t data; int flag;{ register struct uba_device *ui; int unit = minor(dev) >> 3; int cntlr; int targid; register struct sz_softc *sc; register struct buf *bp = &cszbuf[unit]; struct devget *devget; int i; struct size *stp; struct pt *pt = (struct pt *)data; int error; struct sz_rdcap_dt *rdp; struct scsi_devtab *sdp; struct sz_rzmodsns_dt *msdp; struct page_code_3 *p3; struct page_code_4 *p4; struct page_code_5 *p5; DEVGEOMST *devgeom; ui = szdinfo[unit]; cntlr = ui->ui_ctlr; targid = ui->ui_slave; sc = &sz_softc[cntlr]; sdp = (struct scsi_devtab *)sc->sc_devtab[targid]; switch (cmd) { case DIOCGETPT: /* Return disk partition table to user */ case DIOCDGTPT: /* Return default disk partition table */ if (cmd == DIOCGETPT) { /* * Copy pt structure into user's data area. */ *pt = sz_part[unit]; } else { /* * Copy the default partition table to user's data area. */ stp = sc->sc_dstp[targid]; for (i=0; i<8; i++) { pt->pt_part[i].pi_nblocks = stp[i].nblocks; pt->pt_part[i].pi_blkoff = stp[i].blkoffs; } } /* * Change all -1 nblocks to disk unit size. */ for (i=0; i<8; i++) { if (pt->pt_part[i].pi_nblocks == -1) pt->pt_part[i].pi_nblocks = sc->sc_disksize[targid] - pt->pt_part[i].pi_blkoff; } pt->pt_magic = PT_MAGIC; break; /* TODO: what if user does this with open no delay? */ case DIOCSETPT: /* set the driver partition tables */ /* * Only super users can set the pack's partition table.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -