summaryrefslogtreecommitdiff
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
parent13ed7c51079a96587a67b924a6b68c2c2b35d842 (diff)
Add support for ATA PACKET commands. This should make ATAPI cdrom drives,
etc, just work.
-rw-r--r--sys/dev/ata/atascsi.c106
-rw-r--r--sys/dev/ata/atascsi.h6
-rw-r--r--sys/dev/pci/ahci.c7
3 files changed, 112 insertions, 7 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
diff --git a/sys/dev/ata/atascsi.h b/sys/dev/ata/atascsi.h
index c475a35e951..8b407427e82 100644
--- a/sys/dev/ata/atascsi.h
+++ b/sys/dev/ata/atascsi.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: atascsi.h,v 1.15 2007/03/20 11:07:02 dlg Exp $ */
+/* $OpenBSD: atascsi.h,v 1.16 2007/03/20 12:01:18 pascoe Exp $ */
/*
* Copyright (c) 2007 David Gwynne <dlg@openbsd.org>
@@ -27,6 +27,7 @@ struct atascsi;
#define ATA_C_WRITEDMA 0xca
#define ATA_C_READDMA_EXT 0x25
#define ATA_C_WRITEDMA_EXT 0x35
+#define ATA_C_PACKET 0xa0
struct ata_identify {
u_int16_t config; /* 0 */
@@ -180,6 +181,8 @@ struct ata_regs {
struct ata_cmd {
struct ata_regs *tx;
struct ata_regs rx_err;
+ u_int8_t *packetcmd;
+ u_int8_t tag;
u_int8_t st_bmask;
u_int8_t st_pmask;
@@ -201,6 +204,7 @@ struct ata_xfer {
#define ATA_F_NOWAIT (1<<2)
#define ATA_F_POLL (1<<3)
#define ATA_F_PIO (1<<4)
+#define ATA_F_PACKET (1<<5)
volatile int state;
#define ATA_S_SETUP 0
#define ATA_S_PENDING 1
diff --git a/sys/dev/pci/ahci.c b/sys/dev/pci/ahci.c
index 7a95fba59c8..c9348a07403 100644
--- a/sys/dev/pci/ahci.c
+++ b/sys/dev/pci/ahci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ahci.c,v 1.86 2007/03/20 11:22:40 pascoe Exp $ */
+/* $OpenBSD: ahci.c,v 1.87 2007/03/20 12:01:18 pascoe Exp $ */
/*
* Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
@@ -869,6 +869,8 @@ nomem:
ccb->ccb_cmd_hdr->ctba_lo = htole32((u_int32_t)dva);
ccb->ccb_xa.cmd.tx = (struct ata_regs *)ccb->ccb_cmd_table->cfis;
+ ccb->ccb_xa.cmd.packetcmd = ccb->ccb_cmd_table->acmd;
+ ccb->ccb_xa.cmd.tag = i;
ccb->ccb_xa.ata_put_xfer = ahci_ata_put_xfer;
@@ -1781,6 +1783,9 @@ ahci_ata_cmd(struct ata_xfer *xa)
if (xa->flags & ATA_F_WRITE)
cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_W);
+ if (xa->flags & ATA_F_PACKET)
+ cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_A);
+
if (ahci_load_prdt(ccb) != 0)
goto failcmd;