/* * Copyright (c) 1992 OMRON Corporation. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * OMRON Corporation. * * 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 the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 THE REGENTS 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. * * @(#)st.c 8.1 (Berkeley) 6/10/93 */ /* * st.c -- SCSI Disk Device Driver for LUNA-68K * remaked by A.Fujita, MAR-22-1992 */ /* * SCSI CCS (Command Command Set) disk driver. */ #define NST 1 #include <sys/param.h> #include <sys/mtio.h> #include <luna68k/dev/scsireg.h> #include <luna68k/stand/device.h> extern int scsi_test_unit_rdy(); extern int scsi_request_sense(); extern int scsi_immed_command(); extern int scgo(); extern void scfree(); int stinit(), ststrategy(), ststart(), stintr(); struct driver stdriver = { stinit, "st", ststart, (int (*)()) 0, stintr, (int (*)()) 0 }; struct st_softc { struct hp_device *sc_hd; struct devqueue sc_dq; int sc_flags; short sc_type; /* drive type */ short sc_punit; /* physical unit (scsi lun) */ } st_softc[NST]; /* softc flags */ #define STF_ALIVE 0x0001 #define STF_OPEN 0x0002 #define STF_WMODE 0x0004 #define STF_WRTTN 0x0008 #define STF_CMD 0x0010 #define STF_LEOT 0x0020 #define STF_MOVED 0x0040 struct scsi_fmt_sense stsense[NST]; #define stunit(x) (minor(x) & 3) #define stpunit(x) ((x) & 7) #define STDEV_NOREWIND 0x04 #define STDEV_HIDENSITY 0x08 #define STDEV_EXSFMK 0x10 #define STDEV_FIXEDBLK 0x20 #define b_lba b_resid #define STRETRY 2 /* IO retry count */ /* * Initialize */ int stinit(hd) register struct hp_device *hd; { register struct st_softc *sc = &st_softc[hd->hp_unit]; sc->sc_hd = hd; sc->sc_punit = stpunit(hd->hp_flags); sc->sc_type = stident(sc, hd); if (sc->sc_type < 0) return(0); sc->sc_dq.dq_ctlr = hd->hp_ctlr; sc->sc_dq.dq_unit = hd->hp_unit; sc->sc_dq.dq_slave = hd->hp_slave; sc->sc_dq.dq_driver = &stdriver; sc->sc_flags = STF_ALIVE; return(1); } static struct scsi_inquiry inqbuf; static struct scsi_fmt_cdb inq = { 6, CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0 }; int stident(sc, hd) struct st_softc *sc; struct hp_device *hd; { char idstr[32]; int unit; register int ctlr, slave; register int i, stat; register int tries = 10; ctlr = hd->hp_ctlr; slave = hd->hp_slave; unit = sc->sc_punit; /* * See if unit exists and is a disk then read block size & nblocks. */ while ((stat = scsi_immed_command(ctlr, slave, unit, &inq, (u_char *)&inqbuf, sizeof(inqbuf))) != 0) { if (stat < 0 || --tries < 0) return (-1); DELAY(1000); } if (stat) return (-1); switch (inqbuf.type) { case 1: /* tape */ break; default: /* not a disk */ return (-1); } bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28); for (i = 27; i > 23; --i) if (idstr[i] != ' ') break; idstr[i+1] = 0; for (i = 23; i > 7; --i) if (idstr[i] != ' ') break; idstr[i+1] = 0; for (i = 7; i >= 0; --i) if (idstr[i] != ' ') break; idstr[i+1] = 0; printf("st%d: %s %s rev %s\n", hd->hp_unit, idstr, &idstr[8], &idstr[24]); return(inqbuf.type); } /* * Open */ int stopen(dev) dev_t dev; { register int unit = stunit(dev); register struct st_softc *sc = &st_softc[unit]; if (unit >= NST || (sc->sc_flags & STF_ALIVE) == 0) return(-1); if (sc->sc_flags & STF_OPEN) return(-1); sc->sc_flags |= STF_OPEN; sc->sc_flags |= STF_WMODE; sc->sc_flags &= ~STF_MOVED; return(0); } /*ARGSUSED*/ stclose(dev) dev_t dev; { register int unit = stunit(dev); register struct st_softc *sc = &st_softc[unit]; printf("st: sc->sc_flags = 0x%s\n", hexstr(sc->sc_flags, 8)); if ((sc->sc_flags & (STF_WMODE|STF_WRTTN)) == (STF_WMODE|STF_WRTTN)) { st_write_EOF(dev); } if ((minor(dev) & STDEV_NOREWIND) == 0) { st_rewind(dev); } sc->sc_flags &= ~(STF_OPEN|STF_WMODE|STF_WRTTN); return(0); } /* * Strategy */ int ststrategy() { } int ststart(unit) register int unit; { } /* * Interrupt */ /* * Return: * 0 if not really an error * <0 if we should do a retry * >0 if a fatal error */ static int sterror(unit, sc, hp, stat) int unit, stat; register struct st_softc *sc; register struct hp_device *hp; { int cond = 1; stsense[unit].status = stat; if (stat & STS_CHECKCOND) { struct scsi_xsense *sp; scsi_request_sense(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, stsense[unit].sense, sizeof(stsense[unit].sense)); sp = (struct scsi_xsense *)stsense[unit].sense; printf("st%d: scsi sense class %d, code %d", unit, sp->class, sp->code); if (sp->class == 7) { printf(", key %d", sp->key); if (sp->valid) printf(", blk %d", *(int *)&sp->info1); switch (sp->key) { /* no sense, try again */ case 0: cond = -1; break; /* recovered error, not a problem */ case 1: cond = 0; break; } } printf("\n"); } return(cond); } int stintr(unit, stat) register int unit; int stat; { } /* * RAW Device Routines */ char * sense_key(key) int key; { if (key == 0) return("No Sense"); else if (key == 2) return("Not Ready"); else if (key == 3) return("Medium Error"); else if (key == 4) return("Hardware Error"); else if (key == 5) return("Illegal Request"); else if (key == 6) return("Unit Attention"); else if (key == 7) return("Data Protect"); else if (key == 8) return("No Data"); else if (key == 11) return("Aborted Command"); else if (key == 13) return("Volume Overflow"); else return("Unknown Error"); } static struct scsi_fmt_cdb st_cmd = { 6, 0, 0, 0, 0, 0, 0 }; u_char sensebuf[8]; int stread(dev, buf, size) dev_t dev; char *buf; int size; { register int unit = stunit(dev); register struct st_softc *sc = &st_softc[unit]; register struct scsi_fmt_cdb *cdb = &st_cmd; register int nblk = size >> DEV_BSHIFT; struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf; int ctlr, slave, stat; ctlr = sc->sc_hd->hp_ctlr; slave = sc->sc_hd->hp_slave; cdb->cdb[0] = CMD_READ; cdb->cdb[1] = 1; /* unknown setup */ cdb->cdb[2] = (nblk & 0xff0000) >> 16; cdb->cdb[3] = (nblk & 0x00ff00) >> 8; cdb->cdb[4] = (nblk & 0x0000ff); cdb->cdb[5] = 0; /* unknown setup */ stat = scsi_immed_command(ctlr, slave, 0, cdb, buf, size); if (stat == 0) return(size); else { scsi_request_sense(ctlr, slave, 0, sp, 8); if (stat == STS_CHECKCOND) { printf("stread: Sense Key = [%s]", sense_key(sp->key)); if (sp->filemark) printf(" [EOF]"); if (sp->eom) printf(" [EOM]"); printf("\n"); } return(-1); } } int stwrite(dev, buf, size) dev_t dev; char *buf; int size; { register int unit = stunit(dev); register struct st_softc *sc = &st_softc[unit]; register struct scsi_fmt_cdb *cdb = &st_cmd; struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf; register int nblk; int ctlr, slave, stat; nblk = size >> DEV_BSHIFT; if (size % DEV_BSIZE) nblk++; size = nblk << DEV_BSHIFT; ctlr = sc->sc_hd->hp_ctlr; slave = sc->sc_hd->hp_slave; sc->sc_flags |= STF_WRTTN; cdb->cdb[0] = CMD_WRITE; cdb->cdb[1] = 1; /* unknown setup */ cdb->cdb[2] = (nblk & 0xff0000) >> 16; cdb->cdb[3] = (nblk & 0x00ff00) >> 8; cdb->cdb[4] = (nblk & 0x0000ff); cdb->cdb[5] = 0; /* unknown setup */ stat = scsi_immed_command(ctlr, slave, 0, cdb, buf, size); if (stat == 0) return(size); else { scsi_request_sense(ctlr, slave, 0, sp, 8); if (stat == STS_CHECKCOND) { printf("stwrite: Sense Key = [%s]", sense_key(sp->key)); if (sp->eom) printf(" [EOM]"); printf("\n"); } return(-1); } } int stioctl(dev, cmd, data, flag, p) dev_t dev; int cmd; caddr_t data; int flag; struct proc *p; { } st_rewind(dev) dev_t dev; { register int unit = stunit(dev); register struct st_softc *sc = &st_softc[unit]; register struct scsi_fmt_cdb *cdb = &st_cmd; struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf; int ctlr, slave, stat; int retry = 5; ctlr = sc->sc_hd->hp_ctlr; slave = sc->sc_hd->hp_slave; cdb->cdb[0] = CMD_REWIND; cdb->cdb[1] = 1; /* command finished soon */ cdb->cdb[2] = 0; cdb->cdb[3] = 0; cdb->cdb[4] = 0; cdb->cdb[5] = 0; /* unknown setup */ rewind: stat = scsi_immed_command(ctlr, slave, 0, cdb, (char *) 0, 0); if (stat == 0) { return(1); } else { scsi_request_sense(ctlr, slave, 0, sp, 8); if (stat == STS_CHECKCOND) { printf("st_rewind: Sense Key = [%s]", sense_key(sp->key)); printf("\n"); } if (retry > 0) { DELAY(1000000); retry--; goto rewind; } return(0); } } st_write_EOF(dev) dev_t dev; { register int unit = stunit(dev); register struct st_softc *sc = &st_softc[unit]; register struct scsi_fmt_cdb *cdb = &st_cmd; int ctlr, slave, stat; int marks = 1; ctlr = sc->sc_hd->hp_ctlr; slave = sc->sc_hd->hp_slave; cdb->cdb[0] = CMD_WRITE_FILEMARK; cdb->cdb[1] = 1; /* command finished soon */ cdb->cdb[2] = (marks & 0xff0000) >> 16; cdb->cdb[3] = (marks & 0x00ff00) >> 8; cdb->cdb[4] = (marks & 0x0000ff); cdb->cdb[5] = 0; /* unknown setup */ stat = scsi_immed_command(ctlr, slave, 0, cdb, (char *) 0, 0); if (stat == 0) return(1); printf("st: write EOF error\n"); return(0); } int st_skip(dev) dev_t dev; { register int unit = stunit(dev); register struct st_softc *sc = &st_softc[unit]; register struct scsi_fmt_cdb *cdb = &st_cmd; register int nfmk = 1; struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf; int ctlr, slave, stat; ctlr = sc->sc_hd->hp_ctlr; slave = sc->sc_hd->hp_slave; cdb->cdb[0] = CMD_SPACE; cdb->cdb[1] = 1; /* it mean skip until EOF */ cdb->cdb[2] = (nfmk & 0xff0000) >> 16; cdb->cdb[3] = (nfmk & 0x00ff00) >> 8; cdb->cdb[4] = (nfmk & 0x0000ff); cdb->cdb[5] = 0; /* unknown setup */ stat = scsi_immed_command(ctlr, slave, 0, cdb, 0, 0); if (stat == 0) return(0); else { scsi_request_sense(ctlr, slave, 0, sp, 8); if (stat == STS_CHECKCOND) { printf("st_skip: Sense Key = [%s]", sense_key(sp->key)); if (sp->filemark) printf(" [EOF]"); if (sp->eom) printf(" [EOM]"); printf("\n"); } return(-1); } } /* * Dump */ int stdump(dev) dev_t dev; { }