summaryrefslogtreecommitdiff
path: root/sys/scsi/cd.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/scsi/cd.c')
-rw-r--r--sys/scsi/cd.c118
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);