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