BSD 4_4_Lite2 release
[unix-history] / usr / src / sys / hp300 / dev / sd.c
index 0f119c3..95475a9 100644 (file)
@@ -1,13 +1,39 @@
 /*
 /*
- * Copyright (c) 1990 The Regents of the University of California.
- * All rights reserved.
+ * 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.
  *
  *
  * This code is derived from software contributed to Berkeley by
  * Van Jacobson of Lawrence Berkeley Laboratory.
  *
- * %sccs.include.redist.c%
+ * 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.
  *
  *
- *     @(#)sd.c        7.5 (Berkeley) %G%
+ * 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.9 (Berkeley) 5/14/95
  */
 
 /*
  */
 
 /*
 #if NSD > 0
 
 #ifndef lint
 #if NSD > 0
 
 #ifndef lint
-static char rcsid[] = "$Header: sd.c,v 1.3 90/10/10 14:55:10 mike Exp $";
+static 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
 
 #endif
 
-#include "sys/param.h"
-#include "sys/systm.h"
-#include "sys/buf.h"
-#include "sys/dkstat.h"
-#include "sys/disklabel.h"
-#include "sys/malloc.h"
-#include "sys/proc.h"
-
-#include "device.h"
-#include "scsireg.h"
-#include "vm/vm_param.h"
-#include "vm/lock.h"
-#include "vm/vm_statistics.h"
-#include "vm/pmap.h"
-#include "vm/vm_prot.h"
+#include <vm/vm.h>
 
 extern int scsi_test_unit_rdy();
 extern int scsi_request_sense();
 
 extern int scsi_test_unit_rdy();
 extern int scsi_request_sense();
@@ -46,6 +76,7 @@ extern int scsiustart();
 extern int scsigo();
 extern void scsifree();
 extern void scsireset();
 extern int scsigo();
 extern void scsifree();
 extern void scsireset();
+extern void scsi_delay();
 
 extern void disksort();
 extern void biodone();
 
 extern void disksort();
 extern void biodone();
@@ -59,64 +90,15 @@ struct      driver sddriver = {
        sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr,
 };
 
        sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr,
 };
 
-struct size {
-       u_long  strtblk;
-       u_long  endblk;
-       int     nblocks;
-};
-
-struct sdinfo {
-       struct  size part[8];
-};
-
-/*
- * since the SCSI standard tends to hide the disk structure, we define
- * partitions in terms of DEV_BSIZE blocks.  The default partition table
- * (for an unlabeled disk) reserves 512K for a boot area, has an 8 meg
- * root and 32 meg of swap.  The rest of the space on the drive goes in
- * the G partition.  As usual, the C partition covers the entire disk
- * (including the boot area).
- */
-struct sdinfo sddefaultpart = {
-            1024,   17408,   16384   , /* A */
-           17408,   82944,   65536   , /* B */
-               0,       0,       0   , /* C */
-           17408,  115712,   98304   , /* D */
-          115712,  218112,  102400   , /* E */
-          218112,       0,       0   , /* F */
-           82944,       0,       0   , /* G */
-          115712,       0,       0   , /* H */
-};
-
-struct sd_softc {
-       struct  hp_device *sc_hd;
-       struct  devqueue sc_dq;
-       int     sc_format_pid;  /* process using "format" mode */
-       short   sc_flags;
-       short   sc_type;        /* drive type */
-       short   sc_punit;       /* physical unit (scsi lun) */
-       u_short sc_bshift;      /* convert device blocks to DEV_BSIZE blks */
-       u_int   sc_blks;        /* number of blocks on device */
-       int     sc_blksize;     /* device block size in bytes */
-       u_int   sc_wpms;        /* average xfer rate in 16 bit wds/sec. */
-       struct  sdinfo sc_info; /* drive partition table & label info */
-} sd_softc[NSD];
-
-/* sc_flags values */
-#define        SDF_ALIVE       0x1
-
 #ifdef DEBUG
 int sddebug = 1;
 #define SDB_ERROR      0x01
 #define SDB_PARTIAL    0x02
 #ifdef DEBUG
 int sddebug = 1;
 #define SDB_ERROR      0x01
 #define SDB_PARTIAL    0x02
+#define SDB_CAPACITY   0x04
 #endif
 
 #endif
 
-struct sdstats {
-       long    sdresets;
-       long    sdtransfers;
-       long    sdpartials;
-} sdstats[NSD];
-
+struct 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];
 struct buf sdtab[NSD];
 struct scsi_fmt_cdb sdcmd[NSD];
 struct scsi_fmt_sense sdsense[NSD];
@@ -124,13 +106,6 @@ 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 };
 
 static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT };
 static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT };
 
-#define        sdunit(x)       (minor(x) >> 3)
-#define sdpart(x)      (minor(x) & 0x7)
-#define        sdpunit(x)      ((x) & 7)
-#define        b_cylin         b_resid
-
-#define        SDRETRY         2
-
 /*
  * Table of scsi commands users are allowed to access via "format"
  * mode.  0 means not legal.  1 means "immediate" (doesn't need dma).
 /*
  * Table of scsi commands users are allowed to access via "format"
  * mode.  0 means not legal.  1 means "immediate" (doesn't need dma).
@@ -162,12 +137,6 @@ static struct scsi_fmt_cdb inq = {
        CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0
 };
 
        CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0
 };
 
-static u_char capbuf[8];
-struct scsi_fmt_cdb cap = {
-       10,
-       CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
 static int
 sdident(sc, hd)
        struct sd_softc *sc;
 static int
 sdident(sc, hd)
        struct sd_softc *sc;
@@ -177,21 +146,23 @@ sdident(sc, hd)
        register int ctlr, slave;
        register int i;
        register int tries = 10;
        register int ctlr, slave;
        register int i;
        register int tries = 10;
-       int ismo = 0;
+       char idstr[32];
+       int isrm = 0;
 
        ctlr = hd->hp_ctlr;
        slave = hd->hp_slave;
        unit = sc->sc_punit;
 
        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) {
 
        /*
         * 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 (ismo)
+                       if (isrm)
                                break;
                        /* doesn't exist or not a CCS device */
                                break;
                        /* doesn't exist or not a CCS device */
-                       return (-1);
+                       goto failed;
                }
                if (i == STS_CHECKCOND) {
                        u_char sensebuf[128];
                }
                if (i == STS_CHECKCOND) {
                        u_char sensebuf[128];
@@ -201,11 +172,14 @@ sdident(sc, hd)
                                           sizeof(sensebuf));
                        if (sp->class == 7)
                                switch (sp->key) {
                                           sizeof(sensebuf));
                        if (sp->class == 7)
                                switch (sp->key) {
-                               /* not ready -- might be MO with no media */
+                               /*
+                                * 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:
                                case 2:
-                                       if (sp->len == 12 &&
-                                           sensebuf[12] == 10) /* XXX */
-                                               ismo = 1;
+                                       isrm = 1;
                                        break;
                                /* drive doing an RTZ -- give it a while */
                                case 6:
                                        break;
                                /* drive doing an RTZ -- give it a while */
                                case 6:
@@ -222,7 +196,7 @@ sdident(sc, hd)
         */
        if (scsi_immed_command(ctlr, slave, unit, &inq,
                               (u_char *)&inqbuf, sizeof(inqbuf), B_READ))
         */
        if (scsi_immed_command(ctlr, slave, unit, &inq,
                               (u_char *)&inqbuf, sizeof(inqbuf), B_READ))
-               return(-1);
+               goto failed;
        switch (inqbuf.type) {
        case 0:         /* disk */
        case 4:         /* WORM */
        switch (inqbuf.type) {
        case 0:         /* disk */
        case 4:         /* WORM */
@@ -230,42 +204,14 @@ sdident(sc, hd)
        case 7:         /* Magneto-optical */
                break;
        default:        /* not a disk */
        case 7:         /* Magneto-optical */
                break;
        default:        /* not a disk */
-               return (-1);
+               goto failed;
        }
        /*
        }
        /*
-        * XXX determine if this is an HP MO drive.
+        * Get a usable id string
         */
         */
-       {
-               u_long *id = (u_long *)&inqbuf;
-
-               ismo = (id[2] == 0x48502020 &&  /* "HP  " */
-                       id[3] == 0x20202020 &&  /* "    " */
-                       id[4] == 0x53363330 &&  /* "S630" */
-                       id[5] == 0x302e3635 &&  /* "0.65" */
-                       id[6] == 0x30412020);   /* "0A  " */
-       }
-       i = scsi_immed_command(ctlr, slave, unit, &cap,
-                              (u_char *)&capbuf, sizeof(capbuf), B_READ);
-       if (i) {
-               /* XXX unformatted or non-existant MO media; fake it */
-               if (i == STS_CHECKCOND && ismo) {
-                       sc->sc_blks = 318664;
-                       sc->sc_blksize = 1024;
-               } else
-                       return(-1);
-       } else {
-               sc->sc_blks = *(u_int *)&capbuf[0];
-               sc->sc_blksize = *(int *)&capbuf[4];
-       }
-       /* return value of read capacity is last valid block number */
-       sc->sc_blks++;
-
-       if (inqbuf.version != 1)
-               printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit,
-                       inqbuf.type, inqbuf.qual, inqbuf.version);
-       else {
-               char idstr[32];
-
+       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] != ' ')
                bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28);
                for (i = 27; i > 23; --i)
                        if (idstr[i] != ' ')
@@ -279,22 +225,40 @@ sdident(sc, hd)
                        if (idstr[i] != ' ')
                                break;
                idstr[i+1] = 0;
                        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]);
                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;
        }
        }
-       printf(", %d %d byte blocks\n", sc->sc_blks, sc->sc_blksize);
-       if (sc->sc_blksize != DEV_BSIZE) {
-               if (sc->sc_blksize < DEV_BSIZE) {
-                       printf("sd%d: need %d byte blocks - drive ignored\n",
-                               unit, DEV_BSIZE);
-                       return (-1);
-               }
-               for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1)
-                       ++sc->sc_bshift;
-               sc->sc_blks <<= sc->sc_bshift;
-       }
+       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 */
        sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2);        /* XXX */
+       scsi_delay(0);
        return(inqbuf.type);
        return(inqbuf.type);
+failed:
+       scsi_delay(0);
+       return(-1);
 }
 
 int
 }
 
 int
@@ -304,6 +268,12 @@ sdinit(hd)
        register struct sd_softc *sc = &sd_softc[hd->hp_unit];
 
        sc->sc_hd = 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)
        sc->sc_punit = sdpunit(hd->hp_flags);
        sc->sc_type = sdident(sc, hd);
        if (sc->sc_type < 0)
@@ -313,45 +283,7 @@ sdinit(hd)
        sc->sc_dq.dq_slave = hd->hp_slave;
        sc->sc_dq.dq_driver = &sddriver;
 
        sc->sc_dq.dq_slave = hd->hp_slave;
        sc->sc_dq.dq_driver = &sddriver;
 
-       /*
-        * If we don't have a disk label, build a default partition
-        * table with 'standard' size root & swap and everything else
-        * in the G partition.
-        */
-       sc->sc_info = sddefaultpart;
-       /* C gets everything */
-       sc->sc_info.part[2].nblocks = sc->sc_blks;
-       sc->sc_info.part[2].endblk = sc->sc_blks;
-       /* G gets from end of B to end of disk */
-       sc->sc_info.part[6].nblocks = sc->sc_blks - sc->sc_info.part[1].endblk;
-       sc->sc_info.part[6].endblk = sc->sc_blks;
-       /*
-        * We also define the D, E and F paritions as an alternative to
-        * B and G.  D is 48Mb, starts after A and is intended for swapping.
-        * E is 50Mb, starts after D and is intended for /usr. F starts
-        * after E and is what ever is left.
-        */
-       if (sc->sc_blks >= sc->sc_info.part[4].endblk) {
-               sc->sc_info.part[5].nblocks =
-                       sc->sc_blks - sc->sc_info.part[4].endblk;
-               sc->sc_info.part[5].endblk = sc->sc_blks;
-       } else {
-               sc->sc_info.part[5].strtblk = 0;
-               sc->sc_info.part[3] = sc->sc_info.part[5];
-               sc->sc_info.part[4] = sc->sc_info.part[5];
-       }
-       /*
-        * H is a single partition alternative to E and F.
-        */
-       if (sc->sc_blks >= sc->sc_info.part[3].endblk) {
-               sc->sc_info.part[7].nblocks =
-                       sc->sc_blks - sc->sc_info.part[3].endblk;
-               sc->sc_info.part[7].endblk = sc->sc_blks;
-       } else {
-               sc->sc_info.part[7].strtblk = 0;
-       }
-
-       sc->sc_flags = SDF_ALIVE;
+       sc->sc_flags |= SDF_ALIVE;
        return(1);
 }
 
        return(1);
 }
 
@@ -363,6 +295,200 @@ sdreset(sc, hd)
        sdstats[hd->hp_unit].sdresets++;
 }
 
        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.
+ */
+int
+sdgetcapacity(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
+ */
+int
+sdgetinfo(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;
+       /* XXX reset other info since readdisklabel screws with it */
+       lp->d_npartitions = 3;
+       pi[0].p_size = 0;
+       return(0);
+}
+
 int
 sdopen(dev, flags, mode, p)
        dev_t dev;
 int
 sdopen(dev, flags, mode, p)
        dev_t dev;
@@ -371,14 +497,78 @@ sdopen(dev, flags, mode, p)
 {
        register int unit = sdunit(dev);
        register struct sd_softc *sc = &sd_softc[unit];
 {
        register int unit = sdunit(dev);
        register struct sd_softc *sc = &sd_softc[unit];
+       int error, mask;
 
 
-       if (unit >= NSD)
-               return(ENXIO);
-       if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(p->p_ucred, &p->p_acflag))
+       if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
                return(ENXIO);
 
                return(ENXIO);
 
+       /*
+        * 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;
        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);
+}
+
+int
+sdclose(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);
 }
 
        return(0);
 }
 
@@ -420,7 +610,7 @@ sdlblkstrat(bp, bsize)
 
                if (boff || resid < bsize) {
                        sdstats[sdunit(bp->b_dev)].sdpartials++;
 
                if (boff || resid < bsize) {
                        sdstats[sdunit(bp->b_dev)].sdpartials++;
-                       count = MIN(resid, bsize - boff);
+                       count = min(resid, bsize - boff);
                        cbp->b_flags = B_BUSY | B_PHYS | B_READ;
                        cbp->b_blkno = bn - btodb(boff);
                        cbp->b_un.b_addr = cbuf;
                        cbp->b_flags = B_BUSY | B_PHYS | B_READ;
                        cbp->b_blkno = bn - btodb(boff);
                        cbp->b_un.b_addr = cbuf;
@@ -484,36 +674,50 @@ void
 sdstrategy(bp)
        register struct buf *bp;
 {
 sdstrategy(bp)
        register struct buf *bp;
 {
-       register int unit = sdunit(bp->b_dev);
+       int unit = sdunit(bp->b_dev);
        register struct sd_softc *sc = &sd_softc[unit];
        register struct sd_softc *sc = &sd_softc[unit];
-       register struct size *pinfo = &sc->sc_info.part[sdpart(bp->b_dev)];
        register struct buf *dp = &sdtab[unit];
        register struct buf *dp = &sdtab[unit];
+       register struct partition *pinfo;
        register daddr_t bn;
        register int sz, s;
 
        register daddr_t bn;
        register int sz, s;
 
-       if (sc->sc_format_pid) {
+       if (sc->sc_format_pid >= 0) {
                if (sc->sc_format_pid != curproc->p_pid) {      /* XXX */
                        bp->b_error = EPERM;
                if (sc->sc_format_pid != curproc->p_pid) {      /* XXX */
                        bp->b_error = EPERM;
-                       bp->b_flags |= B_ERROR;
-                       goto done;
+                       goto bad;
                }
                bp->b_cylin = 0;
        } else {
                }
                bp->b_cylin = 0;
        } else {
+               if (sc->sc_flags & SDF_ERROR) {
+                       bp->b_error = EIO;
+                       goto bad;
+               }
                bn = bp->b_blkno;
                sz = howmany(bp->b_bcount, DEV_BSIZE);
                bn = bp->b_blkno;
                sz = howmany(bp->b_bcount, DEV_BSIZE);
-               if (bn < 0 || bn + sz > pinfo->nblocks) {
-                       sz = pinfo->nblocks - bn;
+               pinfo = &sc->sc_info.si_label.d_partitions[sdpart(bp->b_dev)];
+               if (bn < 0 || bn + sz > pinfo->p_size) {
+                       sz = pinfo->p_size - bn;
                        if (sz == 0) {
                                bp->b_resid = bp->b_bcount;
                                goto done;
                        }
                        if (sz < 0) {
                                bp->b_error = EINVAL;
                        if (sz == 0) {
                                bp->b_resid = bp->b_bcount;
                                goto done;
                        }
                        if (sz < 0) {
                                bp->b_error = EINVAL;
-                               bp->b_flags |= B_ERROR;
-                               goto done;
+                               goto bad;
                        }
                        bp->b_bcount = dbtob(sz);
                }
                        }
                        bp->b_bcount = dbtob(sz);
                }
+               /*
+                * Check for write to write protected label
+                */
+               if (bn + pinfo->p_offset <= LABELSECTOR &&
+#if LABELSECTOR != 0
+                   bn + pinfo->p_offset + sz > LABELSECTOR &&
+#endif
+                   !(bp->b_flags & B_READ) && !(sc->sc_flags & SDF_WLABEL)) {
+                       bp->b_error = EROFS;
+                       goto bad;
+               }
                /*
                 * Non-aligned or partial-block transfers handled specially.
                 */
                /*
                 * Non-aligned or partial-block transfers handled specially.
                 */
@@ -522,7 +726,7 @@ sdstrategy(bp)
                        sdlblkstrat(bp, sc->sc_blksize);
                        goto done;
                }
                        sdlblkstrat(bp, sc->sc_blksize);
                        goto done;
                }
-               bp->b_cylin = (bn + pinfo->strtblk) >> sc->sc_bshift;
+               bp->b_cylin = (bn + pinfo->p_offset) >> sc->sc_bshift;
        }
        s = splbio();
        disksort(dp, bp);
        }
        s = splbio();
        disksort(dp, bp);
@@ -532,6 +736,8 @@ sdstrategy(bp)
        }
        splx(s);
        return;
        }
        splx(s);
        return;
+bad:
+       bp->b_flags |= B_ERROR;
 done:
        biodone(bp);
 }
 done:
        biodone(bp);
 }
@@ -544,13 +750,19 @@ sdustart(unit)
                sdstart(unit);
 }
 
                sdstart(unit);
 }
 
+/*
+ * Return:
+ *     0       if not really an error
+ *     <0      if we should do a retry
+ *     >0      if a fatal error
+ */
 static int
 sderror(unit, sc, hp, stat)
        int unit, stat;
        register struct sd_softc *sc;
        register struct hp_device *hp;
 {
 static int
 sderror(unit, sc, hp, stat)
        int unit, stat;
        register struct sd_softc *sc;
        register struct hp_device *hp;
 {
-       int retry = 0;
+       int cond = 1;
 
        sdsense[unit].status = stat;
        if (stat & STS_CHECKCOND) {
 
        sdsense[unit].status = stat;
        if (stat & STS_CHECKCOND) {
@@ -566,13 +778,37 @@ sderror(unit, sc, hp, stat)
                        printf(", key %d", sp->key);
                        if (sp->valid)
                                printf(", blk %d", *(int *)&sp->info1);
                        printf(", key %d", sp->key);
                        if (sp->valid)
                                printf(", blk %d", *(int *)&sp->info1);
-                       /* no sense or recovered error, try again */
-                       if (sp->key == 0 || sp->key == 1)
-                               retry = 1;
+                       switch (sp->key) {
+                       /* no sense, try again */
+                       case 0:
+                               cond = -1;
+                               break;
+                       /* recovered error, not a problem */
+                       case 1:
+                               cond = 0;
+                               break;
+                       /* possible media change */
+                       case 6:
+                               /*
+                                * For removable media, if we are doing the
+                                * first open (i.e. reading the label) go
+                                * ahead and retry, otherwise someone has
+                                * changed the media out from under us and
+                                * we should abort any further operations
+                                * until a close is done.
+                                */
+                               if (sc->sc_flags & SDF_RMEDIA) {
+                                       if (sc->sc_flags & SDF_OPENING)
+                                               cond = -1;
+                                       else
+                                               sc->sc_flags |= SDF_ERROR;
+                               }
+                               break;
+                       }
                }
                printf("\n");
        }
                }
                printf("\n");
        }
-       return(retry);
+       return(cond);
 }
 
 static void
 }
 
 static void
@@ -581,15 +817,22 @@ sdfinish(unit, sc, bp)
        register struct sd_softc *sc;
        register struct buf *bp;
 {
        register struct sd_softc *sc;
        register struct buf *bp;
 {
-       sdtab[unit].b_errcnt = 0;
-       sdtab[unit].b_actf = bp->b_actf;
+       register struct buf *dp = &sdtab[unit];
+
+       dp->b_errcnt = 0;
+       dp->b_actf = bp->b_actf;
        bp->b_resid = 0;
        biodone(bp);
        scsifree(&sc->sc_dq);
        bp->b_resid = 0;
        biodone(bp);
        scsifree(&sc->sc_dq);
-       if (sdtab[unit].b_actf)
+       if (dp->b_actf)
                sdustart(unit);
                sdustart(unit);
-       else
-               sdtab[unit].b_active = 0;
+       else {
+               dp->b_active = 0;
+               if (sc->sc_flags & SDF_WANTED) {
+                       sc->sc_flags &= ~SDF_WANTED;
+                       wakeup((caddr_t)dp);
+               }
+       }
 }
 
 void
 }
 
 void
@@ -603,19 +846,25 @@ sdstart(unit)
         * we have the SCSI bus -- in format mode, we may or may not need dma
         * so check now.
         */
         * we have the SCSI bus -- in format mode, we may or may not need dma
         * so check now.
         */
-       if (sc->sc_format_pid && legal_cmds[sdcmd[unit].cdb[0]] > 0) {
+       if (sc->sc_format_pid >= 0 && legal_cmds[sdcmd[unit].cdb[0]] > 0) {
                register struct buf *bp = sdtab[unit].b_actf;
                register int sts;
 
                register struct buf *bp = sdtab[unit].b_actf;
                register int sts;
 
-               sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave,
-                                        sc->sc_punit, &sdcmd[unit],
-                                        bp->b_un.b_addr, bp->b_bcount,
-                                        bp->b_flags & B_READ);
-               sdsense[unit].status = sts;
-               if (sts & 0xfe) {
-                       (void) sderror(unit, sc, hp, sts);
-                       bp->b_flags |= B_ERROR;
-                       bp->b_error = EIO;
+               sdtab[unit].b_errcnt = 0;
+               while (1) {
+                       sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave,
+                                                sc->sc_punit, &sdcmd[unit],
+                                                bp->b_un.b_addr, bp->b_bcount,
+                                                bp->b_flags & B_READ);
+                       sdsense[unit].status = sts;
+                       if ((sts & 0xfe) == 0 ||
+                           (sts = sderror(unit, sc, hp, sts)) == 0)
+                               break;
+                       if (sts > 0 || sdtab[unit].b_errcnt++ >= SDRETRY) {
+                               bp->b_flags |= B_ERROR;
+                               bp->b_error = EIO;
+                               break;
+                       }
                }
                sdfinish(unit, sc, bp);
 
                }
                sdfinish(unit, sc, bp);
 
@@ -633,10 +882,19 @@ sdgo(unit)
        register int pad;
        register struct scsi_fmt_cdb *cmd;
 
        register int pad;
        register struct scsi_fmt_cdb *cmd;
 
-       if (sc->sc_format_pid) {
+       if (sc->sc_format_pid >= 0) {
                cmd = &sdcmd[unit];
                pad = 0;
        } else {
                cmd = &sdcmd[unit];
                pad = 0;
        } else {
+               /*
+                * Drive is in an error state, abort all operations
+                */
+               if (sc->sc_flags & SDF_ERROR) {
+                       bp->b_flags |= B_ERROR;
+                       bp->b_error = EIO;
+                       sdfinish(unit, sc, bp);
+                       return;
+               }
                cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd;
                *(int *)(&cmd->cdb[2]) = bp->b_cylin;
                pad = howmany(bp->b_bcount, sc->sc_blksize);
                cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd;
                *(int *)(&cmd->cdb[2]) = bp->b_cylin;
                pad = howmany(bp->b_bcount, sc->sc_blksize);
@@ -649,6 +907,10 @@ sdgo(unit)
 #endif
                sdstats[unit].sdtransfers++;
        }
 #endif
                sdstats[unit].sdtransfers++;
        }
+#ifdef USELEDS
+       if (inledcontrol == 0)
+               ledcontrol(0, 0, LED_DISK);
+#endif
        if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) {
                if (hp->hp_dk >= 0) {
                        dk_busy |= 1 << hp->hp_dk;
        if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) {
                if (hp->hp_dk >= 0) {
                        dk_busy |= 1 << hp->hp_dk;
@@ -678,7 +940,7 @@ sdintr(unit, stat)
        register struct sd_softc *sc = &sd_softc[unit];
        register struct buf *bp = sdtab[unit].b_actf;
        register struct hp_device *hp = sc->sc_hd;
        register struct sd_softc *sc = &sd_softc[unit];
        register struct buf *bp = sdtab[unit].b_actf;
        register struct hp_device *hp = sc->sc_hd;
-       int retry;
+       int cond;
        
        if (bp == NULL) {
                printf("sd%d: bp == NULL\n", unit);
        
        if (bp == NULL) {
                printf("sd%d: bp == NULL\n", unit);
@@ -692,15 +954,20 @@ sdintr(unit, stat)
                        printf("sd%d: sdintr: bad scsi status 0x%x\n",
                                unit, stat);
 #endif
                        printf("sd%d: sdintr: bad scsi status 0x%x\n",
                                unit, stat);
 #endif
-               retry = sderror(unit, sc, hp, stat);
-               if (retry && sdtab[unit].b_errcnt++ < SDRETRY) {
-                       printf("sd%d: retry #%d\n",
-                              unit, sdtab[unit].b_errcnt);
-                       sdstart(unit);
-                       return;
+               cond = sderror(unit, sc, hp, stat);
+               if (cond) {
+                       if (cond < 0 && sdtab[unit].b_errcnt++ < SDRETRY) {
+#ifdef DEBUG
+                               if (sddebug & SDB_ERROR)
+                                       printf("sd%d: retry #%d\n",
+                                              unit, sdtab[unit].b_errcnt);
+#endif
+                               sdstart(unit);
+                               return;
+                       }
+                       bp->b_flags |= B_ERROR;
+                       bp->b_error = EIO;
                }
                }
-               bp->b_flags |= B_ERROR;
-               bp->b_error = EIO;
        }
        sdfinish(unit, sc, bp);
 }
        }
        sdfinish(unit, sc, bp);
 }
@@ -714,7 +981,7 @@ sdread(dev, uio, flags)
        register int unit = sdunit(dev);
        register int pid;
 
        register int unit = sdunit(dev);
        register int pid;
 
-       if ((pid = sd_softc[unit].sc_format_pid) &&
+       if ((pid = sd_softc[unit].sc_format_pid) >= 0 &&
            pid != uio->uio_procp->p_pid)
                return (EPERM);
                
            pid != uio->uio_procp->p_pid)
                return (EPERM);
                
@@ -730,7 +997,7 @@ sdwrite(dev, uio, flags)
        register int unit = sdunit(dev);
        register int pid;
 
        register int unit = sdunit(dev);
        register int pid;
 
-       if ((pid = sd_softc[unit].sc_format_pid) &&
+       if ((pid = sd_softc[unit].sc_format_pid) >= 0 &&
            pid != uio->uio_procp->p_pid)
                return (EPERM);
                
            pid != uio->uio_procp->p_pid)
                return (EPERM);
                
@@ -740,29 +1007,72 @@ sdwrite(dev, uio, flags)
 int
 sdioctl(dev, cmd, data, flag, p)
        dev_t dev;
 int
 sdioctl(dev, cmd, data, flag, p)
        dev_t dev;
-       int cmd;
+       u_long cmd;
        caddr_t data;
        int flag;
        struct proc *p;
 {
        caddr_t data;
        int flag;
        struct proc *p;
 {
-       register int unit = sdunit(dev);
+       int unit = sdunit(dev);
        register struct sd_softc *sc = &sd_softc[unit];
        register struct sd_softc *sc = &sd_softc[unit];
+       register struct disklabel *lp = &sc->sc_info.si_label;
+       int error, flags;
 
        switch (cmd) {
        default:
                return (EINVAL);
 
 
        switch (cmd) {
        default:
                return (EINVAL);
 
+       case DIOCGDINFO:
+               *(struct disklabel *)data = *lp;
+               return (0);
+
+       case DIOCGPART:
+               ((struct partinfo *)data)->disklab = lp;
+               ((struct partinfo *)data)->part =
+                       &lp->d_partitions[sdpart(dev)];
+               return (0);
+
+        case DIOCWLABEL:
+                if ((flag & FWRITE) == 0)
+                        return (EBADF);
+               if (*(int *)data)
+                       sc->sc_flags |= SDF_WLABEL;
+               else
+                       sc->sc_flags &= ~SDF_WLABEL;
+               return (0);
+
+        case DIOCSDINFO:
+                if ((flag & FWRITE) == 0)
+                        return (EBADF);
+               error = setdisklabel(lp, (struct disklabel *)data,
+                                    (sc->sc_flags & SDF_WLABEL) ? 0
+                                    : sc->sc_info.si_open);
+               return (error);
+
+        case DIOCWDINFO:
+               if ((flag & FWRITE) == 0)
+                       return (EBADF);
+               error = setdisklabel(lp, (struct disklabel *)data,
+                                    (sc->sc_flags & SDF_WLABEL) ? 0
+                                    : sc->sc_info.si_open);
+               if (error)
+                       return (error);
+               flags = sc->sc_flags;
+               sc->sc_flags = SDF_ALIVE | SDF_WLABEL;
+               error = writedisklabel(sdlabdev(dev), sdstrategy, lp);
+               sc->sc_flags = flags;
+               return (error);
+
        case SDIOCSFORMAT:
                /* take this device into or out of "format" mode */
                if (suser(p->p_ucred, &p->p_acflag))
                        return(EPERM);
 
                if (*(int *)data) {
        case SDIOCSFORMAT:
                /* take this device into or out of "format" mode */
                if (suser(p->p_ucred, &p->p_acflag))
                        return(EPERM);
 
                if (*(int *)data) {
-                       if (sc->sc_format_pid)
+                       if (sc->sc_format_pid >= 0)
                                return (EPERM);
                        sc->sc_format_pid = p->p_pid;
                } else
                                return (EPERM);
                        sc->sc_format_pid = p->p_pid;
                } else
-                       sc->sc_format_pid = 0;
+                       sc->sc_format_pid = -1;
                return (0);
 
        case SDIOCGFORMAT:
                return (0);
 
        case SDIOCGFORMAT:
@@ -800,11 +1110,25 @@ sdsize(dev)
 {
        register int unit = sdunit(dev);
        register struct sd_softc *sc = &sd_softc[unit];
 {
        register int unit = sdunit(dev);
        register struct sd_softc *sc = &sd_softc[unit];
+       int psize, didopen = 0;
 
        if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
                return(-1);
 
 
        if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
                return(-1);
 
-       return(sc->sc_info.part[sdpart(dev)].nblocks);
+       /*
+        * We get called very early on (via swapconf)
+        * without the device being open so we may need
+        * to handle it here.
+        */
+       if (sc->sc_info.si_open == 0) {
+               if (sdopen(dev, FREAD|FWRITE, S_IFBLK, NULL))
+                       return(-1);
+               didopen = 1;
+       }
+       psize = sc->sc_info.si_label.d_partitions[sdpart(dev)].p_size;
+       if (didopen)
+               (void) sdclose(dev, FREAD|FWRITE, S_IFBLK, NULL);
+       return (psize);
 }
 
 /*
 }
 
 /*
@@ -818,30 +1142,26 @@ sddump(dev)
        int unit = sdunit(dev);
        register struct sd_softc *sc = &sd_softc[unit];
        register struct hp_device *hp = sc->sc_hd;
        int unit = sdunit(dev);
        register struct sd_softc *sc = &sd_softc[unit];
        register struct hp_device *hp = sc->sc_hd;
+       register struct partition *pinfo;
        register daddr_t baddr;
        register int maddr;
        register int pages, i;
        int stat;
        register daddr_t baddr;
        register int maddr;
        register int pages, i;
        int stat;
-       extern int lowram;
-
-       /*
-        * Hmm... all vax drivers dump maxfree pages which is physmem minus
-        * the message buffer.  Is there a reason for not dumping the
-        * message buffer?  Savecore expects to read 'dumpsize' pages of
-        * dump, where dumpsys() sets dumpsize to physmem!
-        */
-       pages = physmem;
+       extern int lowram, dumpsize;
 
        /* is drive ok? */
        if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
                return (ENXIO);
 
        /* is drive ok? */
        if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
                return (ENXIO);
+       pinfo = &sc->sc_info.si_label.d_partitions[part];
        /* dump parameters in range? */
        /* dump parameters in range? */
-       if (dumplo < 0 || dumplo >= sc->sc_info.part[part].nblocks)
+       if (dumplo < 0 || dumplo >= pinfo->p_size ||
+           pinfo->p_fstype != FS_SWAP)
                return (EINVAL);
                return (EINVAL);
-       if (dumplo + ctod(pages) > sc->sc_info.part[part].nblocks)
-               pages = dtoc(sc->sc_info.part[part].nblocks - dumplo);
+       pages = dumpsize;
+       if (dumplo + ctod(pages) > pinfo->p_size)
+               pages = dtoc(pinfo->p_size - dumplo);
        maddr = lowram;
        maddr = lowram;
-       baddr = dumplo + sc->sc_info.part[part].strtblk;
+       baddr = dumplo + pinfo->p_offset;
        /* scsi bus idle? */
        if (!scsireq(&sc->sc_dq)) {
                scsireset(hp->hp_ctlr);
        /* scsi bus idle? */
        if (!scsireq(&sc->sc_dq)) {
                scsireset(hp->hp_ctlr);
@@ -854,7 +1174,8 @@ sddump(dev)
                if (i && (i % NPGMB) == 0)
                        printf("%d ", i / NPGMB);
 #undef NPBMG
                if (i && (i % NPGMB) == 0)
                        printf("%d ", i / NPGMB);
 #undef NPBMG
-               pmap_enter(pmap_kernel(), vmmap, maddr, VM_PROT_READ, TRUE);
+               pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr,
+                   VM_PROT_READ, TRUE);
                stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit,
                                     vmmap, NBPG, baddr, sc->sc_bshift);
                if (stat) {
                stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit,
                                     vmmap, NBPG, baddr, sc->sc_bshift);
                if (stat) {