summaryrefslogtreecommitdiff
path: root/sys/dev/ata/atascsi.c
diff options
context:
space:
mode:
authorChristopher Pascoe <pascoe@cvs.openbsd.org>2007-03-20 12:01:19 +0000
committerChristopher Pascoe <pascoe@cvs.openbsd.org>2007-03-20 12:01:19 +0000
commit5eb2ced892a32a85dd7a55cd1ac62b1f93a3587f (patch)
tree5d8a9004ddd83b45b2827b08f545dce8a99580d3 /sys/dev/ata/atascsi.c
parent13ed7c51079a96587a67b924a6b68c2c2b35d842 (diff)
Add support for ATA PACKET commands. This should make ATAPI cdrom drives,
etc, just work.
Diffstat (limited to 'sys/dev/ata/atascsi.c')
-rw-r--r--sys/dev/ata/atascsi.c106
1 files changed, 101 insertions, 5 deletions
diff --git a/sys/dev/ata/atascsi.c b/sys/dev/ata/atascsi.c
index ac79c64e72c..c0757cedd8b 100644
--- a/sys/dev/ata/atascsi.c
+++ b/sys/dev/ata/atascsi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: atascsi.c,v 1.22 2007/03/20 11:07:02 dlg Exp $ */
+/* $OpenBSD: atascsi.c,v 1.23 2007/03/20 12:01:18 pascoe Exp $ */
/*
* Copyright (c) 2007 David Gwynne <dlg@openbsd.org>
@@ -75,6 +75,7 @@ int atascsi_disk_sync(struct scsi_xfer *);
int atascsi_disk_sense(struct scsi_xfer *);
int atascsi_atapi_cmd(struct scsi_xfer *);
+void atascsi_atapi_cmd_done(struct ata_xfer *);
int atascsi_stuffup(struct scsi_xfer *);
@@ -147,8 +148,16 @@ atascsi_probe(struct atascsi *as, int port)
return (ENXIO);
type = as->as_methods->probe(as->as_cookie, port);
- if (type != ATA_PORT_T_DISK) /* XXX ATAPI too one day */
- return (ENXIO);
+ switch (type) {
+ case ATA_PORT_T_DISK:
+ break;
+ case ATA_PORT_T_ATAPI:
+ as->as_link.flags |= SDEV_ATAPI;
+ as->as_link.quirks |= SDEV_ONLYBIG;
+ break;
+ default:
+ return (ENODEV);
+ }
ap = malloc(sizeof(struct ata_port), M_DEVBUF, M_WAITOK);
ap->ap_as = as;
@@ -528,11 +537,98 @@ atascsi_disk_sense(struct scsi_xfer *xs)
return (COMPLETE);
}
-
int
atascsi_atapi_cmd(struct scsi_xfer *xs)
{
- return (atascsi_stuffup(xs));
+ struct scsi_link *link = xs->sc_link;
+ struct atascsi *as = link->adapter_softc;
+ struct ata_port *ap = as->as_ports[link->target];
+ int s;
+ struct ata_xfer *xa;
+ u_int8_t *regs;
+
+ s = splbio();
+ xa = ata_get_xfer(ap, xs->flags & SCSI_NOSLEEP);
+ splx(s);
+ if (xa == NULL)
+ return (NO_CCB);
+
+ switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
+ case SCSI_DATA_IN:
+ xa->flags = ATA_F_READ | ATA_F_PACKET;
+ break;
+ case SCSI_DATA_OUT:
+ xa->flags = ATA_F_WRITE | ATA_F_PACKET;
+ break;
+ }
+
+ xa->data = xs->data;
+ xa->datalen = xs->datalen;
+ xa->complete = atascsi_atapi_cmd_done;
+ xa->timeout = xs->timeout;
+ xa->atascsi_private = xs;
+ if (xs->flags & SCSI_POLL)
+ xa->flags |= ATA_F_POLL;
+
+ regs = xa->cmd.tx->regs;
+ regs[H2D_DEVCTL_OR_COMMAND] = H2D_DEVCTL_OR_COMMAND_COMMAND;
+ regs[H2D_COMMAND] = ATA_C_PACKET;
+ regs[SECTOR_COUNT] = xa->cmd.tag << 3;
+ regs[H2D_FEATURES] = 0x01 /* DMA */ |
+ ((xa->flags & ATA_F_WRITE) ? 0x00 : 0x04) /* direction */;
+ regs[LBA_MID] = 0x00; /* byte count low */
+ regs[LBA_HIGH] = 0x20; /* byte count high, limit to 8K per data FIS */
+
+ /* Copy SCSI command into ATAPI packet. */
+ memcpy(xa->cmd.packetcmd, xs->cmd, xs->cmdlen);
+
+ switch (ata_exec(as, xa)) {
+ case ATA_COMPLETE:
+ case ATA_ERROR:
+ return (COMPLETE);
+ case ATA_QUEUED:
+ return (SUCCESSFULLY_QUEUED);
+ default:
+ panic("unexpected return from ata_exec");
+ }
+}
+
+void
+atascsi_atapi_cmd_done(struct ata_xfer *xa)
+{
+ struct scsi_xfer *xs = xa->atascsi_private;
+ struct scsi_sense_data *sd = &xs->sense;
+
+ switch (xa->state) {
+ case ATA_S_COMPLETE:
+ xs->error = XS_NOERROR;
+ break;
+ case ATA_S_ERROR:
+ /* Return PACKET sense data */
+ sd->error_code = SSD_ERRCODE_CURRENT;
+ sd->flags = (xa->cmd.rx_err.regs[D2H_ERROR] & 0xf0) >> 4;
+ if (xa->cmd.rx_err.regs[D2H_ERROR] & 0x04)
+ sd->flags = SKEY_ILLEGAL_REQUEST;
+ if (xa->cmd.rx_err.regs[D2H_ERROR] & 0x02)
+ sd->flags |= SSD_EOM;
+ if (xa->cmd.rx_err.regs[D2H_ERROR] & 0x01)
+ sd->flags |= SSD_ILI;
+ xs->error = XS_SENSE;
+ break;
+ case ATA_S_TIMEOUT:
+ printf("atascsi_atapi_cmd_done, timeout\n");
+ xs->error = XS_TIMEOUT;
+ break;
+ default:
+ panic("atascsi_atapi_cmd_done: unexpected ata_xfer state (%d)",
+ xa->state);
+ }
+
+ xs->resid = xa->resid;
+ ata_put_xfer(xa);
+
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
}
int