diff options
author | gibbs <gibbs@FreeBSD.org> | 1998-09-15 10:40:55 +0000 |
---|---|---|
committer | gibbs <gibbs@FreeBSD.org> | 1998-09-15 10:40:55 +0000 |
commit | 79200df6729d1afbc24596e05c0bee54a2544616 (patch) | |
tree | 454f8a346e1e8ffbde91ed6c5a172835b1d7d78c /sys/scsi/ch.c | |
parent | 4035fc4bcc3a3a3a921bfaa090dd3f7f02b9737a (diff) | |
download | FreeBSD-src-79200df6729d1afbc24596e05c0bee54a2544616.zip FreeBSD-src-79200df6729d1afbc24596e05c0bee54a2544616.tar.gz |
Obsoleted by CAM.
Diffstat (limited to 'sys/scsi/ch.c')
-rw-r--r-- | sys/scsi/ch.c | 750 |
1 files changed, 0 insertions, 750 deletions
diff --git a/sys/scsi/ch.c b/sys/scsi/ch.c deleted file mode 100644 index 9b970fb..0000000 --- a/sys/scsi/ch.c +++ /dev/null @@ -1,750 +0,0 @@ -/* - * Copyright (c) 1996 Jason R. Thorpe <thorpej@and.com> - * All rights reserved. - * - * Partially based on an autochanger driver written by Stefan Grefen - * and on an autochanger driver written by the Systems Programming Group - * at the University of Utah Computer Science Department. - * - * 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 acknowledgements: - * This product includes software developed by Jason R. Thorpe - * for And Communications, http://www.and.com/ - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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: ch.c,v 1.47 1998/06/17 14:13:13 bde Exp $ - */ - -#include "opt_devfs.h" -#include "opt_bounce.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/chio.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#ifdef DEVFS -#include <sys/devfsext.h> -#endif /*DEVFS*/ -#ifdef BOUNCE_BUFFERS -#include <sys/buf.h> -#endif - -#include <scsi/scsi_changer.h> -#include <scsi/scsiconf.h> -#include <scsi/scsi_driver.h> - -#include "ioconf.h" - -#define CHRETRIES 2 -#define CHUNIT(x) (minor((x))) -#define CHSETUNIT(x, y) makedev(major(x), y) - -struct ch_softc { - /* - * Human-readable external name. FreeBSD doesn't have a - * generic hook for this, so we make it look NetBSD-like. See - * comment in chattach(). - */ - struct { - char dv_xname[16]; - } sc_dev; - - /* - * Pointer back to the scsi_link. See comment in chattach(). - */ - struct scsi_link *sc_link; - - int sc_picker; /* current picker */ - - /* - * The following information is obtained from the - * element address assignment page. - */ - int sc_firsts[4]; /* firsts, indexed by CHET_* */ - int sc_counts[4]; /* counts, indexed by CHET_* */ - - /* - * The following mask defines the legal combinations - * of elements for the MOVE MEDIUM command. - */ - u_int8_t sc_movemask[4]; - - /* - * As above, but for EXCHANGE MEDIUM. - */ - u_int8_t sc_exchangemask[4]; - - int flags; /* misc. info */ -#ifdef DEVFS - void *c_devfs_token; - void *ctl_devfs_token; -#endif -}; - -/* sc_flags */ -#define CHF_ROTATE 0x01 /* picker can rotate */ - -static d_open_t chopen; -static d_close_t chclose; -static d_ioctl_t chioctl; - -#define CDEV_MAJOR 17 -static struct cdevsw ch_cdevsw = - { chopen, chclose, noread, nowrite, /*17*/ - chioctl, nostop, nullreset, nodevtotty,/* ch */ - seltrue, nommap, nostrat, "ch", NULL, -1 }; - -/* - * SCSI glue. - */ - -/* - * Under FreeBSD, this macro sets up a bunch of trampoline - * functions that indirect through the SCSI subsystem. - */ -SCSI_DEVICE_ENTRIES(ch) - -static int chunit __P((dev_t)); -static dev_t chsetunit __P((dev_t, int)); - -/* So, like, why not "int"? */ -static errval ch_devopen __P((dev_t, int, int, struct proc *, - struct scsi_link *)); -static errval ch_devioctl __P((dev_t, u_long, caddr_t, int, struct proc *, - struct scsi_link *)); -static errval ch_devclose __P((dev_t, int, int, struct proc *, - struct scsi_link *)); - -static struct scsi_device ch_switch = { - NULL, /* (*err_handler) */ - NULL, /* (*start) */ - NULL, /* (*async) */ - NULL, /* (*done) */ - "ch", /* name */ - 0, /* flags */ - { 0, 0 }, /* spare[2] */ - 0, /* link_flags */ - chattach, /* (*attach) */ - "Medium-Changer", /* desc */ - chopen, /* (*open) */ - sizeof(struct ch_softc), /* sizeof_scsi_data */ - T_CHANGER, /* type */ - chunit, /* (*getunit) */ - chsetunit, /* (*setunit) */ - ch_devopen, /* (*dev_open) */ - ch_devioctl, /* (*dev_ioctl) */ - ch_devclose, /* (*dev_close) */ -}; - -static int ch_move __P((struct ch_softc *, struct changer_move *)); -static int ch_exchange __P((struct ch_softc *, struct changer_exchange *)); -static int ch_position __P((struct ch_softc *, struct changer_position *)); -static int ch_usergetelemstatus __P((struct ch_softc *, int, u_int8_t *)); -static int ch_getelemstatus __P((struct ch_softc *, int, int, caddr_t, size_t)); -static int ch_get_params __P((struct ch_softc *, int)); - -static errval -chattach(link) - struct scsi_link *link; -{ - struct ch_softc *sc = (struct ch_softc *)(link->sd); - u_int32_t unit = link->dev_unit; - - /* - * FreeBSD doesn't have any common way of carrying - * around a device's external name (i.e. <name><unit>), - * so emulate the structure used by NetBSD to keep the - * diffs lower. - */ - bzero(sc->sc_dev.dv_xname, sizeof(sc->sc_dev.dv_xname)); - sprintf(sc->sc_dev.dv_xname, "%s%d", ch_switch.name, unit); - - /* - * FreeBSD gets "softc" info for a device from the - * scsi_link argument passed to indirect entry point functions. - * NetBSD get scsi_link info from softcs that are - * obtained from indexes passed to direct entry point functions. - * We emulate the NetBSD behavior here to keep the diffs - * lower. - */ - sc->sc_link = link; - - /* - * Get information about the device. Note we can't use - * interrupts yet. - */ - if (ch_get_params(sc, SCSI_NOSLEEP|SCSI_NOMASK)) - printf("offline"); - else { - printf("%d slot%s, %d drive%s, %d picker%s", - sc->sc_counts[CHET_ST], (sc->sc_counts[CHET_ST] > 1) ? - "s" : "", - sc->sc_counts[CHET_DT], (sc->sc_counts[CHET_DT] > 1) ? - "s" : "", - sc->sc_counts[CHET_MT], (sc->sc_counts[CHET_MT] > 1) ? - "s" : ""); - if (sc->sc_counts[CHET_IE]) - printf(", %d portal%s", sc->sc_counts[CHET_IE], - (sc->sc_counts[CHET_IE] > 1) ? "s" : ""); - if (bootverbose) { - printf("\n"); /* This will probably look ugly ... bummer. */ - printf("%s: move mask: 0x%x 0x%x 0x%x 0x%x\n", - sc->sc_dev.dv_xname, - sc->sc_movemask[CHET_MT], sc->sc_movemask[CHET_ST], - sc->sc_movemask[CHET_IE], sc->sc_movemask[CHET_DT]); - printf("%s: exchange mask: 0x%x 0x%x 0x%x 0x%x\n", - sc->sc_dev.dv_xname, - sc->sc_exchangemask[CHET_MT], sc->sc_exchangemask[CHET_ST], - sc->sc_exchangemask[CHET_IE], sc->sc_exchangemask[CHET_DT]); - } - } - - /* Default the current picker. */ - sc->sc_picker = sc->sc_firsts[CHET_MT]; - -#ifdef DEVFS - sc->c_devfs_token = devfs_add_devswf(&ch_cdevsw, unit << 4, DV_CHR, - UID_ROOT, GID_OPERATOR, 0600, - "ch%d", unit); - sc->ctl_devfs_token = devfs_add_devswf(&ch_cdevsw, - (unit << 4) | SCSI_CONTROL_MASK, - DV_CHR, - UID_ROOT, GID_OPERATOR, 0600, - "ch%d.ctl", unit); -#endif - return (0); -} - -static errval -ch_devopen(dev, flags, fmt, p, link) - dev_t dev; - int flags, fmt; - struct proc *p; - struct scsi_link *link; -{ - struct ch_softc *sc = (struct ch_softc *)(link->sd); - errval error = 0; - int unit; - - unit = CHUNIT(dev); - - /* - * Only allow one open at a time. - */ - if (link->flags & SDEV_OPEN) - return (EBUSY); - - link->flags |= SDEV_OPEN; - - /* - * Absorb any unit attention errors. Ignore "not ready" - * since this might occur if e.g. a tape isn't actually - * loaded in the drive. - */ - (void)scsi_test_unit_ready(link, SCSI_SILENT); - - /* - * Make sure our parameters are up to date. - */ - if (error = ch_get_params(sc, 0)) - goto bad; - - return (0); - - bad: - link->flags &= ~SDEV_OPEN; - return (error); -} - -static errval -ch_devclose(dev, flags, fmt, p, link) - dev_t dev; - int flags, fmt; - struct proc *p; - struct scsi_link *link; -{ - - link->flags &= ~SDEV_OPEN; - return (0); -} - -static errval -ch_devioctl(dev, cmd, data, flags, p, link) - dev_t dev; - u_long cmd; - caddr_t data; - int flags; - struct proc *p; - struct scsi_link *link; -{ - struct ch_softc *sc = (struct ch_softc *)(link->sd); - caddr_t elemdata; - int error = 0; - - switch (cmd) { - case CHIOMOVE: - error = ch_move(sc, (struct changer_move *)data); - break; - - case CHIOEXCHANGE: - error = ch_exchange(sc, (struct changer_exchange *)data); - break; - - case CHIOPOSITION: - error = ch_position(sc, (struct changer_position *)data); - break; - - case CHIOGPICKER: - *(int *)data = sc->sc_picker - sc->sc_firsts[CHET_MT]; - break; - - case CHIOSPICKER: { - int new_picker = *(int *)data; - - if (new_picker > (sc->sc_counts[CHET_MT] - 1)) - return (EINVAL); - sc->sc_picker = sc->sc_firsts[CHET_MT] + new_picker; - break; } - - case CHIOGPARAMS: { - struct changer_params *cp = (struct changer_params *)data; - - cp->cp_curpicker = sc->sc_picker - sc->sc_firsts[CHET_MT]; - cp->cp_npickers = sc->sc_counts[CHET_MT]; - cp->cp_nslots = sc->sc_counts[CHET_ST]; - cp->cp_nportals = sc->sc_counts[CHET_IE]; - cp->cp_ndrives = sc->sc_counts[CHET_DT]; - break; } - - case CHIOGSTATUS: { - struct changer_element_status *ces = - (struct changer_element_status *)data; - - error = ch_usergetelemstatus(sc, ces->ces_type, ces->ces_data); - break; } - - /* Implement prevent/allow? */ - - default: - error = scsi_do_ioctl(dev, cmd, data, flags, p, link); - break; - } - - return (error); -} - -static int -ch_move(sc, cm) - struct ch_softc *sc; - struct changer_move *cm; -{ - struct scsi_move_medium cmd; - u_int16_t fromelem, toelem; - - /* - * Check arguments. - */ - if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT)) - return (EINVAL); - if ((cm->cm_fromunit > (sc->sc_counts[cm->cm_fromtype] - 1)) || - (cm->cm_tounit > (sc->sc_counts[cm->cm_totype] - 1))) - return (ENODEV); - - /* - * Check the request against the changer's capabilities. - */ - if ((sc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0) - return (EINVAL); - - /* - * Calculate the source and destination elements. - */ - fromelem = sc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit; - toelem = sc->sc_firsts[cm->cm_totype] + cm->cm_tounit; - - /* - * Build the SCSI command. - */ - bzero(&cmd, sizeof(cmd)); - cmd.opcode = MOVE_MEDIUM; - scsi_uto2b(sc->sc_picker, cmd.tea); - scsi_uto2b(fromelem, cmd.src); - scsi_uto2b(toelem, cmd.dst); - if (cm->cm_flags & CM_INVERT) - cmd.flags |= MOVE_MEDIUM_INVERT; - - /* - * Send command to changer. - */ - return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd, - sizeof(cmd), NULL, 0, CHRETRIES, 100000, NULL, 0)); -} - -static int -ch_exchange(sc, ce) - struct ch_softc *sc; - struct changer_exchange *ce; -{ - struct scsi_exchange_medium cmd; - u_int16_t src, dst1, dst2; - - /* - * Check arguments. - */ - if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) || - (ce->ce_sdsttype > CHET_DT)) - return (EINVAL); - if ((ce->ce_srcunit > (sc->sc_counts[ce->ce_srctype] - 1)) || - (ce->ce_fdstunit > (sc->sc_counts[ce->ce_fdsttype] - 1)) || - (ce->ce_sdstunit > (sc->sc_counts[ce->ce_sdsttype] - 1))) - return (ENODEV); - - /* - * Check the request against the changer's capabilities. - */ - if (((sc->sc_exchangemask[ce->ce_srctype] & - (1 << ce->ce_fdsttype)) == 0) || - ((sc->sc_exchangemask[ce->ce_fdsttype] & - (1 << ce->ce_sdsttype)) == 0)) - return (EINVAL); - - /* - * Calculate the source and destination elements. - */ - src = sc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit; - dst1 = sc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit; - dst2 = sc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit; - - /* - * Build the SCSI command. - */ - bzero(&cmd, sizeof(cmd)); - cmd.opcode = EXCHANGE_MEDIUM; - scsi_uto2b(sc->sc_picker, cmd.tea); - scsi_uto2b(src, cmd.src); - scsi_uto2b(dst1, cmd.fdst); - scsi_uto2b(dst2, cmd.sdst); - if (ce->ce_flags & CE_INVERT1) - cmd.flags |= EXCHANGE_MEDIUM_INV1; - if (ce->ce_flags & CE_INVERT2) - cmd.flags |= EXCHANGE_MEDIUM_INV2; - - /* - * Send command to changer. - */ - return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd, - sizeof(cmd), NULL, 0, CHRETRIES, 100000, NULL, 0)); -} - -static int -ch_position(sc, cp) - struct ch_softc *sc; - struct changer_position *cp; -{ - struct scsi_position_to_element cmd; - u_int16_t dst; - - /* - * Check arguments. - */ - if (cp->cp_type > CHET_DT) - return (EINVAL); - if (cp->cp_unit > (sc->sc_counts[cp->cp_type] - 1)) - return (ENODEV); - - /* - * Calculate the destination element. - */ - dst = sc->sc_firsts[cp->cp_type] + cp->cp_unit; - - /* - * Build the SCSI command. - */ - bzero(&cmd, sizeof(cmd)); - cmd.opcode = POSITION_TO_ELEMENT; - scsi_uto2b(sc->sc_picker, cmd.tea); - scsi_uto2b(dst, cmd.dst); - if (cp->cp_flags & CP_INVERT) - cmd.flags |= POSITION_TO_ELEMENT_INVERT; - - /* - * Send command to changer. - */ - return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd, - sizeof(cmd), NULL, 0, CHRETRIES, 100000, NULL, 0)); -} - -/* - * Perform a READ ELEMENT STATUS on behalf of the user, and return to - * the user only the data the user is interested in (i.e. an array of - * flags bytes). - */ -static int -ch_usergetelemstatus(sc, chet, uptr) - struct ch_softc *sc; - int chet; - u_int8_t *uptr; -{ - struct read_element_status_header *st_hdr; - struct read_element_status_page_header *pg_hdr; - struct read_element_status_descriptor *desc; - caddr_t data = NULL; -#ifdef BOUNCE_BUFFERS - int datasize = 0; -#endif - size_t size, desclen; - int avail, i, error = 0; - u_int8_t *user_data = NULL; - - /* - * If there are no elements of the requested type in the changer, - * the request is invalid. - */ - if (sc->sc_counts[chet] == 0) - return (EINVAL); - - /* - * Request one descriptor for the given element type. This - * is used to determine the size of the descriptor so that - * we can allocate enough storage for all of them. We assume - * that the first one can fit into 1k. - */ -#ifdef BOUNCE_BUFFERS - data = (caddr_t)vm_bounce_kva_alloc(btoc(1024)); - if (!data) - return (ENOMEM); - datasize = 1024; -#else - data = (caddr_t)malloc(1024, M_DEVBUF, M_WAITOK); -#endif - if (error = ch_getelemstatus(sc, sc->sc_firsts[chet], 1, data, 1024)) - goto done; - - st_hdr = (struct read_element_status_header *)data; - pg_hdr = (struct read_element_status_page_header *)((char *)st_hdr + - sizeof(struct read_element_status_header)); - desclen = scsi_2btou(pg_hdr->edl); - - size = sizeof(struct read_element_status_header) + - sizeof(struct read_element_status_page_header) + - (desclen * sc->sc_counts[chet]); - - /* - * Reallocate storage for descriptors and get them from the - * device. - */ -#ifdef BOUNCE_BUFFERS - vm_bounce_kva_alloc_free((vm_offset_t)data, btoc(datasize)); - data = (caddr_t)vm_bounce_kva_alloc(btoc(size)); - if (!data) { - error = ENOMEM; - goto done; - } - datasize = size; -#else - free(data, M_DEVBUF); - data = (caddr_t)malloc(size, M_DEVBUF, M_WAITOK); -#endif - if (error = ch_getelemstatus(sc, sc->sc_firsts[chet], - sc->sc_counts[chet], data, size)) - goto done; - - /* - * Fill in the user status array. - */ - st_hdr = (struct read_element_status_header *)data; - avail = scsi_2btou(st_hdr->count); - if (avail != sc->sc_counts[chet]) - printf("%s: warning, READ ELEMENT STATUS avail != count\n", - sc->sc_dev.dv_xname); - - user_data = (u_int8_t *)malloc(avail, M_DEVBUF, M_WAITOK); - - desc = (struct read_element_status_descriptor *)((char *)data + - sizeof(struct read_element_status_header) + - sizeof(struct read_element_status_page_header)); - for (i = 0; i < avail; ++i) { - user_data[i] = desc->flags1; - desc = (struct read_element_status_descriptor *) - ((char *)desc + desclen); - } - - /* Copy flags array out to userspace. */ - error = copyout(user_data, uptr, avail); - - done: -#ifdef BOUNCE_BUFFERS - if (data != NULL) - vm_bounce_kva_alloc_free((vm_offset_t)data, btoc(datasize)); -#else - if (data != NULL) - free(data, M_DEVBUF); -#endif - if (user_data != NULL) - free(user_data, M_DEVBUF); - return (error); -} - -static int -ch_getelemstatus(sc, first, count, data, datalen) - struct ch_softc *sc; - int first, count; - caddr_t data; - size_t datalen; -{ - struct scsi_read_element_status cmd; - - /* - * Build SCSI command. - */ - bzero(&cmd, sizeof(cmd)); - cmd.opcode = READ_ELEMENT_STATUS; - scsi_uto2b(first, cmd.sea); - scsi_uto2b(count, cmd.count); - scsi_uto3b(datalen, cmd.len); - - /* - * Send command to changer. - */ - return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd, - sizeof(cmd), (u_char *)data, datalen, CHRETRIES, 100000, NULL, SCSI_DATA_IN)); -} - - -/* - * Ask the device about itself and fill in the parameters in our - * softc. - */ -static int -ch_get_params(sc, scsiflags) - struct ch_softc *sc; - int scsiflags; -{ - struct scsi_mode_sense cmd; - struct scsi_mode_sense_data { - struct scsi_mode_header header; - union { - struct page_element_address_assignment ea; - struct page_transport_geometry_parameters tg; - struct page_device_capabilities cap; - } pages; - } sense_data; - int error, from; - u_int8_t *moves, *exchanges; - - /* - * Grab info from the element address assignment page. - */ - bzero(&cmd, sizeof(cmd)); - bzero(&sense_data, sizeof(sense_data)); - cmd.op_code = MODE_SENSE; - cmd.byte2 |= 0x08; /* disable block descriptors */ - cmd.page = 0x1d; - cmd.length = (sizeof(sense_data) & 0xff); - error = scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd, - sizeof(cmd), (u_char *)&sense_data, sizeof(sense_data), CHRETRIES, - 6000, NULL, scsiflags | SCSI_DATA_IN); - if (error) { - printf("%s: could not sense element address page\n", - sc->sc_dev.dv_xname); - return (error); - } - - sc->sc_firsts[CHET_MT] = scsi_2btou(sense_data.pages.ea.mtea); - sc->sc_counts[CHET_MT] = scsi_2btou(sense_data.pages.ea.nmte); - sc->sc_firsts[CHET_ST] = scsi_2btou(sense_data.pages.ea.fsea); - sc->sc_counts[CHET_ST] = scsi_2btou(sense_data.pages.ea.nse); - sc->sc_firsts[CHET_IE] = scsi_2btou(sense_data.pages.ea.fieea); - sc->sc_counts[CHET_IE] = scsi_2btou(sense_data.pages.ea.niee); - sc->sc_firsts[CHET_DT] = scsi_2btou(sense_data.pages.ea.fdtea); - sc->sc_counts[CHET_DT] = scsi_2btou(sense_data.pages.ea.ndte); - - /* XXX ask for page trasport geom */ - - /* - * Grab info from the capabilities page. - */ - bzero(&cmd, sizeof(cmd)); - bzero(&sense_data, sizeof(sense_data)); - cmd.op_code = MODE_SENSE; - cmd.byte2 |= 0x08; /* disable block descriptors */ - cmd.page = 0x1f; - cmd.length = (sizeof(sense_data) & 0xff); - error = scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd, - sizeof(cmd), (u_char *)&sense_data, sizeof(sense_data), CHRETRIES, - 6000, NULL, scsiflags | SCSI_DATA_IN); - if (error) { - printf("%s: could not sense capabilities page\n", - sc->sc_dev.dv_xname); - return (error); - } - - bzero(sc->sc_movemask, sizeof(sc->sc_movemask)); - bzero(sc->sc_exchangemask, sizeof(sc->sc_exchangemask)); - moves = &sense_data.pages.cap.move_from_mt; - exchanges = &sense_data.pages.cap.exchange_with_mt; - for (from = CHET_MT; from <= CHET_DT; ++from) { - sc->sc_movemask[from] = moves[from]; - sc->sc_exchangemask[from] = exchanges[from]; - } - - sc->sc_link->flags |= SDEV_MEDIA_LOADED; - return (0); -} - -static int -chunit(dev) - dev_t dev; -{ - - return (CHUNIT(dev)); -} - -static dev_t -chsetunit(dev, unit) - dev_t dev; - int unit; -{ - - return (CHSETUNIT(dev, unit)); -} - - -static ch_devsw_installed = 0; - -static void -ch_drvinit(void *unused) -{ - dev_t dev; - - if( ! ch_devsw_installed ) { - dev = makedev(CDEV_MAJOR, 0); - cdevsw_add(&dev,&ch_cdevsw, NULL); - ch_devsw_installed = 1; - } -} - -SYSINIT(chdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ch_drvinit,NULL) |