From nobody@FreeBSD.org Sun Apr 1 05:59:17 2007 Return-Path: Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id E287B16A4D5 for ; Sun, 1 Apr 2007 05:59:17 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (www.freebsd.org [69.147.83.33]) by mx1.freebsd.org (Postfix) with ESMTP id DBC1013C4CE for ; Sun, 1 Apr 2007 05:59:15 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (localhost [127.0.0.1]) by www.freebsd.org (8.13.1/8.13.1) with ESMTP id l315xFm0097901 for ; Sun, 1 Apr 2007 05:59:15 GMT (envelope-from nobody@www.freebsd.org) Received: (from nobody@localhost) by www.freebsd.org (8.13.1/8.13.1/Submit) id l315sE8g097435; Sun, 1 Apr 2007 05:54:14 GMT (envelope-from nobody) Message-Id: <200704010554.l315sE8g097435@www.freebsd.org> Date: Sun, 1 Apr 2007 05:54:14 GMT From: Richard Burton To: freebsd-gnats-submit@FreeBSD.org Subject: [ata] [patch] No support for ahci atapi sata cd/dvd drives X-Send-Pr-Version: www-3.0 >Number: 111084 >Category: kern >Synopsis: [ata] [patch] No support for ahci atapi sata cd/dvd drives (ICH8) >Confidential: no >Severity: non-critical >Priority: medium >Responsible: sos >State: closed >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Sun Apr 01 06:00:12 GMT 2007 >Closed-Date: Mon Nov 19 11:29:41 UTC 2007 >Last-Modified: Mon Nov 19 11:29:41 UTC 2007 >Originator: Richard Burton >Release: 6.2 >Organization: >Environment: FreeBSD bsdloon.local.net 6.2-RELEASE FreeBSD 6.2-RELEASE #17: Mon Mar 26 12:09:28 AKDT 2007 root@bsdloon.local.net:/usr/obj/usr/src/sys/GENERIC i386 >Description: atapi sata drives attached to an intel ich8 controller are not recognized or supported by the freebsd-6.2 ata driver. This was not obvious (at least to me) from the install documentation, but it is obvious when looking at the ata driver source code. The attached patch provides at least basic support for atapi sata cd and dvd drives attached to the ahci intel ich8 controller on my machine. I can read data cds and dvds, write data cds using burncd, and (with atapicam loaded) write cds and dvds using cdrecord and growisofs. Here is dmesg output relevent to the hardware I have created this patch for: atapci0: port 0xfe00-0xfe07,0xfe10-0xfe13,0xfe20 -0xfe27,0xfe30-0xfe33,0xfec0-0xfedf mem 0xff970000-0xff9707ff irq 20 at device 3 1.2 on pci0 atapci0: Reserved 0x20 bytes for rid 0x20 type 4 at 0xfec0 ioapic0: routing intpin 20 (PCI IRQ 20) to vector 55 atapci0: [MPSAFE] atapci0: Reserved 0x800 bytes for rid 0x24 type 3 at 0xff970000 atapci0: AHCI Version 01.10 controller with 6 ports detected ata2: on atapci0 ata2: SATA connect ready time=0ms ata2: sata_connect devices=0x1 ata2: [MPSAFE] ata3: on atapci0 ata3: SATA connect ready time=0ms ata3: sata_connect devices=0x4 ata3: [MPSAFE] ata4: on atapci0 ata4: SATA connect ready time=0ms ata4: sata_connect devices=0x4 ata4: [MPSAFE] ata5: on atapci0 ata5: SATA connect ready time=0ms ata5: sata_connect devices=0x1 ata5: [MPSAFE] ata6: on atapci0 ata6: SATA connect status=00000004 ata6: [MPSAFE] ata7: on atapci0 ata7: SATA connect status=00000004 ata7: [MPSAFE] .. ata2-master: pio=PIO4 wdma=WDMA2 udma=UDMA133 cable=40 wire ad4: 152587MB at ata2-master SATA300 ad4: 312500000 sectors [310019C/16H/63S] 16 sectors/interrupt 1 depth queue GEOM: new disk ad4 ad4: Intel check1 failed ad4: Adaptec check1 failed ad4: LSI (v3) check1 failed ad4: LSI (v2) check1 failed ad4: FreeBSD check1 failed ata3-master: pio=PIO4 wdma=WDMA2 udma=UDMA100 cable=40 wire acd0: DVDROM drive at ata3 as master acd0: read 1KB/s (8251KB/s), 512KB buffer, SATA150 acd0: Reads: CDR, CDRW, CDDA stream, DVDROM, DVDR, packet acd0: Writes: acd0: Audio: play, 256 volume levels acd0: Mechanism: ejectable tray, unlocked acd0: Medium: no/blank disc ata4-master: pio=PIO4 wdma=WDMA2 udma=UDMA33 cable=40 wire acd1: DVDR drive at ata4 as master acd1: read 8269KB/s (8269KB/s) write 8269KB/s (8269KB/s), 2048KB buffer, SATA150 acd1: Reads: CDR, CDRW, CDDA stream, DVDROM, DVDR, packet acd1: Writes: CDR, CDRW, DVDR, test write, burnproof acd1: Audio: play, 256 volume levels acd1: Mechanism: ejectable tray, unlocked acd1: Medium: no/blank disc ata5-master: pio=PIO4 wdma=WDMA2 udma=UDMA133 cable=40 wire ad10: 476940MB at ata5-master SATA300 ad10: 976773168 sectors [969021C/16H/63S] 16 sectors/interrupt 1 depth queue ad10: Intel check1 failed GEOM: new disk ad10 ad10: Adaptec check1 failed ad10: LSI (v3) check1 failed ad10: LSI (v2) check1 failed ad10: FreeBSD check1 failed This patch is to the 6.2-RELEASE source. Sorry, I don't have a FreeBsd-Current system installed. I can see that some of these changes (i.e. the atapi fis structure) are included in a slightly different form there. However, other changes that I found necessary do not seem to be included yet. >How-To-Repeat: >Fix: Patch attached with submission follows: --- dev/ata/ata-chipset.c.orig Mon Oct 9 08:01:35 2006 +++ dev/ata/ata-chipset.c Mon Mar 26 12:03:11 2007 @@ -68,6 +68,8 @@ static void ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); static void ata_ahci_dmainit(device_t dev); static int ata_ahci_setup_fis(u_int8_t *fis, struct ata_request *request); +/* rgb add engine restart */ +static void ata_ahci_restart_engine(device_t dev); static int ata_acard_chipinit(device_t dev); static int ata_acard_allocate(device_t dev); static int ata_acard_status(device_t dev); @@ -452,7 +454,7 @@ /* setup legacy cruft we need */ ch->r_io[ATA_CYL_LSB].res = ctlr->r_res2; - ch->r_io[ATA_CYL_LSB].offset = ATA_AHCI_P_SIG + 1 + offset; + ch->r_io[ATA_CYL_LSB].offset = ATA_AHCI_P_SIG + 2 + offset; ch->r_io[ATA_CYL_MSB].res = ctlr->r_res2; ch->r_io[ATA_CYL_MSB].offset = ATA_AHCI_P_SIG + 3 + offset; ch->r_io[ATA_STATUS].res = ctlr->r_res2; @@ -493,7 +495,14 @@ ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR)); /* start operations on this channel */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, + /* rgb - add ATAPI cmd */ + if (ch->devices & ATA_ATAPI_MASTER) + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, + (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE | + ATA_AHCI_P_CMD_ATAPI | + ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | ATA_AHCI_P_CMD_ST)); + else + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | ATA_AHCI_P_CMD_ST)); return 0; @@ -506,6 +515,9 @@ struct ata_channel *ch = device_get_softc(dev); struct ata_connect_task *tp; u_int32_t action, istatus, sstatus, error, issued; + /* rgb - add tfd_data */ + u_int32_t tf_data; + /* end rgb additions */ int offset = (ch->unit << 7); int tag = 0; @@ -558,8 +570,24 @@ } /* do we have any device action ? */ - if (!(issued & (1 << tag))) + if (!(issued & (1 << tag))) return 1; + + /* rgb - check for error - This is necessary for atapi + code to work, and it seems to also prevent + occasional disk timeouts that sometimes cause + boot to fail + */ + tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset); + if (tf_data & ATA_S_ERROR) { + if ((tf_data & ATA_S_BUSY) || (tf_data & ATA_S_DRQ)) + return 0; /* for now, let timeout do reset */ + else { + /* restart engine to clear ATA_AHCI_P_CI */ + ata_ahci_restart_engine(ch->dev); + return 1; + } + } } return 0; } @@ -579,6 +607,14 @@ ctp = (struct ata_ahci_cmd_tab *) (ch->dma->work + ATA_AHCI_CT_OFFSET + (ATA_AHCI_CT_SIZE * tag)); + /* rgb - if ATAPI request moves data, make it dma */ + if (request->flags & ATA_R_ATAPI) { + if (request->bytecount && !(request->flags & ATA_R_READ)) + request->flags |= ATA_R_WRITE; + if (request->flags & (ATA_R_READ | ATA_R_WRITE)) + request->flags |= ATA_R_DMA; + } + /* setup the FIS for this request */ /* XXX SOS ATAPI missing still */ if (!(fis_size = ata_ahci_setup_fis(&ctp->cfis[0], request))) { device_printf(request->dev, "setting up SATA FIS failed\n"); @@ -604,10 +640,17 @@ clp->prd_length = entries; clp->cmd_flags = (request->flags & ATA_R_WRITE ? (1<<6) : 0) | (request->flags & ATA_R_ATAPI ? (1<<5) : 0) | +/* rgb - set prefetch flag if ATAPI */ + (request->flags & ATA_R_ATAPI ? (1<<7) : 0) | (fis_size / sizeof(u_int32_t)); clp->bytecount = 0; clp->cmd_table_phys = htole64(ch->dma->work_bus + ATA_AHCI_CT_OFFSET + (ATA_AHCI_CT_SIZE * tag)); + /* rgb - add atapi request */ + if (request->flags & ATA_R_ATAPI) { + bzero(ctp->acmd, 32); + bcopy(request->u.atapi.ccb, ctp->acmd, 16); + } /* clear eventual ACTIVE bit */ ATA_IDX_OUTL(ch, ATA_SACTIVE, ATA_IDX_INL(ch, ATA_SACTIVE) & (1 << tag)); @@ -615,6 +658,28 @@ /* issue the command */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + (ch->unit << 7), (1 << tag)); + /* rgb - handle ATA_DEVICE_RESET requests */ + if (!(request->flags & ATA_R_ATAPI)) { + if (request->u.ata.command == ATA_DEVICE_RESET) { + u_int32_t tf_data; + int timeout = 1000000; + do { + DELAY(10); + tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + (ch->unit << 7)); + } while (tf_data & ATA_S_BUSY && timeout--); + request->status = tf_data; + if (timeout <= 0) { + device_printf(request->dev, "ATA_DEVICE_RESET timeout\n"); + /* should probably do softreset */ + } + if (request->status & ATA_S_ERROR) { + request->error = tf_data >> 8; + ata_ahci_restart_engine(ch->dev); + } + return ATA_OP_FINISHED; + } + } + /* start the timeout */ callout_reset(&request->callout, request->timeout * hz, (timeout_t*)ata_timeout, request); @@ -653,6 +718,36 @@ return ATA_OP_FINISHED; } +/* rgb add ahci_restart_engine */ +static void +ata_ahci_restart_engine(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(dev); + int tmp, offset = (ch->unit <<7); + int timeout = 0; + + /* stop engine */ + tmp = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); + tmp &= ~ATA_AHCI_P_CMD_ST; + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, tmp); + do { + DELAY (1000); + if (timeout++ >500) { + device_printf(ch->dev, "stopping AHCI engine failed\n"); + break; + } + } + while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & + ATA_AHCI_P_CMD_CR); + + /* restart engine */ + tmp = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); + tmp |= ATA_AHCI_P_CMD_ST; + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, tmp); +} + + static void ata_ahci_reset(device_t dev) { @@ -701,7 +796,14 @@ ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset)); /* start operations on this channel */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, + /* rgb - add ATAPI cmd */ + if (ch->devices & ATA_ATAPI_MASTER) + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, + (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE | + ATA_AHCI_P_CMD_ATAPI | + ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | ATA_AHCI_P_CMD_ST)); + else + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | ATA_AHCI_P_CMD_ST)); } @@ -746,6 +848,11 @@ fis[idx++] = 0x27; /* host to device */ fis[idx++] = 0x80; /* command FIS (note PM goes here) */ + + /* rgb - add atapi request */ + switch (request->flags & ATA_R_ATAPI) { + + default: fis[idx++] = request->u.ata.command; fis[idx++] = request->u.ata.feature; @@ -772,6 +879,40 @@ fis[idx++] = 0x00; fis[idx++] = 0x00; fis[idx++] = 0x00; + break; + + case ATA_R_ATAPI: + fis[idx++] = ATA_PACKET_CMD; + if (request->flags & ATA_R_DMA) { + fis[idx++] = ATA_F_DMA; + fis[idx++] = 0x00; + fis[idx++] = 0x00; + fis[idx++] = 0x00; + } + else { + fis[idx++] = 0x00; + fis[idx++] = 0x00; + fis[idx++] = request->transfersize; + fis[idx++] = request->transfersize >> 8; + } + fis[idx++] = atadev->unit; + + fis[idx++] = 0x00; + fis[idx++] = 0x00; + fis[idx++] = 0x00; + fis[idx++] = 0x00; + fis[idx++] = 0x00; + fis[idx++] = 0x00; + fis[idx++] = 0x00; + fis[idx++] = ATA_A_4BIT; + + fis[idx++] = 0x00; + fis[idx++] = 0x00; + fis[idx++] = 0x00; + fis[idx++] = 0x00; + break; + } + return idx; } --- dev/ata/atapi-cd.c.orig Sat Sep 2 09:01:32 2006 +++ dev/ata/atapi-cd.c Wed Mar 21 20:48:42 2007 @@ -699,7 +699,10 @@ request->dev = dev; bcopy(ccb, request->u.atapi.ccb, 16); request->flags = ATA_R_ATAPI; + /* rgb - up timeout to 10 request->timeout = 5; + */ + request->timeout = 10; ata_queue_request(request); if (!request->error && (request->u.atapi.sense.key == 2 || @@ -1234,7 +1237,10 @@ request->flags = ATA_R_ATAPI | ATA_R_READ; request->timeout = 30; ata_queue_request(request); +/* rgb - fix for pr 109270 from Martin Birgmeier if (!request->error && request->u.atapi.sense.error & ATA_SENSE_VALID) +*/ + if (!request->error && request->u.atapi.sense.specific & ATA_SENSE_SPEC_VALID) *finished = ((request->u.atapi.sense.specific2 | (request->u.atapi.sense.specific1 << 8)) * 100) / 65535; else >Release-Note: >Audit-Trail: Responsible-Changed-From-To: freebsd-bugs->sos Responsible-Changed-By: linimon Responsible-Changed-When: Sun Apr 1 11:14:30 UTC 2007 Responsible-Changed-Why: Over to maintainer. http://www.freebsd.org/cgi/query-pr.cgi?pr=111084 State-Changed-From-To: open->closed State-Changed-By: sos State-Changed-When: Mon Nov 19 11:27:59 UTC 2007 State-Changed-Why: SATA ATAPI support has been committed to both rel6, rel7, and current. In a different shape than this patch though. http://www.freebsd.org/cgi/query-pr.cgi?pr=111084 >Unformatted: