📄 sd.c
字号:
/* * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Van Jacobson of Lawrence Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)sd.c 8.4 (Berkeley) 4/22/94 *//* * SCSI CCS (Command Command Set) disk driver. */#include "sd.h"#if NSD > 0#ifndef lintstatic char rcsid[] = "$Header: /sys.lite/hp300/dev/RCS/sd.c,v 1.2 1994/01/10 18:29:19 mike Exp mike $";#endif#include <sys/param.h>#include <sys/systm.h>#include <sys/buf.h>#include <sys/stat.h>#include <sys/dkstat.h>#include <sys/disklabel.h>#include <sys/malloc.h>#include <sys/proc.h>#include <sys/ioctl.h>#include <sys/fcntl.h>#include <hp/dev/device.h>#include <hp300/dev/scsireg.h>#include <hp300/dev/sdvar.h>#ifdef USELEDS#include <hp300/hp300/led.h>#endif#include <vm/vm_param.h>#include <vm/lock.h>#include <vm/vm_prot.h>#include <vm/pmap.h>extern int scsi_test_unit_rdy();extern int scsi_request_sense();extern int scsi_inquiry();extern int scsi_read_capacity();extern int scsi_tt_write();extern int scsireq();extern int scsiustart();extern int scsigo();extern void scsifree();extern void scsireset();extern void scsi_delay();extern void disksort();extern void biodone();extern int physio();extern void TBIS();int sdinit();void sdstrategy(), sdstart(), sdustart(), sdgo(), sdintr();struct driver sddriver = { sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr,};#ifdef DEBUGint sddebug = 1;#define SDB_ERROR 0x01#define SDB_PARTIAL 0x02#define SDB_CAPACITY 0x04#endifstruct sd_softc sd_softc[NSD];struct sdstats sdstats[NSD];struct buf sdtab[NSD];struct scsi_fmt_cdb sdcmd[NSD];struct scsi_fmt_sense sdsense[NSD];static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT };static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT };/* * Table of scsi commands users are allowed to access via "format" * mode. 0 means not legal. 1 means "immediate" (doesn't need dma). * -1 means needs dma and/or wait for intr. */static char legal_cmds[256] = {/***** 0 1 2 3 4 5 6 7 8 9 A B C D E F *//*00*/ 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*10*/ 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,/*20*/ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*a0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};static struct scsi_inquiry inqbuf;static struct scsi_fmt_cdb inq = { 6, CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0};static intsdident(sc, hd) struct sd_softc *sc; struct hp_device *hd;{ int unit; register int ctlr, slave; register int i; register int tries = 10; char idstr[32]; int isrm = 0; ctlr = hd->hp_ctlr; slave = hd->hp_slave; unit = sc->sc_punit; scsi_delay(-1); /* * See if unit exists and is a disk then read block size & nblocks. */ while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) { if (i == -1 || --tries < 0) { if (isrm) break; /* doesn't exist or not a CCS device */ goto failed; } if (i == STS_CHECKCOND) { u_char sensebuf[128]; struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf; scsi_request_sense(ctlr, slave, unit, sensebuf, sizeof(sensebuf)); if (sp->class == 7) switch (sp->key) { /* * Not ready -- might be removable media * device with no media. Assume as much, * if it really isn't, the inquiry commmand * below will fail. */ case 2: isrm = 1; break; /* drive doing an RTZ -- give it a while */ case 6: DELAY(1000000); break; default: break; } } DELAY(1000); } /* * Find out about device */ if (scsi_immed_command(ctlr, slave, unit, &inq, (u_char *)&inqbuf, sizeof(inqbuf), B_READ)) goto failed; switch (inqbuf.type) { case 0: /* disk */ case 4: /* WORM */ case 5: /* CD-ROM */ case 7: /* Magneto-optical */ break; default: /* not a disk */ goto failed; } /* * Get a usable id string */ switch (inqbuf.version) { case 1: case 2: bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28); for (i = 27; i > 23; --i) if (idstr[i] != ' ') break; idstr[i+1] = 0; for (i = 23; i > 7; --i) if (idstr[i] != ' ') break; idstr[i+1] = 0; for (i = 7; i >= 0; --i) if (idstr[i] != ' ') break; idstr[i+1] = 0; break; default: bcopy("UNKNOWN", &idstr[0], 8); bcopy("DRIVE TYPE", &idstr[8], 11); } if (inqbuf.qual & 0x80) sc->sc_flags |= SDF_RMEDIA; if (sdgetcapacity(sc, hd, NODEV) < 0) goto failed; switch (inqbuf.version) { case 1: case 2: printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8], &idstr[24]); if (inqbuf.version == 2) printf(" (SCSI-2)"); break; default: printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit, inqbuf.type, inqbuf.qual, inqbuf.version); break; } if (sc->sc_blks) printf(", %d %d byte blocks", sc->sc_blks >> sc->sc_bshift, sc->sc_blksize); printf("\n"); sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2); /* XXX */ scsi_delay(0); return(inqbuf.type);failed: scsi_delay(0); return(-1);}intsdinit(hd) register struct hp_device *hd;{ register struct sd_softc *sc = &sd_softc[hd->hp_unit]; sc->sc_hd = hd; sc->sc_flags = 0; /* * XXX formerly 0 meant unused but now pid 0 can legitimately * use this interface (sdgetcapacity). */ sc->sc_format_pid = -1; sc->sc_punit = sdpunit(hd->hp_flags); sc->sc_type = sdident(sc, hd); if (sc->sc_type < 0) return(0); sc->sc_dq.dq_ctlr = hd->hp_ctlr; sc->sc_dq.dq_unit = hd->hp_unit; sc->sc_dq.dq_slave = hd->hp_slave; sc->sc_dq.dq_driver = &sddriver; sc->sc_flags |= SDF_ALIVE; return(1);}voidsdreset(sc, hd) register struct sd_softc *sc; register struct hp_device *hd;{ sdstats[hd->hp_unit].sdresets++;}/* * Determine capacity of a drive. * Returns -1 on a failure, 0 on success, 1 on a failure that is probably * due to missing media. */intsdgetcapacity(sc, hd, dev) struct sd_softc *sc; struct hp_device *hd; dev_t dev;{ static struct scsi_fmt_cdb cap = { 10, CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; u_char *capbuf; int i, capbufsize; /* * Cannot use stack space for this buffer since stack KVA may not * be valid (i.e. in context of this process) when the operation * actually starts. */ capbufsize = 8; capbuf = malloc(capbufsize, M_DEVBUF, M_WAITOK); if (dev == NODEV) { i = scsi_immed_command(hd->hp_ctlr, hd->hp_slave, sc->sc_punit, &cap, capbuf, capbufsize, B_READ); } else { struct buf *bp; /* * XXX this is horrible */ if (sc->sc_format_pid >= 0) panic("sdgetcapacity"); bp = malloc(sizeof *bp, M_DEVBUF, M_WAITOK); sc->sc_format_pid = curproc->p_pid; bcopy((caddr_t)&cap, (caddr_t)&sdcmd[hd->hp_unit], sizeof cap); bp->b_dev = dev; bp->b_flags = B_READ | B_BUSY; bp->b_un.b_addr = (caddr_t)capbuf; bp->b_bcount = capbufsize; sdstrategy(bp); i = biowait(bp) ? sdsense[hd->hp_unit].status : 0; free(bp, M_DEVBUF); sc->sc_format_pid = -1; } if (i) { if (i != STS_CHECKCOND || (sc->sc_flags & SDF_RMEDIA) == 0) {#ifdef DEBUG if (sddebug & SDB_CAPACITY) printf("sd%d: read_capacity returns %d\n", hd->hp_unit, i);#endif free(capbuf, M_DEVBUF); return (-1); } /* * XXX assume unformatted or non-existant media */ sc->sc_blks = 0; sc->sc_blksize = DEV_BSIZE; sc->sc_bshift = 0;#ifdef DEBUG if (sddebug & SDB_CAPACITY) printf("sd%d: removable media not present\n", hd->hp_unit);#endif free(capbuf, M_DEVBUF); return (1); } sc->sc_blks = *(u_int *)&capbuf[0]; sc->sc_blksize = *(int *)&capbuf[4]; free(capbuf, M_DEVBUF); sc->sc_bshift = 0; /* return value of read capacity is last valid block number */ sc->sc_blks++; if (sc->sc_blksize != DEV_BSIZE) { if (sc->sc_blksize < DEV_BSIZE) { printf("sd%d: need at least %d byte blocks - %s\n", hd->hp_unit, DEV_BSIZE, "drive ignored"); return (-1); } for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1) ++sc->sc_bshift; sc->sc_blks <<= sc->sc_bshift; }#ifdef DEBUG if (sddebug & SDB_CAPACITY) printf("sd%d: blks=%d, blksize=%d, bshift=%d\n", hd->hp_unit, sc->sc_blks, sc->sc_blksize, sc->sc_bshift);#endif return (0);}/* * Read or constuct a disklabel */intsdgetinfo(dev) dev_t dev;{ int unit = sdunit(dev); register struct sd_softc *sc = &sd_softc[unit]; register struct disklabel *lp = &sc->sc_info.si_label; register struct partition *pi; char *msg, *readdisklabel();#ifdef COMPAT_NOLABEL int usedefault = 1; /* * For CD-ROM just define a single partition */ if (sc->sc_type == 5) usedefault = 0;#endif bzero((caddr_t)lp, sizeof *lp); msg = NULL; /* * If removable media or the size unavailable at boot time * (i.e. unformatted hard disk), attempt to set the capacity * now. */ if ((sc->sc_flags & SDF_RMEDIA) || sc->sc_blks == 0) { switch (sdgetcapacity(sc, sc->sc_hd, dev)) { case 0: break; case -1: /* * Hard error, just return (open will fail). */ return (EIO); case 1: /* * XXX return 0 so open can continue just in case * the media is unformatted and we want to format it. * We set the error flag so they cannot do much else. */ sc->sc_flags |= SDF_ERROR; msg = "unformatted/missing media";#ifdef COMPAT_NOLABEL usedefault = 0;#endif break; } } /* * Set some default values to use while reading the label * (or to use if there isn't a label) and try reading it. */ if (msg == NULL) { lp->d_type = DTYPE_SCSI; lp->d_secsize = DEV_BSIZE; lp->d_nsectors = 32; lp->d_ntracks = 20; lp->d_ncylinders = 1; lp->d_secpercyl = 32*20; lp->d_npartitions = 3; lp->d_partitions[2].p_offset = 0; /* XXX we can open a device even without SDF_ALIVE */ if (sc->sc_blksize == 0) sc->sc_blksize = DEV_BSIZE; /* XXX ensure size is at least one device block */ lp->d_partitions[2].p_size = roundup(LABELSECTOR+1, btodb(sc->sc_blksize)); msg = readdisklabel(sdlabdev(dev), sdstrategy, lp); if (msg == NULL) return (0); } pi = lp->d_partitions; printf("sd%d: WARNING: %s, ", unit, msg);#ifdef COMPAT_NOLABEL if (usedefault) { printf("using old default partitioning\n"); sdmakedisklabel(unit, lp); return(0); }#endif printf("defining `c' partition as entire disk\n"); pi[2].p_size = sc->sc_blks; return(0);}intsdopen(dev, flags, mode, p) dev_t dev; int flags, mode; struct proc *p;{ register int unit = sdunit(dev); register struct sd_softc *sc = &sd_softc[unit]; int mask, error; if (unit >= NSD) return(ENXIO); /* * If a drive's position was fully qualified (i.e. not wildcarded in * any way, we allow root to open the device even though it wasn't * found at autoconfig time. This allows initial formatting of disks. * However, if any part of the specification was wildcarded, we won't * be able to locate the drive so there is nothing we can do. */ if ((sc->sc_flags & SDF_ALIVE) == 0 && (suser(p->p_ucred, &p->p_acflag) || sc->sc_hd->hp_ctlr < 0 || sc->sc_hd->hp_slave < 0)) return(ENXIO); if (sc->sc_flags & SDF_ERROR) return(EIO); /* * Wait for any pending opens/closes to complete */ while (sc->sc_flags & (SDF_OPENING|SDF_CLOSING)) sleep((caddr_t)sc, PRIBIO); /* * On first open, get label and partition info. * We may block reading the label, so be careful * to stop any other opens. */ if (sc->sc_info.si_open == 0) { sc->sc_flags |= SDF_OPENING; error = sdgetinfo(dev); sc->sc_flags &= ~SDF_OPENING; wakeup((caddr_t)sc); if (error) return(error); } if (sc->sc_hd->hp_dk >= 0) dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms; mask = 1 << sdpart(dev); if (mode == S_IFCHR) sc->sc_info.si_copen |= mask; else sc->sc_info.si_bopen |= mask; sc->sc_info.si_open |= mask; return(0);}intsdclose(dev, flag, mode, p) dev_t dev; int flag, mode; struct proc *p;{ int unit = sdunit(dev); register struct sd_softc *sc = &sd_softc[unit]; register struct sdinfo *si = &sc->sc_info; int mask, s; mask = 1 << sdpart(dev); if (mode == S_IFCHR) si->si_copen &= ~mask; else si->si_bopen &= ~mask; si->si_open = si->si_bopen | si->si_copen; /* * On last close, we wait for all activity to cease since * the label/parition info will become invalid. Since we * might sleep, we must block any opens while we are here. * Note we don't have to about other closes since we know * we are the last one. */ if (si->si_open == 0) { sc->sc_flags |= SDF_CLOSING; s = splbio(); while (sdtab[unit].b_active) { sc->sc_flags |= SDF_WANTED; sleep((caddr_t)&sdtab[unit], PRIBIO); } splx(s); sc->sc_flags &= ~(SDF_CLOSING|SDF_WLABEL|SDF_ERROR); wakeup((caddr_t)sc); } sc->sc_format_pid = -1; return(0);}/* * This routine is called for partial block transfers and non-aligned * transfers (the latter only being possible on devices with a block size * larger than DEV_BSIZE). The operation is performed in three steps * using a locally allocated buffer: * 1. transfer any initial partial block * 2. transfer full blocks * 3. transfer any final partial block */static voidsdlblkstrat(bp, bsize) register struct buf *bp; register int bsize;{ register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -