From owner-freebsd-stable@FreeBSD.ORG Mon Nov 5 23:19:46 2007 Return-Path: Delivered-To: freebsd-stable@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 2A0E016A417 for ; Mon, 5 Nov 2007 23:19:46 +0000 (UTC) (envelope-from delphij@delphij.net) Received: from tarsier.geekcn.org (tarsier.geekcn.org [210.51.165.229]) by mx1.freebsd.org (Postfix) with ESMTP id 5CB5513C48D for ; Mon, 5 Nov 2007 23:19:43 +0000 (UTC) (envelope-from delphij@delphij.net) Received: from localhost (tarsier.geekcn.org [210.51.165.229]) by tarsier.geekcn.org (Postfix) with ESMTP id 2DF67EC3D80; Tue, 6 Nov 2007 07:19:35 +0800 (CST) X-Virus-Scanned: amavisd-new at geekcn.org Received: from tarsier.geekcn.org ([210.51.165.229]) by localhost (mail.geekcn.org [210.51.165.229]) (amavisd-new, port 10024) with ESMTP id 3slcLzkX+ZHm; Tue, 6 Nov 2007 07:19:27 +0800 (CST) Received: from charlie.delphij.net (71.5.7.139.ptr.us.xo.net [71.5.7.139]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by tarsier.geekcn.org (Postfix) with ESMTP id 0841AEB1450; Tue, 6 Nov 2007 07:19:24 +0800 (CST) DomainKey-Signature: a=rsa-sha1; s=default; d=delphij.net; c=nofws; q=dns; h=message-id:date:from:reply-to:organization:user-agent: mime-version:to:subject:x-enigmail-version:content-type; b=X3WW6jgHZKaI3/8aSixCjRAU9EdVTUYPwqygoUxnwDl89feDIJzQR7MlxqTNPIFDJ Kt6A/B8BqAO/A6nrRUXkg== Message-ID: <472FA4EE.9070405@delphij.net> Date: Mon, 05 Nov 2007 15:19:10 -0800 From: Xin LI Organization: The FreeBSD Project User-Agent: Thunderbird 2.0.0.6 (X11/20071031) MIME-Version: 1.0 To: freebsd-stable@FreeBSD.org X-Enigmail-Version: 0.95.5 Content-Type: multipart/mixed; boundary="------------000505030308030107050800" Cc: Subject: [CFT] Sync RELENG_6 ata(4) with -CURRENT state X-BeenThere: freebsd-stable@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: d@delphij.net List-Id: Production branch of FreeBSD source code List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 05 Nov 2007 23:19:46 -0000 This is a multi-part message in MIME format. --------------000505030308030107050800 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi, Here is a patch that brings RELENG_6 ata(4) code with all applicable - -CURRENT changes (mostly to support newer devices and some minor bugfixes that were not MFC'ed yet). Please let me know if there is any breakage, thanks! Cheers, - -- Xin LI http://www.delphij.net/ FreeBSD - The Power to Serve! -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (FreeBSD) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFHL6TthcUczkLqiksRAm7gAKCVZ4wl+I4197BZeTo6koIx7s3tvwCffvfv CvhrcJSMcL+SQUotLfA36QE= =vkTw -----END PGP SIGNATURE----- --------------000505030308030107050800 Content-Type: text/x-patch; name="ata.diff" Content-Transfer-Encoding: 8bit Content-Disposition: inline; filename="ata.diff" Index: ata-all.c =================================================================== RCS file: /home/ncvs/src/sys/dev/ata/ata-all.c,v retrieving revision 1.252.2.11 diff -p -u -r1.252.2.11 ata-all.c --- ata-all.c 30 Sep 2006 14:51:48 -0000 1.252.2.11 +++ ata-all.c 5 Nov 2007 23:13:17 -0000 @@ -743,7 +743,7 @@ ata_modify_if_48bit(struct ata_request * atadev->flags &= ~ATA_D_48BIT_ACTIVE; - if ((request->u.ata.lba >= ATA_MAX_28BIT_LBA || + if (((request->u.ata.lba + request->u.ata.count) >= ATA_MAX_28BIT_LBA || request->u.ata.count > 256) && atadev->param.support.command2 & ATA_SUPPORT_ADDRESS48) { Index: ata-all.h =================================================================== RCS file: /home/ncvs/src/sys/dev/ata/ata-all.h,v retrieving revision 1.103.2.11 diff -p -u -r1.103.2.11 ata-all.h --- ata-all.h 7 Jul 2007 11:36:44 -0000 1.103.2.11 +++ ata-all.h 5 Nov 2007 22:45:04 -0000 @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2006 Søren Schmidt + * Copyright (c) 1998 - 2007 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -228,6 +228,29 @@ #define ATA_AHCI_CT_SG_OFFSET 128 #define ATA_AHCI_CT_SIZE 256 +struct ata_ahci_dma_prd { + u_int64_t dba; + u_int32_t reserved; + u_int32_t dbc; /* 0 based */ +#define ATA_AHCI_PRD_MASK 0x003fffff /* max 4MB */ +#define ATA_AHCI_PRD_IPC (1<<31) +} __packed; + +struct ata_ahci_cmd_tab { + u_int8_t cfis[64]; + u_int8_t acmd[32]; + u_int8_t reserved[32]; + struct ata_ahci_dma_prd prd_tab[16]; +} __packed; + +struct ata_ahci_cmd_list { + u_int16_t cmd_flags; + u_int16_t prd_length; /* PRD entries */ + u_int32_t bytecount; + u_int64_t cmd_table_phys; /* 128byte aligned */ +} __packed; + + /* DMA register defines */ #define ATA_DMA_ENTRIES 256 #define ATA_DMA_EOT 0x80000000 @@ -470,6 +493,7 @@ struct ata_channel { #define ATA_ATA_SLAVE 0x02 #define ATA_ATAPI_MASTER 0x04 #define ATA_ATAPI_SLAVE 0x08 +#define ATA_PORTMULTIPLIER 0x10 struct mtx state_mtx; /* state lock */ int state; /* ATA channel state */ Index: ata-chipset.c =================================================================== RCS file: /home/ncvs/src/sys/dev/ata/ata-chipset.c,v retrieving revision 1.126.2.21 diff -p -u -r1.126.2.21 ata-chipset.c --- ata-chipset.c 31 Oct 2007 13:06:17 -0000 1.126.2.21 +++ ata-chipset.c 5 Nov 2007 23:10:07 -0000 @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2006 Søren Schmidt + * Copyright (c) 1998 - 2007 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -55,10 +55,12 @@ __FBSDID("$FreeBSD$"); static int ata_generic_chipinit(device_t dev); static void ata_generic_intr(void *data); static void ata_generic_setmode(device_t dev, int mode); -static void ata_sata_phy_enable(struct ata_channel *ch); +static void ata_sata_phy_check_events(device_t dev); static void ata_sata_phy_event(void *context, int dummy); +static int ata_sata_phy_reset(device_t dev); static int ata_sata_connect(struct ata_channel *ch); static void ata_sata_setmode(device_t dev, int mode); +static int ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis); static int ata_ahci_chipinit(device_t dev); static int ata_ahci_allocate(device_t dev); static int ata_ahci_status(device_t dev); @@ -67,7 +69,7 @@ static int ata_ahci_end_transaction(stru static void ata_ahci_reset(device_t dev); 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); +static int ata_ahci_setup_fis(struct ata_ahci_cmd_tab *ctp, struct ata_request *request); static int ata_acard_chipinit(device_t dev); static int ata_acard_allocate(device_t dev); static int ata_acard_status(device_t dev); @@ -105,14 +107,17 @@ static int ata_jmicron_allocate(device_t static void ata_jmicron_reset(device_t dev); static void ata_jmicron_dmainit(device_t dev); static void ata_jmicron_setmode(device_t dev, int mode); -static int ata_marvell_chipinit(device_t dev); -static int ata_marvell_allocate(device_t dev); -static int ata_marvell_status(device_t dev); -static int ata_marvell_begin_transaction(struct ata_request *request); -static int ata_marvell_end_transaction(struct ata_request *request); -static void ata_marvell_reset(device_t dev); -static void ata_marvell_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); -static void ata_marvell_dmainit(device_t dev); +static int ata_marvell_pata_chipinit(device_t dev); +static int ata_marvell_pata_allocate(device_t dev); +static void ata_marvell_pata_setmode(device_t dev, int mode); +static int ata_marvell_edma_chipinit(device_t dev); +static int ata_marvell_edma_allocate(device_t dev); +static int ata_marvell_edma_status(device_t dev); +static int ata_marvell_edma_begin_transaction(struct ata_request *request); +static int ata_marvell_edma_end_transaction(struct ata_request *request); +static void ata_marvell_edma_reset(device_t dev); +static void ata_marvell_edma_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); +static void ata_marvell_edma_dmainit(device_t dev); static int ata_national_chipinit(device_t dev); static void ata_national_setmode(device_t dev, int mode); static int ata_netcell_chipinit(device_t dev); @@ -154,6 +159,13 @@ static int ata_sii_allocate(device_t dev static int ata_sii_status(device_t dev); static void ata_sii_reset(device_t dev); static void ata_sii_setmode(device_t dev, int mode); +static int ata_siiprb_allocate(device_t dev); +static int ata_siiprb_status(device_t dev); +static int ata_siiprb_begin_transaction(struct ata_request *request); +static int ata_siiprb_end_transaction(struct ata_request *request); +static void ata_siiprb_reset(device_t dev); +static void ata_siiprb_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); +static void ata_siiprb_dmainit(device_t dev); static int ata_sis_chipinit(device_t dev); static int ata_sis_allocate(device_t dev); static void ata_sis_reset(device_t dev); @@ -161,6 +173,7 @@ static void ata_sis_setmode(device_t dev static int ata_via_chipinit(device_t dev); static int ata_via_allocate(device_t dev); static void ata_via_reset(device_t dev); +static void ata_via_setmode(device_t dev, int mode); static void ata_via_southbridge_fixup(device_t dev); static void ata_via_family_setmode(device_t dev, int mode); static struct ata_chip_id *ata_match_chip(device_t dev, struct ata_chip_id *index); @@ -226,33 +239,39 @@ ata_generic_setmode(device_t dev, int mo * SATA support functions */ static void -ata_sata_phy_enable(struct ata_channel *ch) +ata_sata_phy_check_events(device_t dev) { - int loop, retry; + struct ata_channel *ch = device_get_softc(dev); + u_int32_t error = ATA_IDX_INL(ch, ATA_SERROR); - if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE) { - ata_sata_connect(ch); - return; - } + /* clear error bits/interrupt */ + ATA_IDX_OUTL(ch, ATA_SERROR, error); - for (retry = 0; retry < 10; retry++) { - for (loop = 0; loop < 10; loop++) { - ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_RESET); - ata_udelay(100); - if ((ATA_IDX_INL(ch, ATA_SCONTROL) & - ATA_SC_DET_MASK) == ATA_SC_DET_RESET) - break; - } - ata_udelay(5000); - for (loop = 0; loop < 10; loop++) { - ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_IDLE | - ATA_SC_IPM_DIS_PARTIAL | - ATA_SC_IPM_DIS_SLUMBER); - ata_udelay(100); - if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == 0) { - ata_sata_connect(ch); - return; + /* do we have any events flagged ? */ + if (error) { + struct ata_connect_task *tp; + u_int32_t status = ATA_IDX_INL(ch, ATA_SSTATUS); + + /* if we have a connection event deal with it */ + if ((error & ATA_SE_PHY_CHANGED) && + (tp = (struct ata_connect_task *) + malloc(sizeof(struct ata_connect_task), + M_ATA, M_NOWAIT | M_ZERO))) { + + if (((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1) || + ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2)) { + if (bootverbose) + device_printf(ch->dev, "CONNECT requested\n"); + tp->action = ATA_C_ATTACH; + } + else { + if (bootverbose) + device_printf(ch->dev, "DISCONNECT requested\n"); + tp->action = ATA_C_DETACH; } + tp->dev = ch->dev; + TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); + taskqueue_enqueue(taskqueue_thread, &tp->task); } } } @@ -269,7 +288,7 @@ ata_sata_phy_event(void *context, int du if (tp->action == ATA_C_ATTACH) { if (bootverbose) device_printf(tp->dev, "CONNECTED\n"); - ata_sata_connect(ch); + ATA_RESET(tp->dev); ata_identify(tp->dev); } if (tp->action == ATA_C_DETACH) { @@ -290,6 +309,36 @@ ata_sata_phy_event(void *context, int du } static int +ata_sata_phy_reset(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + int loop, retry; + + if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE) + return ata_sata_connect(ch); + + for (retry = 0; retry < 10; retry++) { + for (loop = 0; loop < 10; loop++) { + ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_RESET); + ata_udelay(100); + if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == + ATA_SC_DET_RESET) + break; + } + ata_udelay(5000); + for (loop = 0; loop < 10; loop++) { + ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_IDLE | + ATA_SC_IPM_DIS_PARTIAL | + ATA_SC_IPM_DIS_SLUMBER); + ata_udelay(100); + if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == 0) + return ata_sata_connect(ch); + } + } + return 0; +} + +static int ata_sata_connect(struct ata_channel *ch) { u_int32_t status; @@ -308,31 +357,12 @@ ata_sata_connect(struct ata_channel *ch) device_printf(ch->dev, "SATA connect status=%08x\n", status); return 0; } + if (bootverbose) + device_printf(ch->dev, "SATA connect time=%dms\n", timeout * 10); /* clear SATA error register */ ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR)); - /* find out what type device we got poll for spec'd 31 seconds */ - /* XXX SOS 10 secs for now as I have little patience */ - ch->devices = 0; - for (timeout = 0; timeout < 1000; timeout++) { - if (ATA_IDX_INB(ch, ATA_STATUS) & ATA_S_BUSY) - DELAY(10000); - else - break; - } - if (bootverbose) - device_printf(ch->dev, "SATA connect ready time=%dms\n", timeout * 10); - if (timeout < 1000) { - if ((ATA_IDX_INB(ch, ATA_CYL_LSB) == ATAPI_MAGIC_LSB) && - (ATA_IDX_INB(ch, ATA_CYL_MSB) == ATAPI_MAGIC_MSB)) - ch->devices = ATA_ATAPI_MASTER; - else - ch->devices = ATA_ATA_MASTER; - } - if (bootverbose) - device_printf(ch->dev, "sata_connect devices=0x%b\n", - ch->devices, "\20\3ATAPI_MASTER\1ATA_MASTER"); return 1; } @@ -370,33 +400,53 @@ ata_sata_setmode(device_t dev, int mode) } } +static int +ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis) +{ + struct ata_device *atadev = device_get_softc(request->dev); -/* - * AHCI v1.0 compliant SATA chipset support functions - */ -struct ata_ahci_dma_prd { - u_int64_t dba; - u_int32_t reserved; - u_int32_t dbc; /* 0 based */ -#define ATA_AHCI_PRD_MASK 0x003fffff /* max 4MB */ -#define ATA_AHCI_PRD_IPC (1<<31) -} __packed; - -struct ata_ahci_cmd_tab { - u_int8_t cfis[64]; - u_int8_t acmd[32]; - u_int8_t reserved[32]; - struct ata_ahci_dma_prd prd_tab[16]; -} __packed; - -struct ata_ahci_cmd_list { - u_int16_t cmd_flags; - u_int16_t prd_length; /* PRD entries */ - u_int32_t bytecount; - u_int64_t cmd_table_phys; /* 128byte aligned */ -} __packed; + if (request->flags & ATA_R_ATAPI) { + fis[0] = 0x27; /* host to device */ + fis[1] = 0x80; /* command FIS (note PM goes here) */ + fis[2] = ATA_PACKET_CMD; + if (request->flags & (ATA_R_READ | ATA_R_WRITE)) + fis[3] = ATA_F_DMA; + else { + fis[5] = request->transfersize; + fis[6] = request->transfersize >> 8; + } + fis[7] = ATA_D_LBA | atadev->unit; + fis[15] = ATA_A_4BIT; + return 20; + } + else { + ata_modify_if_48bit(request); + fis[0] = 0x27; /* host to device */ + fis[1] = 0x80; /* command FIS (note PM goes here) */ + fis[2] = request->u.ata.command; + fis[3] = request->u.ata.feature; + fis[4] = request->u.ata.lba; + fis[5] = request->u.ata.lba >> 8; + fis[6] = request->u.ata.lba >> 16; + fis[7] = ATA_D_LBA | atadev->unit; + if (!(atadev->flags & ATA_D_48BIT_ACTIVE)) + fis[7] |= (request->u.ata.lba >> 24 & 0x0f); + fis[8] = request->u.ata.lba >> 24; + fis[9] = request->u.ata.lba >> 32; + fis[10] = request->u.ata.lba >> 40; + fis[11] = request->u.ata.feature >> 8; + fis[12] = request->u.ata.count; + fis[13] = request->u.ata.count >> 8; + fis[15] = ATA_A_4BIT; + return 20; + } + return 0; +} +/* + * AHCI v1.x compliant SATA chipset support functions + */ static int ata_ahci_chipinit(device_t dev) { @@ -418,7 +468,9 @@ ata_ahci_chipinit(device_t dev) ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_AE); /* get the number of HW channels */ - ctlr->channels = (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK)+1; + ctlr->channels = + MAX(flsl(ATA_INL(ctlr->r_res2, ATA_AHCI_PI)), + (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1); /* clear interrupts */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, ATA_INL(ctlr->r_res2, ATA_AHCI_IS)); @@ -441,7 +493,8 @@ ata_ahci_chipinit(device_t dev) device_printf(dev, "AHCI Version %x%x.%x%x controller with %d ports detected\n", (version >> 24) & 0xff, (version >> 16) & 0xff, - (version >> 8) & 0xff, version & 0xff, ctlr->channels); + (version >> 8) & 0xff, version & 0xff, + (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1); return 0; } @@ -451,17 +504,7 @@ ata_ahci_allocate(device_t dev) struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int64_t work; - int offset = (ch->unit << 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_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; - ch->r_io[ATA_STATUS].offset = ATA_AHCI_P_TFD + offset; - ch->r_io[ATA_ALTSTAT].res = ctlr->r_res2; - ch->r_io[ATA_ALTSTAT].offset = ATA_AHCI_P_TFD + offset; + int offset = ch->unit << 7; /* set the SATA resources */ ch->r_io[ATA_SSTATUS].res = ctlr->r_res2; @@ -478,7 +521,7 @@ ata_ahci_allocate(device_t dev) ch->hw.end_transaction = ata_ahci_end_transaction; ch->hw.command = NULL; /* not used here */ - /* setup the work areas */ + /* setup work areas */ work = ch->dma->work_bus + ATA_AHCI_CL_OFFSET; ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLB + offset, work & 0xffffffff); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLBU + offset, work >> 32); @@ -507,62 +550,22 @@ ata_ahci_status(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); - struct ata_connect_task *tp; - u_int32_t action, istatus, sstatus, error, issued; - int offset = (ch->unit << 7); + u_int32_t action = ATA_INL(ctlr->r_res2, ATA_AHCI_IS); + int offset = ch->unit << 7; int tag = 0; - action = ATA_INL(ctlr->r_res2, ATA_AHCI_IS); if (action & (1 << ch->unit)) { - istatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset); - issued = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset); - sstatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_SSTS + offset); - error = ATA_INL(ctlr->r_res2, ATA_AHCI_P_SERR + offset); + u_int32_t istatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset); /* clear interrupt(s) */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, action); + ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, action & (1 << ch->unit)); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, istatus); - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_SERR + offset, error); - - /* do we have cold connect surprise */ - if (istatus & ATA_AHCI_P_IX_CPD) { - printf("ata_ahci_status status=%08x sstatus=%08x error=%08x\n", - istatus, sstatus, error); - } - /* check for and handle connect events */ - if ((istatus & ATA_AHCI_P_IX_PC) && - (tp = (struct ata_connect_task *) - malloc(sizeof(struct ata_connect_task), - M_ATA, M_NOWAIT | M_ZERO))) { - - if (bootverbose) - device_printf(ch->dev, "CONNECT requested\n"); - tp->action = ATA_C_ATTACH; - tp->dev = ch->dev; - TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); - taskqueue_enqueue(taskqueue_thread, &tp->task); - } - - /* check for and handle disconnect events */ - else if ((istatus & ATA_AHCI_P_IX_PRC) && - !((sstatus & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1 || - (sstatus & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2) && - (tp = (struct ata_connect_task *) - malloc(sizeof(struct ata_connect_task), - M_ATA, M_NOWAIT | M_ZERO))) { - - if (bootverbose) - device_printf(ch->dev, "DISCONNECT requested\n"); - tp->action = ATA_C_DETACH; - tp->dev = ch->dev; - TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); - taskqueue_enqueue(taskqueue_thread, &tp->task); - } + /* do we have any PHY events ? */ + ata_sata_phy_check_events(dev); /* do we have any device action ? */ - if (!(issued & (1 << tag))) - return 1; + return (!(ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset) & (1 << tag))); } return 0; } @@ -575,15 +578,16 @@ ata_ahci_begin_transaction(struct ata_re struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); struct ata_ahci_cmd_tab *ctp; struct ata_ahci_cmd_list *clp; + int offset = ch->unit << 7; int tag = 0, entries = 0; int fis_size; - + /* get a piece of the workspace for this request */ ctp = (struct ata_ahci_cmd_tab *) (ch->dma->work + ATA_AHCI_CT_OFFSET + (ATA_AHCI_CT_SIZE * tag)); - /* setup the FIS for this request */ /* XXX SOS ATAPI missing still */ - if (!(fis_size = ata_ahci_setup_fis(&ctp->cfis[0], request))) { + /* setup the FIS for this request */ + if (!(fis_size = ata_ahci_setup_fis(ctp, request))) { device_printf(request->dev, "setting up SATA FIS failed\n"); request->result = EIO; return ATA_OP_FINISHED; @@ -606,7 +610,7 @@ ata_ahci_begin_transaction(struct ata_re clp->prd_length = entries; clp->cmd_flags = (request->flags & ATA_R_WRITE ? (1<<6) : 0) | - (request->flags & ATA_R_ATAPI ? (1<<5) : 0) | + (request->flags & ATA_R_ATAPI ? ((1<<5) | (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 + @@ -615,8 +619,38 @@ ata_ahci_begin_transaction(struct ata_re /* clear eventual ACTIVE bit */ ATA_IDX_OUTL(ch, ATA_SACTIVE, ATA_IDX_INL(ch, ATA_SACTIVE) & (1 << tag)); - /* issue the command */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + (ch->unit << 7), (1 << tag)); + /* set command type bit */ + if (ch->devices & ATA_ATAPI_MASTER) + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, + ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) | + ATA_AHCI_P_CMD_ATAPI); + else + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, + ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & + ~ATA_AHCI_P_CMD_ATAPI); + + /* issue command to controller */ + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, (1 << tag)); + + if (!(request->flags & ATA_R_ATAPI)) { + /* device reset doesn't interrupt */ + 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--); + if (bootverbose) + device_printf(ch->dev, "device_reset timeout=%dus\n", + (1000000-timeout)*10); + request->status = tf_data; + if (request->status & ATA_S_ERROR) + request->error = tf_data >> 8; + return ATA_OP_FINISHED; + } + } /* start the timeout */ callout_reset(&request->callout, request->timeout * hz, @@ -632,13 +666,14 @@ ata_ahci_end_transaction(struct ata_requ struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); struct ata_ahci_cmd_list *clp; u_int32_t tf_data; + int offset = ch->unit << 7; int tag = 0; /* kill the timeout */ callout_stop(&request->callout); /* get status */ - tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + (ch->unit << 7)); + tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset); request->status = tf_data; /* if error status get details */ @@ -661,8 +696,15 @@ ata_ahci_reset(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); - u_int32_t cmd; - int timeout, offset = (ch->unit << 7); + u_int32_t cmd, signature; + int offset = ch->unit << 7; + int timeout; + + if (!(ATA_INL(ctlr->r_res2, ATA_AHCI_PI) & (1 << ch->unit))) { + device_printf(dev, "port not implemented\n"); + return; + } + ch->devices = 0; /* kill off all activity on this channel */ cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); @@ -673,10 +715,11 @@ ata_ahci_reset(device_t dev) timeout = 0; do { DELAY(1000); - if (timeout++ > 500) + if (timeout++ > 500) { device_printf(dev, "stopping AHCI engine failed\n"); break; } + } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR); /* issue Command List Override if supported */ @@ -687,26 +730,53 @@ ata_ahci_reset(device_t dev) timeout = 0; do { DELAY(1000); - if (timeout++ > 500) + if (timeout++ > 500) { device_printf(dev, "executing CLO failed\n"); break; } + } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD+offset)&ATA_AHCI_P_CMD_CLO); } - /* spin up device */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, ATA_AHCI_P_CMD_SUD); + /* reset PHY and decide what is present */ + if (ata_sata_phy_reset(dev)) { - ata_sata_phy_enable(ch); + /* clear any interrupts pending on this channel */ + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, + ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset)); - /* clear any interrupts pending on this channel */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, - ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset)); + /* clear SATA error register */ + ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR)); - /* start operations on this channel */ - 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)); + /* start operations on this channel */ + 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)); + + signature = ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset); + if (bootverbose) + device_printf(dev, "SIGNATURE: %08x\n", signature); + switch (signature) { + case 0x00000101: + ch->devices = ATA_ATA_MASTER; + break; + case 0x96690101: + ch->devices = ATA_PORTMULTIPLIER; + device_printf(ch->dev, "Portmultipliers not supported yet\n"); + ch->devices = 0; + break; + case 0xeb140101: + ch->devices = ATA_ATAPI_MASTER; + break; + default: /* SOS XXX */ + if (bootverbose) + device_printf(ch->dev, "No signature, asuming disk device\n"); + ch->devices = ATA_ATA_MASTER; + } + } + if (bootverbose) + device_printf(dev, "ahci_reset devices=0x%b\n", ch->devices, + "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER"); } static void @@ -742,43 +812,14 @@ ata_ahci_dmainit(device_t dev) } static int -ata_ahci_setup_fis(u_int8_t *fis, struct ata_request *request) +ata_ahci_setup_fis(struct ata_ahci_cmd_tab *ctp, struct ata_request *request) { - struct ata_device *atadev = device_get_softc(request->dev); - int idx = 0; - - /* XXX SOS add ATAPI commands support later */ - ata_modify_if_48bit(request); - - fis[idx++] = 0x27; /* host to device */ - fis[idx++] = 0x80; /* command FIS (note PM goes here) */ - fis[idx++] = request->u.ata.command; - fis[idx++] = request->u.ata.feature; - - fis[idx++] = request->u.ata.lba; - fis[idx++] = request->u.ata.lba >> 8; - fis[idx++] = request->u.ata.lba >> 16; - fis[idx] = ATA_D_LBA | atadev->unit; - if (atadev->flags & ATA_D_48BIT_ACTIVE) - idx++; - else - fis[idx++] |= (request->u.ata.lba >> 24 & 0x0f); - - fis[idx++] = request->u.ata.lba >> 24; - fis[idx++] = request->u.ata.lba >> 32; - fis[idx++] = request->u.ata.lba >> 40; - fis[idx++] = request->u.ata.feature >> 8; - - fis[idx++] = request->u.ata.count; - fis[idx++] = request->u.ata.count >> 8; - fis[idx++] = 0x00; - fis[idx++] = ATA_A_4BIT; - - fis[idx++] = 0x00; - fis[idx++] = 0x00; - fis[idx++] = 0x00; - fis[idx++] = 0x00; - return idx; + bzero(ctp->cfis, 64); + if (request->flags & ATA_R_ATAPI) { + bzero(ctp->acmd, 32); + bcopy(request->u.atapi.ccb, ctp->acmd, 16); + } + return ata_request2fis_h2d(request, &ctp->cfis[0]); } @@ -1350,6 +1391,7 @@ ata_ati_setmode(device_t dev, int mode) } } + /* * Cyrix chipset support functions */ @@ -1702,6 +1744,7 @@ ata_intel_ident(device_t dev) { ATA_I82801HBM_S2, 0, AHCI, 0x00, ATA_SA300, "ICH8M" }, { ATA_I82801IB_S1, 0, AHCI, 0x00, ATA_SA300, "ICH9" }, { ATA_I82801IB_S2, 0, AHCI, 0x00, ATA_SA300, "ICH9" }, + { ATA_I82801IB_AH2, 0, AHCI, 0x00, ATA_SA300, "ICH9" }, { ATA_I82801IB_AH4, 0, AHCI, 0x00, ATA_SA300, "ICH9" }, { ATA_I82801IB_AH6, 0, AHCI, 0x00, ATA_SA300, "ICH9" }, { ATA_I31244, 0, 0, 0x00, ATA_SA150, "31244" }, @@ -1757,7 +1800,7 @@ ata_intel_chipinit(device_t dev) /* SATA parts can be either compat or AHCI */ else { /* force all ports active "the legacy way" */ - pci_write_config(dev, 0x92, pci_read_config(dev, 0x92, 2) | 0x0f,2); + pci_write_config(dev, 0x92, pci_read_config(dev, 0x92, 2) | 0x0f, 2); ctlr->allocate = ata_intel_allocate; ctlr->reset = ata_intel_reset; @@ -1970,37 +2013,8 @@ ata_intel_31244_allocate(device_t dev) static int ata_intel_31244_status(device_t dev) { - struct ata_channel *ch = device_get_softc(dev); - u_int32_t status = ATA_IDX_INL(ch, ATA_SSTATUS); - u_int32_t error = ATA_IDX_INL(ch, ATA_SERROR); - struct ata_connect_task *tp; - - /* check for PHY related interrupts on SATA capable HW */ - if (error) { - /* clear error bits/interrupt */ - ATA_IDX_OUTL(ch, ATA_SERROR, error); - - /* if we have a connection event deal with it */ - if ((error & ATA_SE_PHY_CHANGED) && - (tp = (struct ata_connect_task *) - malloc(sizeof(struct ata_connect_task), - M_ATA, M_NOWAIT | M_ZERO))) { - - if ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1) { - if (bootverbose) - device_printf(ch->dev, "CONNECT requested\n"); - tp->action = ATA_C_ATTACH; - } - else { - if (bootverbose) - device_printf(ch->dev, "DISCONNECT requested\n"); - tp->action = ATA_C_DETACH; - } - tp->dev = ch->dev; - TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); - taskqueue_enqueue(taskqueue_thread, &tp->task); - } - } + /* do we have any PHY events ? */ + ata_sata_phy_check_events(dev); /* any drive action to take care of ? */ return ata_pci_status(dev); @@ -2037,9 +2051,8 @@ ata_intel_31244_command(struct ata_reque static void ata_intel_31244_reset(device_t dev) { - struct ata_channel *ch = device_get_softc(dev); - - ata_sata_phy_enable(ch); + if (ata_sata_phy_reset(dev)) + ata_generic_reset(dev); } @@ -2163,6 +2176,7 @@ ata_jmicron_ident(device_t dev) { ATA_JMB363, 0, 2, 1, ATA_SA300, "JMB363" }, { ATA_JMB365, 0, 1, 2, ATA_SA300, "JMB365" }, { ATA_JMB366, 0, 2, 2, ATA_SA300, "JMB366" }, + { ATA_JMB368, 0, 0, 1, ATA_UDMA6, "JMB368" }, { 0, 0, 0, 0, 0, 0}}; char buffer[64]; @@ -2323,12 +2337,14 @@ ata_marvell_ident(device_t dev) struct ata_pci_controller *ctlr = device_get_softc(dev); struct ata_chip_id *idx; static struct ata_chip_id ids[] = - {{ ATA_M88SX5040, 0, 4, MV5XXX, ATA_SA150, "88SX5040" }, - { ATA_M88SX5041, 0, 4, MV5XXX, ATA_SA150, "88SX5041" }, - { ATA_M88SX5080, 0, 8, MV5XXX, ATA_SA150, "88SX5080" }, - { ATA_M88SX5081, 0, 8, MV5XXX, ATA_SA150, "88SX5081" }, - { ATA_M88SX6041, 0, 4, MV6XXX, ATA_SA300, "88SX6041" }, - { ATA_M88SX6081, 0, 8, MV6XXX, ATA_SA300, "88SX6081" }, + {{ ATA_M88SX5040, 0, 4, MV50XX, ATA_SA150, "88SX5040" }, + { ATA_M88SX5041, 0, 4, MV50XX, ATA_SA150, "88SX5041" }, + { ATA_M88SX5080, 0, 8, MV50XX, ATA_SA150, "88SX5080" }, + { ATA_M88SX5081, 0, 8, MV50XX, ATA_SA150, "88SX5081" }, + { ATA_M88SX6041, 0, 4, MV60XX, ATA_SA300, "88SX6041" }, + { ATA_M88SX6081, 0, 8, MV60XX, ATA_SA300, "88SX6081" }, + { ATA_M88SX6101, 0, 1, MV61XX, ATA_UDMA6, "88SX6101" }, + { ATA_M88SX6145, 0, 2, MV61XX, ATA_UDMA6, "88SX6145" }, { 0, 0, 0, 0, 0, 0}}; char buffer[64]; @@ -2339,12 +2355,62 @@ ata_marvell_ident(device_t dev) idx->text, ata_mode2str(idx->max_dma)); device_set_desc_copy(dev, buffer); ctlr->chip = idx; - ctlr->chipinit = ata_marvell_chipinit; + switch (ctlr->chip->cfg2) { + case MV50XX: + case MV60XX: + ctlr->chipinit = ata_marvell_edma_chipinit; + break; + case MV61XX: + ctlr->chipinit = ata_marvell_pata_chipinit; + break; + } + return 0; +} + +static int +ata_marvell_pata_chipinit(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(dev); + + if (ata_setup_interrupt(dev)) + return ENXIO; + + ctlr->allocate = ata_marvell_pata_allocate; + ctlr->setmode = ata_marvell_pata_setmode; + ctlr->channels = ctlr->chip->cfg1; + return 0; +} + +static int +ata_marvell_pata_allocate(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + + /* setup the usual register normal pci style */ + if (ata_pci_allocate(dev)) + return ENXIO; + + /* dont use 32 bit PIO transfers */ + ch->flags |= ATA_USE_16BIT; + return 0; } +static void +ata_marvell_pata_setmode(device_t dev, int mode) +{ + device_t gparent = GRANDPARENT(dev); + struct ata_pci_controller *ctlr = device_get_softc(gparent); + struct ata_device *atadev = device_get_softc(dev); + + mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma); + mode = ata_check_80pin(dev, mode); + if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode)) + atadev->mode = mode; +} + static int -ata_marvell_chipinit(device_t dev) +ata_marvell_edma_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); @@ -2363,9 +2429,9 @@ ata_marvell_chipinit(device_t dev) /* mask all PCI interrupts */ ATA_OUTL(ctlr->r_res1, 0x01d5c, 0x00000000); - ctlr->allocate = ata_marvell_allocate; - ctlr->reset = ata_marvell_reset; - ctlr->dmainit = ata_marvell_dmainit; + ctlr->allocate = ata_marvell_edma_allocate; + ctlr->reset = ata_marvell_edma_reset; + ctlr->dmainit = ata_marvell_edma_dmainit; ctlr->setmode = ata_sata_setmode; ctlr->channels = ctlr->chip->cfg1; @@ -2391,7 +2457,7 @@ ata_marvell_chipinit(device_t dev) } static int -ata_marvell_allocate(device_t dev) +ata_marvell_edma_allocate(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); @@ -2413,7 +2479,7 @@ ata_marvell_allocate(device_t dev) /* set SATA resources */ switch (ctlr->chip->cfg2) { - case MV5XXX: + case MV50XX: ch->r_io[ATA_SSTATUS].res = ctlr->r_res1; ch->r_io[ATA_SSTATUS].offset = 0x00100 + ATA_MV_HOST_BASE(ch); ch->r_io[ATA_SERROR].res = ctlr->r_res1; @@ -2421,7 +2487,7 @@ ata_marvell_allocate(device_t dev) ch->r_io[ATA_SCONTROL].res = ctlr->r_res1; ch->r_io[ATA_SCONTROL].offset = 0x00108 + ATA_MV_HOST_BASE(ch); break; - case MV6XXX: + case MV60XX: ch->r_io[ATA_SSTATUS].res = ctlr->r_res1; ch->r_io[ATA_SSTATUS].offset = 0x02300 + ATA_MV_EDMA_BASE(ch); ch->r_io[ATA_SERROR].res = ctlr->r_res1; @@ -2436,9 +2502,9 @@ ata_marvell_allocate(device_t dev) ch->flags |= ATA_NO_SLAVE; ch->flags |= ATA_USE_16BIT; /* XXX SOS needed ? */ ata_generic_hw(dev); - ch->hw.begin_transaction = ata_marvell_begin_transaction; - ch->hw.end_transaction = ata_marvell_end_transaction; - ch->hw.status = ata_marvell_status; + ch->hw.begin_transaction = ata_marvell_edma_begin_transaction; + ch->hw.end_transaction = ata_marvell_edma_end_transaction; + ch->hw.status = ata_marvell_edma_status; /* disable the EDMA machinery */ ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000002); @@ -2481,52 +2547,20 @@ ata_marvell_allocate(device_t dev) } static int -ata_marvell_status(device_t dev) +ata_marvell_edma_status(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int32_t cause = ATA_INL(ctlr->r_res1, 0x01d60); int shift = (ch->unit << 1) + (ch->unit > 3); - /* do we have any errors flagged ? */ if (cause & (1 << shift)) { - struct ata_connect_task *tp; - u_int32_t error = - ATA_INL(ctlr->r_res1, 0x02008 + ATA_MV_EDMA_BASE(ch)); - - /* check for and handle disconnect events */ - if ((error & 0x00000008) && - (tp = (struct ata_connect_task *) - malloc(sizeof(struct ata_connect_task), - M_ATA, M_NOWAIT | M_ZERO))) { - - if (bootverbose) - device_printf(ch->dev, "DISCONNECT requested\n"); - tp->action = ATA_C_DETACH; - tp->dev = ch->dev; - TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); - taskqueue_enqueue(taskqueue_thread, &tp->task); - } - - /* check for and handle connect events */ - if ((error & 0x00000010) && - (tp = (struct ata_connect_task *) - malloc(sizeof(struct ata_connect_task), - M_ATA, M_NOWAIT | M_ZERO))) { - if (bootverbose) - device_printf(ch->dev, "CONNECT requested\n"); - tp->action = ATA_C_ATTACH; - tp->dev = ch->dev; - TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); - taskqueue_enqueue(taskqueue_thread, &tp->task); - } - - /* clear SATA error register */ - ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR)); - - /* clear any outstanding error interrupts */ + /* clear interrupt(s) */ ATA_OUTL(ctlr->r_res1, 0x02008 + ATA_MV_EDMA_BASE(ch), 0x0); + + /* do we have any PHY events ? */ + ata_sata_phy_check_events(dev); } /* do we have any device action ? */ @@ -2535,7 +2569,7 @@ ata_marvell_status(device_t dev) /* must be called with ATA channel locked and state_mtx held */ static int -ata_marvell_begin_transaction(struct ata_request *request) +ata_marvell_edma_begin_transaction(struct ata_request *request) { struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); @@ -2627,7 +2661,7 @@ ata_marvell_begin_transaction(struct ata /* must be called with ATA channel locked and state_mtx held */ static int -ata_marvell_end_transaction(struct ata_request *request) +ata_marvell_edma_end_transaction(struct ata_request *request) { struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); @@ -2641,9 +2675,6 @@ ata_marvell_end_transaction(struct ata_r u_int32_t rsp_in, rsp_out; int slot; - /* unload SG list */ - ch->dma->unload(ch->dev); - /* stop timeout */ callout_stop(&request->callout); @@ -2667,8 +2698,12 @@ ata_marvell_end_transaction(struct ata_r if (!(request->status & ATA_S_ERROR) && !(request->flags & ATA_R_TIMEOUT)) request->donecount = request->bytecount; - res = ATA_OP_FINISHED; - } + + /* unload SG list */ + ch->dma->unload(ch->dev); + + res = ATA_OP_FINISHED; + } /* legacy ATA interrupt */ else { @@ -2681,7 +2716,7 @@ ata_marvell_end_transaction(struct ata_r } static void -ata_marvell_reset(device_t dev) +ata_marvell_edma_reset(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); @@ -2701,14 +2736,16 @@ ata_marvell_reset(device_t dev) ATA_OUTL(ctlr->r_res1, 0x0200c + ATA_MV_EDMA_BASE(ch), ~0x0); /* enable channel and test for devices */ - ata_sata_phy_enable(ch); + if (ata_sata_phy_reset(dev)) + ata_generic_reset(dev); /* enable EDMA machinery */ ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000001); } static void -ata_marvell_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) +ata_marvell_edma_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, + int error) { struct ata_dmasetprd_args *args = xsc; struct ata_marvell_dma_prdentry *prd = args->dmatab; @@ -2726,7 +2763,7 @@ ata_marvell_dmasetprd(void *xsc, bus_dma } static void -ata_marvell_dmainit(device_t dev) +ata_marvell_edma_dmainit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); @@ -2734,7 +2771,7 @@ ata_marvell_dmainit(device_t dev) ata_dmainit(dev); if (ch->dma) { /* note start and stop are not used here */ - ch->dma->setprd = ata_marvell_dmasetprd; + ch->dma->setprd = ata_marvell_edma_dmasetprd; if (ATA_INL(ctlr->r_res1, 0x00d00) & 0x00000004) ch->dma->max_address = BUS_SPACE_MAXADDR; @@ -2816,6 +2853,7 @@ ata_national_setmode(device_t dev, int m } } + /* * NetCell chipset support functions */ @@ -2853,13 +2891,13 @@ ata_netcell_allocate(device_t dev) if (ata_pci_allocate(dev)) return ENXIO; - /* don't use 32 bit PIO transfers; these cause the NetCell to return - * garbage */ + /* the NetCell only supports 16 bit PIO transfers */ ch->flags |= ATA_USE_16BIT; return 0; } + /* * nVidia chipset support functions */ @@ -2889,6 +2927,10 @@ ata_nvidia_ident(device_t dev) { ATA_NFORCE_MCP55, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nForce MCP55" }, { ATA_NFORCE_MCP55_S1, 0, 0, NV4|NVQ, ATA_SA300, "nForce MCP55" }, { ATA_NFORCE_MCP55_S2, 0, 0, NV4|NVQ, ATA_SA300, "nForce MCP55" }, + { ATA_NFORCE_MCP61, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nForce MCP61" }, + { ATA_NFORCE_MCP61_S1, 0, 0, NV4|NVQ, ATA_SA300, "nForce MCP61" }, + { ATA_NFORCE_MCP61_S2, 0, 0, NV4|NVQ, ATA_SA300, "nForce MCP61" }, + { ATA_NFORCE_MCP61_S3, 0, 0, NV4|NVQ, ATA_SA300, "nForce MCP61" }, { 0, 0, 0, 0, 0, 0}} ; char buffer[64] ; @@ -2990,59 +3032,26 @@ ata_nvidia_status(device_t dev) struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int offset = ctlr->chip->cfg2 & NV4 ? 0x0440 : 0x0010; - struct ata_connect_task *tp; int shift = ch->unit << (ctlr->chip->cfg2 & NVQ ? 4 : 2); - u_int32_t status; + u_int32_t istatus = ATA_INL(ctlr->r_res2, offset); - /* get and clear interrupt status */ - if (ctlr->chip->cfg2 & NVQ) { - status = ATA_INL(ctlr->r_res2, offset); - ATA_OUTL(ctlr->r_res2, offset, (0x0f << shift) | 0x00f000f0); - } - else { - status = ATA_INB(ctlr->r_res2, offset); - ATA_OUTB(ctlr->r_res2, offset, (0x0f << shift)); - } - - /* check for and handle connect events */ - if (((status & (0x0c << shift)) == (0x04 << shift)) && - (tp = (struct ata_connect_task *) - malloc(sizeof(struct ata_connect_task), - M_ATA, M_NOWAIT | M_ZERO))) { - - if (bootverbose) - device_printf(ch->dev, "CONNECT requested\n"); - tp->action = ATA_C_ATTACH; - tp->dev = ch->dev; - TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); - taskqueue_enqueue(taskqueue_thread, &tp->task); - } - - /* check for and handle disconnect events */ - if ((status & (0x08 << shift)) && - !((status & (0x04 << shift) && ATA_IDX_INL(ch, ATA_SSTATUS))) && - (tp = (struct ata_connect_task *) - malloc(sizeof(struct ata_connect_task), - M_ATA, M_NOWAIT | M_ZERO))) { - - if (bootverbose) - device_printf(ch->dev, "DISCONNECT requested\n"); - tp->action = ATA_C_DETACH; - tp->dev = ch->dev; - TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); - taskqueue_enqueue(taskqueue_thread, &tp->task); - } + /* do we have any PHY events ? */ + if (istatus & (0x0c << shift)) + ata_sata_phy_check_events(dev); + + /* clear interrupt(s) */ + ATA_OUTB(ctlr->r_res2, offset, + (0x0f << shift) | (ctlr->chip->cfg2 & NVQ ? 0x00f000f0 : 0)); /* do we have any device action ? */ - return (status & (0x01 << shift)); + return (istatus & (0x01 << shift)); } static void ata_nvidia_reset(device_t dev) { - struct ata_channel *ch = device_get_softc(dev); - - ata_sata_phy_enable(ch); + if (ata_sata_phy_reset(dev)) + ata_generic_reset(dev); } @@ -3714,7 +3723,8 @@ ata_promise_mio_reset(device_t dev) if ((ctlr->chip->cfg2 == PRSATA) || ((ctlr->chip->cfg2 == PRCMBO) && (ch->unit < 2))) { - ata_sata_phy_enable(ch); + if (ata_sata_phy_reset(dev)) + ata_generic_reset(dev); /* reset and enable plug/unplug intr */ ATA_OUTL(ctlr->r_res2, 0x06c, (0x00000011 << ch->unit)); @@ -3749,7 +3759,8 @@ ata_promise_mio_reset(device_t dev) (ATA_INL(ctlr->r_res2, 0x414 + (ch->unit << 8)) & ~0x00000003) | 0x00000001); - ata_sata_phy_enable(ch); + if (ata_sata_phy_reset(dev)) + ata_generic_reset(dev); /* reset and enable plug/unplug intr */ ATA_OUTL(ctlr->r_res2, 0x060, (0x00000011 << ch->unit)); @@ -4209,6 +4220,8 @@ ata_sii_ident(device_t dev) { ATA_SII3512, 0x00, SIIMEMIO, SIIBUG, ATA_SA150, "SiI 3512" }, { ATA_SII3112, 0x00, SIIMEMIO, SIIBUG, ATA_SA150, "SiI 3112" }, { ATA_SII3112_1, 0x00, SIIMEMIO, SIIBUG, ATA_SA150, "SiI 3112" }, + { ATA_SII3124, 0x00, SIIPRBIO, SII4CH, ATA_SA300, "SiI 3124" }, + { ATA_SII3132, 0x00, SIIPRBIO, 0, ATA_SA300, "SiI 3132" }, { ATA_SII0680, 0x00, SIIMEMIO, SIISETCLK, ATA_UDMA6, "SiI 0680" }, { ATA_CMD649, 0x00, 0, SIIINTR, ATA_UDMA5, "CMD 649" }, { ATA_CMD648, 0x00, 0, SIIINTR, ATA_UDMA4, "CMD 648" }, @@ -4235,7 +4248,38 @@ ata_sii_chipinit(device_t dev) if (ata_setup_interrupt(dev)) return ENXIO; - if (ctlr->chip->cfg1 == SIIMEMIO) { + switch (ctlr->chip->cfg1) { + case SIIPRBIO: + ctlr->r_type1 = SYS_RES_MEMORY; + ctlr->r_rid1 = PCIR_BAR(0); + if (!(ctlr->r_res1 = bus_alloc_resource_any(dev, ctlr->r_type1, + &ctlr->r_rid1, RF_ACTIVE))) + return ENXIO; + + ctlr->r_rid2 = PCIR_BAR(2); + ctlr->r_type2 = SYS_RES_MEMORY; + if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2, + &ctlr->r_rid2, RF_ACTIVE))){ + bus_release_resource(dev, ctlr->r_type1, ctlr->r_rid1,ctlr->r_res1); + return ENXIO; + } + ctlr->allocate = ata_siiprb_allocate; + ctlr->reset = ata_siiprb_reset; + ctlr->dmainit = ata_siiprb_dmainit; + ctlr->setmode = ata_sata_setmode; + ctlr->channels = (ctlr->chip->cfg2 == SII4CH) ? 4 : 2; + + /* reset controller */ + ATA_OUTL(ctlr->r_res1, 0x0040, 0x80000000); + DELAY(10000); + ATA_OUTL(ctlr->r_res1, 0x0040, 0x0000000f); + + /* enable PCI interrupt */ + pci_write_config(dev, PCIR_COMMAND, + pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400, 2); + break; + + case SIIMEMIO: ctlr->r_type2 = SYS_RES_MEMORY; ctlr->r_rid2 = PCIR_BAR(5); if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2, @@ -4257,13 +4301,13 @@ ata_sii_chipinit(device_t dev) ctlr->channels = 4; } - /* enable PCI interrupt as BIOS might not */ - pci_write_config(dev, 0x8a, (pci_read_config(dev, 0x8a, 1) & 0x3f), 1); - /* dont block interrupts from any channel */ pci_write_config(dev, 0x48, (pci_read_config(dev, 0x48, 4) & ~0x03c00000), 4); + /* enable PCI interrupt as BIOS might not */ + pci_write_config(dev, 0x8a, (pci_read_config(dev, 0x8a, 1) & 0x3f), 1); + ctlr->allocate = ata_sii_allocate; if (ctlr->chip->max_dma >= ATA_SA150) { ctlr->reset = ata_sii_reset; @@ -4271,8 +4315,9 @@ ata_sii_chipinit(device_t dev) } else ctlr->setmode = ata_sii_setmode; - } - else { + break; + + default: if ((pci_read_config(dev, 0x51, 1) & 0x08) != 0x08) { device_printf(dev, "HW has secondary channel disabled\n"); ctlr->channels = 1; @@ -4283,6 +4328,7 @@ ata_sii_chipinit(device_t dev) ctlr->allocate = ata_cmd_allocate; ctlr->setmode = ata_cmd_setmode; + break; } return 0; } @@ -4396,8 +4442,6 @@ ata_sii_allocate(device_t dev) ch->r_io[ATA_BMSTAT_PORT].offset = 0x02 + (unit01 << 3) + (unit10 << 8); ch->r_io[ATA_BMDTP_PORT].res = ctlr->r_res2; ch->r_io[ATA_BMDTP_PORT].offset = 0x04 + (unit01 << 3) + (unit10 << 8); - ch->r_io[ATA_BMDEVSPEC_0].res = ctlr->r_res2; - ch->r_io[ATA_BMDEVSPEC_0].offset = 0xa1 + (unit01 << 6) + (unit10 << 8); if (ctlr->chip->max_dma >= ATA_SA150) { ch->r_io[ATA_SSTATUS].res = ctlr->r_res2; @@ -4428,68 +4472,25 @@ ata_sii_status(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); + int offset0 = ((ch->unit & 1) << 3) + ((ch->unit & 2) << 8); + int offset1 = ((ch->unit & 1) << 6) + ((ch->unit & 2) << 8); - /* check for PHY related interrupts on SATA capable HW */ - if (ctlr->chip->max_dma >= ATA_SA150) { - u_int32_t status = ATA_IDX_INL(ch, ATA_SSTATUS); - u_int32_t error = ATA_IDX_INL(ch, ATA_SERROR); - struct ata_connect_task *tp; + /* do we have any PHY events ? */ + if (ctlr->chip->max_dma >= ATA_SA150 && + (ATA_INL(ctlr->r_res2, 0x10 + offset0) & 0x00000010)) + ata_sata_phy_check_events(dev); - if (error) { - /* clear error bits/interrupt */ - ATA_IDX_OUTL(ch, ATA_SERROR, error); - - /* if we have a connection event deal with it */ - if ((error & ATA_SE_PHY_CHANGED) && - (tp = (struct ata_connect_task *) - malloc(sizeof(struct ata_connect_task), - M_ATA, M_NOWAIT | M_ZERO))) { - - if ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1) { - if (bootverbose) - device_printf(ch->dev, "CONNECT requested\n"); - tp->action = ATA_C_ATTACH; - } - else { - if (bootverbose) - device_printf(ch->dev, "DISCONNECT requested\n"); - tp->action = ATA_C_DETACH; - } - tp->dev = ch->dev; - TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); - taskqueue_enqueue(taskqueue_thread, &tp->task); - } - } - } - - /* any drive action to take care of ? */ - if (ATA_IDX_INB(ch, ATA_BMDEVSPEC_0) & 0x08) + if (ATA_INL(ctlr->r_res2, 0xa0 + offset1) & 0x00000800) return ata_pci_status(dev); - else + else return 0; } static void ata_sii_reset(device_t dev) { - struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); - struct ata_channel *ch = device_get_softc(dev); - int offset = ((ch->unit & 1) << 7) + ((ch->unit & 2) << 8); - - /* disable PHY state change interrupt */ - ATA_OUTL(ctlr->r_res2, 0x148 + offset, ~(1 << 16)); - - /* reset controller part for this channel */ - ATA_OUTL(ctlr->r_res2, 0x48, - ATA_INL(ctlr->r_res2, 0x48) | (0xc0 >> ch->unit)); - DELAY(1000); - ATA_OUTL(ctlr->r_res2, 0x48, - ATA_INL(ctlr->r_res2, 0x48) & ~(0xc0 >> ch->unit)); - - ata_sata_phy_enable(ch); - - /* enable PHY state change interrupt */ - ATA_OUTL(ctlr->r_res2, 0x148 + offset, (1 << 16)); + if (ata_sata_phy_reset(dev)) + ata_generic_reset(dev); } static void @@ -4558,6 +4559,312 @@ ata_sii_setmode(device_t dev, int mode) } +struct ata_siiprb_dma_prdentry { + u_int64_t addr; + u_int32_t count; + u_int32_t control; +} __packed; + +struct ata_siiprb_ata_command { + u_int32_t reserved0; + struct ata_siiprb_dma_prdentry prd[126]; +} __packed; + +struct ata_siiprb_atapi_command { + u_int8_t cdb[16]; + struct ata_siiprb_dma_prdentry prd[125]; +} __packed; + +struct ata_siiprb_command { + u_int16_t control; + u_int16_t protocol_override; + u_int32_t transfer_count; + u_int8_t fis[20]; + union { + struct ata_siiprb_ata_command ata; + struct ata_siiprb_atapi_command atapi; + } u; +} __packed; + +static int +ata_siiprb_allocate(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(dev); + int offset = ch->unit * 0x2000; + + /* set the SATA resources */ + ch->r_io[ATA_SSTATUS].res = ctlr->r_res2; + ch->r_io[ATA_SSTATUS].offset = 0x1f04 + offset; + ch->r_io[ATA_SERROR].res = ctlr->r_res2; + ch->r_io[ATA_SERROR].offset = 0x1f08 + offset; + ch->r_io[ATA_SCONTROL].res = ctlr->r_res2; + ch->r_io[ATA_SCONTROL].offset = 0x1f00 + offset; + ch->r_io[ATA_SACTIVE].res = ctlr->r_res2; + ch->r_io[ATA_SACTIVE].offset = 0x1f0c + offset; + + ch->hw.begin_transaction = ata_siiprb_begin_transaction; + ch->hw.end_transaction = ata_siiprb_end_transaction; + ch->hw.status = ata_siiprb_status; + ch->hw.command = NULL; /* not used here */ + return 0; +} + +static int +ata_siiprb_status(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(dev); + int offset = ch->unit * 0x2000; + + if ((ATA_INL(ctlr->r_res1, 0x0044) & (1 << ch->unit))) { + u_int32_t istatus = ATA_INL(ctlr->r_res2, 0x1008 + offset); + + /* do we have any PHY events ? */ + ata_sata_phy_check_events(dev); + + /* clear interrupt(s) */ + ATA_OUTL(ctlr->r_res2, 0x1008 + offset, istatus); + + /* do we have any device action ? */ + return (istatus & 0x00000001); + } + return 0; +} + +static int +ata_siiprb_begin_transaction(struct ata_request *request) +{ + struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); + struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_siiprb_command *prb; + int offset = ch->unit * 0x2000; + u_int64_t prb_bus; + int tag = 0, dummy; + + /* check for 48 bit access and convert if needed */ + ata_modify_if_48bit(request); + + /* get a piece of the workspace for this request */ + prb = (struct ata_siiprb_command *) + (ch->dma->work + (sizeof(struct ata_siiprb_command) * tag)); + + /* set basic prd options ata/atapi etc etc */ + bzero(prb, sizeof(struct ata_siiprb_command)); + + /* setup the FIS for this request */ + if (!ata_request2fis_h2d(request, &prb->fis[0])) { + device_printf(request->dev, "setting up SATA FIS failed\n"); + request->result = EIO; + return ATA_OP_FINISHED; + } + + /* if request moves data setup and load SG list */ + if (request->flags & (ATA_R_READ | ATA_R_WRITE)) { + struct ata_siiprb_dma_prdentry *prd; + + if (request->flags & ATA_R_ATAPI) + prd = &prb->u.atapi.prd[0]; + else + prd = &prb->u.ata.prd[0]; + if (ch->dma->load(ch->dev, request->data, request->bytecount, + request->flags & ATA_R_READ, prd, &dummy)) { + device_printf(request->dev, "setting up DMA failed\n"); + request->result = EIO; + return ATA_OP_FINISHED; + } + } + + /* activate the prb */ + prb_bus = ch->dma->work_bus + (sizeof(struct ata_siiprb_command) * tag); + ATA_OUTL(ctlr->r_res2, + 0x1c00 + offset + (tag * sizeof(u_int64_t)), prb_bus); + ATA_OUTL(ctlr->r_res2, + 0x1c04 + offset + (tag * sizeof(u_int64_t)), prb_bus>>32); + + /* start the timeout */ + callout_reset(&request->callout, request->timeout * hz, + (timeout_t*)ata_timeout, request); + return ATA_OP_CONTINUES; +} + +static int +ata_siiprb_end_transaction(struct ata_request *request) +{ + struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); + struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_siiprb_command *prb; + int offset = ch->unit * 0x2000; + int error, tag = 0; + + /* kill the timeout */ + callout_stop(&request->callout); + + prb = (struct ata_siiprb_command *) + ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + (tag << 7) + offset); + + /* if error status get details */ + request->status = prb->fis[2]; + if (request->status & ATA_S_ERROR) + request->error = prb->fis[3]; + + /* update progress */ + if (!(request->status & ATA_S_ERROR) && !(request->flags & ATA_R_TIMEOUT)) { + if (request->flags & ATA_R_READ) + request->donecount = prb->transfer_count; + else + request->donecount = request->bytecount; + } + + /* any controller errors flagged ? */ + if ((error = ATA_INL(ctlr->r_res2, 0x1024 + offset))) { + printf("ata_siiprb_end_transaction %s error=%08x\n", + ata_cmd2str(request), error); + } + + /* release SG list etc */ + ch->dma->unload(ch->dev); + + return ATA_OP_FINISHED; +} + +static void +ata_siiprb_reset(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(dev); + int offset = ch->unit * 0x2000; + struct ata_siiprb_command *prb; + u_int64_t prb_bus; + u_int32_t status, signature; + int timeout, tag = 0; + + /* reset channel HW */ + ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x00000001); + DELAY(1000); + ATA_OUTL(ctlr->r_res2, 0x1004 + offset, 0x00000001); + DELAY(10000); + + /* poll for channel ready */ + for (timeout = 0; timeout < 1000; timeout++) { + if ((status = ATA_INL(ctlr->r_res2, 0x1000 + offset)) & 0x00040000) + break; + DELAY(1000); + } + if (timeout >= 1000) { + device_printf(ch->dev, "channel HW reset timeout reset failure\n"); + ch->devices = 0; + goto finish; + } + if (bootverbose) + device_printf(ch->dev, "channel HW reset time=%dms\n", timeout * 1); + + /* reset phy */ + if (!ata_sata_phy_reset(dev)) { + if (bootverbose) + device_printf(ch->dev, "phy reset found no device\n"); + ch->devices = 0; + goto finish; + } + + /* get a piece of the workspace for a soft reset request */ + prb = (struct ata_siiprb_command *) + (ch->dma->work + (sizeof(struct ata_siiprb_command) * tag)); + bzero(prb, sizeof(struct ata_siiprb_command)); + prb->control = htole16(0x0080); + + /* activate the soft reset prb */ + prb_bus = ch->dma->work_bus + (sizeof(struct ata_siiprb_command) * tag); + ATA_OUTL(ctlr->r_res2, + 0x1c00 + offset + (tag * sizeof(u_int64_t)), prb_bus); + ATA_OUTL(ctlr->r_res2, + 0x1c04 + offset + (tag * sizeof(u_int64_t)), prb_bus>>32); + + /* poll for channel ready */ + for (timeout = 0; timeout < 1000; timeout++) { + DELAY(1000); + if ((status = ATA_INL(ctlr->r_res2, 0x1008 + offset)) & 0x00010000) + break; + } + if (timeout >= 1000) { + device_printf(ch->dev, "reset timeout - no device found\n"); + ch->devices = 0; + goto finish; + } + if (bootverbose) + device_printf(ch->dev, "soft reset exec time=%dms status=%08x\n", + timeout, status); + + /* find out whats there */ + prb = (struct ata_siiprb_command *) + ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + (tag << 7) + offset); + signature = + prb->fis[12]|(prb->fis[4]<<8)|(prb->fis[5]<<16)|(prb->fis[6]<<24); + if (bootverbose) + device_printf(ch->dev, "signature=%08x\n", signature); + switch (signature) { + case 0xeb140101: + ch->devices = ATA_ATAPI_MASTER; + device_printf(ch->dev, "SATA ATAPI devices not supported yet\n"); + ch->devices = 0; + break; + case 0x96690101: + ch->devices = ATA_PORTMULTIPLIER; + device_printf(ch->dev, "Portmultipliers not supported yet\n"); + ch->devices = 0; + break; + case 0x00000101: + ch->devices = ATA_ATA_MASTER; + break; + default: + ch->devices = 0; + } + +finish: + /* clear interrupt(s) */ + ATA_OUTL(ctlr->r_res2, 0x1008 + offset, 0x000008ff); + + /* require explicit interrupt ack */ + ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x00000008); + + /* 64bit mode */ + ATA_OUTL(ctlr->r_res2, 0x1004 + offset, 0x00000400); + + /* enable interrupts wanted */ + ATA_OUTL(ctlr->r_res2, 0x1010 + offset, 0x000000ff); +} + +static void +ata_siiprb_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) +{ + struct ata_dmasetprd_args *args = xsc; + struct ata_siiprb_dma_prdentry *prd = args->dmatab; + int i; + + if ((args->error = error)) + return; + + for (i = 0; i < nsegs; i++) { + prd[i].addr = htole64(segs[i].ds_addr); + prd[i].count = htole32(segs[i].ds_len); + } + prd[i - 1].control = htole32(ATA_DMA_EOT); +} + +static void +ata_siiprb_dmainit(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + + ata_dmainit(dev); + if (ch->dma) { + /* note start and stop are not used here */ + ch->dma->setprd = ata_siiprb_dmasetprd; + ch->dma->max_address = BUS_SPACE_MAXADDR; + } +} + + /* * Silicon Integrated Systems Corp. (SiS) chipset support functions */ @@ -4714,12 +5021,10 @@ ata_sis_allocate(device_t dev) static void ata_sis_reset(device_t dev) { - struct ata_channel *ch = device_get_softc(dev); - - ata_sata_phy_enable(ch); + if (ata_sata_phy_reset(dev)) + ata_generic_reset(dev); } - static void ata_sis_setmode(device_t dev, int mode) { @@ -4823,6 +5128,7 @@ ata_via_ident(device_t dev) { ATA_VIA8235, 0x00, VIA133, 0x00, ATA_UDMA6, "8235" }, { ATA_VIA8237, 0x00, VIA133, 0x00, ATA_UDMA6, "8237" }, { ATA_VIA8237A, 0x00, VIA133, 0x00, ATA_UDMA6, "8237A" }, + { ATA_VIA8237S, 0x00, VIA133, 0x00, ATA_UDMA6, "8237S" }, { ATA_VIA8251, 0x00, VIA133, 0x00, ATA_UDMA6, "8251" }, { 0, 0, 0, 0, 0, 0 }}; static struct ata_chip_id new_ids[] = @@ -4830,6 +5136,7 @@ ata_via_ident(device_t dev) { ATA_VIA6420, 0x00, 7, 0x00, ATA_SA150, "6420" }, { ATA_VIA6421, 0x00, 6, VIABAR, ATA_SA150, "6421" }, { ATA_VIA8237A, 0x00, 7, 0x00, ATA_SA150, "8237A" }, + { ATA_VIA8237S, 0x00, 7, 0x00, ATA_SA150, "8237S" }, { ATA_VIA8251, 0x00, 0, VIAAHCI, ATA_SA300, "8251" }, { 0, 0, 0, 0, 0, 0 }}; char buffer[64]; @@ -4880,7 +5187,13 @@ ata_via_chipinit(device_t dev) pci_write_config(dev, PCIR_COMMAND, pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400,2); } - ctlr->setmode = ata_sata_setmode; + + if (ctlr->chip->cfg2 & VIABAR) { + ctlr->channels = 3; + ctlr->setmode = ata_via_setmode; + } + else + ctlr->setmode = ata_sata_setmode; return 0; } @@ -4941,6 +5254,8 @@ ata_via_allocate(device_t dev) ch->r_io[i].offset = (i - ATA_BMCMD_PORT)+(ch->unit * ATA_BMIOSIZE); } ata_pci_hw(dev); + if (ch->unit > 1) + return 0; } else { /* setup the usual register normal pci style */ @@ -4964,9 +5279,47 @@ ata_via_allocate(device_t dev) static void ata_via_reset(device_t dev) { + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); - ata_sata_phy_enable(ch); + if ((ctlr->chip->cfg2 & VIABAR) && (ch->unit > 1)) + ata_generic_reset(dev); + else + if (ata_sata_phy_reset(dev)) + ata_generic_reset(dev); +} + +static void +ata_via_setmode(device_t dev, int mode) +{ + device_t gparent = GRANDPARENT(dev); + struct ata_pci_controller *ctlr = device_get_softc(gparent); + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_device *atadev = device_get_softc(dev); + int error; + + if ((ctlr->chip->cfg2 & VIABAR) && (ch->unit > 1)) { + u_int8_t pio_timings[] = { 0xa8, 0x65, 0x65, 0x32, 0x20, + 0x65, 0x32, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; + u_int8_t dma_timings[] = { 0xee, 0xe8, 0xe6, 0xe4, 0xe2, 0xe1, 0xe0 }; + + mode = ata_check_80pin(dev, ata_limit_mode(dev, mode, ATA_UDMA6)); + error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); + if (bootverbose) + device_printf(dev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", ata_mode2str(mode), + ctlr->chip->text); + if (!error) { + pci_write_config(gparent, 0xab, pio_timings[ata_mode2idx(mode)], 1); + if (mode >= ATA_UDMA0) + pci_write_config(gparent, 0xb3, + dma_timings[mode & ATA_MODE_MASK], 1); + atadev->mode = mode; + } + } + else + ata_sata_setmode(dev, mode); } static void @@ -5007,7 +5360,7 @@ ata_via_family_setmode(device_t dev, int struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); u_int8_t timings[] = { 0xa8, 0x65, 0x42, 0x22, 0x20, 0x42, 0x22, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; int modes[][7] = { { 0xc2, 0xc1, 0xc0, 0x00, 0x00, 0x00, 0x00 }, /* VIA ATA33 */ { 0xee, 0xec, 0xea, 0xe9, 0xe8, 0x00, 0x00 }, /* VIA ATA66 */ Index: ata-pci.c =================================================================== RCS file: /home/ncvs/src/sys/dev/ata/ata-pci.c,v retrieving revision 1.105.2.5 diff -p -u -r1.105.2.5 ata-pci.c --- ata-pci.c 11 Feb 2007 23:46:45 -0000 1.105.2.5 +++ ata-pci.c 5 Nov 2007 23:00:01 -0000 @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2006 Søren Schmidt + * Copyright (c) 1998 - 2007 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -62,10 +62,15 @@ static MALLOC_DEFINE(M_ATAPCI, "ata_pci" int ata_legacy(device_t dev) { - return ((pci_read_config(dev, PCIR_PROGIF, 1)&PCIP_STORAGE_IDE_MASTERDEV) && - ((pci_read_config(dev, PCIR_PROGIF, 1) & - (PCIP_STORAGE_IDE_MODEPRIM | PCIP_STORAGE_IDE_MODESEC)) != - (PCIP_STORAGE_IDE_MODEPRIM | PCIP_STORAGE_IDE_MODESEC))); + return (((pci_read_config(dev, PCIR_PROGIF, 1)&PCIP_STORAGE_IDE_MASTERDEV)&& + ((pci_read_config(dev, PCIR_PROGIF, 1) & + (PCIP_STORAGE_IDE_MODEPRIM | PCIP_STORAGE_IDE_MODESEC)) != + (PCIP_STORAGE_IDE_MODEPRIM | PCIP_STORAGE_IDE_MODESEC))) || + (!pci_read_config(dev, PCIR_BAR(0), 4) && + !pci_read_config(dev, PCIR_BAR(1), 4) && + !pci_read_config(dev, PCIR_BAR(2), 4) && + !pci_read_config(dev, PCIR_BAR(3), 4) && + !pci_read_config(dev, PCIR_BAR(5), 4))); } int @@ -214,11 +219,7 @@ ata_pci_attach(device_t dev) /* attach all channels on this controller */ for (unit = 0; unit < ctlr->channels; unit++) { - if (unit == 0 && (pci_get_progif(dev) & 0x81) == 0x80) { - device_add_child(dev, "ata", unit); - continue; - } - if (unit == 1 && (pci_get_progif(dev) & 0x84) == 0x80) { + if ((unit == 0 || unit == 1) && ata_legacy(dev)) { device_add_child(dev, "ata", unit); continue; } @@ -588,8 +589,11 @@ ata_pcichannel_attach(device_t dev) if (ch->dma) ch->dma->alloc(dev); - if ((error = ctlr->allocate(dev))) + if ((error = ctlr->allocate(dev))) { + if (ch->dma) + ch->dma->free(dev); return error; + } return ata_attach(dev); } Index: ata-pci.h =================================================================== RCS file: /home/ncvs/src/sys/dev/ata/ata-pci.h,v retrieving revision 1.49.2.13 diff -p -u -r1.49.2.13 ata-pci.h --- ata-pci.h 31 Oct 2007 13:06:17 -0000 1.49.2.13 +++ ata-pci.h 5 Nov 2007 22:57:19 -0000 @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003 - 2006 Søren Schmidt + * Copyright (c) 2003 - 2007 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -169,6 +169,7 @@ struct ata_connect_task { #define ATA_I82801HBM_S1 0x28298086 #define ATA_I82801HBM_S2 0x282a8086 #define ATA_I82801IB_S1 0x29208086 +#define ATA_I82801IB_AH2 0x29218086 #define ATA_I82801IB_AH6 0x29228086 #define ATA_I82801IB_AH4 0x29238086 #define ATA_I82801IB_S2 0x29268086 @@ -184,6 +185,7 @@ struct ata_connect_task { #define ATA_JMB363 0x2363197b #define ATA_JMB365 0x2365197b #define ATA_JMB366 0x2366197b +#define ATA_JMB368 0x2368197b #define ATA_MARVELL_ID 0x11ab #define ATA_M88SX5040 0x504011ab @@ -192,6 +194,8 @@ struct ata_connect_task { #define ATA_M88SX5081 0x508111ab #define ATA_M88SX6041 0x604111ab #define ATA_M88SX6081 0x608111ab +#define ATA_M88SX6101 0x610111ab +#define ATA_M88SX6145 0x614511ab #define ATA_MICRON_ID 0x1042 #define ATA_MICRON_RZ1000 0x10001042 @@ -224,6 +228,10 @@ struct ata_connect_task { #define ATA_NFORCE_MCP55 0x036e10de #define ATA_NFORCE_MCP55_S1 0x037e10de #define ATA_NFORCE_MCP55_S2 0x037f10de +#define ATA_NFORCE_MCP61 0x03ec10de +#define ATA_NFORCE_MCP61_S1 0x03e710de +#define ATA_NFORCE_MCP61_S2 0x03f610de +#define ATA_NFORCE_MCP61_S3 0x03f710de #define ATA_PROMISE_ID 0x105a #define ATA_PDC20246 0x4d33105a @@ -283,6 +291,8 @@ struct ata_connect_task { #define ATA_SII3512 0x35121095 #define ATA_SII3112 0x31121095 #define ATA_SII3112_1 0x02401095 +#define ATA_SII3124 0x31241095 +#define ATA_SII3132 0x31321095 #define ATA_SII0680 0x06801095 #define ATA_CMD646 0x06461095 #define ATA_CMD648 0x06481095 @@ -349,6 +359,7 @@ struct ata_connect_task { #define ATA_VIA8235 0x31771106 #define ATA_VIA8237 0x32271106 #define ATA_VIA8237A 0x05911106 +#define ATA_VIA8237S 0x53371106 #define ATA_VIA8251 0x33491106 #define ATA_VIA8361 0x31121106 #define ATA_VIA8363 0x03051106 @@ -372,8 +383,9 @@ struct ata_connect_task { #define HPT374 3 #define HPTOLD 0x01 -#define MV5XXX 5 -#define MV6XXX 6 +#define MV50XX 50 +#define MV60XX 60 +#define MV61XX 61 #define PROLD 0 #define PRNEW 1 @@ -394,6 +406,7 @@ struct ata_connect_task { #define SWKSMIO 3 #define SIIMEMIO 1 +#define SIIPRBIO 2 #define SIIINTR 0x01 #define SIISETCLK 0x02 #define SIIBUG 0x04 Index: atapi-cd.c =================================================================== RCS file: /home/ncvs/src/sys/dev/ata/atapi-cd.c,v retrieving revision 1.179.2.7 diff -p -u -r1.179.2.7 atapi-cd.c --- atapi-cd.c 2 Sep 2006 17:01:32 -0000 1.179.2.7 +++ atapi-cd.c 5 Nov 2007 22:48:40 -0000 @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2006 Søren Schmidt + * Copyright (c) 1998 - 2007 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -685,32 +685,25 @@ acd_geom_access(struct g_provider *pp, i { device_t dev = pp->geom->softc; struct acd_softc *cdp = device_get_ivars(dev); - struct ata_request *request; - int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int timeout = 60, track; - if (!(request = ata_alloc_request())) - return ENOMEM; - - /* wait if drive is not finished loading the medium */ + /* check for media present, waiting for loading medium just in case */ while (timeout--) { - bzero(request, sizeof(struct ata_request)); - request->dev = dev; - bcopy(ccb, request->u.atapi.ccb, 16); - request->flags = ATA_R_ATAPI; - request->timeout = 5; - ata_queue_request(request); - if (!request->error && - (request->u.atapi.sense.key == 2 || - request->u.atapi.sense.key == 7) && - request->u.atapi.sense.asc == 4 && - request->u.atapi.sense.ascq == 1) - tsleep(&timeout, PRIBIO, "acdld", hz / 2); - else - break; + if (!acd_mode_sense(dev, ATAPI_CDROM_CAP_PAGE, + (caddr_t)&cdp->cap, sizeof(cdp->cap)) && + cdp->cap.page_code == ATAPI_CDROM_CAP_PAGE) { + if ((cdp->cap.medium_type == MST_FMT_NONE) || + (cdp->cap.medium_type == MST_NO_DISC) || + (cdp->cap.medium_type == MST_DOOR_OPEN) || + (cdp->cap.medium_type == MST_FMT_ERROR)) + return EIO; + else + break; + } + tsleep(&timeout, PRIBIO, "acdld", hz / 2); } - ata_free_request(request); + if (timeout <= 0) + return EIO; if (pp->acr == 0) { acd_prevent_allow(dev, 1); @@ -1234,7 +1227,8 @@ acd_get_progress(device_t dev, int *fini request->flags = ATA_R_ATAPI | ATA_R_READ; request->timeout = 30; ata_queue_request(request); - 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 @@ -1635,13 +1629,15 @@ static void acd_get_cap(device_t dev) { struct acd_softc *cdp = device_get_ivars(dev); + int8_t ccb[16] = { ATAPI_MODE_SENSE_BIG, 0, ATAPI_CDROM_CAP_PAGE, + 0, 0, 0, 0, sizeof(cdp->cap)>>8, sizeof(cdp->cap), + 0, 0, 0, 0, 0, 0, 0 }; int count; /* get drive capabilities, some bugridden drives needs this repeated */ for (count = 0 ; count < 5 ; count++) { - if (!acd_mode_sense(dev, ATAPI_CDROM_CAP_PAGE, - (caddr_t)&cdp->cap, sizeof(cdp->cap)) && - cdp->cap.page_code == ATAPI_CDROM_CAP_PAGE) { + if (!ata_atapicmd(dev, ccb, (caddr_t)&cdp->cap, sizeof(cdp->cap), + ATA_R_READ | ATA_R_QUIET, 5)) { cdp->cap.max_read_speed = ntohs(cdp->cap.max_read_speed); cdp->cap.cur_read_speed = ntohs(cdp->cap.cur_read_speed); cdp->cap.max_write_speed = ntohs(cdp->cap.max_write_speed); @@ -1820,6 +1816,8 @@ acd_describe(device_t dev) printf("CD-R "); break; case MST_CDRW: printf("CD-RW "); break; + case MST_DVD: + printf("DVD "); break; case MST_DOOR_OPEN: printf("door open"); break; case MST_NO_DISC: Index: atapi-cd.h =================================================================== RCS file: /home/ncvs/src/sys/dev/ata/atapi-cd.h,v retrieving revision 1.44.2.1 diff -p -u -r1.44.2.1 atapi-cd.h --- atapi-cd.h 25 Jan 2006 08:13:45 -0000 1.44.2.1 +++ atapi-cd.h 5 Nov 2007 22:45:05 -0000 @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2006 Søren Schmidt + * Copyright (c) 1998 - 2007 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -95,6 +95,7 @@ struct cappage { #define MST_CDROM 0x00 #define MST_CDR 0x10 #define MST_CDRW 0x20 +#define MST_DVD 0x40 #define MST_NO_DISC 0x70 #define MST_DOOR_OPEN 0x71 --------------000505030308030107050800--