diff options
author | Christopher Pascoe <pascoe@cvs.openbsd.org> | 2007-03-20 12:01:19 +0000 |
---|---|---|
committer | Christopher Pascoe <pascoe@cvs.openbsd.org> | 2007-03-20 12:01:19 +0000 |
commit | 5eb2ced892a32a85dd7a55cd1ac62b1f93a3587f (patch) | |
tree | 5d8a9004ddd83b45b2827b08f545dce8a99580d3 | |
parent | 13ed7c51079a96587a67b924a6b68c2c2b35d842 (diff) |
Add support for ATA PACKET commands. This should make ATAPI cdrom drives,
etc, just work.
-rw-r--r-- | sys/dev/ata/atascsi.c | 106 | ||||
-rw-r--r-- | sys/dev/ata/atascsi.h | 6 | ||||
-rw-r--r-- | sys/dev/pci/ahci.c | 7 |
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; |