diff options
Diffstat (limited to 'sys/scsi/cd.c')
-rw-r--r-- | sys/scsi/cd.c | 118 |
1 files changed, 66 insertions, 52 deletions
diff --git a/sys/scsi/cd.c b/sys/scsi/cd.c index 0121681ae20..c75805af618 100644 --- a/sys/scsi/cd.c +++ b/sys/scsi/cd.c @@ -1,4 +1,4 @@ -/* $NetBSD: cd.c,v 1.82 1996/02/14 21:46:52 christos Exp $ */ +/* $NetBSD: cd.c,v 1.90 1996/03/30 21:44:50 christos Exp $ */ /* * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. @@ -63,14 +63,14 @@ #include <sys/cdio.h> #include <sys/proc.h> #include <sys/cpu.h> +#include <sys/conf.h> #include <scsi/scsi_all.h> #include <scsi/scsi_cd.h> #include <scsi/scsi_disk.h> /* rw_big and start_stop come from there */ #include <scsi/scsiconf.h> -#include <scsi/scsi_conf.h> -#define CDOUTSTANDING 2 +#define CDOUTSTANDING 4 #define CDRETRIES 1 #define CDUNIT(z) DISKUNIT(z) @@ -86,6 +86,7 @@ struct cd_softc { #define CDF_WANTED 0x02 #define CDF_WLABEL 0x04 /* label is writable */ #define CDF_LABELLING 0x08 /* writing label */ +#define CDF_ANCIENT 0x10 /* disk is ancient; for minphys */ struct scsi_link *sc_link; /* contains our targ, lun, etc. */ struct cd_parms { int blksize; @@ -117,8 +118,12 @@ int cd_read_toc __P((struct cd_softc *, int, int, struct cd_toc_entry *, int )); int cd_get_parms __P((struct cd_softc *, int)); -struct cfdriver cdcd = { - NULL, "cd", cdmatch, cdattach, DV_DISK, sizeof(struct cd_softc) +struct cfattach cd_ca = { + sizeof(struct cd_softc), cdmatch, cdattach +}; + +struct cfdriver cd_cd = { + NULL, "cd", DV_DISK }; struct dkdriver cddkdriver = { cdstrategy }; @@ -184,10 +189,16 @@ cdattach(parent, self, aux) cd->sc_dk.dk_name = cd->sc_dev.dv_xname; disk_attach(&cd->sc_dk); -#if !defined(i386) || defined(NEWCONFIG) +#if !defined(i386) dk_establish(&cd->sc_dk, &cd->sc_dev); /* XXX */ #endif + /* + * Note if this device is ancient. This is used in cdminphys(). + */ + if ((sa->sa_inqbuf->version & SID_ANSII) == 0) + cd->flags |= CDF_ANCIENT; + printf("\n"); } @@ -242,9 +253,9 @@ cdopen(dev, flag, fmt, p) int error; unit = CDUNIT(dev); - if (unit >= cdcd.cd_ndevs) + if (unit >= cd_cd.cd_ndevs) return ENXIO; - cd = cdcd.cd_devs[unit]; + cd = cd_cd.cd_devs[unit]; if (!cd) return ENXIO; @@ -252,7 +263,7 @@ cdopen(dev, flag, fmt, p) SC_DEBUG(sc_link, SDEV_DB1, ("cdopen: dev=0x%x (unit %d (of %d), partition %d)\n", dev, unit, - cdcd.cd_ndevs, part)); + cd_cd.cd_ndevs, part)); if ((error = cdlock(cd)) != 0) return error; @@ -357,7 +368,7 @@ cdclose(dev, flag, fmt, p) int flag, fmt; struct proc *p; { - struct cd_softc *cd = cdcd.cd_devs[CDUNIT(dev)]; + struct cd_softc *cd = cd_cd.cd_devs[CDUNIT(dev)]; int part = CDPART(dev); int error; @@ -395,7 +406,7 @@ void cdstrategy(bp) struct buf *bp; { - struct cd_softc *cd = cdcd.cd_devs[CDUNIT(bp->b_dev)]; + struct cd_softc *cd = cd_cd.cd_devs[CDUNIT(bp->b_dev)]; int opri; SC_DEBUG(cd->sc_link, SDEV_DB2, ("cdstrategy ")); @@ -549,9 +560,7 @@ cdstart(v) bzero(&cmd_small, sizeof(cmd_small)); cmd_small.opcode = (bp->b_flags & B_READ) ? READ_COMMAND : WRITE_COMMAND; - cmd_small.addr_2 = (blkno >> 16) & 0x1f; - cmd_small.addr_1 = (blkno >> 8) & 0xff; - cmd_small.addr_0 = blkno & 0xff; + _lto3b(blkno, cmd_small.addr); cmd_small.length = nblks & 0xff; cmdlen = sizeof(cmd_small); cmdp = (struct scsi_generic *)&cmd_small; @@ -562,12 +571,8 @@ cdstart(v) bzero(&cmd_big, sizeof(cmd_big)); cmd_big.opcode = (bp->b_flags & B_READ) ? READ_BIG : WRITE_BIG; - cmd_big.addr_3 = (blkno >> 24) & 0xff; - cmd_big.addr_2 = (blkno >> 16) & 0xff; - cmd_big.addr_1 = (blkno >> 8) & 0xff; - cmd_big.addr_0 = blkno & 0xff; - cmd_big.length2 = (nblks >> 8) & 0xff; - cmd_big.length1 = nblks & 0xff; + _lto4b(blkno, cmd_big.addr); + _lto2b(nblks, cmd_big.length); cmdlen = sizeof(cmd_big); cmdp = (struct scsi_generic *)&cmd_big; } @@ -600,16 +605,42 @@ cddone(xs, complete) return (0); } +void +cdminphys(bp) + struct buf *bp; +{ + struct cd_softc *cd = cd_cd.cd_devs[CDUNIT(bp->b_dev)]; + long max; + + /* + * If the device is ancient, we want to make sure that + * the transfer fits into a 6-byte cdb. + * + * XXX Note that the SCSI-I spec says that 256-block transfers + * are allowed in a 6-byte read/write, and are specified + * by settng the "length" to 0. However, we're conservative + * here, allowing only 255-block transfers in case an + * ancient device gets confused by length == 0. A length of 0 + * in a 10-byte read/write actually means 0 blocks. + */ + if (cd->flags & CDF_ANCIENT) { + max = cd->sc_dk.dk_label->d_secsize * 0xff; + + if (bp->b_bcount > max) + bp->b_bcount = max; + } + + (*cd->sc_link->adapter->scsi_minphys)(bp); +} + int cdread(dev, uio, ioflag) dev_t dev; struct uio *uio; int ioflag; { - struct cd_softc *cd = cdcd.cd_devs[CDUNIT(dev)]; - return (physio(cdstrategy, NULL, dev, B_READ, - cd->sc_link->adapter->scsi_minphys, uio)); + return (physio(cdstrategy, NULL, dev, B_READ, cdminphys, uio)); } int @@ -618,10 +649,8 @@ cdwrite(dev, uio, ioflag) struct uio *uio; int ioflag; { - struct cd_softc *cd = cdcd.cd_devs[CDUNIT(dev)]; - return (physio(cdstrategy, NULL, dev, B_WRITE, - cd->sc_link->adapter->scsi_minphys, uio)); + return (physio(cdstrategy, NULL, dev, B_WRITE, cdminphys, uio)); } /* @@ -636,7 +665,7 @@ cdioctl(dev, cmd, addr, flag, p) int flag; struct proc *p; { - struct cd_softc *cd = cdcd.cd_devs[CDUNIT(dev)]; + struct cd_softc *cd = cd_cd.cd_devs[CDUNIT(dev)]; int error; SC_DEBUG(cd->sc_link, SDEV_DB2, ("cdioctl 0x%lx ", cmd)); @@ -730,9 +759,8 @@ cdioctl(dev, cmd, addr, flag, p) &data, len); if (error) return error; - len = min(len, ((data.header.data_len[0] << 8) + - data.header.data_len[1] + - sizeof(struct cd_sub_channel_header))); + len = min(len, _2btol(data.header.data_len) + + sizeof(struct cd_sub_channel_header)); return copyout(&data, args->data, len); } case CDIOREADTOCHEADER: { @@ -968,14 +996,12 @@ cd_size(cd, flags) 2000, NULL, flags | SCSI_DATA_IN) != 0) return 0; - blksize = (rdcap.length_3 << 24) + (rdcap.length_2 << 16) + - (rdcap.length_1 << 8) + rdcap.length_0; + blksize = _4btol(rdcap.length); if (blksize < 512) blksize = 2048; /* some drives lie ! */ cd->params.blksize = blksize; - size = (rdcap.addr_3 << 24) + (rdcap.addr_2 << 16) + - (rdcap.addr_1 << 8) + rdcap.addr_0 + 1; + size = _4btol(rdcap.addr) + 1; if (size < 100) size = 400000; /* ditto */ cd->params.disksize = size; @@ -1036,12 +1062,8 @@ cd_play(cd, blkno, nblks) bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.opcode = PLAY; - scsi_cmd.blk_addr[0] = (blkno >> 24) & 0xff; - scsi_cmd.blk_addr[1] = (blkno >> 16) & 0xff; - scsi_cmd.blk_addr[2] = (blkno >> 8) & 0xff; - scsi_cmd.blk_addr[3] = blkno & 0xff; - scsi_cmd.xfer_len[0] = (nblks >> 8) & 0xff; - scsi_cmd.xfer_len[1] = nblks & 0xff; + _lto4b(blkno, scsi_cmd.blk_addr); + _lto2b(nblks, scsi_cmd.xfer_len); return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd), 0, 0, CDRETRIES, 200000, NULL, 0); } @@ -1058,14 +1080,8 @@ cd_play_big(cd, blkno, nblks) bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.opcode = PLAY_BIG; - scsi_cmd.blk_addr[0] = (blkno >> 24) & 0xff; - scsi_cmd.blk_addr[1] = (blkno >> 16) & 0xff; - scsi_cmd.blk_addr[2] = (blkno >> 8) & 0xff; - scsi_cmd.blk_addr[3] = blkno & 0xff; - scsi_cmd.xfer_len[0] = (nblks >> 24) & 0xff; - scsi_cmd.xfer_len[1] = (nblks >> 16) & 0xff; - scsi_cmd.xfer_len[2] = (nblks >> 8) & 0xff; - scsi_cmd.xfer_len[3] = nblks & 0xff; + _lto4b(blkno, scsi_cmd.blk_addr); + _lto4b(nblks, scsi_cmd.xfer_len); return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd), 0, 0, CDRETRIES, 20000, NULL, 0); } @@ -1159,8 +1175,7 @@ cd_read_subchannel(cd, mode, format, track, data, len) scsi_cmd.byte3 = SRS_SUBQ; scsi_cmd.subchan_format = format; scsi_cmd.track = track; - scsi_cmd.data_len[0] = (len >> 8) & 0xff; - scsi_cmd.data_len[1] = len & 0xff; + _lto2b(len, scsi_cmd.data_len); return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd, sizeof(struct scsi_read_subchannel), (u_char *)data, len, CDRETRIES, 5000, NULL, SCSI_DATA_IN); @@ -1187,8 +1202,7 @@ cd_read_toc(cd, mode, start, data, len) if (mode == CD_MSF_FORMAT) scsi_cmd.byte2 |= CD_MSF; scsi_cmd.from_track = start; - scsi_cmd.data_len[0] = (ntoc >> 8) & 0xff; - scsi_cmd.data_len[1] = ntoc & 0xff; + _lto2b(ntoc, scsi_cmd.data_len); return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd, sizeof(struct scsi_read_toc), (u_char *)data, len, CDRETRIES, 5000, NULL, SCSI_DATA_IN); |