Index: stable/9/share/man/man4/ata.4 =================================================================== --- stable/9/share/man/man4/ata.4 (revision 243117) +++ stable/9/share/man/man4/ata.4 (revision 243118) @@ -1,272 +1,278 @@ .\" Copyright (c) 2011 Alexander Motin .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" -.Dd June 18, 2012 +.Dd October 3, 2012 .Dt ATA 4 .Os .Sh NAME .Nm ata .Nd generic ATA/SATA controller driver .Sh SYNOPSIS To compile this driver into the kernel, place the following lines in your kernel configuration file: .Bd -ragged -offset indent .Cd "device scbus" .Cd "device ata" .Cd "options ATA_CAM" .Ed .Pp Alternatively, to load the driver as set of modules at boot time, place some of the following lines in .Xr loader.conf 5 : .Bd -literal -offset indent ata_load="YES" atacard_load="YES" ataisa_load="YES" atapci_load="YES" ataacard_load="YES" ataacerlabs_load="YES" ataadaptec_load="YES" ataahci_load="YES" ataamd_load="YES" ataati_load="YES" atacenatek_load="YES" atacypress_load="YES" atacyrix_load="YES" atahighpoint_load="YES" ataintel_load="YES" ataite_load="YES" atajmicron_load="YES" atamarvell_load="YES" atamicron_load="YES" atanational_load="YES" atanetcell_load="YES" atanvidia_load="YES" atapromise_load="YES" ataserverworks_load="YES" atasiliconimage_load="YES" atasis_load="YES" atavia_load="YES" .Ed .Pp The first line is for the common hardware independent code, and is a prerequisite for the other modules. The next three lines are generic bus-specific drivers. Of the rest, ataahci is the AHCI driver. The others are vendor-specific PCI drivers. The .Dv ATA_CAM option should always remain in the kernel configuration, to make the driver work as a .Xr CAM 4 subsystem module. .Pp The following tunables are settable from the .Xr loader 8 : .Bl -ohang .It Va hw.ahci.force set to nonzero value for forcing drivers to attach to some known AHCI-capable chips even if they are configured for legacy IDE emulation (the default is 1, force the attach). .It Va hw.ata.ata_dma_check_80pin set to 0 to disable the 80pin cable check (the default is 1, check the cable). .It Va hint.atapci.X.msi set to 1 to allow Message Signalled Interrupts (MSI) to be used by the specified PCI ATA controller, if supported. .It Va hint.ata.X.devX.mode -limits the initial ATA mode for the specified device on specified the channel. +limits the initial ATA mode for the specified device on the specified channel. .It Va hint.ata.X.mode limits the initial ATA mode for every device on the specified channel. .It Va hint.ata.X.pm_level controls SATA interface Power Management for the specified channel, allowing some power savings at the cost of additional command latency. Possible values: .Bl -tag -compact .It 0 Interface Power Management is disabled. This is the default value. .It 1 The device is allowed to initiate a PM state change; the host is passive. .It 2 The host initiates a PARTIAL PM state transition every time a port becomes idle. .It 3 host initiates SLUMBER PM state transition every time port becomes idle. .El Modes 2 and 3 are only supported for AHCI. +.It Va hint.ata. Ns Ar X Ns Va .dev Ns Ar X Ns Va .sata_rev +limits the initial SATA revision (speed) for the specified device +on the specified channel. +Values 1, 2 and 3 are respectively 1.5, 3 and 6Gbps. +.It Va hint.ata. Ns Ar X Ns Va .sata_rev +Same, but for every device on the specified channel. .El .Sh DESCRIPTION The .Nm driver gives the .Xr CAM 4 subsystem access to the ATA (IDE) and SATA ports of many generic controllers. Depending on the controller, each PATA (IDE) port or each one or two SATA ports are represented to CAM as a separate bus with one or two targets. Most of the bus-management details are handled by the ATA/SATA-specific transport of CAM. Connected ATA disks are handled by the ATA protocol disk peripheral driver .Xr ada 4 . ATAPI devices are handled by the SCSI protocol peripheral drivers .Xr cd 4 , .Xr da 4 , .Xr sa 4 , etc. .Pp This driver supports ATA, and for the most of controllers, ATAPI devices. Command queuing and SATA port multipliers are not supported. Device hot-plug and SATA interface power management is supported only on some controllers. .Pp The .Nm driver can change the transfer mode when the system is up and running. See the .Cm negotiate subcommand of .Xr camcontrol 8 . .Pp The .Nm driver sets the maximum transfer mode supported by the hardware as default. However, the .Nm driver sometimes warns: .Dq Sy "DMA limited to UDMA33, non-ATA66 cable or device". This means that the .Nm driver has detected that the required 80 conductor cable is not present or could not be detected properly, or that one of the devices on the channel only accepts up to UDMA2/ATA33. The .Va hw.ata.ata_dma_check_80pin tunable can be set to 0 to disable this check. .Sh HARDWARE The currently supported ATA/SATA controller chips are: .Pp .Bl -tag -width "Silicon Image:" -compact .It Acard: ATP850P, ATP860A, ATP860R, ATP865A, ATP865R. .It ALI: M5228, M5229, M5281, M5283, M5287, M5288, M5289. .It AMD: AMD756, AMD766, AMD768, AMD8111, CS5536. .It ATI: IXP200, IXP300, IXP400, IXP600, IXP700, IXP800. .It CMD: CMD646, CMD646U2, CMD648, CMD649. .It Cypress: Cypress 82C693. .It Cyrix: Cyrix 5530. .It HighPoint: HPT302, HPT366, HPT368, HPT370, HPT371, HPT372, HPT372N, HPT374. .It Intel: 6300ESB, 31244, PIIX, PIIX3, PIIX4, ESB2, ICH, ICH0, ICH2, ICH3, ICH4, ICH5, ICH6, ICH7, ICH8, ICH9, ICH10, SCH, PCH. .It ITE: IT8211F, IT8212F, IT8213F. .It JMicron: JMB360, JMB361, JMB363, JMB365, JMB366, JMB368. .It Marvell 88SX5040, 88SX5041, 88SX5080, 88SX5081, 88SX6041, 88SX6042, 88SX6081, 88SE6101, 88SE6102, 88SE6111, 88SE6121, 88SE6141, 88SE6145, 88SX7042. .It National: SC1100. .It NetCell: NC3000, NC5000. .It nVidia: nForce, nForce2, nForce2 MCP, nForce3, nForce3 MCP, nForce3 Pro, nForce4, MCP51, MCP55, MCP61, MCP65, MCP67, MCP73, MCP77, MCP79, MCP89. .It Promise: PDC20246, PDC20262, PDC20263, PDC20265, PDC20267, PDC20268, PDC20269, PDC20270, PDC20271, PDC20275, PDC20276, PDC20277, PDC20318, PDC20319, PDC20371, PDC20375, PDC20376, PDC20377, PDC20378, PDC20379, PDC20571, PDC20575, PDC20579, PDC20580, PDC20617, PDC20618, PDC20619, PDC20620, PDC20621, PDC20622, PDC40518, PDC40519, PDC40718, PDC40719. .It ServerWorks: HT1000, ROSB4, CSB5, CSB6, K2, Frodo4, Frodo8. .It Silicon Image: SiI0680, SiI3112, SiI3114, SiI3124, SiI3132, SiI3512. .It SiS: SIS180, SIS181, SIS182, SIS5513, SIS530, SIS540, SIS550, SIS620, SIS630, SIS630S, SIS633, SIS635, SIS730, SIS733, SIS735, SIS745, SIS961, SIS962, SIS963, SIS964, SIS965. .It VIA: VT6410, VT6420, VT6421, VT82C586, VT82C586B, VT82C596, VT82C596B, VT82C686, VT82C686A, VT82C686B, VT8231, VT8233, VT8233A, VT8233C, VT8235, VT8237, VT8237A, VT8237S, VT8251, CX700, VX800, VX855, VX900. .El .Pp Some of above chips are also supported by the more featured .Xr ahci 4 , .Xr mvs 4 , and .Xr siis 4 drivers. If both drivers are loaded at the same time, those will have precedence. .Pp Unknown ATA chipsets are supported in PIO modes, and if the standard busmaster DMA registers are present and contain valid setup, DMA is also enabled, although the max mode is limited to UDMA33, as it is not known what the chipset can do and how to program it. .Sh NOTES Please remember that in order to use UDMA4/ATA66 and above modes you .Em must use 80 conductor cables. Please assure that ribbon cables are no longer than 45cm. In case of rounded ATA cables, the length depends on the quality of the cables. SATA cables can be up to 1m long according to the specification. External SATA cables can be 2m long and more, but not all controllers work well on long cables, especially at high speeds. .Sh SEE ALSO .Xr ada 4 , .Xr ahci 4 , .Xr cam 4 , .Xr camcontrol 8 , .Xr cd 4 , .Xr mvs 4 , .Xr siis 4 .Sh HISTORY The .Nm driver first appeared in .Fx 4.0 . It was turned into a .Xr CAM 4 interface module in .Fx 9.0 . .Sh AUTHORS .An Alexander Motin .Aq mav@FreeBSD.org , .An S\(/oren Schmidt .Aq sos@FreeBSD.org Index: stable/9/share/man/man4 =================================================================== --- stable/9/share/man/man4 (revision 243117) +++ stable/9/share/man/man4 (revision 243118) Property changes on: stable/9/share/man/man4 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/share/man/man4:r241144,241160 Index: stable/9/sys/dev/ata/ata-all.c =================================================================== --- stable/9/sys/dev/ata/ata-all.c (revision 243117) +++ stable/9/sys/dev/ata/ata-all.c (revision 243118) @@ -1,1976 +1,1985 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef ATA_CAM #include #include #include #include #include #endif #ifndef ATA_CAM /* device structure */ static d_ioctl_t ata_ioctl; static struct cdevsw ata_cdevsw = { .d_version = D_VERSION, .d_flags = D_NEEDGIANT, /* we need this as newbus isn't mpsafe */ .d_ioctl = ata_ioctl, .d_name = "ata", }; #endif /* prototypes */ #ifndef ATA_CAM static void ata_boot_attach(void); static device_t ata_add_child(device_t, struct ata_device *, int); #else static void ataaction(struct cam_sim *sim, union ccb *ccb); static void atapoll(struct cam_sim *sim); #endif static void ata_conn_event(void *, int); #ifndef ATA_CAM static void bswap(int8_t *, int); static void btrim(int8_t *, int); static void bpack(int8_t *, int8_t *, int); #endif static void ata_interrupt_locked(void *data); #ifdef ATA_CAM static void ata_periodic_poll(void *data); #endif /* global vars */ MALLOC_DEFINE(M_ATA, "ata_generic", "ATA driver generic layer"); int (*ata_raid_ioctl_func)(u_long cmd, caddr_t data) = NULL; #ifndef ATA_CAM struct intr_config_hook *ata_delayed_attach = NULL; #endif devclass_t ata_devclass; uma_zone_t ata_request_zone; uma_zone_t ata_composite_zone; #ifndef ATA_CAM int ata_wc = 1; int ata_setmax = 0; #endif int ata_dma_check_80pin = 1; /* local vars */ #ifndef ATA_CAM static int ata_dma = 1; static int atapi_dma = 1; #endif /* sysctl vars */ SYSCTL_NODE(_hw, OID_AUTO, ata, CTLFLAG_RD, 0, "ATA driver parameters"); #ifndef ATA_CAM TUNABLE_INT("hw.ata.ata_dma", &ata_dma); SYSCTL_INT(_hw_ata, OID_AUTO, ata_dma, CTLFLAG_RDTUN, &ata_dma, 0, "ATA disk DMA mode control"); #endif TUNABLE_INT("hw.ata.ata_dma_check_80pin", &ata_dma_check_80pin); SYSCTL_INT(_hw_ata, OID_AUTO, ata_dma_check_80pin, CTLFLAG_RW, &ata_dma_check_80pin, 1, "Check for 80pin cable before setting ATA DMA mode"); #ifndef ATA_CAM TUNABLE_INT("hw.ata.atapi_dma", &atapi_dma); SYSCTL_INT(_hw_ata, OID_AUTO, atapi_dma, CTLFLAG_RDTUN, &atapi_dma, 0, "ATAPI device DMA mode control"); TUNABLE_INT("hw.ata.wc", &ata_wc); SYSCTL_INT(_hw_ata, OID_AUTO, wc, CTLFLAG_RDTUN, &ata_wc, 0, "ATA disk write caching"); TUNABLE_INT("hw.ata.setmax", &ata_setmax); SYSCTL_INT(_hw_ata, OID_AUTO, setmax, CTLFLAG_RDTUN, &ata_setmax, 0, "ATA disk set max native address"); #endif #ifdef ATA_CAM FEATURE(ata_cam, "ATA devices are accessed through the cam(4) driver"); #endif /* * newbus device interface related functions */ int ata_probe(device_t dev) { return 0; } int ata_attach(device_t dev) { struct ata_channel *ch = device_get_softc(dev); int error, rid; #ifdef ATA_CAM struct cam_devq *devq; const char *res; char buf[64]; int i, mode; #endif /* check that we have a virgin channel to attach */ if (ch->r_irq) return EEXIST; /* initialize the softc basics */ ch->dev = dev; ch->state = ATA_IDLE; bzero(&ch->state_mtx, sizeof(struct mtx)); mtx_init(&ch->state_mtx, "ATA state lock", NULL, MTX_DEF); bzero(&ch->queue_mtx, sizeof(struct mtx)); mtx_init(&ch->queue_mtx, "ATA queue lock", NULL, MTX_DEF); TAILQ_INIT(&ch->ata_queue); TASK_INIT(&ch->conntask, 0, ata_conn_event, dev); #ifdef ATA_CAM for (i = 0; i < 16; i++) { + ch->user[i].revision = 0; + snprintf(buf, sizeof(buf), "dev%d.sata_rev", i); + if (resource_int_value(device_get_name(dev), + device_get_unit(dev), buf, &mode) != 0 && + resource_int_value(device_get_name(dev), + device_get_unit(dev), "sata_rev", &mode) != 0) + mode = -1; + if (mode >= 0) + ch->user[i].revision = mode; ch->user[i].mode = 0; snprintf(buf, sizeof(buf), "dev%d.mode", i); if (resource_string_value(device_get_name(dev), device_get_unit(dev), buf, &res) == 0) mode = ata_str2mode(res); else if (resource_string_value(device_get_name(dev), device_get_unit(dev), "mode", &res) == 0) mode = ata_str2mode(res); else mode = -1; if (mode >= 0) ch->user[i].mode = mode; if (ch->flags & ATA_SATA) ch->user[i].bytecount = 8192; else ch->user[i].bytecount = MAXPHYS; ch->user[i].caps = 0; ch->curr[i] = ch->user[i]; if (ch->pm_level > 0) ch->user[i].caps |= CTS_SATA_CAPS_H_PMREQ; if (ch->pm_level > 1) ch->user[i].caps |= CTS_SATA_CAPS_D_PMREQ; } callout_init(&ch->poll_callout, 1); #endif #ifndef ATA_CAM /* reset the controller HW, the channel and device(s) */ while (ATA_LOCKING(dev, ATA_LF_LOCK) != ch->unit) pause("ataatch", 1); ATA_RESET(dev); ATA_LOCKING(dev, ATA_LF_UNLOCK); #endif /* allocate DMA resources if DMA HW present*/ if (ch->dma.alloc) ch->dma.alloc(dev); /* setup interrupt delivery */ rid = ATA_IRQ_RID; ch->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); if (!ch->r_irq) { device_printf(dev, "unable to allocate interrupt\n"); return ENXIO; } if ((error = bus_setup_intr(dev, ch->r_irq, ATA_INTR_FLAGS, NULL, ata_interrupt, ch, &ch->ih))) { bus_release_resource(dev, SYS_RES_IRQ, rid, ch->r_irq); device_printf(dev, "unable to setup interrupt\n"); return error; } #ifndef ATA_CAM /* probe and attach devices on this channel unless we are in early boot */ if (!ata_delayed_attach) ata_identify(dev); return (0); #else if (ch->flags & ATA_PERIODIC_POLL) callout_reset(&ch->poll_callout, hz, ata_periodic_poll, ch); mtx_lock(&ch->state_mtx); /* Create the device queue for our SIM. */ devq = cam_simq_alloc(1); if (devq == NULL) { device_printf(dev, "Unable to allocate simq\n"); error = ENOMEM; goto err1; } /* Construct SIM entry */ ch->sim = cam_sim_alloc(ataaction, atapoll, "ata", ch, device_get_unit(dev), &ch->state_mtx, 1, 0, devq); if (ch->sim == NULL) { device_printf(dev, "unable to allocate sim\n"); cam_simq_free(devq); error = ENOMEM; goto err1; } if (xpt_bus_register(ch->sim, dev, 0) != CAM_SUCCESS) { device_printf(dev, "unable to register xpt bus\n"); error = ENXIO; goto err2; } if (xpt_create_path(&ch->path, /*periph*/NULL, cam_sim_path(ch->sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { device_printf(dev, "unable to create path\n"); error = ENXIO; goto err3; } mtx_unlock(&ch->state_mtx); return (0); err3: xpt_bus_deregister(cam_sim_path(ch->sim)); err2: cam_sim_free(ch->sim, /*free_devq*/TRUE); ch->sim = NULL; err1: bus_release_resource(dev, SYS_RES_IRQ, rid, ch->r_irq); mtx_unlock(&ch->state_mtx); if (ch->flags & ATA_PERIODIC_POLL) callout_drain(&ch->poll_callout); return (error); #endif } int ata_detach(device_t dev) { struct ata_channel *ch = device_get_softc(dev); #ifndef ATA_CAM device_t *children; int nchildren, i; #endif /* check that we have a valid channel to detach */ if (!ch->r_irq) return ENXIO; /* grap the channel lock so no new requests gets launched */ mtx_lock(&ch->state_mtx); ch->state |= ATA_STALL_QUEUE; mtx_unlock(&ch->state_mtx); #ifdef ATA_CAM if (ch->flags & ATA_PERIODIC_POLL) callout_drain(&ch->poll_callout); #endif #ifndef ATA_CAM /* detach & delete all children */ if (!device_get_children(dev, &children, &nchildren)) { for (i = 0; i < nchildren; i++) if (children[i]) device_delete_child(dev, children[i]); free(children, M_TEMP); } #endif taskqueue_drain(taskqueue_thread, &ch->conntask); #ifdef ATA_CAM mtx_lock(&ch->state_mtx); xpt_async(AC_LOST_DEVICE, ch->path, NULL); xpt_free_path(ch->path); xpt_bus_deregister(cam_sim_path(ch->sim)); cam_sim_free(ch->sim, /*free_devq*/TRUE); ch->sim = NULL; mtx_unlock(&ch->state_mtx); #endif /* release resources */ bus_teardown_intr(dev, ch->r_irq, ch->ih); bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ch->r_irq); ch->r_irq = NULL; /* free DMA resources if DMA HW present*/ if (ch->dma.free) ch->dma.free(dev); mtx_destroy(&ch->state_mtx); mtx_destroy(&ch->queue_mtx); return 0; } static void ata_conn_event(void *context, int dummy) { device_t dev = (device_t)context; #ifdef ATA_CAM struct ata_channel *ch = device_get_softc(dev); union ccb *ccb; mtx_lock(&ch->state_mtx); if (ch->sim == NULL) { mtx_unlock(&ch->state_mtx); return; } ata_reinit(dev); if ((ccb = xpt_alloc_ccb_nowait()) == NULL) return; if (xpt_create_path(&ccb->ccb_h.path, NULL, cam_sim_path(ch->sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { xpt_free_ccb(ccb); return; } xpt_rescan(ccb); mtx_unlock(&ch->state_mtx); #else ata_reinit(dev); #endif } int ata_reinit(device_t dev) { struct ata_channel *ch = device_get_softc(dev); struct ata_request *request; #ifndef ATA_CAM device_t *children; int nchildren, i; /* check that we have a valid channel to reinit */ if (!ch || !ch->r_irq) return ENXIO; if (bootverbose) device_printf(dev, "reiniting channel ..\n"); /* poll for locking the channel */ while (ATA_LOCKING(dev, ATA_LF_LOCK) != ch->unit) pause("atarini", 1); /* catch eventual request in ch->running */ mtx_lock(&ch->state_mtx); if (ch->state & ATA_STALL_QUEUE) { /* Recursive reinits and reinits during detach prohobited. */ mtx_unlock(&ch->state_mtx); return (ENXIO); } if ((request = ch->running)) callout_stop(&request->callout); ch->running = NULL; /* unconditionally grap the channel lock */ ch->state |= ATA_STALL_QUEUE; mtx_unlock(&ch->state_mtx); /* reset the controller HW, the channel and device(s) */ ATA_RESET(dev); /* reinit the children and delete any that fails */ if (!device_get_children(dev, &children, &nchildren)) { mtx_lock(&Giant); /* newbus suckage it needs Giant */ for (i = 0; i < nchildren; i++) { /* did any children go missing ? */ if (children[i] && device_is_attached(children[i]) && ATA_REINIT(children[i])) { /* * if we had a running request and its device matches * this child we need to inform the request that the * device is gone. */ if (request && request->dev == children[i]) { request->result = ENXIO; device_printf(request->dev, "FAILURE - device detached\n"); /* if not timeout finish request here */ if (!(request->flags & ATA_R_TIMEOUT)) ata_finish(request); request = NULL; } device_delete_child(dev, children[i]); } } free(children, M_TEMP); mtx_unlock(&Giant); /* newbus suckage dealt with, release Giant */ } /* if we still have a good request put it on the queue again */ if (request && !(request->flags & ATA_R_TIMEOUT)) { device_printf(request->dev, "WARNING - %s requeued due to channel reset", ata_cmd2str(request)); if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) printf(" LBA=%ju", request->u.ata.lba); printf("\n"); request->flags |= ATA_R_REQUEUE; ata_queue_request(request); } /* we're done release the channel for new work */ mtx_lock(&ch->state_mtx); ch->state = ATA_IDLE; mtx_unlock(&ch->state_mtx); ATA_LOCKING(dev, ATA_LF_UNLOCK); /* Add new children. */ /* ata_identify(dev); */ if (bootverbose) device_printf(dev, "reinit done ..\n"); /* kick off requests on the queue */ ata_start(dev); #else xpt_freeze_simq(ch->sim, 1); if ((request = ch->running)) { ch->running = NULL; if (ch->state == ATA_ACTIVE) ch->state = ATA_IDLE; callout_stop(&request->callout); if (ch->dma.unload) ch->dma.unload(request); request->result = ERESTART; ata_cam_end_transaction(dev, request); } /* reset the controller HW, the channel and device(s) */ ATA_RESET(dev); /* Tell the XPT about the event */ xpt_async(AC_BUS_RESET, ch->path, NULL); xpt_release_simq(ch->sim, TRUE); #endif return(0); } int ata_suspend(device_t dev) { struct ata_channel *ch; /* check for valid device */ if (!dev || !(ch = device_get_softc(dev))) return ENXIO; #ifdef ATA_CAM if (ch->flags & ATA_PERIODIC_POLL) callout_drain(&ch->poll_callout); mtx_lock(&ch->state_mtx); xpt_freeze_simq(ch->sim, 1); while (ch->state != ATA_IDLE) msleep(ch, &ch->state_mtx, PRIBIO, "atasusp", hz/100); mtx_unlock(&ch->state_mtx); #else /* wait for the channel to be IDLE or detached before suspending */ while (ch->r_irq) { mtx_lock(&ch->state_mtx); if (ch->state == ATA_IDLE) { ch->state = ATA_ACTIVE; mtx_unlock(&ch->state_mtx); break; } mtx_unlock(&ch->state_mtx); tsleep(ch, PRIBIO, "atasusp", hz/10); } ATA_LOCKING(dev, ATA_LF_UNLOCK); #endif return(0); } int ata_resume(device_t dev) { struct ata_channel *ch; int error; /* check for valid device */ if (!dev || !(ch = device_get_softc(dev))) return ENXIO; #ifdef ATA_CAM mtx_lock(&ch->state_mtx); error = ata_reinit(dev); xpt_release_simq(ch->sim, TRUE); mtx_unlock(&ch->state_mtx); if (ch->flags & ATA_PERIODIC_POLL) callout_reset(&ch->poll_callout, hz, ata_periodic_poll, ch); #else /* reinit the devices, we dont know what mode/state they are in */ error = ata_reinit(dev); /* kick off requests on the queue */ ata_start(dev); #endif return error; } void ata_interrupt(void *data) { #ifdef ATA_CAM struct ata_channel *ch = (struct ata_channel *)data; mtx_lock(&ch->state_mtx); xpt_batch_start(ch->sim); #endif ata_interrupt_locked(data); #ifdef ATA_CAM xpt_batch_done(ch->sim); mtx_unlock(&ch->state_mtx); #endif } static void ata_interrupt_locked(void *data) { struct ata_channel *ch = (struct ata_channel *)data; struct ata_request *request; #ifndef ATA_CAM mtx_lock(&ch->state_mtx); #endif do { /* ignore interrupt if its not for us */ if (ch->hw.status && !ch->hw.status(ch->dev)) break; /* do we have a running request */ if (!(request = ch->running)) break; ATA_DEBUG_RQ(request, "interrupt"); /* safetycheck for the right state */ if (ch->state == ATA_IDLE) { device_printf(request->dev, "interrupt on idle channel ignored\n"); break; } /* * we have the HW locks, so end the transaction for this request * if it finishes immediately otherwise wait for next interrupt */ if (ch->hw.end_transaction(request) == ATA_OP_FINISHED) { ch->running = NULL; if (ch->state == ATA_ACTIVE) ch->state = ATA_IDLE; #ifdef ATA_CAM ata_cam_end_transaction(ch->dev, request); #else mtx_unlock(&ch->state_mtx); ATA_LOCKING(ch->dev, ATA_LF_UNLOCK); ata_finish(request); #endif return; } } while (0); #ifndef ATA_CAM mtx_unlock(&ch->state_mtx); #endif } #ifdef ATA_CAM static void ata_periodic_poll(void *data) { struct ata_channel *ch = (struct ata_channel *)data; callout_reset(&ch->poll_callout, hz, ata_periodic_poll, ch); ata_interrupt(ch); } #endif void ata_print_cable(device_t dev, u_int8_t *who) { device_printf(dev, "DMA limited to UDMA33, %s found non-ATA66 cable\n", who); } #ifndef ATA_CAM int ata_check_80pin(device_t dev, int mode) { struct ata_device *atadev = device_get_softc(dev); if (!ata_dma_check_80pin) { if (bootverbose) device_printf(dev, "Skipping 80pin cable check\n"); return mode; } if (mode > ATA_UDMA2 && !(atadev->param.hwres & ATA_CABLE_ID)) { ata_print_cable(dev, "device"); mode = ATA_UDMA2; } return mode; } #endif #ifndef ATA_CAM void ata_setmode(device_t dev) { struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); int error, mode, pmode; mode = atadev->mode; do { pmode = mode = ata_limit_mode(dev, mode, ATA_DMA_MAX); mode = ATA_SETMODE(device_get_parent(dev), atadev->unit, mode); if ((ch->flags & (ATA_CHECKS_CABLE | ATA_SATA)) == 0) mode = ata_check_80pin(dev, mode); } while (pmode != mode); /* Interate till successfull negotiation. */ error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); if (bootverbose) device_printf(dev, "%ssetting %s\n", (error) ? "FAILURE " : "", ata_mode2str(mode)); atadev->mode = mode; } #endif /* * device related interfaces */ #ifndef ATA_CAM static int ata_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int32_t flag, struct thread *td) { device_t device, *children; struct ata_ioc_devices *devices = (struct ata_ioc_devices *)data; int *value = (int *)data; int i, nchildren, error = ENOTTY; switch (cmd) { case IOCATAGMAXCHANNEL: /* In case we have channel 0..n this will return n+1. */ *value = devclass_get_maxunit(ata_devclass); error = 0; break; case IOCATAREINIT: if (*value >= devclass_get_maxunit(ata_devclass) || !(device = devclass_get_device(ata_devclass, *value)) || !device_is_attached(device)) return ENXIO; error = ata_reinit(device); break; case IOCATAATTACH: if (*value >= devclass_get_maxunit(ata_devclass) || !(device = devclass_get_device(ata_devclass, *value)) || !device_is_attached(device)) return ENXIO; error = DEVICE_ATTACH(device); break; case IOCATADETACH: if (*value >= devclass_get_maxunit(ata_devclass) || !(device = devclass_get_device(ata_devclass, *value)) || !device_is_attached(device)) return ENXIO; error = DEVICE_DETACH(device); break; case IOCATADEVICES: if (devices->channel >= devclass_get_maxunit(ata_devclass) || !(device = devclass_get_device(ata_devclass, devices->channel)) || !device_is_attached(device)) return ENXIO; bzero(devices->name[0], 32); bzero(&devices->params[0], sizeof(struct ata_params)); bzero(devices->name[1], 32); bzero(&devices->params[1], sizeof(struct ata_params)); if (!device_get_children(device, &children, &nchildren)) { for (i = 0; i < nchildren; i++) { if (children[i] && device_is_attached(children[i])) { struct ata_device *atadev = device_get_softc(children[i]); if (atadev->unit == ATA_MASTER) { /* XXX SOS PM */ strncpy(devices->name[0], device_get_nameunit(children[i]), 32); bcopy(&atadev->param, &devices->params[0], sizeof(struct ata_params)); } if (atadev->unit == ATA_SLAVE) { /* XXX SOS PM */ strncpy(devices->name[1], device_get_nameunit(children[i]), 32); bcopy(&atadev->param, &devices->params[1], sizeof(struct ata_params)); } } } free(children, M_TEMP); error = 0; } else error = ENODEV; break; default: if (ata_raid_ioctl_func) error = ata_raid_ioctl_func(cmd, data); } return error; } #endif #ifndef ATA_CAM int ata_device_ioctl(device_t dev, u_long cmd, caddr_t data) { struct ata_device *atadev = device_get_softc(dev); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_ioc_request *ioc_request = (struct ata_ioc_request *)data; struct ata_params *params = (struct ata_params *)data; int *mode = (int *)data; struct ata_request *request; caddr_t buf; int error; switch (cmd) { case IOCATAREQUEST: if (ioc_request->count > (ch->dma.max_iosize ? ch->dma.max_iosize : DFLTPHYS)) { return (EFBIG); } if (!(buf = malloc(ioc_request->count, M_ATA, M_NOWAIT))) { return ENOMEM; } if (!(request = ata_alloc_request())) { free(buf, M_ATA); return ENOMEM; } request->dev = atadev->dev; if (ioc_request->flags & ATA_CMD_WRITE) { error = copyin(ioc_request->data, buf, ioc_request->count); if (error) { free(buf, M_ATA); ata_free_request(request); return error; } } if (ioc_request->flags & ATA_CMD_ATAPI) { request->flags = ATA_R_ATAPI; bcopy(ioc_request->u.atapi.ccb, request->u.atapi.ccb, 16); } else { request->u.ata.command = ioc_request->u.ata.command; request->u.ata.feature = ioc_request->u.ata.feature; request->u.ata.lba = ioc_request->u.ata.lba; request->u.ata.count = ioc_request->u.ata.count; } request->timeout = ioc_request->timeout; request->data = buf; request->bytecount = ioc_request->count; request->transfersize = request->bytecount; if (ioc_request->flags & ATA_CMD_CONTROL) request->flags |= ATA_R_CONTROL; if (ioc_request->flags & ATA_CMD_READ) request->flags |= ATA_R_READ; if (ioc_request->flags & ATA_CMD_WRITE) request->flags |= ATA_R_WRITE; ata_queue_request(request); if (request->flags & ATA_R_ATAPI) { bcopy(&request->u.atapi.sense, &ioc_request->u.atapi.sense, sizeof(struct atapi_sense)); } else { ioc_request->u.ata.command = request->u.ata.command; ioc_request->u.ata.feature = request->u.ata.feature; ioc_request->u.ata.lba = request->u.ata.lba; ioc_request->u.ata.count = request->u.ata.count; } ioc_request->error = request->result; if (ioc_request->flags & ATA_CMD_READ) error = copyout(buf, ioc_request->data, ioc_request->count); else error = 0; free(buf, M_ATA); ata_free_request(request); return error; case IOCATAGPARM: ata_getparam(atadev, 0); bcopy(&atadev->param, params, sizeof(struct ata_params)); return 0; case IOCATASMODE: atadev->mode = *mode; ata_setmode(dev); return 0; case IOCATAGMODE: *mode = atadev->mode | (ATA_GETREV(device_get_parent(dev), atadev->unit) << 8); return 0; case IOCATASSPINDOWN: atadev->spindown = *mode; return 0; case IOCATAGSPINDOWN: *mode = atadev->spindown; return 0; default: return ENOTTY; } } #endif #ifndef ATA_CAM static void ata_boot_attach(void) { struct ata_channel *ch; int ctlr; mtx_lock(&Giant); /* newbus suckage it needs Giant */ /* kick of probe and attach on all channels */ for (ctlr = 0; ctlr < devclass_get_maxunit(ata_devclass); ctlr++) { if ((ch = devclass_get_softc(ata_devclass, ctlr))) { ata_identify(ch->dev); } } /* release the hook that got us here, we are only needed once during boot */ if (ata_delayed_attach) { config_intrhook_disestablish(ata_delayed_attach); free(ata_delayed_attach, M_TEMP); ata_delayed_attach = NULL; } mtx_unlock(&Giant); /* newbus suckage dealt with, release Giant */ } #endif /* * misc support functions */ #ifndef ATA_CAM static device_t ata_add_child(device_t parent, struct ata_device *atadev, int unit) { device_t child; if ((child = device_add_child(parent, (unit < 0) ? NULL : "ad", unit))) { device_set_softc(child, atadev); device_quiet(child); atadev->dev = child; atadev->max_iosize = DEV_BSIZE; atadev->mode = ATA_PIO_MAX; } return child; } #endif #ifndef ATA_CAM int ata_getparam(struct ata_device *atadev, int init) { struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); struct ata_request *request; const char *res; char buf[64]; u_int8_t command = 0; int error = ENOMEM, retries = 2, mode = -1; if (ch->devices & (ATA_ATA_MASTER << atadev->unit)) command = ATA_ATA_IDENTIFY; if (ch->devices & (ATA_ATAPI_MASTER << atadev->unit)) command = ATA_ATAPI_IDENTIFY; if (!command) return ENXIO; while (retries-- > 0 && error) { if (!(request = ata_alloc_request())) break; request->dev = atadev->dev; request->timeout = 1; request->retries = 0; request->u.ata.command = command; request->flags = (ATA_R_READ|ATA_R_AT_HEAD|ATA_R_DIRECT); if (!bootverbose) request->flags |= ATA_R_QUIET; request->data = (void *)&atadev->param; request->bytecount = sizeof(struct ata_params); request->donecount = 0; request->transfersize = DEV_BSIZE; ata_queue_request(request); error = request->result; ata_free_request(request); } if (!error && (isprint(atadev->param.model[0]) || isprint(atadev->param.model[1]))) { struct ata_params *atacap = &atadev->param; int16_t *ptr; for (ptr = (int16_t *)atacap; ptr < (int16_t *)atacap + sizeof(struct ata_params)/2; ptr++) { *ptr = le16toh(*ptr); } if (!(!strncmp(atacap->model, "FX", 2) || !strncmp(atacap->model, "NEC", 3) || !strncmp(atacap->model, "Pioneer", 7) || !strncmp(atacap->model, "SHARP", 5))) { bswap(atacap->model, sizeof(atacap->model)); bswap(atacap->revision, sizeof(atacap->revision)); bswap(atacap->serial, sizeof(atacap->serial)); } btrim(atacap->model, sizeof(atacap->model)); bpack(atacap->model, atacap->model, sizeof(atacap->model)); btrim(atacap->revision, sizeof(atacap->revision)); bpack(atacap->revision, atacap->revision, sizeof(atacap->revision)); btrim(atacap->serial, sizeof(atacap->serial)); bpack(atacap->serial, atacap->serial, sizeof(atacap->serial)); if (bootverbose) printf("ata%d-%s: pio=%s wdma=%s udma=%s cable=%s wire\n", device_get_unit(ch->dev), ata_unit2str(atadev), ata_mode2str(ata_pmode(atacap)), ata_mode2str(ata_wmode(atacap)), ata_mode2str(ata_umode(atacap)), (atacap->hwres & ATA_CABLE_ID) ? "80":"40"); if (init) { char buffer[64]; sprintf(buffer, "%.40s/%.8s", atacap->model, atacap->revision); device_set_desc_copy(atadev->dev, buffer); if ((atadev->param.config & ATA_PROTO_ATAPI) && (atadev->param.config != ATA_CFA_MAGIC1) && (atadev->param.config != ATA_CFA_MAGIC2)) { if (atapi_dma && (atadev->param.config & ATA_DRQ_MASK) != ATA_DRQ_INTR && ata_umode(&atadev->param) >= ATA_UDMA2) atadev->mode = ATA_DMA_MAX; } else { if (ata_dma && (ata_umode(&atadev->param) > 0 || ata_wmode(&atadev->param) > 0)) atadev->mode = ATA_DMA_MAX; } snprintf(buf, sizeof(buf), "dev%d.mode", atadev->unit); if (resource_string_value(device_get_name(ch->dev), device_get_unit(ch->dev), buf, &res) == 0) mode = ata_str2mode(res); else if (resource_string_value(device_get_name(ch->dev), device_get_unit(ch->dev), "mode", &res) == 0) mode = ata_str2mode(res); if (mode >= 0) atadev->mode = mode; } } else { if (!error) error = ENXIO; } return error; } #endif #ifndef ATA_CAM int ata_identify(device_t dev) { struct ata_channel *ch = device_get_softc(dev); struct ata_device *atadev; device_t *children; device_t child, master = NULL; int nchildren, i, n = ch->devices; if (bootverbose) device_printf(dev, "Identifying devices: %08x\n", ch->devices); mtx_lock(&Giant); /* Skip existing devices. */ if (!device_get_children(dev, &children, &nchildren)) { for (i = 0; i < nchildren; i++) { if (children[i] && (atadev = device_get_softc(children[i]))) n &= ~((ATA_ATA_MASTER | ATA_ATAPI_MASTER) << atadev->unit); } free(children, M_TEMP); } /* Create new devices. */ if (bootverbose) device_printf(dev, "New devices: %08x\n", n); if (n == 0) { mtx_unlock(&Giant); return (0); } for (i = 0; i < ATA_PM; ++i) { if (n & (((ATA_ATA_MASTER | ATA_ATAPI_MASTER) << i))) { int unit = -1; if (!(atadev = malloc(sizeof(struct ata_device), M_ATA, M_NOWAIT | M_ZERO))) { device_printf(dev, "out of memory\n"); return ENOMEM; } atadev->unit = i; #ifdef ATA_STATIC_ID if (n & (ATA_ATA_MASTER << i)) unit = (device_get_unit(dev) << 1) + i; #endif if ((child = ata_add_child(dev, atadev, unit))) { /* * PATA slave should be identified first, to allow * device cable detection on master to work properly. */ if (i == 0 && (n & ATA_PORTMULTIPLIER) == 0 && (n & ((ATA_ATA_MASTER | ATA_ATAPI_MASTER) << 1)) != 0) { master = child; continue; } if (ata_getparam(atadev, 1)) { device_delete_child(dev, child); free(atadev, M_ATA); } } else free(atadev, M_ATA); } } if (master) { atadev = device_get_softc(master); if (ata_getparam(atadev, 1)) { device_delete_child(dev, master); free(atadev, M_ATA); } } bus_generic_probe(dev); bus_generic_attach(dev); mtx_unlock(&Giant); return 0; } #endif void ata_default_registers(device_t dev) { struct ata_channel *ch = device_get_softc(dev); /* fill in the defaults from whats setup already */ ch->r_io[ATA_ERROR].res = ch->r_io[ATA_FEATURE].res; ch->r_io[ATA_ERROR].offset = ch->r_io[ATA_FEATURE].offset; ch->r_io[ATA_IREASON].res = ch->r_io[ATA_COUNT].res; ch->r_io[ATA_IREASON].offset = ch->r_io[ATA_COUNT].offset; ch->r_io[ATA_STATUS].res = ch->r_io[ATA_COMMAND].res; ch->r_io[ATA_STATUS].offset = ch->r_io[ATA_COMMAND].offset; ch->r_io[ATA_ALTSTAT].res = ch->r_io[ATA_CONTROL].res; ch->r_io[ATA_ALTSTAT].offset = ch->r_io[ATA_CONTROL].offset; } void ata_modify_if_48bit(struct ata_request *request) { struct ata_channel *ch = device_get_softc(request->parent); struct ata_device *atadev = device_get_softc(request->dev); request->flags &= ~ATA_R_48BIT; 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) { /* translate command into 48bit version */ switch (request->u.ata.command) { case ATA_READ: request->u.ata.command = ATA_READ48; break; case ATA_READ_MUL: request->u.ata.command = ATA_READ_MUL48; break; case ATA_READ_DMA: if (ch->flags & ATA_NO_48BIT_DMA) { if (request->transfersize > DEV_BSIZE) request->u.ata.command = ATA_READ_MUL48; else request->u.ata.command = ATA_READ48; request->flags &= ~ATA_R_DMA; } else request->u.ata.command = ATA_READ_DMA48; break; case ATA_READ_DMA_QUEUED: if (ch->flags & ATA_NO_48BIT_DMA) { if (request->transfersize > DEV_BSIZE) request->u.ata.command = ATA_READ_MUL48; else request->u.ata.command = ATA_READ48; request->flags &= ~ATA_R_DMA; } else request->u.ata.command = ATA_READ_DMA_QUEUED48; break; case ATA_WRITE: request->u.ata.command = ATA_WRITE48; break; case ATA_WRITE_MUL: request->u.ata.command = ATA_WRITE_MUL48; break; case ATA_WRITE_DMA: if (ch->flags & ATA_NO_48BIT_DMA) { if (request->transfersize > DEV_BSIZE) request->u.ata.command = ATA_WRITE_MUL48; else request->u.ata.command = ATA_WRITE48; request->flags &= ~ATA_R_DMA; } else request->u.ata.command = ATA_WRITE_DMA48; break; case ATA_WRITE_DMA_QUEUED: if (ch->flags & ATA_NO_48BIT_DMA) { if (request->transfersize > DEV_BSIZE) request->u.ata.command = ATA_WRITE_MUL48; else request->u.ata.command = ATA_WRITE48; request->u.ata.command = ATA_WRITE48; request->flags &= ~ATA_R_DMA; } else request->u.ata.command = ATA_WRITE_DMA_QUEUED48; break; case ATA_FLUSHCACHE: request->u.ata.command = ATA_FLUSHCACHE48; break; case ATA_SET_MAX_ADDRESS: request->u.ata.command = ATA_SET_MAX_ADDRESS48; break; default: return; } request->flags |= ATA_R_48BIT; } else if (atadev->param.support.command2 & ATA_SUPPORT_ADDRESS48) { /* translate command into 48bit version */ switch (request->u.ata.command) { case ATA_FLUSHCACHE: request->u.ata.command = ATA_FLUSHCACHE48; break; case ATA_READ_NATIVE_MAX_ADDRESS: request->u.ata.command = ATA_READ_NATIVE_MAX_ADDRESS48; break; case ATA_SET_MAX_ADDRESS: request->u.ata.command = ATA_SET_MAX_ADDRESS48; break; default: return; } request->flags |= ATA_R_48BIT; } } void ata_udelay(int interval) { /* for now just use DELAY, the timer/sleep subsytems are not there yet */ if (1 || interval < (1000000/hz) || ata_delayed_attach) DELAY(interval); else pause("ataslp", interval/(1000000/hz)); } #ifndef ATA_CAM const char * ata_unit2str(struct ata_device *atadev) { struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); static char str[8]; if (ch->devices & ATA_PORTMULTIPLIER) sprintf(str, "port%d", atadev->unit); else sprintf(str, "%s", atadev->unit == ATA_MASTER ? "master" : "slave"); return str; } #endif const char * ata_mode2str(int mode) { switch (mode) { case -1: return "UNSUPPORTED"; case ATA_PIO0: return "PIO0"; case ATA_PIO1: return "PIO1"; case ATA_PIO2: return "PIO2"; case ATA_PIO3: return "PIO3"; case ATA_PIO4: return "PIO4"; case ATA_WDMA0: return "WDMA0"; case ATA_WDMA1: return "WDMA1"; case ATA_WDMA2: return "WDMA2"; case ATA_UDMA0: return "UDMA16"; case ATA_UDMA1: return "UDMA25"; case ATA_UDMA2: return "UDMA33"; case ATA_UDMA3: return "UDMA40"; case ATA_UDMA4: return "UDMA66"; case ATA_UDMA5: return "UDMA100"; case ATA_UDMA6: return "UDMA133"; case ATA_SA150: return "SATA150"; case ATA_SA300: return "SATA300"; default: if (mode & ATA_DMA_MASK) return "BIOSDMA"; else return "BIOSPIO"; } } int ata_str2mode(const char *str) { if (!strcasecmp(str, "PIO0")) return (ATA_PIO0); if (!strcasecmp(str, "PIO1")) return (ATA_PIO1); if (!strcasecmp(str, "PIO2")) return (ATA_PIO2); if (!strcasecmp(str, "PIO3")) return (ATA_PIO3); if (!strcasecmp(str, "PIO4")) return (ATA_PIO4); if (!strcasecmp(str, "WDMA0")) return (ATA_WDMA0); if (!strcasecmp(str, "WDMA1")) return (ATA_WDMA1); if (!strcasecmp(str, "WDMA2")) return (ATA_WDMA2); if (!strcasecmp(str, "UDMA0")) return (ATA_UDMA0); if (!strcasecmp(str, "UDMA16")) return (ATA_UDMA0); if (!strcasecmp(str, "UDMA1")) return (ATA_UDMA1); if (!strcasecmp(str, "UDMA25")) return (ATA_UDMA1); if (!strcasecmp(str, "UDMA2")) return (ATA_UDMA2); if (!strcasecmp(str, "UDMA33")) return (ATA_UDMA2); if (!strcasecmp(str, "UDMA3")) return (ATA_UDMA3); if (!strcasecmp(str, "UDMA44")) return (ATA_UDMA3); if (!strcasecmp(str, "UDMA4")) return (ATA_UDMA4); if (!strcasecmp(str, "UDMA66")) return (ATA_UDMA4); if (!strcasecmp(str, "UDMA5")) return (ATA_UDMA5); if (!strcasecmp(str, "UDMA100")) return (ATA_UDMA5); if (!strcasecmp(str, "UDMA6")) return (ATA_UDMA6); if (!strcasecmp(str, "UDMA133")) return (ATA_UDMA6); return (-1); } #ifndef ATA_CAM const char * ata_satarev2str(int rev) { switch (rev) { case 0: return ""; case 1: return "SATA 1.5Gb/s"; case 2: return "SATA 3Gb/s"; case 3: return "SATA 6Gb/s"; case 0xff: return "SATA"; default: return "???"; } } #endif int ata_atapi(device_t dev, int target) { struct ata_channel *ch = device_get_softc(dev); return (ch->devices & (ATA_ATAPI_MASTER << target)); } #ifndef ATA_CAM int ata_pmode(struct ata_params *ap) { if (ap->atavalid & ATA_FLAG_64_70) { if (ap->apiomodes & 0x02) return ATA_PIO4; if (ap->apiomodes & 0x01) return ATA_PIO3; } if (ap->mwdmamodes & 0x04) return ATA_PIO4; if (ap->mwdmamodes & 0x02) return ATA_PIO3; if (ap->mwdmamodes & 0x01) return ATA_PIO2; if ((ap->retired_piomode & ATA_RETIRED_PIO_MASK) == 0x200) return ATA_PIO2; if ((ap->retired_piomode & ATA_RETIRED_PIO_MASK) == 0x100) return ATA_PIO1; if ((ap->retired_piomode & ATA_RETIRED_PIO_MASK) == 0x000) return ATA_PIO0; return ATA_PIO0; } #endif #ifndef ATA_CAM int ata_wmode(struct ata_params *ap) { if (ap->mwdmamodes & 0x04) return ATA_WDMA2; if (ap->mwdmamodes & 0x02) return ATA_WDMA1; if (ap->mwdmamodes & 0x01) return ATA_WDMA0; return -1; } #endif #ifndef ATA_CAM int ata_umode(struct ata_params *ap) { if (ap->atavalid & ATA_FLAG_88) { if (ap->udmamodes & 0x40) return ATA_UDMA6; if (ap->udmamodes & 0x20) return ATA_UDMA5; if (ap->udmamodes & 0x10) return ATA_UDMA4; if (ap->udmamodes & 0x08) return ATA_UDMA3; if (ap->udmamodes & 0x04) return ATA_UDMA2; if (ap->udmamodes & 0x02) return ATA_UDMA1; if (ap->udmamodes & 0x01) return ATA_UDMA0; } return -1; } #endif #ifndef ATA_CAM int ata_limit_mode(device_t dev, int mode, int maxmode) { struct ata_device *atadev = device_get_softc(dev); if (maxmode && mode > maxmode) mode = maxmode; if (mode >= ATA_UDMA0 && ata_umode(&atadev->param) > 0) return min(mode, ata_umode(&atadev->param)); if (mode >= ATA_WDMA0 && ata_wmode(&atadev->param) > 0) return min(mode, ata_wmode(&atadev->param)); if (mode > ata_pmode(&atadev->param)) return min(mode, ata_pmode(&atadev->param)); return mode; } #endif #ifndef ATA_CAM static void bswap(int8_t *buf, int len) { u_int16_t *ptr = (u_int16_t*)(buf + len); while (--ptr >= (u_int16_t*)buf) *ptr = ntohs(*ptr); } #endif #ifndef ATA_CAM static void btrim(int8_t *buf, int len) { int8_t *ptr; for (ptr = buf; ptr < buf+len; ++ptr) if (!*ptr || *ptr == '_') *ptr = ' '; for (ptr = buf + len - 1; ptr >= buf && *ptr == ' '; --ptr) *ptr = 0; } #endif #ifndef ATA_CAM static void bpack(int8_t *src, int8_t *dst, int len) { int i, j, blank; for (i = j = blank = 0 ; i < len; i++) { if (blank && src[i] == ' ') continue; if (blank && src[i] != ' ') { dst[j++] = src[i]; blank = 0; continue; } if (src[i] == ' ') { blank = 1; if (i == 0) continue; } dst[j++] = src[i]; } if (j < len) dst[j] = 0x00; } #endif #ifdef ATA_CAM void ata_cam_begin_transaction(device_t dev, union ccb *ccb) { struct ata_channel *ch = device_get_softc(dev); struct ata_request *request; if (!(request = ata_alloc_request())) { device_printf(dev, "FAILURE - out of memory in start\n"); ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); return; } bzero(request, sizeof(*request)); /* setup request */ request->dev = NULL; request->parent = dev; request->unit = ccb->ccb_h.target_id; if (ccb->ccb_h.func_code == XPT_ATA_IO) { request->data = ccb->ataio.data_ptr; request->bytecount = ccb->ataio.dxfer_len; request->u.ata.command = ccb->ataio.cmd.command; request->u.ata.feature = ((uint16_t)ccb->ataio.cmd.features_exp << 8) | (uint16_t)ccb->ataio.cmd.features; request->u.ata.count = ((uint16_t)ccb->ataio.cmd.sector_count_exp << 8) | (uint16_t)ccb->ataio.cmd.sector_count; if (ccb->ataio.cmd.flags & CAM_ATAIO_48BIT) { request->flags |= ATA_R_48BIT; request->u.ata.lba = ((uint64_t)ccb->ataio.cmd.lba_high_exp << 40) | ((uint64_t)ccb->ataio.cmd.lba_mid_exp << 32) | ((uint64_t)ccb->ataio.cmd.lba_low_exp << 24); } else { request->u.ata.lba = ((uint64_t)(ccb->ataio.cmd.device & 0x0f) << 24); } request->u.ata.lba |= ((uint64_t)ccb->ataio.cmd.lba_high << 16) | ((uint64_t)ccb->ataio.cmd.lba_mid << 8) | (uint64_t)ccb->ataio.cmd.lba_low; if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE && ccb->ataio.cmd.flags & CAM_ATAIO_DMA) request->flags |= ATA_R_DMA; if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) request->flags |= ATA_R_READ; if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) request->flags |= ATA_R_WRITE; } else { request->data = ccb->csio.data_ptr; request->bytecount = ccb->csio.dxfer_len; bcopy((ccb->ccb_h.flags & CAM_CDB_POINTER) ? ccb->csio.cdb_io.cdb_ptr : ccb->csio.cdb_io.cdb_bytes, request->u.atapi.ccb, ccb->csio.cdb_len); request->flags |= ATA_R_ATAPI; if (ch->curr[ccb->ccb_h.target_id].atapi == 16) request->flags |= ATA_R_ATAPI16; if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE && ch->curr[ccb->ccb_h.target_id].mode >= ATA_DMA) request->flags |= ATA_R_DMA; if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) request->flags |= ATA_R_READ; if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) request->flags |= ATA_R_WRITE; } request->transfersize = min(request->bytecount, ch->curr[ccb->ccb_h.target_id].bytecount); request->retries = 0; request->timeout = (ccb->ccb_h.timeout + 999) / 1000; callout_init_mtx(&request->callout, &ch->state_mtx, CALLOUT_RETURNUNLOCKED); request->ccb = ccb; ch->running = request; ch->state = ATA_ACTIVE; if (ch->hw.begin_transaction(request) == ATA_OP_FINISHED) { ch->running = NULL; ch->state = ATA_IDLE; ata_cam_end_transaction(dev, request); return; } } static void ata_cam_request_sense(device_t dev, struct ata_request *request) { struct ata_channel *ch = device_get_softc(dev); union ccb *ccb = request->ccb; ch->requestsense = 1; bzero(request, sizeof(*request)); request->dev = NULL; request->parent = dev; request->unit = ccb->ccb_h.target_id; request->data = (void *)&ccb->csio.sense_data; request->bytecount = ccb->csio.sense_len; request->u.atapi.ccb[0] = ATAPI_REQUEST_SENSE; request->u.atapi.ccb[4] = ccb->csio.sense_len; request->flags |= ATA_R_ATAPI; if (ch->curr[ccb->ccb_h.target_id].atapi == 16) request->flags |= ATA_R_ATAPI16; if (ch->curr[ccb->ccb_h.target_id].mode >= ATA_DMA) request->flags |= ATA_R_DMA; request->flags |= ATA_R_READ; request->transfersize = min(request->bytecount, ch->curr[ccb->ccb_h.target_id].bytecount); request->retries = 0; request->timeout = (ccb->ccb_h.timeout + 999) / 1000; callout_init_mtx(&request->callout, &ch->state_mtx, CALLOUT_RETURNUNLOCKED); request->ccb = ccb; ch->running = request; ch->state = ATA_ACTIVE; if (ch->hw.begin_transaction(request) == ATA_OP_FINISHED) { ch->running = NULL; ch->state = ATA_IDLE; ata_cam_end_transaction(dev, request); return; } } static void ata_cam_process_sense(device_t dev, struct ata_request *request) { struct ata_channel *ch = device_get_softc(dev); union ccb *ccb = request->ccb; int fatalerr = 0; ch->requestsense = 0; if (request->flags & ATA_R_TIMEOUT) fatalerr = 1; if ((request->flags & ATA_R_TIMEOUT) == 0 && (request->status & ATA_S_ERROR) == 0 && request->result == 0) { ccb->ccb_h.status |= CAM_AUTOSNS_VALID; } else { ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_AUTOSENSE_FAIL; } ata_free_request(request); xpt_done(ccb); /* Do error recovery if needed. */ if (fatalerr) ata_reinit(dev); } void ata_cam_end_transaction(device_t dev, struct ata_request *request) { struct ata_channel *ch = device_get_softc(dev); union ccb *ccb = request->ccb; int fatalerr = 0; if (ch->requestsense) { ata_cam_process_sense(dev, request); return; } ccb->ccb_h.status &= ~CAM_STATUS_MASK; if (request->flags & ATA_R_TIMEOUT) { xpt_freeze_simq(ch->sim, 1); ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_CMD_TIMEOUT | CAM_RELEASE_SIMQ; fatalerr = 1; } else if (request->status & ATA_S_ERROR) { if (ccb->ccb_h.func_code == XPT_ATA_IO) { ccb->ccb_h.status |= CAM_ATA_STATUS_ERROR; } else { ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; } } else if (request->result == ERESTART) ccb->ccb_h.status |= CAM_REQUEUE_REQ; else if (request->result != 0) ccb->ccb_h.status |= CAM_REQ_CMP_ERR; else ccb->ccb_h.status |= CAM_REQ_CMP; if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP && !(ccb->ccb_h.status & CAM_DEV_QFRZN)) { xpt_freeze_devq(ccb->ccb_h.path, 1); ccb->ccb_h.status |= CAM_DEV_QFRZN; } if (ccb->ccb_h.func_code == XPT_ATA_IO && ((request->status & ATA_S_ERROR) || (ccb->ataio.cmd.flags & CAM_ATAIO_NEEDRESULT))) { struct ata_res *res = &ccb->ataio.res; res->status = request->status; res->error = request->error; res->lba_low = request->u.ata.lba; res->lba_mid = request->u.ata.lba >> 8; res->lba_high = request->u.ata.lba >> 16; res->device = request->u.ata.lba >> 24; res->lba_low_exp = request->u.ata.lba >> 24; res->lba_mid_exp = request->u.ata.lba >> 32; res->lba_high_exp = request->u.ata.lba >> 40; res->sector_count = request->u.ata.count; res->sector_count_exp = request->u.ata.count >> 8; } if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { if (ccb->ccb_h.func_code == XPT_ATA_IO) { ccb->ataio.resid = ccb->ataio.dxfer_len - request->donecount; } else { ccb->csio.resid = ccb->csio.dxfer_len - request->donecount; } } if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR && (ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) ata_cam_request_sense(dev, request); else { ata_free_request(request); xpt_done(ccb); } /* Do error recovery if needed. */ if (fatalerr) ata_reinit(dev); } static int ata_check_ids(device_t dev, union ccb *ccb) { struct ata_channel *ch = device_get_softc(dev); if (ccb->ccb_h.target_id > ((ch->flags & ATA_NO_SLAVE) ? 0 : 1)) { ccb->ccb_h.status = CAM_TID_INVALID; xpt_done(ccb); return (-1); } if (ccb->ccb_h.target_lun != 0) { ccb->ccb_h.status = CAM_LUN_INVALID; xpt_done(ccb); return (-1); } return (0); } static void ataaction(struct cam_sim *sim, union ccb *ccb) { device_t dev, parent; struct ata_channel *ch; CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ataaction func_code=%x\n", ccb->ccb_h.func_code)); ch = (struct ata_channel *)cam_sim_softc(sim); dev = ch->dev; switch (ccb->ccb_h.func_code) { /* Common cases first */ case XPT_ATA_IO: /* Execute the requested I/O operation */ case XPT_SCSI_IO: if (ata_check_ids(dev, ccb)) return; if ((ch->devices & ((ATA_ATA_MASTER | ATA_ATAPI_MASTER) << ccb->ccb_h.target_id)) == 0) { ccb->ccb_h.status = CAM_SEL_TIMEOUT; break; } if (ch->running) device_printf(dev, "already running!\n"); if (ccb->ccb_h.func_code == XPT_ATA_IO && (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) && (ccb->ataio.cmd.control & ATA_A_RESET)) { struct ata_res *res = &ccb->ataio.res; bzero(res, sizeof(*res)); if (ch->devices & (ATA_ATA_MASTER << ccb->ccb_h.target_id)) { res->lba_high = 0; res->lba_mid = 0; } else { res->lba_high = 0xeb; res->lba_mid = 0x14; } ccb->ccb_h.status = CAM_REQ_CMP; break; } ata_cam_begin_transaction(dev, ccb); return; case XPT_EN_LUN: /* Enable LUN as a target */ case XPT_TARGET_IO: /* Execute target I/O request */ case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ case XPT_ABORT: /* Abort the specified CCB */ /* XXX Implement */ ccb->ccb_h.status = CAM_REQ_INVALID; break; case XPT_SET_TRAN_SETTINGS: { struct ccb_trans_settings *cts = &ccb->cts; struct ata_cam_device *d; if (ata_check_ids(dev, ccb)) return; if (cts->type == CTS_TYPE_CURRENT_SETTINGS) d = &ch->curr[ccb->ccb_h.target_id]; else d = &ch->user[ccb->ccb_h.target_id]; if (ch->flags & ATA_SATA) { if (cts->xport_specific.sata.valid & CTS_SATA_VALID_REVISION) d->revision = cts->xport_specific.sata.revision; if (cts->xport_specific.sata.valid & CTS_SATA_VALID_MODE) { if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { d->mode = ATA_SETMODE(ch->dev, ccb->ccb_h.target_id, cts->xport_specific.sata.mode); } else d->mode = cts->xport_specific.sata.mode; } if (cts->xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT) d->bytecount = min(8192, cts->xport_specific.sata.bytecount); if (cts->xport_specific.sata.valid & CTS_SATA_VALID_ATAPI) d->atapi = cts->xport_specific.sata.atapi; if (cts->xport_specific.sata.valid & CTS_SATA_VALID_CAPS) d->caps = cts->xport_specific.sata.caps; } else { if (cts->xport_specific.ata.valid & CTS_ATA_VALID_MODE) { if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { d->mode = ATA_SETMODE(ch->dev, ccb->ccb_h.target_id, cts->xport_specific.ata.mode); } else d->mode = cts->xport_specific.ata.mode; } if (cts->xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT) d->bytecount = cts->xport_specific.ata.bytecount; if (cts->xport_specific.ata.valid & CTS_ATA_VALID_ATAPI) d->atapi = cts->xport_specific.ata.atapi; } ccb->ccb_h.status = CAM_REQ_CMP; break; } case XPT_GET_TRAN_SETTINGS: { struct ccb_trans_settings *cts = &ccb->cts; struct ata_cam_device *d; if (ata_check_ids(dev, ccb)) return; if (cts->type == CTS_TYPE_CURRENT_SETTINGS) d = &ch->curr[ccb->ccb_h.target_id]; else d = &ch->user[ccb->ccb_h.target_id]; cts->protocol = PROTO_UNSPECIFIED; cts->protocol_version = PROTO_VERSION_UNSPECIFIED; if (ch->flags & ATA_SATA) { cts->transport = XPORT_SATA; cts->transport_version = XPORT_VERSION_UNSPECIFIED; cts->xport_specific.sata.valid = 0; cts->xport_specific.sata.mode = d->mode; cts->xport_specific.sata.valid |= CTS_SATA_VALID_MODE; cts->xport_specific.sata.bytecount = d->bytecount; cts->xport_specific.sata.valid |= CTS_SATA_VALID_BYTECOUNT; if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { cts->xport_specific.sata.revision = ATA_GETREV(dev, ccb->ccb_h.target_id); if (cts->xport_specific.sata.revision != 0xff) { cts->xport_specific.sata.valid |= CTS_SATA_VALID_REVISION; } cts->xport_specific.sata.caps = d->caps & CTS_SATA_CAPS_D; if (ch->pm_level) { cts->xport_specific.sata.caps |= CTS_SATA_CAPS_H_PMREQ; } cts->xport_specific.sata.caps &= ch->user[ccb->ccb_h.target_id].caps; cts->xport_specific.sata.valid |= CTS_SATA_VALID_CAPS; } else { cts->xport_specific.sata.revision = d->revision; cts->xport_specific.sata.valid |= CTS_SATA_VALID_REVISION; cts->xport_specific.sata.caps = d->caps; cts->xport_specific.sata.valid |= CTS_SATA_VALID_CAPS; } cts->xport_specific.sata.atapi = d->atapi; cts->xport_specific.sata.valid |= CTS_SATA_VALID_ATAPI; } else { cts->transport = XPORT_ATA; cts->transport_version = XPORT_VERSION_UNSPECIFIED; cts->xport_specific.ata.valid = 0; cts->xport_specific.ata.mode = d->mode; cts->xport_specific.ata.valid |= CTS_ATA_VALID_MODE; cts->xport_specific.ata.bytecount = d->bytecount; cts->xport_specific.ata.valid |= CTS_ATA_VALID_BYTECOUNT; cts->xport_specific.ata.atapi = d->atapi; cts->xport_specific.ata.valid |= CTS_ATA_VALID_ATAPI; } ccb->ccb_h.status = CAM_REQ_CMP; break; } case XPT_RESET_BUS: /* Reset the specified SCSI bus */ case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ ata_reinit(dev); ccb->ccb_h.status = CAM_REQ_CMP; break; case XPT_TERM_IO: /* Terminate the I/O process */ /* XXX Implement */ ccb->ccb_h.status = CAM_REQ_INVALID; break; case XPT_PATH_INQ: /* Path routing inquiry */ { struct ccb_pathinq *cpi = &ccb->cpi; parent = device_get_parent(dev); cpi->version_num = 1; /* XXX??? */ cpi->hba_inquiry = PI_SDTR_ABLE; cpi->target_sprt = 0; cpi->hba_misc = PIM_SEQSCAN; cpi->hba_eng_cnt = 0; if (ch->flags & ATA_NO_SLAVE) cpi->max_target = 0; else cpi->max_target = 1; cpi->max_lun = 0; cpi->initiator_id = 0; cpi->bus_id = cam_sim_bus(sim); if (ch->flags & ATA_SATA) cpi->base_transfer_speed = 150000; else cpi->base_transfer_speed = 3300; strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); strncpy(cpi->hba_vid, "ATA", HBA_IDLEN); strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); cpi->unit_number = cam_sim_unit(sim); if (ch->flags & ATA_SATA) cpi->transport = XPORT_SATA; else cpi->transport = XPORT_ATA; cpi->transport_version = XPORT_VERSION_UNSPECIFIED; cpi->protocol = PROTO_ATA; cpi->protocol_version = PROTO_VERSION_UNSPECIFIED; cpi->maxio = ch->dma.max_iosize ? ch->dma.max_iosize : DFLTPHYS; if (device_get_devclass(device_get_parent(parent)) == devclass_find("pci")) { cpi->hba_vendor = pci_get_vendor(parent); cpi->hba_device = pci_get_device(parent); cpi->hba_subvendor = pci_get_subvendor(parent); cpi->hba_subdevice = pci_get_subdevice(parent); } cpi->ccb_h.status = CAM_REQ_CMP; break; } default: ccb->ccb_h.status = CAM_REQ_INVALID; break; } xpt_done(ccb); } static void atapoll(struct cam_sim *sim) { struct ata_channel *ch = (struct ata_channel *)cam_sim_softc(sim); ata_interrupt_locked(ch); } #endif /* * module handeling */ static int ata_module_event_handler(module_t mod, int what, void *arg) { #ifndef ATA_CAM static struct cdev *atacdev; #endif switch (what) { case MOD_LOAD: #ifndef ATA_CAM /* register controlling device */ atacdev = make_dev(&ata_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0600, "ata"); if (cold) { /* register boot attach to be run when interrupts are enabled */ if (!(ata_delayed_attach = (struct intr_config_hook *) malloc(sizeof(struct intr_config_hook), M_TEMP, M_NOWAIT | M_ZERO))) { printf("ata: malloc of delayed attach hook failed\n"); return EIO; } ata_delayed_attach->ich_func = (void*)ata_boot_attach; if (config_intrhook_establish(ata_delayed_attach) != 0) { printf("ata: config_intrhook_establish failed\n"); free(ata_delayed_attach, M_TEMP); } } #endif return 0; case MOD_UNLOAD: #ifndef ATA_CAM /* deregister controlling device */ destroy_dev(atacdev); #endif return 0; default: return EOPNOTSUPP; } } static moduledata_t ata_moduledata = { "ata", ata_module_event_handler, NULL }; DECLARE_MODULE(ata, ata_moduledata, SI_SUB_CONFIGURE, SI_ORDER_SECOND); MODULE_VERSION(ata, 1); #ifdef ATA_CAM MODULE_DEPEND(ata, cam, 1, 1, 1); #endif static void ata_init(void) { ata_request_zone = uma_zcreate("ata_request", sizeof(struct ata_request), NULL, NULL, NULL, NULL, 0, 0); ata_composite_zone = uma_zcreate("ata_composite", sizeof(struct ata_composite), NULL, NULL, NULL, NULL, 0, 0); } SYSINIT(ata_register, SI_SUB_DRIVERS, SI_ORDER_SECOND, ata_init, NULL); static void ata_uninit(void) { uma_zdestroy(ata_composite_zone); uma_zdestroy(ata_request_zone); } SYSUNINIT(ata_unregister, SI_SUB_DRIVERS, SI_ORDER_SECOND, ata_uninit, NULL); Index: stable/9/sys/dev/ata/ata-all.h =================================================================== --- stable/9/sys/dev/ata/ata-all.h (revision 243117) +++ stable/9/sys/dev/ata/ata-all.h (revision 243118) @@ -1,764 +1,765 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #include "opt_ata.h" #if 0 #define ATA_LEGACY_SUPPORT /* Enable obsolete features that break * some modern devices */ #endif /* ATA register defines */ #define ATA_DATA 0 /* (RW) data */ #define ATA_FEATURE 1 /* (W) feature */ #define ATA_F_DMA 0x01 /* enable DMA */ #define ATA_F_OVL 0x02 /* enable overlap */ #define ATA_COUNT 2 /* (W) sector count */ #define ATA_SECTOR 3 /* (RW) sector # */ #define ATA_CYL_LSB 4 /* (RW) cylinder# LSB */ #define ATA_CYL_MSB 5 /* (RW) cylinder# MSB */ #define ATA_DRIVE 6 /* (W) Sector/Drive/Head */ #define ATA_D_LBA 0x40 /* use LBA addressing */ #define ATA_D_IBM 0xa0 /* 512 byte sectors, ECC */ #define ATA_COMMAND 7 /* (W) command */ #define ATA_ERROR 8 /* (R) error */ #define ATA_E_ILI 0x01 /* illegal length */ #define ATA_E_NM 0x02 /* no media */ #define ATA_E_ABORT 0x04 /* command aborted */ #define ATA_E_MCR 0x08 /* media change request */ #define ATA_E_IDNF 0x10 /* ID not found */ #define ATA_E_MC 0x20 /* media changed */ #define ATA_E_UNC 0x40 /* uncorrectable data */ #define ATA_E_ICRC 0x80 /* UDMA crc error */ #define ATA_E_ATAPI_SENSE_MASK 0xf0 /* ATAPI sense key mask */ #define ATA_IREASON 9 /* (R) interrupt reason */ #define ATA_I_CMD 0x01 /* cmd (1) | data (0) */ #define ATA_I_IN 0x02 /* read (1) | write (0) */ #define ATA_I_RELEASE 0x04 /* released bus (1) */ #define ATA_I_TAGMASK 0xf8 /* tag mask */ #define ATA_STATUS 10 /* (R) status */ #define ATA_ALTSTAT 11 /* (R) alternate status */ #define ATA_S_ERROR 0x01 /* error */ #define ATA_S_INDEX 0x02 /* index */ #define ATA_S_CORR 0x04 /* data corrected */ #define ATA_S_DRQ 0x08 /* data request */ #define ATA_S_DSC 0x10 /* drive seek completed */ #define ATA_S_SERVICE 0x10 /* drive needs service */ #define ATA_S_DWF 0x20 /* drive write fault */ #define ATA_S_DMA 0x20 /* DMA ready */ #define ATA_S_READY 0x40 /* drive ready */ #define ATA_S_BUSY 0x80 /* busy */ #define ATA_CONTROL 12 /* (W) control */ #define ATA_CTLOFFSET 0x206 /* control register offset */ #define ATA_PCCARD_CTLOFFSET 0x0e /* do for PCCARD devices */ #define ATA_PC98_CTLOFFSET 0x10c /* do for PC98 devices */ #define ATA_A_IDS 0x02 /* disable interrupts */ #define ATA_A_RESET 0x04 /* RESET controller */ #ifdef ATA_LEGACY_SUPPORT #define ATA_A_4BIT 0x08 /* 4 head bits: obsolete 1996 */ #else #define ATA_A_4BIT 0x00 #endif #define ATA_A_HOB 0x80 /* High Order Byte enable */ /* SATA register defines */ #define ATA_SSTATUS 13 #define ATA_SS_DET_MASK 0x0000000f #define ATA_SS_DET_NO_DEVICE 0x00000000 #define ATA_SS_DET_DEV_PRESENT 0x00000001 #define ATA_SS_DET_PHY_ONLINE 0x00000003 #define ATA_SS_DET_PHY_OFFLINE 0x00000004 #define ATA_SS_SPD_MASK 0x000000f0 #define ATA_SS_SPD_NO_SPEED 0x00000000 #define ATA_SS_SPD_GEN1 0x00000010 #define ATA_SS_SPD_GEN2 0x00000020 #define ATA_SS_IPM_MASK 0x00000f00 #define ATA_SS_IPM_NO_DEVICE 0x00000000 #define ATA_SS_IPM_ACTIVE 0x00000100 #define ATA_SS_IPM_PARTIAL 0x00000200 #define ATA_SS_IPM_SLUMBER 0x00000600 #define ATA_SERROR 14 #define ATA_SE_DATA_CORRECTED 0x00000001 #define ATA_SE_COMM_CORRECTED 0x00000002 #define ATA_SE_DATA_ERR 0x00000100 #define ATA_SE_COMM_ERR 0x00000200 #define ATA_SE_PROT_ERR 0x00000400 #define ATA_SE_HOST_ERR 0x00000800 #define ATA_SE_PHY_CHANGED 0x00010000 #define ATA_SE_PHY_IERROR 0x00020000 #define ATA_SE_COMM_WAKE 0x00040000 #define ATA_SE_DECODE_ERR 0x00080000 #define ATA_SE_PARITY_ERR 0x00100000 #define ATA_SE_CRC_ERR 0x00200000 #define ATA_SE_HANDSHAKE_ERR 0x00400000 #define ATA_SE_LINKSEQ_ERR 0x00800000 #define ATA_SE_TRANSPORT_ERR 0x01000000 #define ATA_SE_UNKNOWN_FIS 0x02000000 #define ATA_SCONTROL 15 #define ATA_SC_DET_MASK 0x0000000f #define ATA_SC_DET_IDLE 0x00000000 #define ATA_SC_DET_RESET 0x00000001 #define ATA_SC_DET_DISABLE 0x00000004 #define ATA_SC_SPD_MASK 0x000000f0 #define ATA_SC_SPD_NO_SPEED 0x00000000 #define ATA_SC_SPD_SPEED_GEN1 0x00000010 #define ATA_SC_SPD_SPEED_GEN2 0x00000020 +#define ATA_SC_SPD_SPEED_GEN3 0x00000040 #define ATA_SC_IPM_MASK 0x00000f00 #define ATA_SC_IPM_NONE 0x00000000 #define ATA_SC_IPM_DIS_PARTIAL 0x00000100 #define ATA_SC_IPM_DIS_SLUMBER 0x00000200 #define ATA_SACTIVE 16 /* SATA AHCI v1.0 register defines */ #define ATA_AHCI_CAP 0x00 #define ATA_AHCI_CAP_NPMASK 0x0000001f #define ATA_AHCI_CAP_SXS 0x00000020 #define ATA_AHCI_CAP_EMS 0x00000040 #define ATA_AHCI_CAP_CCCS 0x00000080 #define ATA_AHCI_CAP_NCS 0x00001F00 #define ATA_AHCI_CAP_NCS_SHIFT 8 #define ATA_AHCI_CAP_PSC 0x00002000 #define ATA_AHCI_CAP_SSC 0x00004000 #define ATA_AHCI_CAP_PMD 0x00008000 #define ATA_AHCI_CAP_FBSS 0x00010000 #define ATA_AHCI_CAP_SPM 0x00020000 #define ATA_AHCI_CAP_SAM 0x00080000 #define ATA_AHCI_CAP_ISS 0x00F00000 #define ATA_AHCI_CAP_ISS_SHIFT 20 #define ATA_AHCI_CAP_SCLO 0x01000000 #define ATA_AHCI_CAP_SAL 0x02000000 #define ATA_AHCI_CAP_SALP 0x04000000 #define ATA_AHCI_CAP_SSS 0x08000000 #define ATA_AHCI_CAP_SMPS 0x10000000 #define ATA_AHCI_CAP_SSNTF 0x20000000 #define ATA_AHCI_CAP_SNCQ 0x40000000 #define ATA_AHCI_CAP_64BIT 0x80000000 #define ATA_AHCI_GHC 0x04 #define ATA_AHCI_GHC_AE 0x80000000 #define ATA_AHCI_GHC_IE 0x00000002 #define ATA_AHCI_GHC_HR 0x00000001 #define ATA_AHCI_IS 0x08 #define ATA_AHCI_PI 0x0c #define ATA_AHCI_VS 0x10 #define ATA_AHCI_OFFSET 0x80 #define ATA_AHCI_P_CLB 0x100 #define ATA_AHCI_P_CLBU 0x104 #define ATA_AHCI_P_FB 0x108 #define ATA_AHCI_P_FBU 0x10c #define ATA_AHCI_P_IS 0x110 #define ATA_AHCI_P_IE 0x114 #define ATA_AHCI_P_IX_DHR 0x00000001 #define ATA_AHCI_P_IX_PS 0x00000002 #define ATA_AHCI_P_IX_DS 0x00000004 #define ATA_AHCI_P_IX_SDB 0x00000008 #define ATA_AHCI_P_IX_UF 0x00000010 #define ATA_AHCI_P_IX_DP 0x00000020 #define ATA_AHCI_P_IX_PC 0x00000040 #define ATA_AHCI_P_IX_DI 0x00000080 #define ATA_AHCI_P_IX_PRC 0x00400000 #define ATA_AHCI_P_IX_IPM 0x00800000 #define ATA_AHCI_P_IX_OF 0x01000000 #define ATA_AHCI_P_IX_INF 0x04000000 #define ATA_AHCI_P_IX_IF 0x08000000 #define ATA_AHCI_P_IX_HBD 0x10000000 #define ATA_AHCI_P_IX_HBF 0x20000000 #define ATA_AHCI_P_IX_TFE 0x40000000 #define ATA_AHCI_P_IX_CPD 0x80000000 #define ATA_AHCI_P_CMD 0x118 #define ATA_AHCI_P_CMD_ST 0x00000001 #define ATA_AHCI_P_CMD_SUD 0x00000002 #define ATA_AHCI_P_CMD_POD 0x00000004 #define ATA_AHCI_P_CMD_CLO 0x00000008 #define ATA_AHCI_P_CMD_FRE 0x00000010 #define ATA_AHCI_P_CMD_CCS_MASK 0x00001f00 #define ATA_AHCI_P_CMD_ISS 0x00002000 #define ATA_AHCI_P_CMD_FR 0x00004000 #define ATA_AHCI_P_CMD_CR 0x00008000 #define ATA_AHCI_P_CMD_CPS 0x00010000 #define ATA_AHCI_P_CMD_PMA 0x00020000 #define ATA_AHCI_P_CMD_HPCP 0x00040000 #define ATA_AHCI_P_CMD_ISP 0x00080000 #define ATA_AHCI_P_CMD_CPD 0x00100000 #define ATA_AHCI_P_CMD_ATAPI 0x01000000 #define ATA_AHCI_P_CMD_DLAE 0x02000000 #define ATA_AHCI_P_CMD_ALPE 0x04000000 #define ATA_AHCI_P_CMD_ASP 0x08000000 #define ATA_AHCI_P_CMD_ICC_MASK 0xf0000000 #define ATA_AHCI_P_CMD_NOOP 0x00000000 #define ATA_AHCI_P_CMD_ACTIVE 0x10000000 #define ATA_AHCI_P_CMD_PARTIAL 0x20000000 #define ATA_AHCI_P_CMD_SLUMBER 0x60000000 #define ATA_AHCI_P_TFD 0x120 #define ATA_AHCI_P_SIG 0x124 #define ATA_AHCI_P_SSTS 0x128 #define ATA_AHCI_P_SCTL 0x12c #define ATA_AHCI_P_SERR 0x130 #define ATA_AHCI_P_SACT 0x134 #define ATA_AHCI_P_CI 0x138 #define ATA_AHCI_P_SNTF 0x13C #define ATA_AHCI_P_FBS 0x140 #define ATA_AHCI_CL_SIZE 32 #define ATA_AHCI_CL_OFFSET 0 #define ATA_AHCI_FB_OFFSET (ATA_AHCI_CL_SIZE * 32) #define ATA_AHCI_CT_OFFSET (ATA_AHCI_FB_OFFSET + 4096) #define ATA_AHCI_CT_SIZE (2176 + 128) 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]; #define ATA_AHCI_DMA_ENTRIES 129 struct ata_ahci_dma_prd prd_tab[ATA_AHCI_DMA_ENTRIES]; } __packed; struct ata_ahci_cmd_list { u_int16_t cmd_flags; #define ATA_AHCI_CMD_ATAPI 0x0020 #define ATA_AHCI_CMD_WRITE 0x0040 #define ATA_AHCI_CMD_PREFETCH 0x0080 #define ATA_AHCI_CMD_RESET 0x0100 #define ATA_AHCI_CMD_BIST 0x0200 #define ATA_AHCI_CMD_CLR_BUSY 0x0400 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 #define ATA_BMCMD_PORT 17 #define ATA_BMCMD_START_STOP 0x01 #define ATA_BMCMD_WRITE_READ 0x08 #define ATA_BMDEVSPEC_0 18 #define ATA_BMSTAT_PORT 19 #define ATA_BMSTAT_ACTIVE 0x01 #define ATA_BMSTAT_ERROR 0x02 #define ATA_BMSTAT_INTERRUPT 0x04 #define ATA_BMSTAT_MASK 0x07 #define ATA_BMSTAT_DMA_MASTER 0x20 #define ATA_BMSTAT_DMA_SLAVE 0x40 #define ATA_BMSTAT_DMA_SIMPLEX 0x80 #define ATA_BMDEVSPEC_1 20 #define ATA_BMDTP_PORT 21 #define ATA_IDX_ADDR 22 #define ATA_IDX_DATA 23 #define ATA_MAX_RES 24 /* misc defines */ #define ATA_PRIMARY 0x1f0 #define ATA_SECONDARY 0x170 #define ATA_PC98_BANK 0x432 #define ATA_IOSIZE 0x08 #define ATA_PC98_IOSIZE 0x10 #define ATA_CTLIOSIZE 0x01 #define ATA_BMIOSIZE 0x08 #define ATA_PC98_BANKIOSIZE 0x01 #define ATA_IOADDR_RID 0 #define ATA_CTLADDR_RID 1 #define ATA_BMADDR_RID 0x20 #define ATA_PC98_CTLADDR_RID 8 #define ATA_PC98_BANKADDR_RID 9 #define ATA_IRQ_RID 0 #define ATA_DEV(unit) ((unit > 0) ? 0x10 : 0) #define ATA_CFA_MAGIC1 0x844A #define ATA_CFA_MAGIC2 0x848A #define ATA_CFA_MAGIC3 0x8400 #define ATAPI_MAGIC_LSB 0x14 #define ATAPI_MAGIC_MSB 0xeb #define ATAPI_P_READ (ATA_S_DRQ | ATA_I_IN) #define ATAPI_P_WRITE (ATA_S_DRQ) #define ATAPI_P_CMDOUT (ATA_S_DRQ | ATA_I_CMD) #define ATAPI_P_DONEDRQ (ATA_S_DRQ | ATA_I_CMD | ATA_I_IN) #define ATAPI_P_DONE (ATA_I_CMD | ATA_I_IN) #define ATAPI_P_ABORT 0 #define ATA_INTR_FLAGS (INTR_MPSAFE|INTR_TYPE_BIO|INTR_ENTROPY) #define ATA_OP_CONTINUES 0 #define ATA_OP_FINISHED 1 #define ATA_MAX_28BIT_LBA 268435455UL #ifndef ATA_REQUEST_TIMEOUT #define ATA_REQUEST_TIMEOUT 10 #endif /* structure used for composite atomic operations */ #define MAX_COMPOSITES 32 /* u_int32_t bits */ struct ata_composite { struct mtx lock; /* control lock */ u_int32_t rd_needed; /* needed read subdisks */ u_int32_t rd_done; /* done read subdisks */ u_int32_t wr_needed; /* needed write subdisks */ u_int32_t wr_depend; /* write depends on subdisks */ u_int32_t wr_done; /* done write subdisks */ struct ata_request *request[MAX_COMPOSITES]; u_int32_t residual; /* bytes still to transfer */ caddr_t data_1; caddr_t data_2; }; /* structure used to queue an ATA/ATAPI request */ struct ata_request { device_t dev; /* device handle */ device_t parent; /* channel handle */ int unit; /* physical unit */ union { struct { u_int8_t command; /* command reg */ u_int16_t feature; /* feature reg */ u_int16_t count; /* count reg */ u_int64_t lba; /* lba reg */ } ata; struct { u_int8_t ccb[16]; /* ATAPI command block */ struct atapi_sense sense; /* ATAPI request sense data */ u_int8_t saved_cmd; /* ATAPI saved command */ } atapi; } u; u_int32_t bytecount; /* bytes to transfer */ u_int32_t transfersize; /* bytes pr transfer */ caddr_t data; /* pointer to data buf */ u_int32_t tag; /* HW tag of this request */ int flags; #define ATA_R_CONTROL 0x00000001 #define ATA_R_READ 0x00000002 #define ATA_R_WRITE 0x00000004 #define ATA_R_ATAPI 0x00000008 #define ATA_R_DMA 0x00000010 #define ATA_R_QUIET 0x00000020 #define ATA_R_TIMEOUT 0x00000040 #define ATA_R_48BIT 0x00000080 #define ATA_R_ORDERED 0x00000100 #define ATA_R_AT_HEAD 0x00000200 #define ATA_R_REQUEUE 0x00000400 #define ATA_R_THREAD 0x00000800 #define ATA_R_DIRECT 0x00001000 #define ATA_R_ATAPI16 0x00010000 #define ATA_R_ATAPI_INTR 0x00020000 #define ATA_R_DEBUG 0x10000000 #define ATA_R_DANGER1 0x20000000 #define ATA_R_DANGER2 0x40000000 struct ata_dmaslot *dma; /* DMA slot of this request */ u_int8_t status; /* ATA status */ u_int8_t error; /* ATA error */ u_int32_t donecount; /* bytes transferred */ int result; /* result error code */ void (*callback)(struct ata_request *request); struct sema done; /* request done sema */ int retries; /* retry count */ int timeout; /* timeout for this cmd */ struct callout callout; /* callout management */ struct task task; /* task management */ struct bio *bio; /* bio for this request */ int this; /* this request ID */ struct ata_composite *composite; /* for composite atomic ops */ void *driver; /* driver specific */ TAILQ_ENTRY(ata_request) chain; /* list management */ #ifdef ATA_CAM union ccb *ccb; #endif }; /* define this for debugging request processing */ #if 0 #define ATA_DEBUG_RQ(request, string) \ { \ if (request->flags & ATA_R_DEBUG) \ device_printf(request->parent, "req=%p %s " string "\n", \ request, ata_cmd2str(request)); \ } #else #define ATA_DEBUG_RQ(request, string) #endif /* structure describing an ATA/ATAPI device */ struct ata_device { device_t dev; /* device handle */ int unit; /* physical unit */ #define ATA_MASTER 0x00 #define ATA_SLAVE 0x01 #define ATA_PM 0x0f struct ata_params param; /* ata param structure */ int mode; /* current transfermode */ u_int32_t max_iosize; /* max IO size */ int spindown; /* idle spindown timeout */ struct callout spindown_timer; int spindown_state; int flags; #define ATA_D_USE_CHS 0x0001 #define ATA_D_MEDIA_CHANGED 0x0002 #define ATA_D_ENC_PRESENT 0x0004 }; /* structure for holding DMA Physical Region Descriptors (PRD) entries */ struct ata_dma_prdentry { u_int32_t addr; u_int32_t count; }; /* structure used by the setprd function */ struct ata_dmasetprd_args { void *dmatab; int nsegs; int error; }; struct ata_dmaslot { u_int8_t status; /* DMA status */ bus_dma_tag_t sg_tag; /* SG list DMA tag */ bus_dmamap_t sg_map; /* SG list DMA map */ void *sg; /* DMA transfer table */ bus_addr_t sg_bus; /* bus address of dmatab */ bus_dma_tag_t data_tag; /* data DMA tag */ bus_dmamap_t data_map; /* data DMA map */ }; /* structure holding DMA related information */ struct ata_dma { bus_dma_tag_t dmatag; /* parent DMA tag */ bus_dma_tag_t work_tag; /* workspace DMA tag */ bus_dmamap_t work_map; /* workspace DMA map */ u_int8_t *work; /* workspace */ bus_addr_t work_bus; /* bus address of dmatab */ #define ATA_DMA_SLOTS 1 int dma_slots; /* DMA slots allocated */ struct ata_dmaslot slot[ATA_DMA_SLOTS]; u_int32_t alignment; /* DMA SG list alignment */ u_int32_t boundary; /* DMA SG list boundary */ u_int32_t segsize; /* DMA SG list segment size */ u_int32_t max_iosize; /* DMA data max IO size */ u_int64_t max_address; /* highest DMA'able address */ int flags; #define ATA_DMA_ACTIVE 0x01 /* DMA transfer in progress */ void (*alloc)(device_t dev); void (*free)(device_t dev); void (*setprd)(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); int (*load)(struct ata_request *request, void *addr, int *nsegs); int (*unload)(struct ata_request *request); int (*start)(struct ata_request *request); int (*stop)(struct ata_request *request); void (*reset)(device_t dev); }; /* structure holding lowlevel functions */ struct ata_lowlevel { u_int32_t (*softreset)(device_t dev, int pmport); int (*pm_read)(device_t dev, int port, int reg, u_int32_t *result); int (*pm_write)(device_t dev, int port, int reg, u_int32_t value); int (*status)(device_t dev); int (*begin_transaction)(struct ata_request *request); int (*end_transaction)(struct ata_request *request); int (*command)(struct ata_request *request); void (*tf_read)(struct ata_request *request); void (*tf_write)(struct ata_request *request); }; /* structure holding resources for an ATA channel */ struct ata_resource { struct resource *res; int offset; }; #ifdef ATA_CAM struct ata_cam_device { u_int revision; int mode; u_int bytecount; u_int atapi; u_int caps; }; #endif /* structure describing an ATA channel */ struct ata_channel { device_t dev; /* device handle */ int unit; /* physical channel */ int attached; /* channel is attached */ struct ata_resource r_io[ATA_MAX_RES];/* I/O resources */ struct resource *r_irq; /* interrupt of this channel */ void *ih; /* interrupt handle */ struct ata_lowlevel hw; /* lowlevel HW functions */ struct ata_dma dma; /* DMA data / functions */ int flags; /* channel flags */ #define ATA_NO_SLAVE 0x01 #define ATA_USE_16BIT 0x02 #define ATA_ATAPI_DMA_RO 0x04 #define ATA_NO_48BIT_DMA 0x08 #define ATA_ALWAYS_DMASTAT 0x10 #define ATA_CHECKS_CABLE 0x20 #define ATA_NO_ATAPI_DMA 0x40 #define ATA_SATA 0x80 #define ATA_DMA_BEFORE_CMD 0x100 #define ATA_KNOWN_PRESENCE 0x200 #define ATA_STATUS_IS_LONG 0x400 #define ATA_PERIODIC_POLL 0x800 int pm_level; /* power management level */ int devices; /* what is present */ #define ATA_ATA_MASTER 0x00000001 #define ATA_ATA_SLAVE 0x00000002 #define ATA_PORTMULTIPLIER 0x00008000 #define ATA_ATAPI_MASTER 0x00010000 #define ATA_ATAPI_SLAVE 0x00020000 struct mtx state_mtx; /* state lock */ int state; /* ATA channel state */ #define ATA_IDLE 0x0000 #define ATA_ACTIVE 0x0001 #define ATA_STALL_QUEUE 0x0002 struct mtx queue_mtx; /* queue lock */ TAILQ_HEAD(, ata_request) ata_queue; /* head of ATA queue */ struct ata_request *freezepoint; /* composite freezepoint */ struct ata_request *running; /* currently running request */ struct task conntask; /* PHY events handling task */ #ifdef ATA_CAM struct cam_sim *sim; struct cam_path *path; struct ata_cam_device user[16]; /* User-specified settings */ struct ata_cam_device curr[16]; /* Current settings */ int requestsense; /* CCB waiting for SENSE. */ #endif struct callout poll_callout; /* Periodic status poll. */ }; /* disk bay/enclosure related */ #define ATA_LED_OFF 0x00 #define ATA_LED_RED 0x01 #define ATA_LED_GREEN 0x02 #define ATA_LED_ORANGE 0x03 #define ATA_LED_MASK 0x03 /* externs */ extern int (*ata_raid_ioctl_func)(u_long cmd, caddr_t data); extern struct intr_config_hook *ata_delayed_attach; extern devclass_t ata_devclass; extern int ata_wc; extern int ata_setmax; extern int ata_dma_check_80pin; /* public prototypes */ /* ata-all.c: */ int ata_probe(device_t dev); int ata_attach(device_t dev); int ata_detach(device_t dev); int ata_reinit(device_t dev); int ata_suspend(device_t dev); int ata_resume(device_t dev); void ata_interrupt(void *data); int ata_device_ioctl(device_t dev, u_long cmd, caddr_t data); int ata_getparam(struct ata_device *atadev, int init); int ata_identify(device_t dev); void ata_default_registers(device_t dev); void ata_modify_if_48bit(struct ata_request *request); void ata_udelay(int interval); const char *ata_unit2str(struct ata_device *atadev); const char *ata_mode2str(int mode); int ata_str2mode(const char *str); const char *ata_satarev2str(int rev); int ata_atapi(device_t dev, int target); int ata_pmode(struct ata_params *ap); int ata_wmode(struct ata_params *ap); int ata_umode(struct ata_params *ap); int ata_limit_mode(device_t dev, int mode, int maxmode); void ata_setmode(device_t dev); void ata_print_cable(device_t dev, u_int8_t *who); int ata_check_80pin(device_t dev, int mode); #ifdef ATA_CAM void ata_cam_begin_transaction(device_t dev, union ccb *ccb); void ata_cam_end_transaction(device_t dev, struct ata_request *request); #endif /* ata-queue.c: */ int ata_controlcmd(device_t dev, u_int8_t command, u_int16_t feature, u_int64_t lba, u_int16_t count); int ata_atapicmd(device_t dev, u_int8_t *ccb, caddr_t data, int count, int flags, int timeout); void ata_queue_request(struct ata_request *request); void ata_start(device_t dev); void ata_finish(struct ata_request *request); void ata_timeout(struct ata_request *); void ata_catch_inflight(device_t dev); void ata_fail_requests(device_t dev); void ata_drop_requests(device_t dev); const char *ata_cmd2str(struct ata_request *request); /* ata-lowlevel.c: */ void ata_generic_hw(device_t dev); int ata_begin_transaction(struct ata_request *); int ata_end_transaction(struct ata_request *); void ata_generic_reset(device_t dev); int ata_generic_command(struct ata_request *request); /* ata-dma.c: */ void ata_dmainit(device_t); void ata_dmafini(device_t dev); /* ata-sata.c: */ void ata_sata_phy_check_events(device_t dev, int port); int ata_sata_scr_read(struct ata_channel *ch, int port, int reg, uint32_t *val); int ata_sata_scr_write(struct ata_channel *ch, int port, int reg, uint32_t val); int ata_sata_phy_reset(device_t dev, int port, int quick); int ata_sata_setmode(device_t dev, int target, int mode); int ata_sata_getrev(device_t dev, int target); int ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis); void ata_pm_identify(device_t dev); /* macros for alloc/free of struct ata_request */ extern uma_zone_t ata_request_zone; #define ata_alloc_request() uma_zalloc(ata_request_zone, M_NOWAIT | M_ZERO) #define ata_free_request(request) { \ if (!(request->flags & ATA_R_DANGER2)) \ uma_zfree(ata_request_zone, request); \ } /* macros for alloc/free of struct ata_composite */ extern uma_zone_t ata_composite_zone; #define ata_alloc_composite() uma_zalloc(ata_composite_zone, M_NOWAIT | M_ZERO) #define ata_free_composite(composite) uma_zfree(ata_composite_zone, composite) MALLOC_DECLARE(M_ATA); /* misc newbus defines */ #define GRANDPARENT(dev) device_get_parent(device_get_parent(dev)) /* macros to hide busspace uglyness */ #define ATA_INB(res, offset) \ bus_read_1((res), (offset)) #define ATA_INW(res, offset) \ bus_read_2((res), (offset)) #define ATA_INL(res, offset) \ bus_read_4((res), (offset)) #define ATA_INSW(res, offset, addr, count) \ bus_read_multi_2((res), (offset), (addr), (count)) #define ATA_INSW_STRM(res, offset, addr, count) \ bus_read_multi_stream_2((res), (offset), (addr), (count)) #define ATA_INSL(res, offset, addr, count) \ bus_read_multi_4((res), (offset), (addr), (count)) #define ATA_INSL_STRM(res, offset, addr, count) \ bus_read_multi_stream_4((res), (offset), (addr), (count)) #define ATA_OUTB(res, offset, value) \ bus_write_1((res), (offset), (value)) #define ATA_OUTW(res, offset, value) \ bus_write_2((res), (offset), (value)) #define ATA_OUTL(res, offset, value) \ bus_write_4((res), (offset), (value)) #define ATA_OUTSW(res, offset, addr, count) \ bus_write_multi_2((res), (offset), (addr), (count)) #define ATA_OUTSW_STRM(res, offset, addr, count) \ bus_write_multi_stream_2((res), (offset), (addr), (count)) #define ATA_OUTSL(res, offset, addr, count) \ bus_write_multi_4((res), (offset), (addr), (count)) #define ATA_OUTSL_STRM(res, offset, addr, count) \ bus_write_multi_stream_4((res), (offset), (addr), (count)) #define ATA_IDX_INB(ch, idx) \ ATA_INB(ch->r_io[idx].res, ch->r_io[idx].offset) #define ATA_IDX_INW(ch, idx) \ ATA_INW(ch->r_io[idx].res, ch->r_io[idx].offset) #define ATA_IDX_INL(ch, idx) \ ATA_INL(ch->r_io[idx].res, ch->r_io[idx].offset) #define ATA_IDX_INSW(ch, idx, addr, count) \ ATA_INSW(ch->r_io[idx].res, ch->r_io[idx].offset, addr, count) #define ATA_IDX_INSW_STRM(ch, idx, addr, count) \ ATA_INSW_STRM(ch->r_io[idx].res, ch->r_io[idx].offset, addr, count) #define ATA_IDX_INSL(ch, idx, addr, count) \ ATA_INSL(ch->r_io[idx].res, ch->r_io[idx].offset, addr, count) #define ATA_IDX_INSL_STRM(ch, idx, addr, count) \ ATA_INSL_STRM(ch->r_io[idx].res, ch->r_io[idx].offset, addr, count) #define ATA_IDX_OUTB(ch, idx, value) \ ATA_OUTB(ch->r_io[idx].res, ch->r_io[idx].offset, value) #define ATA_IDX_OUTW(ch, idx, value) \ ATA_OUTW(ch->r_io[idx].res, ch->r_io[idx].offset, value) #define ATA_IDX_OUTL(ch, idx, value) \ ATA_OUTL(ch->r_io[idx].res, ch->r_io[idx].offset, value) #define ATA_IDX_OUTSW(ch, idx, addr, count) \ ATA_OUTSW(ch->r_io[idx].res, ch->r_io[idx].offset, addr, count) #define ATA_IDX_OUTSW_STRM(ch, idx, addr, count) \ ATA_OUTSW_STRM(ch->r_io[idx].res, ch->r_io[idx].offset, addr, count) #define ATA_IDX_OUTSL(ch, idx, addr, count) \ ATA_OUTSL(ch->r_io[idx].res, ch->r_io[idx].offset, addr, count) #define ATA_IDX_OUTSL_STRM(ch, idx, addr, count) \ ATA_OUTSL_STRM(ch->r_io[idx].res, ch->r_io[idx].offset, addr, count) Index: stable/9/sys/dev/ata/ata-sata.c =================================================================== --- stable/9/sys/dev/ata/ata-sata.c (revision 243117) +++ stable/9/sys/dev/ata/ata-sata.c (revision 243118) @@ -1,353 +1,370 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void ata_sata_phy_check_events(device_t dev, int port) { struct ata_channel *ch = device_get_softc(dev); u_int32_t error, status; ata_sata_scr_read(ch, port, ATA_SERROR, &error); /* Check that SError value is sane. */ if (error == 0xffffffff) return; /* Clear set error bits/interrupt. */ if (error) ata_sata_scr_write(ch, port, ATA_SERROR, error); /* if we have a connection event deal with it */ if ((error & ATA_SE_PHY_CHANGED) && (ch->pm_level == 0)) { if (bootverbose) { ata_sata_scr_read(ch, port, ATA_SSTATUS, &status); if (((status & ATA_SS_DET_MASK) == ATA_SS_DET_PHY_ONLINE) && ((status & ATA_SS_SPD_MASK) != ATA_SS_SPD_NO_SPEED) && ((status & ATA_SS_IPM_MASK) == ATA_SS_IPM_ACTIVE)) { device_printf(dev, "CONNECT requested\n"); } else device_printf(dev, "DISCONNECT requested\n"); } taskqueue_enqueue(taskqueue_thread, &ch->conntask); } } int ata_sata_scr_read(struct ata_channel *ch, int port, int reg, uint32_t *val) { if (ch->hw.pm_read != NULL) return (ch->hw.pm_read(ch->dev, port, reg, val)); if (ch->r_io[reg].res) { *val = ATA_IDX_INL(ch, reg); return (0); } return (-1); } int ata_sata_scr_write(struct ata_channel *ch, int port, int reg, uint32_t val) { if (ch->hw.pm_write != NULL) return (ch->hw.pm_write(ch->dev, port, reg, val)); if (ch->r_io[reg].res) { ATA_IDX_OUTL(ch, reg, val); return (0); } return (-1); } static int ata_sata_connect(struct ata_channel *ch, int port, int quick) { u_int32_t status; int timeout, t; /* wait up to 1 second for "connect well" */ timeout = (quick == 2) ? 0 : 100; t = 0; while (1) { if (ata_sata_scr_read(ch, port, ATA_SSTATUS, &status)) return (0); if (((status & ATA_SS_DET_MASK) == ATA_SS_DET_PHY_ONLINE) && ((status & ATA_SS_SPD_MASK) != ATA_SS_SPD_NO_SPEED) && ((status & ATA_SS_IPM_MASK) == ATA_SS_IPM_ACTIVE)) break; if (++t > timeout) break; ata_udelay(10000); } if (bootverbose) { if (t > timeout) { if (port < 0) { device_printf(ch->dev, "SATA connect timeout status=%08x\n", status); } else { device_printf(ch->dev, "p%d: SATA connect timeout status=%08x\n", port, status); } } else if (port < 0) { device_printf(ch->dev, "SATA connect time=%dms status=%08x\n", t * 10, status); } else { device_printf(ch->dev, "p%d: SATA connect time=%dms status=%08x\n", port, t * 10, status); } } /* clear SATA error register */ ata_sata_scr_write(ch, port, ATA_SERROR, 0xffffffff); return ((t > timeout) ? 0 : 1); } int ata_sata_phy_reset(device_t dev, int port, int quick) { struct ata_channel *ch = device_get_softc(dev); - int loop, retry; - uint32_t val; + int loop, retry, sata_rev; + uint32_t val, val1; +#ifdef ATA_CAM + sata_rev = ch->user[port < 0 ? 0 : port].revision; + if (sata_rev > 0) + quick = 0; +#else + sata_rev = 0; +#endif + if (quick) { if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val)) return (0); if ((val & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE) { ata_sata_scr_write(ch, port, ATA_SCONTROL, ATA_SC_DET_IDLE | ((ch->pm_level > 0) ? 0 : ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER)); return ata_sata_connect(ch, port, quick); } } if (bootverbose) { if (port < 0) { device_printf(dev, "hard reset ...\n"); } else { device_printf(dev, "p%d: hard reset ...\n", port); } } + if (sata_rev == 1) + val1 = ATA_SC_SPD_SPEED_GEN1; + else if (sata_rev == 2) + val1 = ATA_SC_SPD_SPEED_GEN2; + else if (sata_rev == 3) + val1 = ATA_SC_SPD_SPEED_GEN3; + else + val1 = 0; for (retry = 0; retry < 10; retry++) { for (loop = 0; loop < 10; loop++) { - if (ata_sata_scr_write(ch, port, ATA_SCONTROL, ATA_SC_DET_RESET)) + if (ata_sata_scr_write(ch, port, ATA_SCONTROL, ATA_SC_DET_RESET | + val1 | ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER)) goto fail; ata_udelay(100); if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val)) goto fail; if ((val & ATA_SC_DET_MASK) == ATA_SC_DET_RESET) break; } ata_udelay(5000); for (loop = 0; loop < 10; loop++) { if (ata_sata_scr_write(ch, port, ATA_SCONTROL, - ATA_SC_DET_IDLE | ((ch->pm_level > 0) ? 0 : + ATA_SC_DET_IDLE | val1 | ((ch->pm_level > 0) ? 0 : ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER))) goto fail; ata_udelay(100); if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val)) goto fail; if ((val & ATA_SC_DET_MASK) == 0) return ata_sata_connect(ch, port, 0); } } fail: /* Clear SATA error register. */ ata_sata_scr_write(ch, port, ATA_SERROR, 0xffffffff); if (bootverbose) { if (port < 0) { device_printf(dev, "hard reset failed\n"); } else { device_printf(dev, "p%d: hard reset failed\n", port); } } return (0); } int ata_sata_setmode(device_t dev, int target, int mode) { return (min(mode, ATA_UDMA5)); } int ata_sata_getrev(device_t dev, int target) { struct ata_channel *ch = device_get_softc(dev); if (ch->r_io[ATA_SSTATUS].res) return ((ATA_IDX_INL(ch, ATA_SSTATUS) & 0x0f0) >> 4); return (0xff); } int ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis) { if (request->flags & ATA_R_ATAPI) { fis[0] = 0x27; /* host to device */ fis[1] = 0x80 | (request->unit & 0x0f); 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; fis[15] = ATA_A_4BIT; return 20; } else { fis[0] = 0x27; /* host to device */ fis[1] = 0x80 | (request->unit & 0x0f); 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; if (!(request->flags & ATA_R_48BIT)) fis[7] |= (ATA_D_IBM | (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; } void ata_pm_identify(device_t dev) { struct ata_channel *ch = device_get_softc(dev); u_int32_t pm_chipid, pm_revision, pm_ports; int port; /* get PM vendor & product data */ if (ch->hw.pm_read(dev, ATA_PM, 0, &pm_chipid)) { device_printf(dev, "error getting PM vendor data\n"); return; } /* get PM revision data */ if (ch->hw.pm_read(dev, ATA_PM, 1, &pm_revision)) { device_printf(dev, "error getting PM revison data\n"); return; } /* get number of HW ports on the PM */ if (ch->hw.pm_read(dev, ATA_PM, 2, &pm_ports)) { device_printf(dev, "error getting PM port info\n"); return; } pm_ports &= 0x0000000f; /* chip specific quirks */ switch (pm_chipid) { case 0x37261095: /* This PM declares 6 ports, while only 5 of them are real. * Port 5 is enclosure management bridge port, which has implementation * problems, causing probe faults. Hide it for now. */ device_printf(dev, "SiI 3726 (rev=%x) Port Multiplier with %d (5) ports\n", pm_revision, pm_ports); pm_ports = 5; break; case 0x47261095: /* This PM declares 7 ports, while only 5 of them are real. * Port 5 is some fake "Config Disk" with 640 sectors size, * port 6 is enclosure management bridge port. * Both fake ports has implementation problems, causing * probe faults. Hide them for now. */ device_printf(dev, "SiI 4726 (rev=%x) Port Multiplier with %d (5) ports\n", pm_revision, pm_ports); pm_ports = 5; break; default: device_printf(dev, "Port Multiplier (id=%08x rev=%x) with %d ports\n", pm_chipid, pm_revision, pm_ports); } /* reset all ports and register if anything connected */ for (port=0; port < pm_ports; port++) { u_int32_t signature; if (!ata_sata_phy_reset(dev, port, 1)) continue; /* * XXX: I have no idea how to properly wait for PMP port hardreset * completion. Without this delay soft reset does not completes * successfully. */ DELAY(1000000); signature = ch->hw.softreset(dev, port); if (bootverbose) device_printf(dev, "p%d: SIGNATURE=%08x\n", port, signature); /* figure out whats there */ switch (signature >> 16) { case 0x0000: ch->devices |= (ATA_ATA_MASTER << port); continue; case 0xeb14: ch->devices |= (ATA_ATAPI_MASTER << port); continue; } } } Index: stable/9/sys/dev =================================================================== --- stable/9/sys/dev (revision 243117) +++ stable/9/sys/dev (revision 243118) Property changes on: stable/9/sys/dev ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/dev:r241144,241160 Index: stable/9/sys =================================================================== --- stable/9/sys (revision 243117) +++ stable/9/sys (revision 243118) Property changes on: stable/9/sys ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys:r241144,241160