153931Shibler /* 253931Shibler * Copyright (c) 1991 University of Utah. 353931Shibler * Copyright (c) 1990 The Regents of the University of California. 453931Shibler * All rights reserved. 553931Shibler * 653931Shibler * This code is derived from software contributed to Berkeley by 753931Shibler * the Systems Programming Group of the University of Utah Computer 853931Shibler * Science Department. 953931Shibler * 1053931Shibler * %sccs.include.redist.c% 1153931Shibler * 1253931Shibler * from: Utah $Hdr: ac.c 1.5 92/01/21$ 1353931Shibler * 14*56507Sbostic * @(#)ac.c 7.2 (Berkeley) 10/11/92 1553931Shibler */ 1653931Shibler 1753931Shibler /* 1853931Shibler * SCSI driver for MO autochanger. 1953931Shibler * 2053931Shibler * Very crude. Because of the lack of connect/disconnect support in the 2153931Shibler * scsi driver, this driver can tie up the SCSI bus for a long time. It 2253931Shibler * also grabs a DMA channel and holds it for the duration even though it 2353931Shibler * never uses it. 2453931Shibler */ 2553931Shibler 2653931Shibler #include "ac.h" 2753931Shibler #if NAC > 0 2853931Shibler 29*56507Sbostic #include <sys/param.h> 30*56507Sbostic #include <sys/buf.h> 31*56507Sbostic #include <sys/errno.h> 32*56507Sbostic #include <sys/user.h> 33*56507Sbostic #include <sys/ioctl.h> 34*56507Sbostic #include <sys/kernel.h> 35*56507Sbostic #include <sys/malloc.h> 3653931Shibler 37*56507Sbostic #include <hp/dev/device.h> 3853931Shibler 39*56507Sbostic #include <hp300/dev/scsireg.h> 40*56507Sbostic #include <hp300/dev/acioctl.h> 41*56507Sbostic #include <hp300/dev/acvar.h> 42*56507Sbostic 4353931Shibler extern int scsi_test_unit_rdy(); 4453931Shibler extern int scsi_request_sense(); 4553931Shibler extern int scsiustart(); 4653931Shibler extern int scsigo(); 4753931Shibler extern void scsifree(); 4853931Shibler extern void scsireset(); 4953931Shibler extern void scsi_delay(); 5053931Shibler 5153931Shibler extern int scsi_immed_command(); 5253931Shibler 5353931Shibler int acinit(), acstart(), acgo(), acintr(); 5453931Shibler 5553931Shibler struct driver acdriver = { 5653931Shibler acinit, "ac", acstart, acgo, acintr, 5753931Shibler }; 5853931Shibler 5953931Shibler struct ac_softc ac_softc[NAC]; 6053931Shibler static struct buf acbuf[NAC]; 6153931Shibler static struct scsi_fmt_cdb accmd[NAC]; 6253931Shibler 6353931Shibler #ifdef DEBUG 6453931Shibler int ac_debug = 0x0000; 6553931Shibler #define ACD_FOLLOW 0x0001 6653931Shibler #define ACD_OPEN 0x0002 6753931Shibler #endif 6853931Shibler 6953931Shibler acinit(hd) 7053931Shibler register struct hp_device *hd; 7153931Shibler { 7253931Shibler int unit = hd->hp_unit; 7353931Shibler register struct ac_softc *sc = &ac_softc[unit]; 7453931Shibler 7553931Shibler sc->sc_hd = hd; 7653931Shibler sc->sc_punit = hd->hp_flags & 7; 7753931Shibler if (acident(sc, hd) < 0) 7853931Shibler return(0); 7953931Shibler sc->sc_dq.dq_unit = unit; 8053931Shibler sc->sc_dq.dq_ctlr = hd->hp_ctlr; 8153931Shibler sc->sc_dq.dq_slave = hd->hp_slave; 8253931Shibler sc->sc_dq.dq_driver = &acdriver; 8353931Shibler sc->sc_bp = &acbuf[unit]; 8453931Shibler sc->sc_cmd = &accmd[unit]; 8553931Shibler sc->sc_flags = ACF_ALIVE; 8653931Shibler return(1); 8753931Shibler } 8853931Shibler 8953931Shibler acident(sc, hd) 9053931Shibler register struct ac_softc *sc; 9153931Shibler register struct hp_device *hd; 9253931Shibler { 9353931Shibler int unit; 9453931Shibler register int ctlr, slave; 9553931Shibler int i, stat; 9653931Shibler int tries = 5; 9753931Shibler char idstr[32]; 9853931Shibler struct scsi_inquiry inqbuf; 9953931Shibler static struct scsi_fmt_cdb inq = { 10053931Shibler 6, 10153931Shibler CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0 10253931Shibler }; 10353931Shibler 10453931Shibler ctlr = hd->hp_ctlr; 10553931Shibler slave = hd->hp_slave; 10653931Shibler unit = sc->sc_punit; 10753931Shibler scsi_delay(-1); 10853931Shibler 10953931Shibler /* 11053931Shibler * See if device is ready 11153931Shibler */ 11253931Shibler while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) { 11353931Shibler if (i == -1 || --tries < 0) 11453931Shibler /* doesn't exist or not a CCS device */ 11553931Shibler goto failed; 11653931Shibler if (i == STS_CHECKCOND) { 11753931Shibler u_char sensebuf[128]; 11853931Shibler struct scsi_xsense *sp; 11953931Shibler 12053931Shibler scsi_request_sense(ctlr, slave, unit, 12153931Shibler sensebuf, sizeof(sensebuf)); 12253931Shibler sp = (struct scsi_xsense *) sensebuf; 12353931Shibler if (sp->class == 7 && sp->key == 6) 12453931Shibler /* drive doing an RTZ -- give it a while */ 12553931Shibler DELAY(1000000); 12653931Shibler } 12753931Shibler DELAY(1000); 12853931Shibler } 12953931Shibler /* 13053931Shibler * Find out if it is an autochanger 13153931Shibler */ 13253931Shibler if (scsi_immed_command(ctlr, slave, unit, &inq, 13353931Shibler (u_char *)&inqbuf, sizeof(inqbuf), B_READ)) 13453931Shibler goto failed; 13553931Shibler 13653931Shibler if (inqbuf.type != 8 || inqbuf.qual != 0x80 || inqbuf.version != 2) 13753931Shibler goto failed; 13853931Shibler 13953931Shibler bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28); 14053931Shibler for (i = 27; i > 23; --i) 14153931Shibler if (idstr[i] != ' ') 14253931Shibler break; 14353931Shibler idstr[i+1] = 0; 14453931Shibler for (i = 23; i > 7; --i) 14553931Shibler if (idstr[i] != ' ') 14653931Shibler break; 14753931Shibler idstr[i+1] = 0; 14853931Shibler for (i = 7; i >= 0; --i) 14953931Shibler if (idstr[i] != ' ') 15053931Shibler break; 15153931Shibler idstr[i+1] = 0; 15253931Shibler printf("ac%d: %s %s rev %s\n", hd->hp_unit, 15353931Shibler &idstr[0], &idstr[8], &idstr[24]); 15453931Shibler 15553931Shibler scsi_delay(0); 15653931Shibler return(inqbuf.type); 15753931Shibler failed: 15853931Shibler scsi_delay(0); 15953931Shibler return(-1); 16053931Shibler } 16153931Shibler 16253931Shibler /*ARGSUSED*/ 16353931Shibler acopen(dev, flag, mode, p) 16453931Shibler dev_t dev; 16553931Shibler int flag, mode; 16653931Shibler struct proc *p; 16753931Shibler { 16853931Shibler register int unit = minor(dev); 16953931Shibler register struct ac_softc *sc = &ac_softc[unit]; 17053931Shibler int error = 0; 17153931Shibler 17253931Shibler if (unit >= NAC || (sc->sc_flags & ACF_ALIVE) == 0) 17353931Shibler error = ENXIO; 17453931Shibler else if (sc->sc_flags & ACF_OPEN) 17553931Shibler error = EBUSY; 17653931Shibler else if (acgeteinfo(dev)) 17753931Shibler error = EIO; 17853931Shibler else 17953931Shibler sc->sc_flags |= ACF_OPEN; 18053931Shibler return(error); 18153931Shibler } 18253931Shibler 18353931Shibler /*ARGSUSED*/ 18453931Shibler acclose(dev, flag, mode, p) 18553931Shibler dev_t dev; 18653931Shibler int flag, mode; 18753931Shibler struct proc *p; 18853931Shibler { 18953931Shibler struct ac_softc *sc = &ac_softc[minor(dev)]; 19053931Shibler 19153931Shibler sc->sc_flags &= ~ACF_OPEN; 19253931Shibler } 19353931Shibler 19453931Shibler #define ACRESLEN(ep) \ 19553931Shibler (8 + (ep)->nmte*12 + (ep)->nse*12 + (ep)->niee*12 + (ep)->ndte*20) 19653931Shibler 19753931Shibler /*ARGSUSED*/ 19853931Shibler acioctl(dev, cmd, data, flag, p) 19953931Shibler dev_t dev; 20053931Shibler int cmd; 20153931Shibler caddr_t data; 20253931Shibler int flag; 20353931Shibler struct proc *p; 20453931Shibler { 20553931Shibler register struct ac_softc *sc = &ac_softc[minor(dev)]; 20653931Shibler char *dp; 20753931Shibler int dlen, error = 0; 20853931Shibler 20953931Shibler switch (cmd) { 21053931Shibler 21153931Shibler default: 21253931Shibler return (EINVAL); 21353931Shibler 21453931Shibler /* perform an init element status and mode sense to reset state */ 21553931Shibler case ACIOCINIT: 21653931Shibler error = accommand(dev, ACCMD_INITES, (caddr_t)0, 0); 21753931Shibler if (!error) 21853931Shibler error = acgeteinfo(dev); 21953931Shibler break; 22053931Shibler 22153931Shibler /* copy internal element information */ 22253931Shibler case ACIOCGINFO: 22353931Shibler *(struct acinfo *)data = sc->sc_einfo; 22453931Shibler break; 22553931Shibler 22653931Shibler case ACIOCRAWES: 22753931Shibler { 22853931Shibler struct acbuffer *acbp = (struct acbuffer *)data; 22953931Shibler 23053931Shibler dlen = ACRESLEN(&sc->sc_einfo); 23153931Shibler dp = (char *) malloc(dlen, M_DEVBUF, M_WAITOK); 23253931Shibler error = accommand(dev, ACCMD_READES, dp, dlen); 23353931Shibler if (!error) { 23453931Shibler dlen = *(int *)&dp[4] + 8; 23553931Shibler if (dlen > acbp->buflen) 23653931Shibler dlen = acbp->buflen; 23753931Shibler error = copyout(dp, acbp->bufptr, dlen); 23853931Shibler } 23953931Shibler break; 24053931Shibler } 24153931Shibler 24253931Shibler case ACIOCGSTAT: 24353931Shibler { 24453931Shibler struct acbuffer *acbp = (struct acbuffer *)data; 24553931Shibler 24653931Shibler dlen = ACRESLEN(&sc->sc_einfo); 24753931Shibler dp = (char *) malloc(dlen, M_DEVBUF, M_WAITOK); 24853931Shibler error = accommand(dev, ACCMD_READES, dp, dlen); 24953931Shibler if (!error) { 25053931Shibler int ne; 25153931Shibler char *tbuf; 25253931Shibler 25353931Shibler ne = sc->sc_einfo.nmte + sc->sc_einfo.nse + 25453931Shibler sc->sc_einfo.niee + sc->sc_einfo.ndte; 25553931Shibler dlen = ne * sizeof(struct aceltstat); 25653931Shibler tbuf = (char *) malloc(dlen, M_DEVBUF, M_WAITOK); 25753931Shibler acconvert(dp, tbuf, ne); 25853931Shibler if (dlen > acbp->buflen) 25953931Shibler dlen = acbp->buflen; 26053931Shibler error = copyout(tbuf, acbp->bufptr, dlen); 26153931Shibler free(tbuf, M_DEVBUF); 26253931Shibler } 26353931Shibler free(dp, M_DEVBUF); 26453931Shibler break; 26553931Shibler } 26653931Shibler 26753931Shibler case ACIOCMOVE: 26853931Shibler error = accommand(dev, ACCMD_MOVEM, data, 26953931Shibler sizeof(struct acmove)); 27053931Shibler break; 27153931Shibler } 27253931Shibler return(error); 27353931Shibler } 27453931Shibler 27553931Shibler accommand(dev, command, bufp, buflen) 27653931Shibler dev_t dev; 27753931Shibler int command; 27853931Shibler char *bufp; 27953931Shibler int buflen; 28053931Shibler { 28153931Shibler int unit = minor(dev); 28253931Shibler register struct ac_softc *sc = &ac_softc[unit]; 28353931Shibler register struct buf *bp = sc->sc_bp; 28453931Shibler register struct scsi_fmt_cdb *cmd = sc->sc_cmd; 28553931Shibler int error; 28653931Shibler 28753931Shibler #ifdef DEBUG 28853931Shibler if (ac_debug & ACD_FOLLOW) 28953931Shibler printf("accommand(dev=%x, cmd=%x, buf=%x, buflen=%x)\n", 29053931Shibler dev, command, bufp, buflen); 29153931Shibler #endif 29253931Shibler if (sc->sc_flags & ACF_ACTIVE) 29353931Shibler panic("accommand: active!"); 29453931Shibler 29553931Shibler sc->sc_flags |= ACF_ACTIVE; 29653931Shibler bzero((caddr_t)cmd->cdb, sizeof(cmd->cdb)); 29753931Shibler cmd->cdb[0] = command; 29853931Shibler 29953931Shibler switch (command) { 30053931Shibler case ACCMD_INITES: 30153931Shibler cmd->len = 6; 30253931Shibler break; 30353931Shibler case ACCMD_READES: 30453931Shibler cmd->len = 12; 30553931Shibler *(short *)&cmd->cdb[2] = 0; 30653931Shibler *(short *)&cmd->cdb[4] = 30753931Shibler sc->sc_einfo.nmte + sc->sc_einfo.nse + 30853931Shibler sc->sc_einfo.niee + sc->sc_einfo.ndte; 30953931Shibler cmd->cdb[7] = buflen >> 16; 31053931Shibler cmd->cdb[8] = buflen >> 8; 31153931Shibler cmd->cdb[9] = buflen; 31253931Shibler break; 31353931Shibler case ACCMD_MODESENSE: 31453931Shibler cmd->len = 6; 31553931Shibler cmd->cdb[2] = 0x3F; /* all pages */ 31653931Shibler cmd->cdb[4] = buflen; 31753931Shibler break; 31853931Shibler case ACCMD_MOVEM: 31953931Shibler cmd->len = 12; 32053931Shibler *(short *)&cmd->cdb[2] = sc->sc_picker; 32153931Shibler *(short *)&cmd->cdb[4] = *(short *)&bufp[0]; 32253931Shibler *(short *)&cmd->cdb[6] = *(short *)&bufp[2]; 32353931Shibler if (*(short *)&bufp[4] & AC_INVERT) 32453931Shibler cmd->cdb[10] = 1; 32553931Shibler bufp = 0; 32653931Shibler buflen = 0; 32753931Shibler break; 32853931Shibler default: 32953931Shibler panic("accommand: bad command"); 33053931Shibler } 33153931Shibler bp->b_flags = B_BUSY|B_READ; 33253931Shibler bp->b_dev = dev; 33353931Shibler bp->b_un.b_addr = bufp; 33453931Shibler bp->b_bcount = buflen; 33553931Shibler bp->b_resid = 0; 33653931Shibler bp->b_blkno = 0; 33753931Shibler bp->b_error = 0; 33853931Shibler if (scsireq(&sc->sc_dq)) 33953931Shibler acstart(unit); 34053931Shibler error = biowait(bp); 34153931Shibler sc->sc_flags &= ~ACF_ACTIVE; 34253931Shibler return (error); 34353931Shibler } 34453931Shibler 34553931Shibler acstart(unit) 34653931Shibler int unit; 34753931Shibler { 34853931Shibler #ifdef DEBUG 34953931Shibler if (ac_debug & ACD_FOLLOW) 35053931Shibler printf("acstart(unit=%x)\n", unit); 35153931Shibler #endif 35253931Shibler if (scsiustart(ac_softc[unit].sc_hd->hp_ctlr)) 35353931Shibler acgo(unit); 35453931Shibler } 35553931Shibler 35653931Shibler acgo(unit) 35753931Shibler int unit; 35853931Shibler { 35953931Shibler register struct ac_softc *sc = &ac_softc[unit]; 36053931Shibler register struct buf *bp = sc->sc_bp; 36153931Shibler struct hp_device *hp = sc->sc_hd; 36253931Shibler int stat; 36353931Shibler 36453931Shibler #ifdef DEBUG 36553931Shibler if (ac_debug & ACD_FOLLOW) 36653931Shibler printf("acgo(unit=%x): ", unit); 36753931Shibler #endif 36853931Shibler stat = scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, 36953931Shibler bp, sc->sc_cmd, 0); 37053931Shibler #ifdef DEBUG 37153931Shibler if (ac_debug & ACD_FOLLOW) 37253931Shibler printf("scsigo returns %x\n", stat); 37353931Shibler #endif 37453931Shibler if (stat) { 37553931Shibler bp->b_error = EIO; 37653931Shibler bp->b_flags |= B_ERROR; 37753931Shibler (void) biodone(bp); 37853931Shibler scsifree(&sc->sc_dq); 37953931Shibler } 38053931Shibler } 38153931Shibler 38253931Shibler acintr(unit, stat) 38353931Shibler int unit, stat; 38453931Shibler { 38553931Shibler register struct ac_softc *sc = &ac_softc[unit]; 38653931Shibler register struct buf *bp = sc->sc_bp; 38753931Shibler u_char sensebuf[78]; 38853931Shibler struct scsi_xsense *sp; 38953931Shibler 39053931Shibler #ifdef DEBUG 39153931Shibler if (ac_debug & ACD_FOLLOW) 39253931Shibler printf("acintr(unit=%x, stat=%x)\n", unit, stat); 39353931Shibler #endif 39453931Shibler switch (stat) { 39553931Shibler case 0: 39653931Shibler bp->b_resid = 0; 39753931Shibler break; 39853931Shibler case STS_CHECKCOND: 39953931Shibler scsi_request_sense(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, 40053931Shibler sc->sc_punit, sensebuf, sizeof sensebuf); 40153931Shibler sp = (struct scsi_xsense *)sensebuf; 40253931Shibler printf("ac%d: acintr sense key=%x, ac=%x, acq=%x\n", 40353931Shibler unit, sp->key, sp->info4, sp->len); 40453931Shibler bp->b_flags |= B_ERROR; 40553931Shibler bp->b_error = EIO; 40653931Shibler break; 40753931Shibler default: 40853931Shibler printf("ac%d: acintr unknown status 0x%x\n", unit, stat); 40953931Shibler break; 41053931Shibler } 41153931Shibler (void) biodone(sc->sc_bp); 41253931Shibler scsifree(&sc->sc_dq); 41353931Shibler } 41453931Shibler 41553931Shibler acgeteinfo(dev) 41653931Shibler dev_t dev; 41753931Shibler { 41853931Shibler register struct ac_softc *sc = &ac_softc[minor(dev)]; 41953931Shibler register char *bp; 42053931Shibler char msbuf[48]; 42153931Shibler int error; 42253931Shibler 42353931Shibler bzero(msbuf, sizeof msbuf); 42453931Shibler error = accommand(dev, ACCMD_MODESENSE, msbuf, sizeof msbuf); 42553931Shibler if (error) 42653931Shibler return(error); 42753931Shibler bp = &msbuf[4]; 42853931Shibler while (bp < &msbuf[48]) { 42953931Shibler switch (bp[0] & 0x3F) { 43053931Shibler case 0x1D: 43153931Shibler sc->sc_einfo = *(struct acinfo *)&bp[2]; 43253931Shibler sc->sc_picker = sc->sc_einfo.fmte; /* XXX */ 43353931Shibler return(0); 43453931Shibler case 0x1E: 43553931Shibler bp += 4; 43653931Shibler break; 43753931Shibler case 0x1F: 43853931Shibler bp += 20; 43953931Shibler break; 44053931Shibler default: 44153931Shibler printf("acgeteinfo: bad page type %x\n", bp[0]); 44253931Shibler return(EIO); 44353931Shibler } 44453931Shibler } 44553931Shibler return(EIO); 44653931Shibler } 44753931Shibler 44853931Shibler acconvert(sbuf, dbuf, ne) 44953931Shibler char *sbuf, *dbuf; 45053931Shibler int ne; 45153931Shibler { 45253931Shibler register struct aceltstat *ep = (struct aceltstat *)dbuf; 45353931Shibler register struct ac_restatphdr *phdr; 45453931Shibler register struct ac_restatdb *dbp; 45553931Shibler struct ac_restathdr *hdr; 45653931Shibler #ifdef DEBUG 45753931Shibler register int bcount; 45853931Shibler #endif 45953931Shibler 46053931Shibler hdr = (struct ac_restathdr *)&sbuf[0]; 46153931Shibler sbuf += sizeof *hdr; 46253931Shibler #ifdef DEBUG 46353931Shibler if (ac_debug & ACD_FOLLOW) 46453931Shibler printf("element status: first=%d, num=%d, len=%d\n", 46553931Shibler hdr->ac_felt, hdr->ac_nelt, hdr->ac_bcount); 46653931Shibler if (hdr->ac_nelt != ne) { 46753931Shibler printf("acconvert: # of elements, %d != %d\n", 46853931Shibler hdr->ac_nelt, ne); 46953931Shibler if (hdr->ac_nelt < ne) 47053931Shibler ne = hdr->ac_nelt; 47153931Shibler } 47253931Shibler bcount = hdr->ac_bcount; 47353931Shibler #endif 47453931Shibler while (ne) { 47553931Shibler phdr = (struct ac_restatphdr *)sbuf; 47653931Shibler sbuf += sizeof *phdr; 47753931Shibler #ifdef DEBUG 47853931Shibler bcount -= sizeof *phdr; 47953931Shibler #endif 48053931Shibler dbp = (struct ac_restatdb *)sbuf; 48153931Shibler sbuf += phdr->ac_bcount; 48253931Shibler #ifdef DEBUG 48353931Shibler bcount -= phdr->ac_bcount; 48453931Shibler #endif 48553931Shibler while (dbp < (struct ac_restatdb *)sbuf) { 48653931Shibler ep->type = phdr->ac_type; 48753931Shibler ep->eaddr = dbp->ac_eaddr; 48853931Shibler ep->flags = 0; 48953931Shibler if (dbp->ac_full) 49053931Shibler ep->flags |= AC_FULL; 49153931Shibler if (dbp->ac_exc) 49253931Shibler ep->flags |= AC_ERROR; 49353931Shibler if (dbp->ac_acc) 49453931Shibler ep->flags |= AC_ACCESS; 49553931Shibler dbp = (struct ac_restatdb *) 49653931Shibler ((char *)dbp + phdr->ac_dlen); 49753931Shibler ep++; 49853931Shibler ne--; 49953931Shibler } 50053931Shibler #ifdef DEBUG 50153931Shibler if (ne < 0 || bcount < 0) 50253931Shibler panic("acconvert: inconsistant"); 50353931Shibler #endif 50453931Shibler } 50553931Shibler } 50653931Shibler #endif 507