📄 scsi_disk.c
字号:
#ifndef lintstatic char *sccsid = "@(#)scsi_disk.c 4.4 (ULTRIX) 2/21/91";#endif lint/************************************************************************ * * * Copyright (c) 1984,86,87,88,89 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//************************************************************************ * * scsi_disk.c 23-Jun-89 * * VAX SCSI device driver (disk routines) * * Modification history: * * 19-Feb-91 Robin Miller * o Correct race condition in the rzcommand() function by adding the * appropriate spl synchronization. Previously, if multiple processes * attempted simultaneous access to a drive, processes could be left * in an uninterruptable sleep state. * o Correct sleep priority when waiting for prior I/O to complete. * o Catch signals if sleeping at an interruptable priority so buffer * resources can be released and proper error code (EINTR) returned. * o Remove #ifdef FORMAT conditionalization since we always want this. * * 11-Sep-90 Robin Miller * Added check in DEVIOCGET ioctl() command for Extra Density (ED) * 2.88MB RX26 floppy diskette. Also set Double Density (DD) flag * appropriately for RX23/RX26 3.5" or RX33 5.25" diskettes. * * 20-Aug-90 Robin Miller * Set iostat milliseconds per word transfer rate (dk_mspw) for * RX26 in rzopen(), depending on which diskette type (ED/HD/DD) * is loaded in the drive. * * 09-Aug-90 Robin Miller * Modified check for write protect status for DEVIOCGET ioctl() * so write lock is returned for all CD-ROM's, not just RRD40. * * 13-Nov-89 Janet Schank * Changed the refrence of nNSCSI to nNSCSIBUS. * * 29-Oct-89 Fred Canter * Changed the DEVGETGEOM ioctl mode sense code to validate the * page code, i.e., make sure the disk gave us the page we asked for. * One of the non-DEC disks returns page 56 instead of a check * condition when we ask for page 5 (unsupported page for hard disks). * * 08-Oct-89 Fred Canter * Remove error log #ifdef OLDWAY. * * 07-Oct-89 Fred Canter * Added DEVGETGEOM ioctl to return disk geometry information. * * 01-Oct-89 Fred Canter * Fixed a bug in the RX23 SoftPC hooks. Media type ID returned * by DEVIOGET ioctl was incorrect because first read capacity * after unit attention failed (media change). * * Bug fix. Disks (except RRD40) were not reporting correct * write locked status via the devioget ioctl. * * 23-Jul-89 Fred Canter * Convert DBBR printfs to error log calls. * RX33 support. * * 22-Jul-89 John A. Gallant * Added SCSI_NODBBR flag for disks without BBR. * Added error messages to DBBR code. * * 16-Jul-89 Fred Canter * Do a mode select to get disk geometry. * * 23-Jun-89 John A. Gallant * Added the disk command completion routine. Added the DBBR code. * * 20-Jun-89 Fred Canter * Convert to scsi_devtab. * * 11-Jun-89 Fred Canter * Added media changed and density information to devget structure. * So softpc application can make better use of the floppy drive. * * 08-Jun-89 Fred Canter * Removed RX23 RDCAP hack and handle case where RDCAP can fail if * an unformatted floppy is in the RX23, in rzopen(). * * 06-Jun-89 Fred Canter * Set iostat dk_mspw transfer rate for RX23 in rzopen(), depending * on which type floppy (HD/DD) in loaded in the drive. * * 24-May-89 Fred Canter * Changes to match the new, more general rzdisk utility. * Changed the mode select data structures so an address and * length are passed with the ioctl. This allows pages to be * added to rzdisk without requiring a kernel rebuild. * * 06-Apr-89 Fred Canter * Added b_comand to replace b_command for local command buffers. * Use b_gid instead of b_resid to store command. * * 12-Feb-89 Fred Canter * Added function header comments to each routine. * * 17-Dec-88 Fred Canter * Added pseudo commands to resolve the conflict between * SZ_UNLOAD and SZ_SSUNIT both being opcode 0x1b. * * 08-Dec-88 Alan Frechette * Return an error if either of the KMALLOC calls in rzspecial fails. * * 04-Dec-88 Fred Canter * Changes to rzspecial(). Allow all commands except: format, * reassign block, and read defect data on the CDROM. * Return EROFS instead of ENXIO if command not allowed on CDROM. * Wait 20 seconds in rzopen for CDROM to come on-line (was 10). * * 03-Nov-88 Alan Frechette * Added in support for disk maintainence. Added the commands * FORMAT UNIT, REASSIGN BLOCK, READ DEFECT DATA, MODE SENSE, * MODE SELECT, INQUIRY and VERIFY DATA. These are all new * ioctl calls. * * 16-Oct-88 Fred Canter * Clean up comments. * * 28-Sep-88 Fred Canter * Clean up copmments. Report DEV_WRTLCK flag with DEVIOCGET ioctl * so RRD40 will return write locked and fsck will be NO WRITE. * Buf fix - rzopen() had a call to tzcommand(). * * 13-Sep-88 Fred Canter * Increased RRD40 retry time to 10 seconds in rzopen to allow * for RRD40 spin up delay, which could take up to 5 seconds. * * 17-Aug-88 Fred Canter * Created this file by moving the SCSI disk specific files * from the old combined driver (scsi.c) to scsi_disk.c. * ***********************************************************************/#include "../data/scsi_data.c"#include "scsi_debug.h"/* * Disk open routine (need func header) */extern int geterror(), wakeup();extern int hz;extern int sz_unit_rcvdiag[]; /* If zero, need unit's selftest status */extern int sz_retries[]; /* retry counter *//* * Unit on line flag. Set to one if the * device is on-line. Set to zero on any unit * attention condition. */extern int sz_unit_online[];/* * * Name: rzopen -Disk open routine * * Abstract: This routine is called each time an RZ disk device * is opened. This routine: makes sure the device * exists, checks for device on-line via test unit * ready, does a mode select (lbn size 512), finds * disks size via read capacity, and reads in disk's * partition table. * * Inputs: * * dev ULTRIX major/minor device number. * flag How to open flag (read, write, NDELAY). * * Outputs: * Possible error messages (eg, device off-line). * sz_unit_online flag set. * * Return Values: * * ENXIO No such device or address (non extistent device). * EIO I/O error (device off-line, could not get size, etc). * 0 Open succeeded. * * Side Effects: * rzcommand() called. * sleep() called. * */rzopen(dev, flag)dev_t dev;int flag;{ register struct uba_device *ui; register struct sz_softc *sc; int unit = minor(dev) >> 3; int cntlr; int targid; int retry, retrylimit; int retval; int dev_ready, ssunit_cnt; int i; struct size *stp; struct sz_rdcap_dt *rdp; int rzstrategy(); /* * Order of following checks in important. */ if (unit >= nNSZ) return(ENXIO); ui = szdinfo[unit]; if ((ui == 0) || (ui->ui_alive == 0)) return(ENXIO); cntlr = ui->ui_ctlr; if (cntlr >= nNSCSIBUS) return(ENXIO); targid = ui->ui_slave; sc = &sz_softc[cntlr]; if (sc->sc_alive[targid] == 0) return(ENXIO); if (((sc->sc_devtyp[targid] & SZ_DISK) == 0) && ((sc->sc_devtyp[targid] & SZ_CDROM) == 0)) return(ENXIO); /* * This is a strange use of the FNDELAY flag. It * is here to allow the installation finder program * to open the device when the tape cartridge is not * inserted. The installation finder program needs * to do an ioctl, so open must succeed whether or * not a cartridge is present. */ /* * Clear sc_flags, device will lockup after any * hard error (DEV_HARDERR set) if we don't. * TODO: other drivers look at dis_eot_??[]! */ sc->sc_flags[targid] = 0; sc->sc_szflags[targid] &= ~SZ_NODEVICE; /* * Get selftest result, if we haven't already. * The rz_rcvdiag() routine will return * SZ_NODEVICE if anything is wrong. */ /* * TODO: * The RRD40 is the only disk that supports the * receive diagnostics command. We need to write * a rz_rcvdiag() routine if we decide to use it. *//* if (sz_unit_rcvdiag[unit] == 0) *//* sc->sc_szflags[targid] |= rz_rcvdiag(dev); */ /* * Try to bring the drive on line. * * The disks take about 10 seconds to spin up. * They should already be spinning by the time we get here, * but we must make sure the drive is spinning to cover * the remote possibility that it went off line. * We try for 20 seconds to bring the drive on-line. * * The RRD40 comes online almost instantly (about 1 second). * However, it can take 17.9 seconds for error recovery. * So, we try for 20 seconds to bring the drive on-line. * This also allows the user some think time to realize the * CDROM is off-line and load the CD. */ dev_ready = 0; ssunit_cnt = 0; retrylimit = 20; for (retry = 0; retry < retrylimit; retry++) { if (sc->sc_szflags[targid] & SZ_NODEVICE) { if (flag & FNDELAY) break; else return(ENXIO); } rzcommand(dev, SZ_TUR, 1, 0); if (sc->sc_c_status[targid] == SZ_GOOD) { dev_ready = 1; break; } else if (sc->sc_c_status[targid] == SZ_BAD) { continue; } else if (sc->sc_c_status[targid] == SZ_CHKCND) { retval = SZ_RETRY; switch(sc->sc_c_snskey[targid]) { case SZ_NOSENSE: case SZ_RECOVERR: retval = SZ_SUCCESS; dev_ready = 1; break; case SZ_NOTREADY: /* * Send start unit command twice. The first one * could fail due to unit attention. * We don't confuse the issue with error checking! */ if (ssunit_cnt < 2) { rzcommand(dev, SZ_P_SSUNIT, 1, 0); ssunit_cnt++; } timeout(wakeup, (caddr_t)&sc->sc_alive[targid], hz); sleep((caddr_t)&sc->sc_alive[targid], PZERO + 1); if (!(sc->sc_flags[targid] & DEV_EOM)) { sc->sc_flags[targid] = 0; } break; case SZ_UNITATTEN: sz_unit_online[unit] = 0; /* just retry */ break; default: /* TODO: may want to retry? */ if (!(sc->sc_flags[targid] & DEV_EOM)) { sc->sc_flags[targid] = 0; } if(flag & FNDELAY) { sc->sc_szflags[targid] |= SZ_NODEVICE; retval = SZ_SUCCESS; } else { return(ENXIO); } break; } /* end of switch */ if (retval == SZ_SUCCESS) break; /* from for loop */ else continue; /* with for loop */ } else { /* TODO: debug */ printf("rzopen: impossible sc_c_status (val=%d)\n", sc->sc_c_status[targid]); continue; /* retry */ } } /* end for loop */ if (retry >= retrylimit) { if (!(flag & FNDELAY)) { DEV_UGH(sc->sc_device[targid], unit, "offline"); return(EIO); } } /* * If SZ_NODEVICE is not set (i.e., the device exists) * and the device is off-line, do a mode select. * This sets the Logical Block Size to 512 bytes. * NOTE: RZ disk drives have 512 bytes as the * default LBN size, but we set and check it anyway. * NOTE: production RRD40 drives default to 512 byte lbn size. * The RRD40's physical sector size is 2KB. */ if (!(sc->sc_szflags[targid] & SZ_NODEVICE) && (sz_unit_online[unit] == 0)) { /* * Use MODSEL to specify 512 byte LBNs. * TODO: later on we may want to change other parameters. */ for (retry = 0; retry < 5; retry++) { rzcommand(dev, SZ_MODSEL, 1, 0); if (sc->sc_c_status[targid] == SZ_GOOD) break; } if ((retry >= 5) && ((flag & FNDELAY) == 0)) { printf("rzopen: %s unit %d: mode select failed\n", sc->sc_device[targid], unit); return(EIO); } /* * Use RDCAP to determine the size of the disk. * Also verify LBN size is really 512 bytes. * NOTE: CD size depends on how much data was mastered * on the CD. Must get size after each media change. * NOTE: RDCAP will fail if the floppy is unformatted. */ for (retry = 0; retry < 5; retry++) { rzcommand(dev, SZ_RDCAP, 1, 0); if (sc->sc_c_status[targid] == SZ_GOOD) break; } if (retry >= 5) { sc->sc_disksize[targid] = 0; if ((flag & FNDELAY) == 0) { printf("rzopen: %s unit %d: read capacity failed\n", sc->sc_device[targid], unit); return(EIO); } } else { rdp = (struct sz_rdcap_dt *)&sc->sz_dat[targid]; i = (rdp->lbaddr3 << 24) & 0xff000000; i |= (rdp->lbaddr2 << 16) & 0x00ff0000; i |= (rdp->lbaddr1 << 8) & 0x0000ff00; i |= rdp->lbaddr0 & 0x000000ff; /* * RDCAP returns the address of the last LBN. * We must add one to get the number of LBNs. */ sc->sc_disksize[targid] = (daddr_t)(i + 1); /* * Verify LBN size is 512 bytes. */ i = (rdp->blklen3 << 24) & 0xff000000; i |= (rdp->blklen2 << 16) & 0x00ff0000; i |= (rdp->blklen1 << 8) & 0x0000ff00; i |= rdp->blklen0 & 0x000000ff; if (i != 512) { if (!(flag & FNDELAY)) { printf("rzopen: %s unit %d: %s (size = %d)\n", sc->sc_device[targid], unit, "could not set LBN size to 512 bytes", i); return(EIO); } } } /* * Set the milliseconds per word transfer rate for the * RX23/26/33 SCSI floppy depending on the media size. * RX23: If size = 2880 (1.44MB) then the floppy is 18 sector * otherwise assume the floppy is 9 sector. * RX26: If size = 5760 (2.88MB) then the floppy is 36 sector * If size = 2880 (1.44MB) then the floppy is 18 sector * otherwise assume the floppy is 9 sector. * RX33: If size = 2400 (1.2MB) then the floppy is 15 sector * otherwise assume the floppy is 10 sector. */ if (sc->sc_devtyp[targid] == RX23) { if (sc->sc_disksize[targid] == 2880) dk_mspw[ui->ui_dk] = 0.0000434; else dk_mspw[ui->ui_dk] = 0.0000868; } if (sc->sc_devtyp[targid] == RX26) { if (sc->sc_disksize[targid] == 5760) /* ED */ dk_mspw[ui->ui_dk] = 0.0000217; else if (sc->sc_disksize[targid] == 2880) /* HD */ dk_mspw[ui->ui_dk] = 0.0000434; else /* DD */ dk_mspw[ui->ui_dk] = 0.0000868; } if (sc->sc_devtyp[targid] == RX33) { if (sc->sc_disksize[targid] == 2400) dk_mspw[ui->ui_dk] = 0.0000434; else dk_mspw[ui->ui_dk] = 0.0000781; } } /* NOTE: set for debug, but not used */ sc->sc_openf[targid] = 1; /* * See if we need to read in the partition table from the disk. * The conditions we will have to read from the disk is if the * partition table valid bit has not been set for the volume * is invalid. */ /* * Assume that the default values before trying to * see if the partition tables are on the disk. The * reason that we do this is that the strategy routine * is used to read in the superblock but uses the * partition info. So we must first assume the * default values. */ /* TODO: this looks wrong. If rsblk fails next time * we will think the partition table is good, but * it will be the default pt not the one read from the disk. */ if ((sz_part[unit].pt_valid == 0) || (sz_unit_online[unit] == 0)) { stp = sc->sc_dstp[targid]; for( i = 0; i < 8; i++ ) { sz_part[unit].pt_part[i].pi_nblocks = stp[i].nblocks; sz_part[unit].pt_part[i].pi_blkoff = stp[i].blkoffs; } sz_part[unit].pt_valid = PT_VALID; /* * Default partition are now set. Call rsblk to set * the driver's partition tables, if any exists, from * the "a" partition superblock */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -