summaryrefslogtreecommitdiffstats
path: root/sys/scsi/od.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/scsi/od.c')
-rw-r--r--sys/scsi/od.c966
1 files changed, 0 insertions, 966 deletions
diff --git a/sys/scsi/od.c b/sys/scsi/od.c
deleted file mode 100644
index 5943b50..0000000
--- a/sys/scsi/od.c
+++ /dev/null
@@ -1,966 +0,0 @@
-/*
- * Copyright (c) 1995,1996 Shunsuke Akiyama. All rights reserved.
- *
- * 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 Shunsuke Akiyama.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Shunsuke Akiyama 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 Shunsuke Akiyama 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.
- *
- * $Id: od.c,v 1.45 1998/07/30 15:16:05 bde Exp $
- */
-
-/*
- * Compile option defines:
- */
-
-/*
- * If drive returns sense key as 0x02 with vendor specific additional
- * sense code (ASC) and additional sense code qualifier (ASCQ), or
- * illegal ASC and ASCQ. This cause an error (NOT READY) and retrying.
- * To suppress this, uncomment following.
- * Or put "options OD_BOGUS_NOT_READY" entry into your kernel
- * configuration file.
- *
-#define OD_BOGUS_NOT_READY
- */
-
-/*
- * For an automatic spindown, try this. Again, preferrably as an
- * option in your config file.
- * WARNING! Use at your own risk. Joerg's ancient SONY SMO drive
- * groks it fine, while Shunsuke's Fujitsu chokes on it and times
- * out.
-#define OD_AUTO_TURNOFF
- */
-
-#include "opt_bounce.h"
-#include "opt_devfs.h"
-#include "opt_scsi.h"
-#include "opt_od.h"
-
-#define SPLOD splbio
-#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/dkbad.h>
-#include <sys/systm.h>
-#include <sys/conf.h>
-#include <sys/buf.h>
-#include <sys/cdio.h>
-#include <sys/dkstat.h>
-#include <sys/disklabel.h>
-#include <sys/diskslice.h>
-#ifdef DEVFS
-#include <sys/devfsext.h>
-#endif /*DEVFS*/
-#include <scsi/scsi_disk.h>
-#include <scsi/scsiconf.h>
-#include <scsi/scsi_debug.h>
-#include <scsi/scsi_driver.h>
-
-#include "ioconf.h"
-
-static u_int32_t odstrats, odqueues;
-
-#define SECSIZE 512 /* default sector size */
-#define ODOUTSTANDING 4
-#define OD_RETRIES 4
-
-#define PARTITION(dev) dkpart(dev)
-#define ODUNIT(dev) dkunit(dev)
-
-/* XXX introduce a dkmodunit() macro for this. */
-#define ODSETUNIT(DEV, U) \
- makedev(major(DEV), dkmakeminor((U), dkslice(DEV), dkpart(DEV)))
-
-struct scsi_data {
- u_int32_t flags;
-#define ODINIT 0x04 /* device has been init'd */
- struct disk_parms {
- u_char heads; /* Number of heads */
- u_int16_t cyls; /* Number of cylinders (fictitious) */
- u_int16_t sectors; /* Number of sectors/track */
- u_int16_t secsiz; /* Number of bytes/sector */
- u_int32_t disksize; /* total number sectors */
- u_int16_t rpm; /* medium rotation rate */
- } params;
- struct diskslices *dk_slices; /* virtual drives */
- struct buf_queue_head buf_queue;
- int dkunit; /* disk stats unit number */
-#ifdef DEVFS
- /* Eventually move all these to common disk struct. */
- void *b_devfs_token;
- void *c_devfs_token;
- void *ctl_devfs_token;
-#endif
-};
-
-static errval od_get_parms __P((int unit, int flags));
-#ifdef notyet
-static errval od_reassign_blocks __P((int unit, int block));
-#endif
-static u_int32_t od_size __P((int unit, int flags));
-static int od_sense_handler __P((struct scsi_xfer *));
-static void odstart __P((u_int32_t, u_int32_t));
-static void odstrategy1 __P((struct buf *));
-
-static dev_t odsetunit(dev_t dev, int unit) { return ODSETUNIT(dev, unit); }
-static int odunit(dev_t dev) { return ODUNIT(dev); }
-
-static errval od_open __P((dev_t dev, int mode, int fmt, struct proc *p,
- struct scsi_link *sc_link));
-static errval od_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag,
- struct proc *p, struct scsi_link *sc_link);
-static errval od_close __P((dev_t dev, int fflag, int fmt, struct proc *p,
- struct scsi_link *sc_link));
-static void od_strategy(struct buf *bp, struct scsi_link *sc_link);
-
-static d_open_t odopen;
-static d_read_t odread;
-static d_write_t odwrite;
-static d_close_t odclose;
-static d_ioctl_t odioctl;
-static d_strategy_t odstrategy;
-
-#define CDEV_MAJOR 70
-#define BDEV_MAJOR 20
-static struct cdevsw od_cdevsw = {
- odopen, odclose, odread, odwrite,
- odioctl, nostop, nullreset, nodevtotty,
- seltrue, nommap, odstrategy, "od",
- NULL, -1, nodump, nopsize,
- D_DISK, 0, -1 };
-
-/*
- * Actually include the interface routines
- */
-SCSI_DEVICE_ENTRIES(od)
-
-static struct scsi_device od_switch =
-{
- od_sense_handler,
- odstart, /* have a queue, served by this */
- NULL, /* have no async handler */
- NULL, /* Use default 'done' routine */
- "od",
- 0,
- {0, 0},
- 0, /* Link flags */
- odattach,
- "Optical",
- odopen,
- sizeof(struct scsi_data),
- T_OPTICAL,
- odunit,
- odsetunit,
- od_open,
- od_ioctl,
- od_close,
- od_strategy,
-};
-
-static __inline void
-od_registerdev(int unit)
-{
- if(dk_ndrive < DK_NDRIVE) {
- sprintf(dk_names[dk_ndrive], "od%d", unit);
- dk_wpms[dk_ndrive] = (4*1024*1024/2); /* 4MB/sec */
- SCSI_DATA(&od_switch, unit)->dkunit = dk_ndrive++;
- } else {
- SCSI_DATA(&od_switch, unit)->dkunit = -1;
- }
-}
-
-
-/*
- * The routine called by the low level scsi routine when it discovers
- * a device suitable for this driver.
- */
-static errval
-odattach(struct scsi_link *sc_link)
-{
- u_int32_t unit;
- struct disk_parms *dp;
-#ifdef DEVFS
- int mynor;
-#endif
-
- struct scsi_data *od = sc_link->sd;
-
- unit = sc_link->dev_unit;
-
- dp = &(od->params);
-
- if (sc_link->opennings > ODOUTSTANDING)
- sc_link->opennings = ODOUTSTANDING;
-
- bufq_init(&od->buf_queue);
- /*
- * Use the subdriver to request information regarding
- * the drive. We cannot use interrupts yet, so the
- * request must specify this.
- */
- scsi_start_unit(sc_link, SCSI_NOSLEEP | SCSI_NOMASK
- | SCSI_ERR_OK | SCSI_SILENT);
- od_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT);
- /*
- * if we don't have actual parameters, assume 512 bytes/sec
- * (could happen on removable media - MOD)
- * -- this avoids the division below from falling over
- */
- if(dp->secsiz == 0) dp->secsiz = SECSIZE;
- if (dp->disksize != 0) {
- printf("%luMB (%lu %u byte sectors)",
- (u_long)(dp->disksize / ((1024L * 1024L) / dp->secsiz)),
- (u_long)dp->disksize, dp->secsiz);
- } else {
- printf("od not present");
- }
-
-#ifndef SCSI_REPORT_GEOMETRY
- if ( (sc_link->flags & SDEV_BOOTVERBOSE) )
-#endif
- {
- sc_print_addr(sc_link);
- printf("with approximate %d cyls, %d heads, and %d sectors/track",
- dp->cyls, dp->heads, dp->sectors);
- }
-#ifdef OD_AUTO_TURNOFF
- scsi_stop_unit(sc_link, 0, SCSI_ERR_OK | SCSI_SILENT);
-#endif /* OD_AUTO_TURNOFF */
-
- od->flags |= ODINIT;
- od_registerdev(unit);
-
-#ifdef DEVFS
- mynor = dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART);
- od->b_devfs_token = devfs_add_devswf(&od_cdevsw, mynor, DV_BLK,
- UID_ROOT, GID_OPERATOR, 0640,
- "od%d", unit);
- od->c_devfs_token = devfs_add_devswf(&od_cdevsw, mynor, DV_CHR,
- UID_ROOT, GID_OPERATOR, 0640,
- "rod%d", unit);
- mynor = dkmakeminor(unit, 0, 0); /* XXX */
- od->ctl_devfs_token = devfs_add_devswf(&od_cdevsw,
- mynor | SCSI_CONTROL_MASK,
- DV_CHR,
- UID_ROOT, GID_WHEEL, 0600,
- "rod%d.ctl", unit);
-#endif
-
- return 0;
-}
-
-/*
- * open the device. Make sure the partition info is a up-to-date as can be.
- */
-static errval
-od_open(dev, mode, fmt, p, sc_link)
- dev_t dev;
- int mode;
- int fmt;
- struct proc *p;
- struct scsi_link *sc_link;
-{
- errval errcode = 0;
- u_int32_t unit;
- struct disklabel label;
- struct scsi_data *od;
-
- unit = ODUNIT(dev);
- od = sc_link->sd;
-
- /*
- * Make sure the disk has been initialized
- * At some point in the future, get the scsi driver
- * to look for a new device if we are not initted
- */
- if ((!od) || (!(od->flags & ODINIT))) {
- return ENXIO;
- }
-
- SC_DEBUG(sc_link, SDEV_DB1,
- ("od_open: dev=0x%lx (unit %lu, partition %d)\n",
- (u_long)dev, (u_long)unit, PARTITION(dev)));
-
- /*
- * Try to start the drive, and try to clear "Unit Attention"
- * condition, when media had been changed before.
- * This operation also clears the SDEV_MEDIA_LOADED flag in its
- * error handling routine.
- */
- scsi_start_unit(sc_link, SCSI_SILENT);
- scsi_prevent(sc_link, PR_PREVENT, SCSI_ERR_OK | SCSI_SILENT);
-
- /*
- * Make sure the drive is ready.
- */
- scsi_test_unit_ready(sc_link, 0);
-
- SC_DEBUG(sc_link, SDEV_DB3, ("'start' attempted "));
-
- sc_link->flags |= SDEV_OPEN; /* unit attn becomes an err now */
- /*
- * If it's been invalidated, then forget the label.
- */
- if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
- /*
- * If somebody still has it open, then forbid re-entry.
- */
- if (dsisopen(od->dk_slices)) {
- errcode = ENXIO;
- goto bad;
- }
-
- if (od->dk_slices != NULL)
- dsgone(&od->dk_slices);
- }
-
- /*
- * This time actually take notice of error returns
- */
- if (scsi_test_unit_ready(sc_link, SCSI_SILENT) != 0) {
- SC_DEBUG(sc_link, SDEV_DB3, ("not ready\n"));
- errcode = ENXIO;
- goto bad;
- }
- SC_DEBUG(sc_link, SDEV_DB3, ("device present\n"));
-
- /*
- * Load the physical device parameters
- */
- errcode = od_get_parms(unit, 0); /* sets SDEV_MEDIA_LOADED */
- if (errcode) {
- goto bad;
- }
- switch (od->params.secsiz) {
- case SECSIZE :
- case 1024 :
- case 2048 :
- break;
- default :
- printf("od%lu: Can't deal with %u bytes logical blocks\n",
- (u_long)unit, od->params.secsiz);
- Debugger("od");
- errcode = ENXIO;
- goto bad;
- }
- SC_DEBUG(sc_link, SDEV_DB3, ("params loaded "));
-
- /* Build label for whole disk. */
- bzero(&label, sizeof label);
- label.d_type = DTYPE_SCSI;
- label.d_secsize = od->params.secsiz;
- label.d_nsectors = od->params.sectors;
- label.d_ntracks = od->params.heads;
- label.d_ncylinders = od->params.cyls;
- label.d_secpercyl = od->params.heads * od->params.sectors;
- label.d_rpm = od->params.rpm; /* maybe wrong */
- if (label.d_secpercyl == 0)
- label.d_secpercyl = 64*32;
- /* XXX as long as it's not 0
- * - readdisklabel divides by it (?)
- */
- label.d_secperunit = od->params.disksize;
-
- /* Initialize slice tables. */
- errcode = dsopen("od", dev, fmt, 0, &od->dk_slices, &label, odstrategy1,
- (ds_setgeom_t *)NULL, &od_cdevsw);
- if (errcode != 0)
- goto bad;
- SC_DEBUG(sc_link, SDEV_DB3, ("Slice tables initialized "));
-
- SC_DEBUG(sc_link, SDEV_DB3, ("open %lu %lu\n",
- (u_long)odstrats, (u_long)odqueues));
-
- return 0;
-
-bad:
- if (!dsisopen(od->dk_slices)) {
- scsi_prevent(sc_link, PR_ALLOW, SCSI_ERR_OK | SCSI_SILENT);
-#ifdef OD_AUTO_TURNOFF
- scsi_stop_unit(sc_link, 0, SCSI_ERR_OK | SCSI_SILENT);
-#endif /* OD_AUTO_TURNOFF */
- sc_link->flags &= ~SDEV_OPEN;
- }
- return errcode;
-}
-
-/*
- * close the device.. only called if we are the LAST occurence of an open
- * device. Convenient now but usually a pain.
- */
-static errval
-od_close(dev, fflag, fmt, p, sc_link)
- dev_t dev;
- int fflag;
- int fmt;
- struct proc *p;
- struct scsi_link *sc_link;
-{
- struct scsi_data *od;
-
- od = sc_link->sd;
- dsclose(dev, fmt, od->dk_slices);
- if (!dsisopen(od->dk_slices)) {
- scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT | SCSI_ERR_OK);
-#ifdef OD_AUTO_TURNOFF
- scsi_stop_unit(sc_link, 0, SCSI_ERR_OK | SCSI_SILENT);
-#endif /* OD_AUTO_TURNOFF */
- sc_link->flags &= ~SDEV_OPEN;
- }
- return 0;
-}
-
-static int
-odread(dev_t dev, struct uio *uio, int ioflag)
-{
- return (physio(odstrategy, NULL, dev, 1, minphys, uio));
-}
-
-static int
-odwrite(dev_t dev, struct uio *uio, int ioflag)
-{
- return (physio(odstrategy, NULL, dev, 0, minphys, uio));
-}
-
-/*
- * Actually translate the requested transfer into one the physical driver
- * can understand. The transfer is described by a buf and will include
- * only one physical transfer.
- */
-static void
-od_strategy(struct buf *bp, struct scsi_link *sc_link)
-{
- u_int32_t opri;
- struct scsi_data *od;
- u_int32_t unit;
-
- odstrats++;
- unit = ODUNIT((bp->b_dev));
- od = sc_link->sd;
-
- /*
- * If the device has been made invalid, error out
- */
- if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
- bp->b_error = EIO;
- goto bad;
- }
-
- /*
- * Do bounds checking, adjust transfer, and set b_pblkno.
- */
- if (dscheck(bp, od->dk_slices) <= 0)
- goto done; /* XXX check b_resid */
-
- opri = SPLOD();
-
- /*
- * Use a bounce buffer if necessary
- */
-#ifdef BOUNCE_BUFFERS
- if (sc_link->flags & SDEV_BOUNCE)
- vm_bounce_alloc(bp);
-#endif
-
- /*
- * Place it in the queue of disk activities for this disk
- */
- bufq_insert_tail(&od->buf_queue, bp);
-
- /*
- * Tell the device to get going on the transfer if it's
- * not doing anything, otherwise just wait for completion
- */
- odstart(unit, 0);
-
- splx(opri);
- return /*0*/;
-bad:
- bp->b_flags |= B_ERROR;
-done:
-
- /*
- * Correctly set the buf to indicate a completed xfer
- */
- bp->b_resid = bp->b_bcount;
- biodone(bp);
- return /*0*/;
-}
-
-static void
-odstrategy1(struct buf *bp)
-{
- /*
- * XXX - do something to make odstrategy() but not this block while
- * we're doing dsinit() and dsioctl().
- */
- odstrategy(bp);
-}
-
-/*
- * odstart looks to see if there is a buf waiting for the device
- * and that the device is not already busy. If both are true,
- * It dequeues the buf and creates a scsi command to perform the
- * transfer in the buf. The transfer request will call scsi_done
- * on completion, which will in turn call this routine again
- * so that the next queued transfer is performed.
- * The bufs are queued by the strategy routine (odstrategy)
- *
- * This routine is also called after other non-queued requests
- * have been made of the scsi driver, to ensure that the queue
- * continues to be drained.
- *
- * must be called at the correct (highish) spl level
- * odstart() is called at SPLOD from odstrategy and scsi_done
- */
-static void
-odstart(u_int32_t unit, u_int32_t flags)
-{
- register struct scsi_link *sc_link = SCSI_LINK(&od_switch, unit);
- register struct scsi_data *od = sc_link->sd;
- struct buf *bp = 0;
- struct scsi_rw_big cmd;
- u_int32_t blkno, nblk;
- u_int32_t secsize;
-
- SC_DEBUG(sc_link, SDEV_DB2, ("odstart "));
- /*
- * Check if the device has room for another command
- */
- while (sc_link->opennings) {
-
- /*
- * there is excess capacity, but a special waits
- * It'll need the adapter as soon as we clear out of the
- * way and let it run (user level wait).
- */
- if (sc_link->flags & SDEV_WAITING) {
- return;
- }
- /*
- * See if there is a buf with work for us to do..
- */
- bp = bufq_first(&od->buf_queue);
- if (bp == NULL) { /* yes, an assign */
- return;
- }
- bufq_remove(&od->buf_queue, bp);
-
- /*
- * If the device has become invalid, abort all the
- * reads and writes until all files have been closed and
- * re-openned
- */
- if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
- goto bad;
- }
- /*
- * We have a buf, now we know we are going to go through
- * With this thing..
- */
- secsize = od->params.secsiz;
- blkno = bp->b_pblkno;
- if (bp->b_bcount & (secsize - 1))
- {
- goto bad;
- }
- nblk = bp->b_bcount / secsize;
-
- /*
- * Fill out the scsi command
- */
- cmd.op_code = (bp->b_flags & B_READ)
- ? READ_BIG : WRITE_BIG;
- scsi_uto4b(blkno, &cmd.addr_3);
- scsi_uto2b(nblk, &cmd.length2);
- cmd.byte2 = cmd.reserved = cmd.control = 0;
- /*
- * Call the routine that chats with the adapter.
- * Note: we cannot sleep as we may be an interrupt
- */
- if (scsi_scsi_cmd(sc_link,
- (struct scsi_generic *) &cmd,
- sizeof(cmd),
- (u_char *) bp->b_data,
- bp->b_bcount,
- OD_RETRIES,
- 100000,
- bp,
- flags | ((bp->b_flags & B_READ) ?
- SCSI_DATA_IN : SCSI_DATA_OUT))
- == SUCCESSFULLY_QUEUED) {
- odqueues++;
- if(od->dkunit >= 0) {
- dk_xfer[od->dkunit]++;
- dk_seek[od->dkunit]++; /* don't know */
- dk_wds[od->dkunit] += bp->b_bcount >> 6;
- }
- } else {
-bad:
- printf("od%lu: oops not queued\n", (u_long)unit);
- bp->b_error = EIO;
- bp->b_flags |= B_ERROR;
- biodone(bp);
- }
- }
-}
-
-/*
- * Perform special action on behalf of the user
- * Knows about the internals of this device
- */
-static errval
-od_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p,
- struct scsi_link *sc_link)
-{
- /* struct od_cmd_buf *args; */
- errval error;
- struct scsi_data *od;
-
- /*
- * Find the device that the user is talking about
- */
- od = sc_link->sd;
- SC_DEBUG(sc_link, SDEV_DB1, ("odioctl (0x%lx)", cmd));
-
- /*
- * If the device is not valid.. abandon ship
- */
- if (!(sc_link->flags & SDEV_MEDIA_LOADED))
- return EIO;
-
- switch (cmd) {
- case DIOCSBAD:
- error = EINVAL;
- break;
- case CDIOCEJECT:
- error = scsi_stop_unit(sc_link, 1, 0);
- sc_link->flags &= ~SDEV_MEDIA_LOADED;
- break;
- case CDIOCALLOW:
- error = scsi_prevent(sc_link, PR_ALLOW, 0);
- break;
- case CDIOCPREVENT:
- error = scsi_prevent(sc_link, PR_PREVENT, 0);
- break;
- default:
- error = dsioctl("od", dev, cmd, addr, flag, &od->dk_slices,
- odstrategy1, (ds_setgeom_t *)NULL);
- if (error == ENOIOCTL) {
- if (PARTITION(dev) != RAW_PART) {
- error = ENOTTY;
- } else {
- error = scsi_do_ioctl(dev, cmd, addr,
- flag, p, sc_link);
- }
- }
- break;
- }
- return error;
-}
-
-/*
- * Find out from the device what its capacity is
- */
-static u_int32_t
-od_size(unit, flags)
- int unit, flags;
-{
- struct scsi_read_cap_data rdcap;
- struct scsi_read_capacity rdcap_cmd;
- struct scsi_link *sc_link = SCSI_LINK(&od_switch, unit);
- struct scsi_data *od = sc_link->sd;
- struct scsi_mode_sense mdsense_cmd;
- struct scsi_mode_sense_data {
- struct scsi_mode_header header;
- struct blk_desc blk_desc;
- union disk_pages pages;
- } scsi_sense;
-
- /*
- * make up a scsi command and ask the scsi driver to do
- * it for you.
- */
- bzero(&rdcap_cmd, sizeof(rdcap_cmd));
- rdcap_cmd.op_code = READ_CAPACITY;
-
- /*
- * If the command works, interpret the result as a 4 byte
- * number of blocks
- */
- if (scsi_scsi_cmd(sc_link,
- (struct scsi_generic *) &rdcap_cmd,
- sizeof(rdcap_cmd),
- (u_char *) & rdcap,
- sizeof(rdcap),
- OD_RETRIES,
- 10000,
- NULL,
- flags | SCSI_DATA_IN) != 0) {
- return 0;
- } else {
- od->params.disksize = scsi_4btou(&rdcap.addr_3) + 1;
- od->params.secsiz = scsi_4btou(&rdcap.length_3);
- }
-
- /*
- * do a "mode sense page 4" (rigid disk drive geometry)
- */
- bzero(&mdsense_cmd, sizeof(mdsense_cmd));
- mdsense_cmd.op_code = MODE_SENSE;
- mdsense_cmd.page = 4;
- mdsense_cmd.length = 0x20;
- /*
- * If the command worked, use the results to fill out
- * the parameter structure
- */
- if (scsi_scsi_cmd(sc_link,
- (struct scsi_generic *) &mdsense_cmd,
- sizeof(mdsense_cmd),
- (u_char *) & scsi_sense,
- sizeof(scsi_sense),
- OD_RETRIES,
- 10000,
- NULL,
- flags | SCSI_SILENT | SCSI_DATA_IN) != 0) {
-
- /* default to a fictitious geometry */
- od->params.heads = 64;
- } else {
- SC_DEBUG(sc_link, SDEV_DB3,
- ("%lu cyls, %d heads, %lu rpm\n",
- (u_long)scsi_3btou(&scsi_sense.pages.rigid_geometry.ncyl_2),
- scsi_sense.pages.rigid_geometry.nheads,
- (u_long)scsi_2btou(
- &scsi_sense.pages.rigid_geometry.medium_rot_rate_1)));
-
- od->params.heads = scsi_sense.pages.rigid_geometry.nheads;
- if (od->params.heads == 0)
- od->params.heads = 64; /* fictitious */
- od->params.rpm =
- scsi_2btou(&scsi_sense.pages.rigid_geometry.medium_rot_rate_1);
- }
-
- /*
- * do a "mode sense page 3" (format device)
- */
- bzero(&mdsense_cmd, sizeof(mdsense_cmd));
- mdsense_cmd.op_code = MODE_SENSE;
- mdsense_cmd.page = 3;
- mdsense_cmd.length = 0x20;
- /*
- * If the command worked, use the results to fill out
- * the parameter structure
- */
- if (scsi_scsi_cmd(sc_link,
- (struct scsi_generic *) &mdsense_cmd,
- sizeof(mdsense_cmd),
- (u_char *) & scsi_sense,
- sizeof(scsi_sense),
- OD_RETRIES,
- 10000,
- NULL,
- flags | SCSI_SILENT | SCSI_DATA_IN) != 0) {
-
- /* default to a fictitious geometry */
- od->params.sectors = 32;
- } else {
- SC_DEBUG(sc_link, SDEV_DB3,
- ("%d secs\n",
- scsi_2btou(&scsi_sense.pages.disk_format.ph_sec_t_1)));
-
- od->params.sectors =
- scsi_2btou(&scsi_sense.pages.disk_format.ph_sec_t_1);
- if (od->params.sectors == 0)
- od->params.sectors = 32; /* fictitious */
- }
-
- return od->params.disksize;
-}
-
-#ifdef notyet
-/*
- * Tell the device to map out a defective block
- */
-static errval
-od_reassign_blocks(unit, block)
- int unit, block;
-{
- struct scsi_reassign_blocks scsi_cmd;
- struct scsi_reassign_blocks_data rbdata;
- struct scsi_link *sc_link = SCSI_LINK(&od_switch, unit);
-
- bzero(&scsi_cmd, sizeof(scsi_cmd));
- bzero(&rbdata, sizeof(rbdata));
- scsi_cmd.op_code = REASSIGN_BLOCKS;
-
- rbdata.length_msb = 0;
- rbdata.length_lsb = sizeof(rbdata.defect_descriptor[0]);
- scsi_uto4b(block, &rbdata.defect_descriptor[0].dlbaddr_3);
-
- return scsi_scsi_cmd(sc_link,
- (struct scsi_generic *) &scsi_cmd,
- sizeof(scsi_cmd),
- (u_char *) & rbdata,
- sizeof(rbdata),
- OD_RETRIES,
- 20000,
- NULL,
- SCSI_DATA_OUT);
-}
-#endif
-
-/*
- * Get the scsi driver to send a full inquiry to the
- * device and use the results to fill out the disk
- * parameter structure.
- */
-static errval
-od_get_parms(unit, flags)
- int unit, flags;
-{
- struct scsi_link *sc_link = SCSI_LINK(&od_switch, unit);
- struct scsi_data *od = sc_link->sd;
- struct disk_parms *disk_parms = &od->params;
- u_int32_t sectors;
- errval retval;
-
- /*
- * First check if we have it all loaded
- */
- if (sc_link->flags & SDEV_MEDIA_LOADED)
- return 0;
-
- /*
- * Use fictitious geometry, this depends on the size of medium.
- */
- sectors = od_size(unit, flags);
- /* od_size() sets secsiz, disksize, sectors, and heads */
-
- /* fictitious number of cylinders, so that C*H*S <= total */
- if (disk_parms->sectors != 0 && disk_parms->heads != 0) {
- disk_parms->cyls =
- sectors / (disk_parms->sectors * disk_parms->heads);
- } else {
- disk_parms->cyls = 0;
- }
-
- if (sectors != 0) {
- sc_link->flags |= SDEV_MEDIA_LOADED;
- retval = 0;
- } else {
- retval = ENXIO;
- }
- return retval;
-}
-
-/*
- * sense handler: Called to determine what to do when the
- * device returns a CHECK CONDITION.
- */
-
-static int
-od_sense_handler(struct scsi_xfer *xs)
-{
- struct scsi_sense_data *sense;
- struct scsi_sense_extended *ext;
- int asc, ascq;
-
- sense = &(xs->sense);
- ext = (struct scsi_sense_extended *)&(sense->ext.extended);
-
- /* I don't know what the heck to do with a deferred error,
- * so I'll just kick it back to the caller.
- */
- if ((sense->error_code & SSD_ERRCODE) == 0x71)
- return SCSIRET_CONTINUE;
-
-#ifdef OD_BOGUS_NOT_READY
- if (((sense->error_code & SSD_ERRCODE) == 0x70) &&
- ((sense->ext.extended.flags & SSD_KEY) == 0x02))
- /* No point in retrying Not Ready */
- return SCSIRET_CONTINUE;
-#endif
-
- if (((sense->error_code & SSD_ERRCODE) == 0x70) &&
- ((sense->ext.extended.flags & SSD_KEY) == 0x04))
- /* No point in retrying Hardware Failure */
- return SCSIRET_CONTINUE;
-
- if (((sense->error_code & SSD_ERRCODE) == 0x70) &&
- ((sense->ext.extended.flags & SSD_KEY) == 0x05))
- /* No point in retrying Illegal Requests */
- return SCSIRET_CONTINUE;
-
- asc = (ext->extra_len >= 5) ? ext->add_sense_code : 0;
- ascq = (ext->extra_len >= 6) ? ext->add_sense_code_qual : 0;
-
- if (asc == 0x11 || asc == 0x30 || asc == 0x31 || asc == 0x53
- || asc == 0x5a) {
- /* Unrecovered errors */
- return SCSIRET_CONTINUE;
- }
- if (asc == 0x21 && ascq == 0) {
- /* Logical block address out of range */
- return SCSIRET_CONTINUE;
- }
- if (asc == 0x27 && ascq == 0) {
- /* Write protected */
- return SCSIRET_CONTINUE;
- }
- if (asc == 0x28 && ascq == 0) {
- /* Not ready to ready transition */
- /* (medium may have changed) */
- return SCSIRET_CONTINUE;
- }
- if (asc == 0x3a && ascq == 0) {
- /* Medium not present */
- return SCSIRET_CONTINUE;
- }
-
- /* Retry all disk errors.
- */
- scsi_sense_print(xs);
- if (xs->retries)
- printf(", retries:%d\n", xs->retries);
- else
- printf(", FAILURE\n");
-
- return SCSIRET_DO_RETRY;
-}
-
-static od_devsw_installed = 0;
-
-static void od_drvinit(void *unused)
-{
-
- if( ! od_devsw_installed ) {
- cdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &od_cdevsw);
- od_devsw_installed = 1;
- }
-}
-
-SYSINIT(oddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,od_drvinit,NULL)
OpenPOWER on IntegriCloud