152130Smckusick /* 264089Sbostic * Copyright (c) 1992, 1993 364089Sbostic * The Regents of the University of California. All rights reserved. 452130Smckusick * 552130Smckusick * This code is derived from software contributed to Berkeley by 652130Smckusick * Van Jacobson of Lawrence Berkeley Laboratory and Ralph Campbell. 752130Smckusick * 852130Smckusick * %sccs.include.redist.c% 952130Smckusick * 10*68012Smckusick * @(#)rz.c 8.3 (Berkeley) 11/30/94 1152130Smckusick */ 1252130Smckusick 1352130Smckusick /* 1452130Smckusick * SCSI CCS (Command Command Set) disk driver. 1553202Sralph * NOTE: The name was changed from "sd" to "rz" for DEC naming compatibility. 1652130Smckusick * I guess I can't avoid confusion someplace. 1752130Smckusick */ 1852130Smckusick #include "rz.h" 1952130Smckusick #if NRZ > 0 2052130Smckusick 2156522Sbostic #include <sys/param.h> 2256522Sbostic #include <sys/systm.h> 2356522Sbostic #include <sys/buf.h> 2456522Sbostic #include <sys/errno.h> 2556522Sbostic #include <sys/fcntl.h> 2656522Sbostic #include <sys/ioctl.h> 2756522Sbostic #include <sys/dkstat.h> 2856522Sbostic #include <sys/disklabel.h> 2956522Sbostic #include <sys/malloc.h> 3056522Sbostic #include <sys/proc.h> 3156522Sbostic #include <sys/uio.h> 3256522Sbostic #include <sys/stat.h> 3356522Sbostic #include <sys/syslog.h> 3452130Smckusick 3556522Sbostic #include <ufs/ffs/fs.h> 3652130Smckusick 3756525Sbostic #include <pmax/dev/device.h> 3856525Sbostic #include <pmax/dev/scsi.h> 3956522Sbostic 4052130Smckusick extern int splbio(); 4152130Smckusick extern void splx(); 4252130Smckusick extern int physio(); 4352130Smckusick 4452130Smckusick int rzprobe(); 4552130Smckusick void rzstrategy(), rzstart(), rzdone(); 4652130Smckusick 4752130Smckusick struct driver rzdriver = { 4852130Smckusick "rz", rzprobe, rzstart, rzdone, 4952130Smckusick }; 5052130Smckusick 5152130Smckusick struct size { 5252130Smckusick u_long strtblk; 5353202Sralph u_long nblocks; 5452130Smckusick }; 5552130Smckusick 5652130Smckusick /* 5752130Smckusick * Since the SCSI standard tends to hide the disk structure, we define 5852130Smckusick * partitions in terms of DEV_BSIZE blocks. The default partition table 5953202Sralph * (for an unlabeled disk) reserves 8K for a boot area, has an 8 meg 6052130Smckusick * root and 32 meg of swap. The rest of the space on the drive goes in 6152130Smckusick * the G partition. As usual, the C partition covers the entire disk 6252130Smckusick * (including the boot area). 6352130Smckusick */ 6456629Sralph static struct size rzdefaultpart[MAXPARTITIONS] = { 6553202Sralph 0, 16384, /* A */ 6653202Sralph 16384, 65536, /* B */ 6753202Sralph 0, 0, /* C */ 6853202Sralph 17408, 0, /* D */ 6953202Sralph 115712, 0, /* E */ 7053202Sralph 218112, 0, /* F */ 7153202Sralph 81920, 0, /* G */ 7253202Sralph 115712, 0, /* H */ 7352130Smckusick }; 7452130Smckusick 7553202Sralph #define RAWPART 2 /* 'c' partition */ /* XXX */ 7653202Sralph 7752130Smckusick struct rzstats { 7852130Smckusick long rzresets; 7952130Smckusick long rztransfers; 8052130Smckusick long rzpartials; 8152130Smckusick }; 8252130Smckusick 8352130Smckusick struct rz_softc { 8452130Smckusick struct scsi_device *sc_sd; /* physical unit info */ 8553202Sralph pid_t sc_format_pid; /* process using "format" mode */ 8653202Sralph u_long sc_openpart; /* partitions open */ 8753202Sralph u_long sc_bopenpart; /* block partitions open */ 8853202Sralph u_long sc_copenpart; /* character partitions open */ 8952130Smckusick short sc_flags; /* see below */ 9052130Smckusick short sc_type; /* drive type from INQUIRY cmd */ 9152130Smckusick u_int sc_blks; /* number of blocks on device */ 9252130Smckusick int sc_blksize; /* device block size in bytes */ 9352130Smckusick int sc_bshift; /* convert device blocks to DEV_BSIZE */ 9452130Smckusick u_int sc_wpms; /* average xfer rate in 16bit wds/sec */ 9553202Sralph struct disklabel sc_label; /* disk label for this disk */ 9652130Smckusick struct rzstats sc_stats; /* statisic counts */ 9752130Smckusick struct buf sc_tab; /* queue of pending operations */ 9852130Smckusick struct buf sc_buf; /* buf for doing I/O */ 9952130Smckusick struct buf sc_errbuf; /* buf for doing REQUEST_SENSE */ 10052130Smckusick struct ScsiCmd sc_cmd; /* command for controller */ 10152130Smckusick ScsiGroup1Cmd sc_rwcmd; /* SCSI cmd if not in "format" mode */ 10252130Smckusick struct scsi_fmt_cdb sc_cdb; /* SCSI cmd if in "format" mode */ 10352130Smckusick struct scsi_fmt_sense sc_sense; /* sense data from last cmd */ 104*68012Smckusick u_char sc_capbuf[8]; /* buffer for SCSI_READ_CAPACITY */ 10552130Smckusick } rz_softc[NRZ]; 10652130Smckusick 10752130Smckusick /* sc_flags values */ 108*68012Smckusick #define RZF_ALIVE 0x0001 /* drive found and ready */ 109*68012Smckusick #define RZF_SENSEINPROGRESS 0x0002 /* REQUEST_SENSE command in progress */ 110*68012Smckusick #define RZF_ALTCMD 0x0004 /* alternate command in progress */ 111*68012Smckusick #define RZF_HAVELABEL 0x0008 /* valid label found on disk */ 112*68012Smckusick #define RZF_WLABEL 0x0010 /* label is writeable */ 113*68012Smckusick #define RZF_WAIT 0x0020 /* waiting for sc_tab to drain */ 114*68012Smckusick #define RZF_REMOVEABLE 0x0040 /* disk is removable */ 115*68012Smckusick #define RZF_TRYSYNC 0x0080 /* try synchronous operation */ 116*68012Smckusick #define RZF_NOERR 0x0100 /* don't print error messages */ 11752130Smckusick 11852130Smckusick #ifdef DEBUG 11952130Smckusick int rzdebug = 3; 12052130Smckusick #define RZB_ERROR 0x01 12152130Smckusick #define RZB_PARTIAL 0x02 12252130Smckusick #define RZB_PRLABEL 0x04 12352130Smckusick #endif 12452130Smckusick 12553202Sralph #define rzunit(x) (minor(x) >> 3) 12652130Smckusick #define rzpart(x) (minor(x) & 0x7) 12752130Smckusick #define b_cylin b_resid 12852130Smckusick 12952130Smckusick /* 13052130Smckusick * Table of scsi commands users are allowed to access via "format" mode. 13152130Smckusick * 0 means not legal. 13252130Smckusick * 1 means legal. 13352130Smckusick */ 13452130Smckusick static char legal_cmds[256] = { 13552130Smckusick /***** 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 13652130Smckusick /*00*/ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13752130Smckusick /*10*/ 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 13852130Smckusick /*20*/ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13952130Smckusick /*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14052130Smckusick /*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14152130Smckusick /*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14252130Smckusick /*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14352130Smckusick /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14452130Smckusick /*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14552130Smckusick /*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14652130Smckusick /*a0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14752130Smckusick /*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14852130Smckusick /*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14952130Smckusick /*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15052130Smckusick /*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15152130Smckusick /*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15252130Smckusick }; 15352130Smckusick 15452130Smckusick /* 155*68012Smckusick * Test to see if the unit is ready and if not, try to make it ready. 156*68012Smckusick * Also, find the drive capacity. 15752130Smckusick */ 158*68012Smckusick static int 159*68012Smckusick rzready(sc) 160*68012Smckusick register struct rz_softc *sc; 16152130Smckusick { 16252130Smckusick register int tries, i; 16352130Smckusick ScsiClass7Sense *sp; 16452130Smckusick 165*68012Smckusick /* don't print SCSI errors */ 166*68012Smckusick sc->sc_flags |= RZF_NOERR; 16752130Smckusick 168*68012Smckusick /* see if the device is ready */ 16952130Smckusick for (tries = 10; ; ) { 17052130Smckusick sc->sc_cdb.len = sizeof(ScsiGroup0Cmd); 171*68012Smckusick scsiGroup0Cmd(SCSI_TEST_UNIT_READY, sc->sc_rwcmd.unitNumber, 172*68012Smckusick 0, 0, (ScsiGroup0Cmd *)sc->sc_cdb.cdb); 17352130Smckusick sc->sc_buf.b_flags = B_BUSY | B_PHYS | B_READ; 17452130Smckusick sc->sc_buf.b_bcount = 0; 17552130Smckusick sc->sc_buf.b_un.b_addr = (caddr_t)0; 17656629Sralph sc->sc_buf.b_actf = (struct buf *)0; 17756629Sralph sc->sc_tab.b_actf = &sc->sc_buf; 17852130Smckusick 17952130Smckusick sc->sc_cmd.cmd = sc->sc_cdb.cdb; 18052130Smckusick sc->sc_cmd.cmdlen = sc->sc_cdb.len; 18152130Smckusick sc->sc_cmd.buf = (caddr_t)0; 18252130Smckusick sc->sc_cmd.buflen = 0; 18352130Smckusick /* setup synchronous data transfers if the device supports it */ 184*68012Smckusick if (tries == 10 && (sc->sc_flags & RZF_TRYSYNC)) 18552130Smckusick sc->sc_cmd.flags = SCSICMD_USE_SYNC; 18652130Smckusick else 18752130Smckusick sc->sc_cmd.flags = 0; 18852130Smckusick 18952130Smckusick (*sc->sc_sd->sd_cdriver->d_start)(&sc->sc_cmd); 19052130Smckusick if (!biowait(&sc->sc_buf)) 19152130Smckusick break; 19252130Smckusick if (--tries < 0) 193*68012Smckusick return (0); 19452130Smckusick if (!(sc->sc_sense.status & SCSI_STATUS_CHECKCOND)) 19552130Smckusick goto again; 19652130Smckusick sp = (ScsiClass7Sense *)sc->sc_sense.sense; 19752130Smckusick if (sp->error7 != 0x70) 19852130Smckusick goto again; 19952130Smckusick if (sp->key == SCSI_CLASS7_UNIT_ATTN && tries != 9) { 20052130Smckusick /* drive recalibrating, give it a while */ 20152130Smckusick DELAY(1000000); 20252130Smckusick continue; 20352130Smckusick } 20452130Smckusick if (sp->key == SCSI_CLASS7_NOT_READY) { 20552130Smckusick ScsiStartStopCmd *cp; 20652130Smckusick 20752130Smckusick /* try to spin-up disk with start/stop command */ 20852130Smckusick sc->sc_cdb.len = sizeof(ScsiGroup0Cmd); 20952130Smckusick cp = (ScsiStartStopCmd *)sc->sc_cdb.cdb; 21052130Smckusick cp->command = SCSI_START_STOP; 211*68012Smckusick cp->unitNumber = sc->sc_rwcmd.unitNumber; 21252130Smckusick cp->immed = 0; 21352130Smckusick cp->loadEject = 0; 21452130Smckusick cp->start = 1; 21552130Smckusick cp->pad1 = 0; 21652130Smckusick cp->pad2 = 0; 21752130Smckusick cp->pad3 = 0; 21852130Smckusick cp->pad4 = 0; 21952130Smckusick cp->control = 0; 22052130Smckusick sc->sc_buf.b_flags = B_BUSY | B_PHYS | B_READ; 22152130Smckusick sc->sc_buf.b_bcount = 0; 22252130Smckusick sc->sc_buf.b_un.b_addr = (caddr_t)0; 22356629Sralph sc->sc_buf.b_actf = (struct buf *)0; 22456629Sralph sc->sc_tab.b_actf = &sc->sc_buf; 225*68012Smckusick rzstart(sc->sc_cmd.unit); 22652130Smckusick if (biowait(&sc->sc_buf)) 227*68012Smckusick return (0); 22852130Smckusick continue; 22952130Smckusick } 23052130Smckusick again: 23152130Smckusick DELAY(1000); 23252130Smckusick } 23352130Smckusick 234*68012Smckusick /* print SCSI errors */ 235*68012Smckusick sc->sc_flags &= ~RZF_NOERR; 236*68012Smckusick 23752130Smckusick /* find out how big a disk this is */ 23852130Smckusick sc->sc_cdb.len = sizeof(ScsiGroup1Cmd); 239*68012Smckusick scsiGroup1Cmd(SCSI_READ_CAPACITY, sc->sc_rwcmd.unitNumber, 0, 0, 24052130Smckusick (ScsiGroup1Cmd *)sc->sc_cdb.cdb); 24152130Smckusick sc->sc_buf.b_flags = B_BUSY | B_PHYS | B_READ; 242*68012Smckusick sc->sc_buf.b_bcount = sizeof(sc->sc_capbuf); 243*68012Smckusick sc->sc_buf.b_un.b_addr = (caddr_t)sc->sc_capbuf; 24456629Sralph sc->sc_buf.b_actf = (struct buf *)0; 24556629Sralph sc->sc_tab.b_actf = &sc->sc_buf; 246*68012Smckusick sc->sc_flags |= RZF_ALTCMD; 247*68012Smckusick rzstart(sc->sc_cmd.unit); 248*68012Smckusick sc->sc_flags &= ~RZF_ALTCMD; 249*68012Smckusick if (biowait(&sc->sc_buf) || sc->sc_buf.b_resid != 0) 250*68012Smckusick return (0); 251*68012Smckusick sc->sc_blks = ((sc->sc_capbuf[0] << 24) | (sc->sc_capbuf[1] << 16) | 252*68012Smckusick (sc->sc_capbuf[2] << 8) | sc->sc_capbuf[3]) + 1; 253*68012Smckusick sc->sc_blksize = (sc->sc_capbuf[4] << 24) | (sc->sc_capbuf[5] << 16) | 254*68012Smckusick (sc->sc_capbuf[6] << 8) | sc->sc_capbuf[7]; 255*68012Smckusick 256*68012Smckusick sc->sc_bshift = 0; 257*68012Smckusick for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1) 258*68012Smckusick ++sc->sc_bshift; 259*68012Smckusick sc->sc_blks <<= sc->sc_bshift; 260*68012Smckusick 261*68012Smckusick return (1); 262*68012Smckusick } 263*68012Smckusick 264*68012Smckusick /* 265*68012Smckusick * Test to see if device is present. 266*68012Smckusick * Return true if found and initialized ok. 267*68012Smckusick */ 268*68012Smckusick rzprobe(sd) 269*68012Smckusick register struct scsi_device *sd; 270*68012Smckusick { 271*68012Smckusick register struct rz_softc *sc = &rz_softc[sd->sd_unit]; 272*68012Smckusick register int i; 273*68012Smckusick ScsiInquiryData inqbuf; 274*68012Smckusick ScsiClass7Sense *sp; 275*68012Smckusick 276*68012Smckusick /* init some parameters that don't change */ 277*68012Smckusick sc->sc_sd = sd; 278*68012Smckusick sc->sc_cmd.sd = sd; 279*68012Smckusick sc->sc_cmd.unit = sd->sd_unit; 280*68012Smckusick sc->sc_rwcmd.unitNumber = sd->sd_slave; 281*68012Smckusick 282*68012Smckusick /* try to find out what type of device this is */ 283*68012Smckusick sc->sc_format_pid = 1; /* force use of sc_cdb */ 284*68012Smckusick sc->sc_flags = RZF_NOERR; /* don't print SCSI errors */ 285*68012Smckusick sc->sc_cdb.len = sizeof(ScsiGroup0Cmd); 286*68012Smckusick scsiGroup0Cmd(SCSI_INQUIRY, sd->sd_slave, 0, sizeof(inqbuf), 287*68012Smckusick (ScsiGroup0Cmd *)sc->sc_cdb.cdb); 288*68012Smckusick sc->sc_buf.b_flags = B_BUSY | B_PHYS | B_READ; 289*68012Smckusick sc->sc_buf.b_bcount = sizeof(inqbuf); 290*68012Smckusick sc->sc_buf.b_un.b_addr = (caddr_t)&inqbuf; 291*68012Smckusick sc->sc_buf.b_actf = (struct buf *)0; 292*68012Smckusick sc->sc_tab.b_actf = &sc->sc_buf; 29352130Smckusick rzstart(sd->sd_unit); 294*68012Smckusick if (biowait(&sc->sc_buf) || 295*68012Smckusick (i = sizeof(inqbuf) - sc->sc_buf.b_resid) < 5) 29652130Smckusick goto bad; 297*68012Smckusick switch (inqbuf.type) { 298*68012Smckusick case SCSI_DISK_TYPE: /* disk */ 299*68012Smckusick case SCSI_WORM_TYPE: /* WORM */ 300*68012Smckusick case SCSI_ROM_TYPE: /* CD-ROM */ 301*68012Smckusick case SCSI_OPTICAL_MEM_TYPE: /* Magneto-optical */ 302*68012Smckusick break; 30352130Smckusick 304*68012Smckusick default: /* not a disk */ 305*68012Smckusick goto bad; 306*68012Smckusick } 307*68012Smckusick sc->sc_type = inqbuf.type; 308*68012Smckusick if (inqbuf.flags & SCSI_SYNC) 309*68012Smckusick sc->sc_flags |= RZF_TRYSYNC; 310*68012Smckusick 311*68012Smckusick if (!inqbuf.rmb) { 312*68012Smckusick if (!rzready(sc)) 313*68012Smckusick goto bad; 314*68012Smckusick } 315*68012Smckusick 31652130Smckusick printf("rz%d at %s%d drive %d slave %d", sd->sd_unit, 31752130Smckusick sd->sd_cdriver->d_name, sd->sd_ctlr, sd->sd_drive, 31852130Smckusick sd->sd_slave); 31967478Smckusick if (inqbuf.version > 2 || i < 36) 32052130Smckusick printf(" type 0x%x, qual 0x%x, ver %d", 32152130Smckusick inqbuf.type, inqbuf.qualifier, inqbuf.version); 32252130Smckusick else { 32352130Smckusick char vid[9], pid[17], revl[5]; 32452130Smckusick 32552130Smckusick bcopy((caddr_t)inqbuf.vendorID, (caddr_t)vid, 8); 32652130Smckusick bcopy((caddr_t)inqbuf.productID, (caddr_t)pid, 16); 32752130Smckusick bcopy((caddr_t)inqbuf.revLevel, (caddr_t)revl, 4); 32852130Smckusick for (i = 8; --i > 0; ) 32952130Smckusick if (vid[i] != ' ') 33052130Smckusick break; 33152130Smckusick vid[i+1] = 0; 33252130Smckusick for (i = 16; --i > 0; ) 33352130Smckusick if (pid[i] != ' ') 33452130Smckusick break; 33552130Smckusick pid[i+1] = 0; 33652130Smckusick for (i = 4; --i > 0; ) 33752130Smckusick if (revl[i] != ' ') 33852130Smckusick break; 33952130Smckusick revl[i+1] = 0; 34052130Smckusick printf(" %s %s rev %s", vid, pid, revl); 34152130Smckusick } 34252130Smckusick printf(", %d %d byte blocks\n", sc->sc_blks, sc->sc_blksize); 343*68012Smckusick if (!inqbuf.rmb && sc->sc_blksize != DEV_BSIZE) { 34452130Smckusick if (sc->sc_blksize < DEV_BSIZE) { 34552130Smckusick printf("rz%d: need %d byte blocks - drive ignored\n", 34652130Smckusick sd->sd_unit, DEV_BSIZE); 34752130Smckusick goto bad; 34852130Smckusick } 34952130Smckusick } 35052130Smckusick sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2); /* XXX */ 35152130Smckusick sc->sc_format_pid = 0; 352*68012Smckusick sc->sc_flags |= RZF_ALIVE; 353*68012Smckusick if (inqbuf.rmb) 354*68012Smckusick sc->sc_flags |= RZF_REMOVEABLE; 35552130Smckusick sc->sc_buf.b_flags = 0; 35652130Smckusick return (1); 35752130Smckusick 35852130Smckusick bad: 35952130Smckusick /* doesn't exist or not a CCS device */ 36052130Smckusick sc->sc_format_pid = 0; 36152130Smckusick sc->sc_buf.b_flags = 0; 36252130Smckusick return (0); 36352130Smckusick } 36452130Smckusick 36552130Smckusick /* 36652130Smckusick * This routine is called for partial block transfers and non-aligned 36752130Smckusick * transfers (the latter only being possible on devices with a block size 36852130Smckusick * larger than DEV_BSIZE). The operation is performed in three steps 36952130Smckusick * using a locally allocated buffer: 37052130Smckusick * 1. transfer any initial partial block 37152130Smckusick * 2. transfer full blocks 37252130Smckusick * 3. transfer any final partial block 37352130Smckusick */ 37452130Smckusick static void 37552130Smckusick rzlblkstrat(bp, bsize) 37652130Smckusick register struct buf *bp; 37752130Smckusick register int bsize; 37852130Smckusick { 37952130Smckusick register struct buf *cbp; 38052130Smckusick caddr_t cbuf; 38152130Smckusick register int bn, resid; 38252130Smckusick register caddr_t addr; 38352130Smckusick 38452130Smckusick cbp = (struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK); 38552130Smckusick cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK); 38652130Smckusick bzero((caddr_t)cbp, sizeof(*cbp)); 38752130Smckusick cbp->b_proc = curproc; 38852130Smckusick cbp->b_dev = bp->b_dev; 38952130Smckusick bn = bp->b_blkno; 39052130Smckusick resid = bp->b_bcount; 39152130Smckusick addr = bp->b_un.b_addr; 39252130Smckusick #ifdef DEBUG 39352130Smckusick if (rzdebug & RZB_PARTIAL) 39452130Smckusick printf("rzlblkstrat: bp %x flags %x bn %x resid %x addr %x\n", 39552130Smckusick bp, bp->b_flags, bn, resid, addr); 39652130Smckusick #endif 39752130Smckusick 39852130Smckusick while (resid > 0) { 39952130Smckusick register int boff = dbtob(bn) & (bsize - 1); 40052130Smckusick register int count; 40152130Smckusick 40252130Smckusick if (boff || resid < bsize) { 40352130Smckusick rz_softc[rzunit(bp->b_dev)].sc_stats.rzpartials++; 40455746Sralph count = min(resid, bsize - boff); 40552130Smckusick cbp->b_flags = B_BUSY | B_PHYS | B_READ; 40652130Smckusick cbp->b_blkno = bn - btodb(boff); 40752130Smckusick cbp->b_un.b_addr = cbuf; 40852130Smckusick cbp->b_bcount = bsize; 40952130Smckusick #ifdef DEBUG 41052130Smckusick if (rzdebug & RZB_PARTIAL) 41152130Smckusick printf(" readahead: bn %x cnt %x off %x addr %x\n", 41252130Smckusick cbp->b_blkno, count, boff, addr); 41352130Smckusick #endif 41452130Smckusick rzstrategy(cbp); 41552130Smckusick biowait(cbp); 41652130Smckusick if (cbp->b_flags & B_ERROR) { 41752130Smckusick bp->b_flags |= B_ERROR; 41852130Smckusick bp->b_error = cbp->b_error; 41952130Smckusick break; 42052130Smckusick } 42152130Smckusick if (bp->b_flags & B_READ) { 42252130Smckusick bcopy(&cbuf[boff], addr, count); 42352130Smckusick goto done; 42452130Smckusick } 42552130Smckusick bcopy(addr, &cbuf[boff], count); 42652130Smckusick #ifdef DEBUG 42752130Smckusick if (rzdebug & RZB_PARTIAL) 42852130Smckusick printf(" writeback: bn %x cnt %x off %x addr %x\n", 42952130Smckusick cbp->b_blkno, count, boff, addr); 43052130Smckusick #endif 43152130Smckusick } else { 43252130Smckusick count = resid & ~(bsize - 1); 43352130Smckusick cbp->b_blkno = bn; 43452130Smckusick cbp->b_un.b_addr = addr; 43552130Smckusick cbp->b_bcount = count; 43652130Smckusick #ifdef DEBUG 43752130Smckusick if (rzdebug & RZB_PARTIAL) 43852130Smckusick printf(" fulltrans: bn %x cnt %x addr %x\n", 43952130Smckusick cbp->b_blkno, count, addr); 44052130Smckusick #endif 44152130Smckusick } 44252130Smckusick cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ); 44352130Smckusick rzstrategy(cbp); 44452130Smckusick biowait(cbp); 44552130Smckusick if (cbp->b_flags & B_ERROR) { 44652130Smckusick bp->b_flags |= B_ERROR; 44752130Smckusick bp->b_error = cbp->b_error; 44852130Smckusick break; 44952130Smckusick } 45052130Smckusick done: 45152130Smckusick bn += btodb(count); 45252130Smckusick resid -= count; 45352130Smckusick addr += count; 45452130Smckusick #ifdef DEBUG 45552130Smckusick if (rzdebug & RZB_PARTIAL) 45652130Smckusick printf(" done: bn %x resid %x addr %x\n", 45752130Smckusick bn, resid, addr); 45852130Smckusick #endif 45952130Smckusick } 46052130Smckusick free(cbuf, M_DEVBUF); 46152130Smckusick free(cbp, M_DEVBUF); 46252130Smckusick } 46352130Smckusick 46452130Smckusick void 46552130Smckusick rzstrategy(bp) 46652130Smckusick register struct buf *bp; 46752130Smckusick { 46852130Smckusick register int unit = rzunit(bp->b_dev); 46952130Smckusick register int part = rzpart(bp->b_dev); 47052130Smckusick register struct rz_softc *sc = &rz_softc[unit]; 47153202Sralph register struct partition *pp = &sc->sc_label.d_partitions[part]; 47256629Sralph register daddr_t bn; 47356629Sralph register long sz, s; 47452130Smckusick 47552130Smckusick if (sc->sc_format_pid) { 47652130Smckusick if (sc->sc_format_pid != curproc->p_pid) { 47752130Smckusick bp->b_error = EPERM; 47852130Smckusick goto bad; 47952130Smckusick } 48052130Smckusick bp->b_cylin = 0; 48152130Smckusick } else { 48252130Smckusick bn = bp->b_blkno; 48356629Sralph sz = howmany(bp->b_bcount, DEV_BSIZE); 48456629Sralph if ((unsigned)bn + sz > pp->p_size) { 48556629Sralph sz = pp->p_size - bn; 48653202Sralph /* if exactly at end of disk, return an EOF */ 48756629Sralph if (sz == 0) { 48852130Smckusick bp->b_resid = bp->b_bcount; 48952130Smckusick goto done; 49052130Smckusick } 49153202Sralph /* if none of it fits, error */ 49256629Sralph if (sz < 0) { 49353202Sralph bp->b_error = EINVAL; 49453202Sralph goto bad; 49553202Sralph } 49653202Sralph /* otherwise, truncate */ 49756629Sralph bp->b_bcount = dbtob(sz); 49853202Sralph } 49953202Sralph /* check for write to write protected label */ 50053202Sralph if (bn + pp->p_offset <= LABELSECTOR && 50153202Sralph #if LABELSECTOR != 0 50253202Sralph bn + pp->p_offset + sz > LABELSECTOR && 50353202Sralph #endif 50453202Sralph !(bp->b_flags & B_READ) && !(sc->sc_flags & RZF_WLABEL)) { 50553202Sralph bp->b_error = EROFS; 50652130Smckusick goto bad; 50752130Smckusick } 50852130Smckusick /* 50952130Smckusick * Non-aligned or partial-block transfers handled specially. 51052130Smckusick */ 51152130Smckusick s = sc->sc_blksize - 1; 51252130Smckusick if ((dbtob(bn) & s) || (bp->b_bcount & s)) { 51352130Smckusick rzlblkstrat(bp, sc->sc_blksize); 51452130Smckusick goto done; 51552130Smckusick } 51653202Sralph bp->b_cylin = (bn + pp->p_offset) >> sc->sc_bshift; 51752130Smckusick } 51852130Smckusick /* don't let disksort() see sc_errbuf */ 51952130Smckusick while (sc->sc_flags & RZF_SENSEINPROGRESS) 52052130Smckusick printf("SENSE\n"); /* XXX */ 52152130Smckusick s = splbio(); 52252130Smckusick disksort(&sc->sc_tab, bp); 52352130Smckusick if (sc->sc_tab.b_active == 0) { 52452130Smckusick sc->sc_tab.b_active = 1; 52552130Smckusick rzstart(unit); 52652130Smckusick } 52752130Smckusick splx(s); 52852130Smckusick return; 52952130Smckusick bad: 53052130Smckusick bp->b_flags |= B_ERROR; 53152130Smckusick done: 53252130Smckusick biodone(bp); 53352130Smckusick } 53452130Smckusick 53552130Smckusick void 53652130Smckusick rzstart(unit) 53752130Smckusick int unit; 53852130Smckusick { 53952130Smckusick register struct rz_softc *sc = &rz_softc[unit]; 54052130Smckusick register struct buf *bp = sc->sc_tab.b_actf; 54152130Smckusick register int n; 54252130Smckusick 54352130Smckusick sc->sc_cmd.buf = bp->b_un.b_addr; 54452130Smckusick sc->sc_cmd.buflen = bp->b_bcount; 54552130Smckusick 546*68012Smckusick if (sc->sc_format_pid || 547*68012Smckusick (sc->sc_flags & (RZF_SENSEINPROGRESS | RZF_ALTCMD))) { 54852130Smckusick sc->sc_cmd.flags = !(bp->b_flags & B_READ) ? 54952130Smckusick SCSICMD_DATA_TO_DEVICE : 0; 55052130Smckusick sc->sc_cmd.cmd = sc->sc_cdb.cdb; 55152130Smckusick sc->sc_cmd.cmdlen = sc->sc_cdb.len; 55252130Smckusick } else { 55352130Smckusick if (bp->b_flags & B_READ) { 55452130Smckusick sc->sc_cmd.flags = 0; 55552130Smckusick sc->sc_rwcmd.command = SCSI_READ_EXT; 55652130Smckusick } else { 55752130Smckusick sc->sc_cmd.flags = SCSICMD_DATA_TO_DEVICE; 55852130Smckusick sc->sc_rwcmd.command = SCSI_WRITE_EXT; 55952130Smckusick } 56052130Smckusick sc->sc_cmd.cmd = (u_char *)&sc->sc_rwcmd; 56152130Smckusick sc->sc_cmd.cmdlen = sizeof(sc->sc_rwcmd); 56252130Smckusick n = bp->b_cylin; 56352130Smckusick sc->sc_rwcmd.highAddr = n >> 24; 56452130Smckusick sc->sc_rwcmd.midHighAddr = n >> 16; 56552130Smckusick sc->sc_rwcmd.midLowAddr = n >> 8; 56652130Smckusick sc->sc_rwcmd.lowAddr = n; 56752130Smckusick n = howmany(bp->b_bcount, sc->sc_blksize); 56852130Smckusick sc->sc_rwcmd.highBlockCount = n >> 8; 56952130Smckusick sc->sc_rwcmd.lowBlockCount = n; 57052130Smckusick #ifdef DEBUG 57152130Smckusick if ((bp->b_bcount & (sc->sc_blksize - 1)) != 0) 57252130Smckusick printf("rz%d: partial block xfer -- %x bytes\n", 57352130Smckusick unit, bp->b_bcount); 57452130Smckusick #endif 57552130Smckusick sc->sc_stats.rztransfers++; 57652130Smckusick if ((n = sc->sc_sd->sd_dk) >= 0) { 57752130Smckusick dk_busy |= 1 << n; 57852130Smckusick ++dk_seek[n]; 57952130Smckusick ++dk_xfer[n]; 58052130Smckusick dk_wds[n] += bp->b_bcount >> 6; 58152130Smckusick } 58252130Smckusick } 58352130Smckusick 58452130Smckusick /* tell controller to start this command */ 58552130Smckusick (*sc->sc_sd->sd_cdriver->d_start)(&sc->sc_cmd); 58652130Smckusick } 58752130Smckusick 58852130Smckusick /* 58952130Smckusick * This is called by the controller driver when the command is done. 59052130Smckusick */ 59152130Smckusick void 59252130Smckusick rzdone(unit, error, resid, status) 59352130Smckusick register int unit; 59452130Smckusick int error; /* error number from errno.h */ 59552130Smckusick int resid; /* amount not transfered */ 59652130Smckusick int status; /* SCSI status byte */ 59752130Smckusick { 59852130Smckusick register struct rz_softc *sc = &rz_softc[unit]; 59952130Smckusick register struct buf *bp = sc->sc_tab.b_actf; 60052130Smckusick register struct scsi_device *sd = sc->sc_sd; 60152130Smckusick 60252130Smckusick if (bp == NULL) { 60352130Smckusick printf("rz%d: bp == NULL\n", unit); 60452130Smckusick return; 60552130Smckusick } 60652130Smckusick if (sd->sd_dk >= 0) 60752130Smckusick dk_busy &= ~(1 << sd->sd_dk); 60852130Smckusick if (sc->sc_flags & RZF_SENSEINPROGRESS) { 60952130Smckusick sc->sc_flags &= ~RZF_SENSEINPROGRESS; 61056629Sralph sc->sc_tab.b_actf = bp = bp->b_actf; /* remove sc_errbuf */ 61152130Smckusick 61252130Smckusick if (error || (status & SCSI_STATUS_CHECKCOND)) { 61352130Smckusick #ifdef DEBUG 61452130Smckusick if (rzdebug & RZB_ERROR) 61552130Smckusick printf("rz%d: error reading sense data: error %d scsi status 0x%x\n", 61652130Smckusick unit, error, status); 61752130Smckusick #endif 61852130Smckusick /* 61952130Smckusick * We got an error during the REQUEST_SENSE, 62052130Smckusick * fill in no sense for data. 62152130Smckusick */ 62252130Smckusick sc->sc_sense.sense[0] = 0x70; 62352130Smckusick sc->sc_sense.sense[2] = SCSI_CLASS7_NO_SENSE; 624*68012Smckusick } else if (!(sc->sc_flags & RZF_NOERR)) { 62552130Smckusick printf("rz%d: ", unit); 62652130Smckusick scsiPrintSense((ScsiClass7Sense *)sc->sc_sense.sense, 62752130Smckusick sizeof(sc->sc_sense.sense) - resid); 62852130Smckusick } 62952130Smckusick } else if (error || (status & SCSI_STATUS_CHECKCOND)) { 63052130Smckusick #ifdef DEBUG 631*68012Smckusick if (!(sc->sc_flags & RZF_NOERR) && (rzdebug & RZB_ERROR)) 63252130Smckusick printf("rz%d: error %d scsi status 0x%x\n", 63352130Smckusick unit, error, status); 63452130Smckusick #endif 63552130Smckusick /* save error info */ 63652130Smckusick sc->sc_sense.status = status; 63752130Smckusick bp->b_flags |= B_ERROR; 63852130Smckusick bp->b_error = error; 63952130Smckusick bp->b_resid = resid; 64052130Smckusick 64152130Smckusick if (status & SCSI_STATUS_CHECKCOND) { 64252130Smckusick /* 64352130Smckusick * Start a REQUEST_SENSE command. 64452130Smckusick * Since we are called at interrupt time, we can't 64552130Smckusick * wait for the command to finish; that's why we use 64652130Smckusick * the sc_flags field. 64752130Smckusick */ 64852130Smckusick sc->sc_flags |= RZF_SENSEINPROGRESS; 64952130Smckusick sc->sc_cdb.len = sizeof(ScsiGroup0Cmd); 65052130Smckusick scsiGroup0Cmd(SCSI_REQUEST_SENSE, sd->sd_slave, 0, 65152130Smckusick sizeof(sc->sc_sense.sense), 65252130Smckusick (ScsiGroup0Cmd *)sc->sc_cdb.cdb); 65352130Smckusick sc->sc_errbuf.b_flags = B_BUSY | B_PHYS | B_READ; 65452130Smckusick sc->sc_errbuf.b_bcount = sizeof(sc->sc_sense.sense); 65552130Smckusick sc->sc_errbuf.b_un.b_addr = (caddr_t)sc->sc_sense.sense; 65656629Sralph sc->sc_errbuf.b_actf = bp; 65752130Smckusick sc->sc_tab.b_actf = &sc->sc_errbuf; 65852130Smckusick rzstart(unit); 65952130Smckusick return; 66052130Smckusick } 66152130Smckusick } else { 66252130Smckusick sc->sc_sense.status = status; 66352130Smckusick bp->b_resid = resid; 66452130Smckusick } 66552130Smckusick 66656629Sralph sc->sc_tab.b_actf = bp->b_actf; 66752130Smckusick biodone(bp); 66852130Smckusick if (sc->sc_tab.b_actf) 66952130Smckusick rzstart(unit); 67053202Sralph else { 67152130Smckusick sc->sc_tab.b_active = 0; 67253202Sralph /* finish close protocol */ 67353202Sralph if (sc->sc_openpart == 0) 67453202Sralph wakeup((caddr_t)&sc->sc_tab); 67553202Sralph } 67652130Smckusick } 67752130Smckusick 67864088Smckusick /* 67964088Smckusick * Read or constuct a disklabel 68064088Smckusick */ 68164088Smckusick void 68264088Smckusick rzgetinfo(dev) 68364088Smckusick dev_t dev; 68464088Smckusick { 68564088Smckusick register int unit = rzunit(dev); 68664088Smckusick register struct rz_softc *sc = &rz_softc[unit]; 68764088Smckusick register struct disklabel *lp = &sc->sc_label; 68864088Smckusick register int i; 68964088Smckusick char *msg; 69064088Smckusick int part; 69164088Smckusick extern char *readdisklabel(); 69264088Smckusick 69364088Smckusick part = rzpart(dev); 69464088Smckusick sc->sc_flags |= RZF_HAVELABEL; 69564088Smckusick 696*68012Smckusick if (sc->sc_type == SCSI_ROM_TYPE) { 697*68012Smckusick lp->d_type = DTYPE_SCSI; 698*68012Smckusick lp->d_secsize = sc->sc_blksize; 699*68012Smckusick lp->d_nsectors = 100; 700*68012Smckusick lp->d_ntracks = 1; 701*68012Smckusick lp->d_ncylinders = (sc->sc_blks / 100) + 1; 702*68012Smckusick lp->d_secpercyl = 100; 703*68012Smckusick lp->d_secperunit = sc->sc_blks; 704*68012Smckusick lp->d_rpm = 300; 705*68012Smckusick lp->d_interleave = 1; 706*68012Smckusick lp->d_flags = D_REMOVABLE; 707*68012Smckusick lp->d_npartitions = 1; 708*68012Smckusick lp->d_partitions[0].p_offset = 0; 709*68012Smckusick lp->d_partitions[0].p_size = sc->sc_blks; 710*68012Smckusick lp->d_partitions[0].p_fstype = FS_ISO9660; 711*68012Smckusick lp->d_magic = DISKMAGIC; 712*68012Smckusick lp->d_magic2 = DISKMAGIC; 713*68012Smckusick lp->d_checksum = dkcksum(lp); 714*68012Smckusick return; 715*68012Smckusick } 716*68012Smckusick 71764088Smckusick lp->d_type = DTYPE_SCSI; 71864088Smckusick lp->d_secsize = DEV_BSIZE; 71964088Smckusick lp->d_secpercyl = 1 << sc->sc_bshift; 72064088Smckusick lp->d_npartitions = MAXPARTITIONS; 72164088Smckusick lp->d_partitions[part].p_offset = 0; 72264088Smckusick lp->d_partitions[part].p_size = sc->sc_blks; 72364088Smckusick 72464088Smckusick /* 72564088Smckusick * Now try to read the disklabel 72664088Smckusick */ 72764088Smckusick msg = readdisklabel(dev, rzstrategy, lp); 72864088Smckusick if (msg == NULL) 72964088Smckusick return; 73064088Smckusick 73164088Smckusick printf("rz%d: WARNING: %s\n", unit, msg); 732*68012Smckusick lp->d_magic = DISKMAGIC; 733*68012Smckusick lp->d_magic2 = DISKMAGIC; 734*68012Smckusick lp->d_type = DTYPE_SCSI; 735*68012Smckusick lp->d_subtype = 0; 736*68012Smckusick lp->d_typename[0] = '\0'; 737*68012Smckusick lp->d_secsize = DEV_BSIZE; 738*68012Smckusick lp->d_secperunit = sc->sc_blks; 739*68012Smckusick lp->d_npartitions = MAXPARTITIONS; 740*68012Smckusick lp->d_bbsize = BBSIZE; 741*68012Smckusick lp->d_sbsize = SBSIZE; 74264088Smckusick for (i = 0; i < MAXPARTITIONS; i++) { 743*68012Smckusick lp->d_partitions[i].p_size = rzdefaultpart[i].nblocks; 744*68012Smckusick lp->d_partitions[i].p_offset = rzdefaultpart[i].strtblk; 74564088Smckusick } 746*68012Smckusick lp->d_partitions[RAWPART].p_size = sc->sc_blks; 74764088Smckusick } 74864088Smckusick 74952130Smckusick int 75052130Smckusick rzopen(dev, flags, mode, p) 75152130Smckusick dev_t dev; 75252130Smckusick int flags, mode; 75352130Smckusick struct proc *p; 75452130Smckusick { 75552130Smckusick register int unit = rzunit(dev); 75652130Smckusick register struct rz_softc *sc = &rz_softc[unit]; 75753202Sralph register struct disklabel *lp; 75853202Sralph register int i; 75953202Sralph int part; 76053202Sralph u_long mask; 76152130Smckusick 76253202Sralph if (unit >= NRZ || !(sc->sc_flags & RZF_ALIVE)) 76352130Smckusick return (ENXIO); 76453202Sralph 765*68012Smckusick /* make sure disk is ready */ 766*68012Smckusick if (sc->sc_flags & RZF_REMOVEABLE) { 767*68012Smckusick if (!rzready(sc)) 768*68012Smckusick return (ENXIO); 769*68012Smckusick } 770*68012Smckusick 77153202Sralph /* try to read disk label and partition table information */ 77253202Sralph part = rzpart(dev); 77364088Smckusick if (!(sc->sc_flags & RZF_HAVELABEL)) 77464088Smckusick rzgetinfo(dev); 77564088Smckusick 77653202Sralph lp = &sc->sc_label; 77753202Sralph if (part >= lp->d_npartitions || lp->d_partitions[part].p_size == 0) 77852130Smckusick return (ENXIO); 77953202Sralph /* 78053202Sralph * Warn if a partition is opened that overlaps another 78153202Sralph * already open, unless either is the `raw' partition 78253202Sralph * (whole disk). 78353202Sralph */ 78453202Sralph mask = 1 << part; 78553202Sralph if ((sc->sc_openpart & mask) == 0 && part != RAWPART) { 78653202Sralph register struct partition *pp; 78753202Sralph u_long start, end; 78852130Smckusick 78953202Sralph pp = &lp->d_partitions[part]; 79053202Sralph start = pp->p_offset; 79153202Sralph end = pp->p_offset + pp->p_size; 79253202Sralph for (pp = lp->d_partitions, i = 0; 79353202Sralph i < lp->d_npartitions; pp++, i++) { 79453202Sralph if (pp->p_offset + pp->p_size <= start || 79553202Sralph pp->p_offset >= end || i == RAWPART) 79653202Sralph continue; 79753202Sralph if (sc->sc_openpart & (1 << i)) 79853202Sralph log(LOG_WARNING, 79953202Sralph "rz%d%c: overlaps open partition (%c)\n", 80053202Sralph unit, part + 'a', i + 'a'); 80153202Sralph } 80253202Sralph } 80353202Sralph switch (mode) { 80453202Sralph case S_IFCHR: 80553202Sralph sc->sc_copenpart |= mask; 80653202Sralph break; 80753202Sralph case S_IFBLK: 80853202Sralph sc->sc_bopenpart |= mask; 80953202Sralph break; 81053202Sralph } 81153202Sralph sc->sc_openpart |= mask; 81252130Smckusick if (sc->sc_sd->sd_dk >= 0) 81352130Smckusick dk_wpms[sc->sc_sd->sd_dk] = sc->sc_wpms; 81452130Smckusick return (0); 81552130Smckusick } 81652130Smckusick 81753202Sralph rzclose(dev, flags, mode) 81852130Smckusick dev_t dev; 81953202Sralph int flags, mode; 82052130Smckusick { 82153202Sralph register struct rz_softc *sc = &rz_softc[rzunit(dev)]; 82253202Sralph u_long mask = (1 << rzpart(dev)); 82353202Sralph int s; 82453202Sralph 82553202Sralph switch (mode) { 82653202Sralph case S_IFCHR: 82753202Sralph sc->sc_copenpart &= ~mask; 82853202Sralph break; 82953202Sralph case S_IFBLK: 83053202Sralph sc->sc_bopenpart &= ~mask; 83153202Sralph break; 83253202Sralph } 83353202Sralph sc->sc_openpart = sc->sc_copenpart | sc->sc_bopenpart; 83453202Sralph 83553202Sralph /* 83653202Sralph * Should wait for I/O to complete on this partition even if 83753202Sralph * others are open, but wait for work on blkflush(). 83853202Sralph */ 83953202Sralph if (sc->sc_openpart == 0) { 84053202Sralph s = splbio(); 84153202Sralph while (sc->sc_tab.b_actf) 84253202Sralph sleep((caddr_t)&sc->sc_tab, PZERO - 1); 84353202Sralph splx(s); 84453202Sralph sc->sc_flags &= ~RZF_WLABEL; 84553202Sralph } 84652130Smckusick return (0); 84752130Smckusick } 84852130Smckusick 84952130Smckusick int 85052130Smckusick rzread(dev, uio) 85152130Smckusick dev_t dev; 85252130Smckusick struct uio *uio; 85352130Smckusick { 85452130Smckusick register struct rz_softc *sc = &rz_softc[rzunit(dev)]; 85552130Smckusick 85652130Smckusick if (sc->sc_format_pid && sc->sc_format_pid != curproc->p_pid) 85752130Smckusick return (EPERM); 85852130Smckusick 85952130Smckusick return (physio(rzstrategy, (struct buf *)0, dev, 86052130Smckusick B_READ, minphys, uio)); 86152130Smckusick } 86252130Smckusick 86352130Smckusick int 86452130Smckusick rzwrite(dev, uio) 86552130Smckusick dev_t dev; 86652130Smckusick struct uio *uio; 86752130Smckusick { 86852130Smckusick register struct rz_softc *sc = &rz_softc[rzunit(dev)]; 86952130Smckusick 870*68012Smckusick if (sc->sc_type == SCSI_ROM_TYPE) 871*68012Smckusick return (EROFS); 872*68012Smckusick 87352130Smckusick if (sc->sc_format_pid && sc->sc_format_pid != curproc->p_pid) 87452130Smckusick return (EPERM); 87552130Smckusick 87652130Smckusick return (physio(rzstrategy, (struct buf *)0, dev, 87752130Smckusick B_WRITE, minphys, uio)); 87852130Smckusick } 87952130Smckusick 88052130Smckusick int 88152130Smckusick rzioctl(dev, cmd, data, flag, p) 88252130Smckusick dev_t dev; 88352130Smckusick int cmd; 88452130Smckusick caddr_t data; 88552130Smckusick int flag; 88652130Smckusick struct proc *p; 88752130Smckusick { 88852130Smckusick register struct rz_softc *sc = &rz_softc[rzunit(dev)]; 88953202Sralph int error; 89053202Sralph int flags; 89152130Smckusick 89252130Smckusick switch (cmd) { 89352130Smckusick default: 89452130Smckusick return (EINVAL); 89552130Smckusick 89652130Smckusick case SDIOCSFORMAT: 89752130Smckusick /* take this device into or out of "format" mode */ 89852130Smckusick if (suser(p->p_ucred, &p->p_acflag)) 89952130Smckusick return (EPERM); 90052130Smckusick 90152130Smckusick if (*(int *)data) { 90252130Smckusick if (sc->sc_format_pid) 90352130Smckusick return (EPERM); 90452130Smckusick sc->sc_format_pid = p->p_pid; 90552130Smckusick } else 90652130Smckusick sc->sc_format_pid = 0; 90752130Smckusick return (0); 90852130Smckusick 90952130Smckusick case SDIOCGFORMAT: 91052130Smckusick /* find out who has the device in format mode */ 91152130Smckusick *(int *)data = sc->sc_format_pid; 91252130Smckusick return (0); 91352130Smckusick 91452130Smckusick case SDIOCSCSICOMMAND: 91552130Smckusick /* 91652130Smckusick * Save what user gave us as SCSI cdb to use with next 91752130Smckusick * read or write to the char device. 91852130Smckusick */ 91952130Smckusick if (sc->sc_format_pid != p->p_pid) 92052130Smckusick return (EPERM); 92152130Smckusick if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0) 92252130Smckusick return (EINVAL); 92352130Smckusick bcopy(data, (caddr_t)&sc->sc_cdb, sizeof(sc->sc_cdb)); 92452130Smckusick return (0); 92552130Smckusick 92652130Smckusick case SDIOCSENSE: 92752130Smckusick /* 92852130Smckusick * return the SCSI sense data saved after the last 92952130Smckusick * operation that completed with "check condition" status. 93052130Smckusick */ 93152130Smckusick bcopy((caddr_t)&sc->sc_sense, data, sizeof(sc->sc_sense)); 93252130Smckusick return (0); 93352130Smckusick 93453202Sralph case DIOCGDINFO: 93553202Sralph /* get the current disk label */ 93653202Sralph *(struct disklabel *)data = sc->sc_label; 93753202Sralph return (0); 93853202Sralph 93953202Sralph case DIOCSDINFO: 94053202Sralph /* set the current disk label */ 94153202Sralph if (!(flag & FWRITE)) 94253202Sralph return (EBADF); 94356629Sralph error = setdisklabel(&sc->sc_label, 94453202Sralph (struct disklabel *)data, 94556629Sralph (sc->sc_flags & RZF_WLABEL) ? 0 : sc->sc_openpart); 94656629Sralph return (error); 94753202Sralph 94853202Sralph case DIOCGPART: 94953202Sralph /* return the disk partition data */ 95053202Sralph ((struct partinfo *)data)->disklab = &sc->sc_label; 95153202Sralph ((struct partinfo *)data)->part = 95253202Sralph &sc->sc_label.d_partitions[rzpart(dev)]; 95353202Sralph return (0); 95453202Sralph 95553202Sralph case DIOCWLABEL: 95653202Sralph if (!(flag & FWRITE)) 95753202Sralph return (EBADF); 95853202Sralph if (*(int *)data) 95953202Sralph sc->sc_flags |= RZF_WLABEL; 96053202Sralph else 96153202Sralph sc->sc_flags &= ~RZF_WLABEL; 96253202Sralph return (0); 96353202Sralph 96453202Sralph case DIOCWDINFO: 96553202Sralph /* write the disk label to disk */ 96653202Sralph if (!(flag & FWRITE)) 96753202Sralph return (EBADF); 96853202Sralph error = setdisklabel(&sc->sc_label, 96953202Sralph (struct disklabel *)data, 97053202Sralph (sc->sc_flags & RZF_WLABEL) ? 0 : sc->sc_openpart); 97153202Sralph if (error) 97253202Sralph return (error); 97353202Sralph 97453202Sralph /* simulate opening partition 0 so write succeeds */ 97553202Sralph flags = sc->sc_flags; 97653202Sralph sc->sc_flags = RZF_ALIVE | RZF_WLABEL; 97753202Sralph error = writedisklabel(dev, rzstrategy, &sc->sc_label); 97853202Sralph sc->sc_flags = flags; 97953202Sralph return (error); 98052130Smckusick } 98152130Smckusick /*NOTREACHED*/ 98252130Smckusick } 98352130Smckusick 98452130Smckusick int 98552130Smckusick rzsize(dev) 98652130Smckusick dev_t dev; 98752130Smckusick { 98852130Smckusick register int unit = rzunit(dev); 98953202Sralph register int part = rzpart(dev); 99052130Smckusick register struct rz_softc *sc = &rz_softc[unit]; 99152130Smckusick 99264088Smckusick if (unit >= NRZ || !(sc->sc_flags & RZF_ALIVE)) 99352130Smckusick return (-1); 99452130Smckusick 99564088Smckusick /* 99664088Smckusick * We get called very early on (via swapconf) 99764088Smckusick * without the device being open so we need to 99864088Smckusick * read the disklabel here. 99964088Smckusick */ 100064088Smckusick if (!(sc->sc_flags & RZF_HAVELABEL)) 100164088Smckusick rzgetinfo(dev); 100264088Smckusick 100364088Smckusick if (part >= sc->sc_label.d_npartitions) 100464088Smckusick return (-1); 100553202Sralph return (sc->sc_label.d_partitions[part].p_size); 100652130Smckusick } 100752130Smckusick 100852130Smckusick /* 100952130Smckusick * Non-interrupt driven, non-dma dump routine. 101052130Smckusick */ 101152130Smckusick int 101252130Smckusick rzdump(dev) 101352130Smckusick dev_t dev; 101452130Smckusick { 101552130Smckusick #ifdef notdef 101652130Smckusick int part = rzpart(dev); 101752130Smckusick int unit = rzunit(dev); 101852130Smckusick register struct rz_softc *sc = &rz_softc[unit]; 101952130Smckusick register struct scsi_device *sd = sc->sc_hd; 102052130Smckusick register daddr_t baddr; 102152130Smckusick register int maddr; 102252130Smckusick register int pages, i; 102352130Smckusick int stat; 102452130Smckusick extern int lowram; 102552130Smckusick 102652130Smckusick /* 102752130Smckusick * Hmm... all vax drivers dump maxfree pages which is physmem minus 102852130Smckusick * the message buffer. Is there a reason for not dumping the 102952130Smckusick * message buffer? Savecore expects to read 'dumpsize' pages of 103052130Smckusick * dump, where dumpsys() sets dumpsize to physmem! 103152130Smckusick */ 103252130Smckusick pages = physmem; 103352130Smckusick 103452130Smckusick /* is drive ok? */ 103552130Smckusick if (unit >= NRZ || (sc->sc_flags & RZF_ALIVE) == 0) 103652130Smckusick return (ENXIO); 103752130Smckusick /* dump parameters in range? */ 103852130Smckusick if (dumplo < 0 || dumplo >= sc->sc_info.part[part].nblocks) 103952130Smckusick return (EINVAL); 104052130Smckusick if (dumplo + ctod(pages) > sc->sc_info.part[part].nblocks) 104152130Smckusick pages = dtoc(sc->sc_info.part[part].nblocks - dumplo); 104252130Smckusick maddr = lowram; 104352130Smckusick baddr = dumplo + sc->sc_info.part[part].strtblk; 104452130Smckusick /* scsi bus idle? */ 104552130Smckusick if (!scsireq(&sc->sc_dq)) { 104652130Smckusick scsireset(sd->sd_ctlr); 104752130Smckusick sc->sc_stats.rzresets++; 104852130Smckusick printf("[ drive %d reset ] ", unit); 104952130Smckusick } 105052130Smckusick for (i = 0; i < pages; i++) { 105152130Smckusick #define NPGMB (1024*1024/NBPG) 105252130Smckusick /* print out how many Mbs we have dumped */ 105352130Smckusick if (i && (i % NPGMB) == 0) 105452130Smckusick printf("%d ", i / NPGMB); 105552130Smckusick #undef NPBMG 105652130Smckusick mapin(mmap, (u_int)vmmap, btop(maddr), PG_URKR|PG_CI|PG_V); 105752130Smckusick stat = scsi_tt_write(sd->sd_ctlr, sd->sd_drive, sd->sd_slave, 105852130Smckusick vmmap, NBPG, baddr, sc->sc_bshift); 105952130Smckusick if (stat) { 106052130Smckusick printf("rzdump: scsi write error 0x%x\n", stat); 106152130Smckusick return (EIO); 106252130Smckusick } 106352130Smckusick maddr += NBPG; 106452130Smckusick baddr += ctod(1); 106552130Smckusick } 106652130Smckusick return (0); 106759823Sralph #else /* notdef */ 106852130Smckusick return (ENXIO); 106959823Sralph #endif /* notdef */ 107052130Smckusick } 107152130Smckusick #endif 1072