diff options
author | sos <sos@FreeBSD.org> | 2005-03-30 12:03:40 +0000 |
---|---|---|
committer | sos <sos@FreeBSD.org> | 2005-03-30 12:03:40 +0000 |
commit | f820cdfe2975b10fc33cce539d92cc867aad4576 (patch) | |
tree | d973712ac291429795c126539153aec43f4cd2c1 /sys | |
parent | 20adbdefb7ad9134b3f40790a428eae30d071089 (diff) | |
download | FreeBSD-src-f820cdfe2975b10fc33cce539d92cc867aad4576.zip FreeBSD-src-f820cdfe2975b10fc33cce539d92cc867aad4576.tar.gz |
This is the much rumoured ATA mkIII update that I've been working on.
o ATA is now fully newbus'd and split into modules.
This means that on a modern system you just load "atapci and ata"
to get the base support, and then one or more of the device
subdrivers "atadisk atapicd atapifd atapist ataraid".
All can be loaded/unloaded anytime, but for obvious reasons you
dont want to unload atadisk when you have mounted filesystems.
o The device identify part of the probe has been rewritten to fix
the problems with odd devices the old had, and to try to remove
so of the long delays some HW could provoke. Also probing is done
without the need for interrupts, making earlier probing possible.
o SATA devices can be hot inserted/removed and devices will be created/
removed in /dev accordingly.
NOTE: only supported on controllers that has this feature:
Promise and Silicon Image for now.
On other controllers the usual atacontrol detach/attach dance is
still needed.
o Support for "atomic" composite ATA requests used for RAID.
o ATA RAID support has been rewritten and and now supports these
metadata formats:
"Adaptec HostRAID"
"Highpoint V2 RocketRAID"
"Highpoint V3 RocketRAID"
"Intel MatrixRAID"
"Integrated Technology Express"
"LSILogic V2 MegaRAID"
"LSILogic V3 MegaRAID"
"Promise FastTrak"
"Silicon Image Medley"
"FreeBSD PseudoRAID"
o Update the ioctl API to match new RAID levels etc.
o Update atacontrol to know about the new RAID levels etc
NOTE: you need to recompile atacontrol with the new sys/ata.h,
make world will take care of that.
NOTE2: that rebuild is done differently from the old system as
the rebuild is now done piggybacked on read requests to the
array, so atacontrol simply starts a background "dd" to rebuild
the array.
o The reinit code has been worked over to be much more robust.
o The timeout code has been overhauled for races.
o Support of new chipsets.
o Lots of fixes for bugs found while doing the modulerization and
reviewing the old code.
Missing or changed features from current ATA:
o atapi-cd no longer has support for ATAPI changers. Todays its
much cheaper and alot faster to copy those CD images to disk
and serve them from there. Besides they dont seem to be made
anymore, maybe for that exact reason.
o ATA RAID can only read metadata from all the above metadata formats,
not write all of them (Promise and Highpoint V2 so far). This means
that arrays can be picked up from the BIOS, but they cannot be
created from FreeBSD. There is more to it than just the missing
write metadata support, those formats are not unique to a given
controller like Promise and Highpoint formats, instead they exist
for several types, and even worse, some controllers can have
different formats and its impossible to tell which one.
The outcome is that we cannot reliably create the metadata of those
formats and be sure the controller BIOS will understand it.
However write support is needed to update/fail/rebuild the arrays
properly so it sits fairly high on the TODO list.
o So far atapicam is not supported with these changes. When/if this
will change is up to the maintainer of atapi-cam so go there for
questions.
HW donated by: Webveveriet AS
HW donated by: Frode Nordahl
HW donated by: Yahoo!
HW donated by: Sentex
Patience by: Vife and my boys (and even the cats)
Diffstat (limited to 'sys')
40 files changed, 8279 insertions, 5878 deletions
diff --git a/sys/conf/files b/sys/conf/files index c734acc..73fd93a 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -387,6 +387,7 @@ dev/an/if_an_isa.c optional an isa dev/an/if_an_pccard.c optional an pccard dev/an/if_an_pci.c optional an pci dev/asr/asr.c optional asr pci +dev/ata/ata_if.m optional ata dev/ata/ata-all.c optional ata dev/ata/ata-card.c optional ata pccard dev/ata/ata-cbus.c optional ata pc98 diff --git a/sys/conf/kmod.mk b/sys/conf/kmod.mk index c753254..07d0c38 100644 --- a/sys/conf/kmod.mk +++ b/sys/conf/kmod.mk @@ -298,8 +298,9 @@ ${_src}: .endfor .endif -MFILES?= dev/acpica/acpi_if.m dev/eisa/eisa_if.m dev/iicbus/iicbb_if.m \ - dev/iicbus/iicbus_if.m dev/mii/miibus_if.m dev/ofw/ofw_bus_if.m \ +MFILES?= dev/acpica/acpi_if.m dev/ata/ata_if.m dev/eisa/eisa_if.m \ + dev/iicbus/iicbb_if.m dev/iicbus/iicbus_if.m \ + dev/mii/miibus_if.m dev/ofw/ofw_bus_if.m \ dev/pccard/card_if.m dev/pccard/power_if.m dev/pci/pci_if.m \ dev/pci/pcib_if.m dev/ppbus/ppbus_if.m dev/smbus/smbus_if.m \ dev/sound/pcm/ac97_if.m dev/sound/pcm/channel_if.m \ diff --git a/sys/conf/options b/sys/conf/options index 25608bc..eb0174f 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -303,12 +303,6 @@ ISP_FW_CRASH_DUMP opt_isp.h # Options used in the 'ata' ATA/ATAPI driver ATA_STATIC_ID opt_ata.h ATA_NOPCI opt_ata.h -DEV_ATADISK opt_ata.h -DEV_ATAPICD opt_ata.h -DEV_ATAPIST opt_ata.h -DEV_ATAPIFD opt_ata.h -DEV_ATAPICAM opt_ata.h -DEV_ATARAID opt_ata.h # Net stuff. ACCEPT_FILTER_DATA diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index ca38b5b..45786e3 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/ata.h> #include <sys/kernel.h> +#include <sys/module.h> #include <sys/endian.h> #include <sys/ctype.h> #include <sys/conf.h> @@ -51,33 +52,27 @@ __FBSDID("$FreeBSD$"); #ifdef __alpha__ #include <machine/md_var.h> #endif -#include <geom/geom_disk.h> #include <dev/ata/ata-all.h> -#include <dev/ata/ata-disk.h> -#include <dev/ata/ata-raid.h> +#include <dev/ata/ata-commands.h> +#include <ata_if.h> -/* device structures */ -static d_ioctl_t ata_ioctl; +/* device structure */ +static d_ioctl_t ata_ioctl; static struct cdevsw ata_cdevsw = { - .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, - .d_ioctl = ata_ioctl, - .d_name = "ata", + .d_version = D_VERSION, + .d_flags = D_NEEDGIANT, /* we need this as newbus isn't safe */ + .d_ioctl = ata_ioctl, + .d_name = "ata", }; /* prototypes */ -static void ata_shutdown(void *, int); static void ata_interrupt(void *); -static int ata_getparam(struct ata_device *, u_int8_t); -static void ata_identify_devices(struct ata_channel *); static void ata_boot_attach(void); -static void bswap(int8_t *, int); -static void btrim(int8_t *, int); -static void bpack(int8_t *, int8_t *, int); -static void ata_init(void); +device_t ata_add_child(driver_t *driver, device_t parent, struct ata_device *atadev, const char *name, int unit); /* global vars */ MALLOC_DEFINE(M_ATA, "ATA generic", "ATA driver generic layer"); +int (*ata_ioctl_func)(struct ata_cmd *iocmd) = NULL; devclass_t ata_devclass; uma_zone_t ata_zone; int ata_wc = 1; @@ -86,19 +81,18 @@ int ata_wc = 1; static struct intr_config_hook *ata_delayed_attach = NULL; static int ata_dma = 1; static int atapi_dma = 1; -static int ata_resuming = 0; /* sysctl vars */ SYSCTL_NODE(_hw, OID_AUTO, ata, CTLFLAG_RD, 0, "ATA driver parameters"); 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"); -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.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"); /* * newbus device interface related functions @@ -106,231 +100,147 @@ SYSCTL_INT(_hw_ata, OID_AUTO, atapi_dma, CTLFLAG_RDTUN, &atapi_dma, 0, int ata_probe(device_t dev) { - struct ata_channel *ch; - - if (!dev || !(ch = device_get_softc(dev))) - return ENXIO; - - if (ch->r_irq) - return EEXIST; - return 0; } int ata_attach(device_t dev) { - struct ata_channel *ch; + struct ata_channel *ch = device_get_softc(dev); int error, rid; - if (!dev || !(ch = device_get_softc(dev))) - return ENXIO; + /* check that we have a virgin channel to attach */ + if (ch->r_irq) + return EEXIST; /* initialize the softc basics */ - ch->device[MASTER].channel = ch; - ch->device[MASTER].unit = ATA_MASTER; - ch->device[MASTER].mode = ATA_PIO; - ch->device[SLAVE].channel = ch; - ch->device[SLAVE].unit = ATA_SLAVE; - ch->device[SLAVE].mode = ATA_PIO; 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); /* initialise device(s) on this channel */ - while (ch->locking(ch, ATA_LF_LOCK) != ch->unit) + while (ATA_LOCKING(device_get_parent(dev), dev, ATA_LF_LOCK) != ch->unit) tsleep(&error, PRIBIO, "ataatch", 1); ch->hw.reset(ch); - ch->locking(ch, ATA_LF_UNLOCK); + ATA_LOCKING(device_get_parent(dev), dev, ATA_LF_UNLOCK); + /* 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) { - ata_printf(ch, -1, "unable to allocate interrupt\n"); + device_printf(dev, "unable to allocate interrupt\n"); return ENXIO; } if ((error = bus_setup_intr(dev, ch->r_irq, ATA_INTR_FLAGS, ata_interrupt, ch, &ch->ih))) { - ata_printf(ch, -1, "unable to setup interrupt\n"); + device_printf(dev, "unable to setup interrupt\n"); return error; } - /* initialize queue and associated lock */ - bzero(&ch->queue_mtx, sizeof(struct mtx)); - mtx_init(&ch->queue_mtx, "ATA queue lock", NULL, MTX_DEF); - TAILQ_INIT(&ch->ata_queue); - /* do not attach devices if we are in early boot */ if (ata_delayed_attach) return 0; - ata_identify_devices(ch); - - if (ch->device[MASTER].attach) - ch->device[MASTER].attach(&ch->device[MASTER]); - if (ch->device[SLAVE].attach) - ch->device[SLAVE].attach(&ch->device[SLAVE]); -#ifdef DEV_ATAPICAM - atapi_cam_attach_bus(ch); -#endif + /* probe and attach devices on this channel */ + bus_generic_probe(dev); + bus_generic_attach(dev); return 0; } int ata_detach(device_t dev) { - struct ata_channel *ch; + struct ata_channel *ch = device_get_softc(dev); + device_t *children; + int nchildren, i; - if (!dev || !(ch = device_get_softc(dev)) || !ch->r_irq) + /* check that we have a vaild channel to detach */ + if (!ch->r_irq) return ENXIO; - /* mark devices on this channel as detaching */ - ch->device[MASTER].flags |= ATA_D_DETACHING; - ch->device[SLAVE].flags |= ATA_D_DETACHING; + /* 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); + } - /* fail outstanding requests on this channel */ + /* fail outstanding requests on this channel (SOS shouldn't be any XXX ) */ ata_fail_requests(ch, NULL); - /* unlock the channel */ - mtx_lock(&ch->state_mtx); - ch->state = ATA_IDLE; - mtx_unlock(&ch->state_mtx); - ch->locking(ch, ATA_LF_UNLOCK); - - /* detach devices on this channel */ - if (ch->device[MASTER].detach) - ch->device[MASTER].detach(&ch->device[MASTER]); - if (ch->device[SLAVE].detach) - ch->device[SLAVE].detach(&ch->device[SLAVE]); -#ifdef DEV_ATAPICAM - atapi_cam_detach_bus(ch); -#endif - - /* flush cache and powerdown device */ - if (ch->device[MASTER].param) { - if (ch->device[MASTER].param->support.command2 & ATA_SUPPORT_FLUSHCACHE) - ata_controlcmd(&ch->device[MASTER], ATA_FLUSHCACHE, 0, 0, 0); - ata_controlcmd(&ch->device[MASTER], ATA_SLEEP, 0, 0, 0); - free(ch->device[MASTER].param, M_ATA); - ch->device[MASTER].param = NULL; - } - if (ch->device[SLAVE].param) { - if (ch->device[SLAVE].param->support.command2 & ATA_SUPPORT_FLUSHCACHE) - ata_controlcmd(&ch->device[SLAVE], ATA_FLUSHCACHE, 0, 0, 0); - ata_controlcmd(&ch->device[SLAVE], ATA_SLEEP, 0, 0, 0); - free(ch->device[SLAVE].param, M_ATA); - ch->device[SLAVE].param = NULL; - } - ch->device[MASTER].mode = ATA_PIO; - ch->device[SLAVE].mode = ATA_PIO; - ch->devices = 0; - + /* 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; + mtx_destroy(&ch->state_mtx); mtx_destroy(&ch->queue_mtx); return 0; } int -ata_reinit(struct ata_channel *ch) +ata_reinit(device_t dev) { - int devices, misdev, newdev; + struct ata_channel *ch = device_get_softc(dev); + device_t *children; + int nchildren, i; - if (!ch->r_irq) + if (!ch || !ch->r_irq) return ENXIO; if (bootverbose) - ata_printf(ch, -1, "reiniting channel ..\n"); + device_printf(dev, "reiniting channel ..\n"); - /* poll for locking of this channel */ - while (ch->locking(ch, ATA_LF_LOCK) != ch->unit) - tsleep(&devices, PRIBIO, "atarint", 1); + /* poll for locking the channel */ + while (ATA_LOCKING(device_get_parent(dev), dev, ATA_LF_LOCK) != ch->unit) + tsleep(&dev, PRIBIO, "atarini", 1); - ata_catch_inflight(ch); - - /* grap the channel lock no matter what */ + /* grap the channel lock */ mtx_lock(&ch->state_mtx); - ch->state = ATA_ACTIVE; + ch->state = ATA_STALL_QUEUE; mtx_unlock(&ch->state_mtx); - if (ch->flags & ATA_IMMEDIATE_MODE) - return EIO; - else - ch->flags |= ATA_IMMEDIATE_MODE; - - devices = ch->devices; - + /* reset the channel and devices */ ch->hw.reset(ch); - if (bootverbose) - ata_printf(ch, -1, "resetting done ..\n"); - - /* detach what left the channel during reset */ - if ((misdev = devices & ~ch->devices)) { - if ((misdev & (ATA_ATA_MASTER | ATA_ATAPI_MASTER)) && - ch->device[MASTER].detach) { - ata_fail_requests(ch, &ch->device[MASTER]); - ch->device[MASTER].detach(&ch->device[MASTER]); - free(ch->device[MASTER].param, M_ATA); - ch->device[MASTER].param = NULL; - } - if ((misdev & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE)) && - ch->device[SLAVE].detach) { - ata_fail_requests(ch, &ch->device[SLAVE]); - ch->device[SLAVE].detach(&ch->device[SLAVE]); - free(ch->device[SLAVE].param, M_ATA); - ch->device[SLAVE].param = NULL; + /* 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++) { + if (children[i] && device_is_attached(children[i])) + if (ATA_REINIT(children[i])) { + if (ch->running->dev == children[i]) { + device_printf(ch->running->dev, + "FAILURE - device detached\n"); + ch->running->dev = NULL; + ch->running = NULL; + } + device_delete_child(dev, children[i]); + } } + free(children, M_TEMP); + mtx_unlock(&Giant); /* newbus suckage dealt with, release Giant */ } - /* identify what is present on the channel now */ - ata_identify_devices(ch); - - /* detach what left the channel during identify */ - if ((misdev = devices & ~ch->devices)) { - if ((misdev & (ATA_ATA_MASTER | ATA_ATAPI_MASTER)) && - ch->device[MASTER].detach) { - ata_fail_requests(ch, &ch->device[MASTER]); - ch->device[MASTER].detach(&ch->device[MASTER]); - free(ch->device[MASTER].param, M_ATA); - ch->device[MASTER].param = NULL; - } - if ((misdev & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE)) && - ch->device[SLAVE].detach) { - ata_fail_requests(ch, &ch->device[SLAVE]); - ch->device[SLAVE].detach(&ch->device[SLAVE]); - free(ch->device[SLAVE].param, M_ATA); - ch->device[SLAVE].param = NULL; - } - } + /* catch running request if any */ + ata_catch_inflight(ch); - ch->flags &= ~ATA_IMMEDIATE_MODE; + /* we're done release the channel for new work */ mtx_lock(&ch->state_mtx); ch->state = ATA_IDLE; mtx_unlock(&ch->state_mtx); - ch->locking(ch, ATA_LF_UNLOCK); - - /* attach new devices */ - if ((newdev = ~devices & ch->devices)) { - if ((newdev & (ATA_ATA_MASTER | ATA_ATAPI_MASTER)) && - ch->device[MASTER].attach) - ch->device[MASTER].attach(&ch->device[MASTER]); - if ((newdev & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE)) && - ch->device[SLAVE].attach) - ch->device[SLAVE].attach(&ch->device[SLAVE]); - } - -#ifdef DEV_ATAPICAM - atapi_cam_reinit_bus(ch); -#endif + ATA_LOCKING(device_get_parent(dev), dev, ATA_LF_UNLOCK); if (bootverbose) - ata_printf(ch, -1, "device config done ..\n"); + device_printf(dev, "reinit done ..\n"); - ata_start(ch); + /* kick off requests on the queue */ + ata_start(dev); return 0; } @@ -342,6 +252,7 @@ ata_suspend(device_t dev) if (!dev || !(ch = device_get_softc(dev))) return ENXIO; + /* wait for the channel to be IDLE before when enter suspend mode */ while (1) { mtx_lock(&ch->state_mtx); if (ch->state == ATA_IDLE) { @@ -352,7 +263,7 @@ ata_suspend(device_t dev) mtx_unlock(&ch->state_mtx); tsleep(ch, PRIBIO, "atasusp", hz/10); } - ch->locking(ch, ATA_LF_UNLOCK); + ATA_LOCKING(device_get_parent(dev), dev, ATA_LF_UNLOCK); return 0; } @@ -365,30 +276,12 @@ ata_resume(device_t dev) if (!dev || !(ch = device_get_softc(dev))) return ENXIO; - ata_resuming = 1; - error = ata_reinit(ch); - ata_start(ch); - ata_resuming = 0; - return error; -} - -static void -ata_shutdown(void *arg, int howto) -{ - struct ata_channel *ch; - int ctlr; + /* reinit the devices, we dont know what mode/state they have */ + error = ata_reinit(dev); - /* flush cache on all devices */ - for (ctlr = 0; ctlr < devclass_get_maxunit(ata_devclass); ctlr++) { - if (!(ch = devclass_get_softc(ata_devclass, ctlr))) - continue; - if (ch->device[MASTER].param && - ch->device[MASTER].param->support.command2 & ATA_SUPPORT_FLUSHCACHE) - ata_controlcmd(&ch->device[MASTER], ATA_FLUSHCACHE, 0, 0, 0); - if (ch->device[SLAVE].param && - ch->device[SLAVE].param->support.command2 & ATA_SUPPORT_FLUSHCACHE) - ata_controlcmd(&ch->device[SLAVE], ATA_FLUSHCACHE, 0, 0, 0); - } + /* kick off requests on the queue */ + ata_start(dev); + return error; } static void @@ -400,7 +293,7 @@ ata_interrupt(void *data) mtx_lock(&ch->state_mtx); do { /* do we have a running request */ - if (!(request = ch->running)) + if (ch->state & ATA_TIMEOUT || !(request = ch->running)) break; ATA_DEBUG_RQ(request, "interrupt"); @@ -413,30 +306,30 @@ ata_interrupt(void *data) } /* check for the right state */ - if (ch->state == ATA_ACTIVE) { + if (ch->state == ATA_ACTIVE || ch->state == ATA_STALL_QUEUE) { request->flags |= ATA_R_INTR_SEEN; - ch->state = ATA_INTERRUPT; } else { - ata_prtdev(request->device, - "interrupt state=%d unexpected\n", ch->state); + device_printf(request->dev, + "interrupt state=%d unexpected\n", ch->state); break; } + /* + * we have the HW locks, so start the tranaction for this request + * if it finishes immediately we dont need to wait for interrupt + */ if (ch->hw.end_transaction(request) == ATA_OP_FINISHED) { ch->running = NULL; - if (ch->flags & ATA_IMMEDIATE_MODE) - ch->state = ATA_ACTIVE; - else + if (ch->state == ATA_ACTIVE) ch->state = ATA_IDLE; mtx_unlock(&ch->state_mtx); - ch->locking(ch, ATA_LF_UNLOCK); + ATA_LOCKING(device_get_parent(ch->dev), ch->dev, ATA_LF_UNLOCK); ata_finish(request); return; } else { request->flags &= ~ATA_R_INTR_SEEN; - ch->state = ATA_ACTIVE; } } while (0); mtx_unlock(&ch->state_mtx); @@ -450,537 +343,350 @@ ata_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td) { struct ata_cmd *iocmd = (struct ata_cmd *)addr; - device_t device = devclass_get_device(ata_devclass, iocmd->channel); - struct ata_channel *ch; - struct ata_device *atadev; + device_t *children, device = NULL; struct ata_request *request; caddr_t buf; + int nchildren, i; int error = ENOTTY; if (cmd != IOCATA) - return error; - - DROP_GIANT(); - switch (iocmd->cmd) { - case ATAGMAXCHANNEL: + return ENOTSUP; + if (iocmd->cmd == ATAGMAXCHANNEL) { iocmd->u.maxchan = devclass_get_maxunit(ata_devclass); - error = 0; - break; + return 0; + } + if (iocmd->channel < 0 || + iocmd->channel >= devclass_get_maxunit(ata_devclass)) { + return ENXIO; + } + if (!(device = devclass_get_device(ata_devclass, iocmd->channel))) + return ENXIO; + switch (iocmd->cmd) { case ATAGPARM: - if (!device || !(ch = device_get_softc(device))) { - error = ENXIO; - break; + if (!device_get_children(device, &children, &nchildren)) { + struct ata_channel *ch; + + if (!(ch = device_get_softc(device))) + return ENXIO; + iocmd->u.param.type[0] = + ch->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER); + iocmd->u.param.type[1] = + ch->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE); + 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) { + strcpy(iocmd->u.param.name[0], + device_get_nameunit(children[i])); + bcopy(&atadev->param, &iocmd->u.param.params[0], + sizeof(struct ata_params)); + } + if (atadev->unit == ATA_SLAVE) { + strcpy(iocmd->u.param.name[1], + device_get_nameunit(children[i])); + bcopy(&atadev->param, &iocmd->u.param.params[1], + sizeof(struct ata_params)); + } + } + } + free(children, M_TEMP); + error = 0; } - iocmd->u.param.type[MASTER] = - ch->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER); - iocmd->u.param.type[SLAVE] = - ch->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE); - if (ch->device[MASTER].name) - strcpy(iocmd->u.param.name[MASTER], ch->device[MASTER].name); - if (ch->device[SLAVE].name) - strcpy(iocmd->u.param.name[SLAVE], ch->device[SLAVE].name); - if (ch->device[MASTER].param) - bcopy(ch->device[MASTER].param, &iocmd->u.param.params[MASTER], - sizeof(struct ata_params)); - if (ch->device[SLAVE].param) - bcopy(ch->device[SLAVE].param, &iocmd->u.param.params[SLAVE], - sizeof(struct ata_params)); - error = 0; + else + error = ENXIO; break; case ATAGMODE: - if (!device || !(ch = device_get_softc(device))) { - error = ENXIO; - break; + 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]); + + atadev = device_get_softc(children[i]); + if (atadev->unit == ATA_MASTER) + iocmd->u.mode.mode[0] = atadev->mode; + if (atadev->unit == ATA_SLAVE) + iocmd->u.mode.mode[1] = atadev->mode; + } + free(children, M_TEMP); + } + error = 0; } - iocmd->u.mode.mode[MASTER] = ch->device[MASTER].mode; - iocmd->u.mode.mode[SLAVE] = ch->device[SLAVE].mode; - error = 0; + else + error = ENXIO; break; case ATASMODE: - if (!device || !(ch = device_get_softc(device))) { - error = ENXIO; - break; + 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) { + atadev->mode = iocmd->u.mode.mode[0]; + ATA_SETMODE(device_get_parent(device), children[i]); + iocmd->u.mode.mode[0] = atadev->mode; + } + if (atadev->unit == ATA_SLAVE) { + atadev->mode = iocmd->u.mode.mode[1]; + ATA_SETMODE(device_get_parent(device), children[i]); + iocmd->u.mode.mode[1] = atadev->mode; + } + } + } + free(children, M_TEMP); + error = 0; } - if (iocmd->u.mode.mode[MASTER] >= 0 && ch->device[MASTER].param) - ch->device[MASTER].setmode(&ch->device[MASTER], - iocmd->u.mode.mode[MASTER]); - iocmd->u.mode.mode[MASTER] = ch->device[MASTER].mode; - if (iocmd->u.mode.mode[SLAVE] >= 0 && ch->device[SLAVE].param) - ch->device[SLAVE].setmode(&ch->device[SLAVE], - iocmd->u.mode.mode[SLAVE]); - iocmd->u.mode.mode[SLAVE] = ch->device[SLAVE].mode; - error = 0; + else + error = ENXIO; break; case ATAREQUEST: - if (!device || !(ch = device_get_softc(device))) { - error = ENXIO; - break; - } - if (!(atadev = &ch->device[iocmd->device])) { - error = ENODEV; - break; - } - if (!(buf = malloc(iocmd->u.request.count, M_ATA, M_NOWAIT))) { - error = ENOMEM; - break; - } - if (!(request = ata_alloc_request())) { - error = ENOMEM; - free(buf, M_ATA); - break; - } - if (iocmd->u.request.flags & ATA_CMD_WRITE) { - error = copyin(iocmd->u.request.data, buf, iocmd->u.request.count); - if (error) { - free(buf, M_ATA); - ata_free_request(request); - break; + 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 (ATA_DEV(atadev->unit) == iocmd->device) { + if (!(buf = malloc(iocmd->u.request.count, + M_ATA, M_NOWAIT))) { + error = ENOMEM; + break; + } + if (!(request = ata_alloc_request())) { + error = ENOMEM; + free(buf, M_ATA); + break; + } + if (iocmd->u.request.flags & ATA_CMD_WRITE) { + error = copyin(iocmd->u.request.data, buf, + iocmd->u.request.count); + if (error) { + free(buf, M_ATA); + ata_free_request(request); + break; + } + } + request->dev = atadev->dev; + if (iocmd->u.request.flags & ATA_CMD_ATAPI) { + request->flags = ATA_R_ATAPI; + bcopy(iocmd->u.request.u.atapi.ccb, + request->u.atapi.ccb, 16); + } + else { + request->u.ata.command = + iocmd->u.request.u.ata.command; + request->u.ata.feature = + iocmd->u.request.u.ata.feature; + request->u.ata.lba = iocmd->u.request.u.ata.lba; + request->u.ata.count = iocmd->u.request.u.ata.count; + } + request->timeout = iocmd->u.request.timeout; + request->data = buf; + request->bytecount = iocmd->u.request.count; + request->transfersize = request->bytecount; + if (iocmd->u.request.flags & ATA_CMD_CONTROL) + request->flags |= ATA_R_CONTROL; + if (iocmd->u.request.flags & ATA_CMD_READ) + request->flags |= ATA_R_READ; + if (iocmd->u.request.flags & ATA_CMD_WRITE) + request->flags |= ATA_R_WRITE; + ata_queue_request(request); + if (!(request->flags & ATA_R_ATAPI)) { + iocmd->u.request.u.ata.command = + request->u.ata.command; + iocmd->u.request.u.ata.feature = + request->u.ata.feature; + iocmd->u.request.u.ata.lba = request->u.ata.lba; + iocmd->u.request.u.ata.count = request->u.ata.count; + } + iocmd->u.request.error = request->result; + if (iocmd->u.request.flags & ATA_CMD_READ) + error = copyout(buf, iocmd->u.request.data, + iocmd->u.request.count); + else + error = 0; + free(buf, M_ATA); + ata_free_request(request); + break; + } + } } + free(children, M_TEMP); } - - request->device = atadev; - - if (iocmd->u.request.flags & ATA_CMD_ATAPI) { - request->flags = ATA_R_ATAPI; - bcopy(iocmd->u.request.u.atapi.ccb, request->u.atapi.ccb, 16); - } - else { - request->u.ata.command = iocmd->u.request.u.ata.command; - request->u.ata.feature = iocmd->u.request.u.ata.feature; - request->u.ata.lba = iocmd->u.request.u.ata.lba; - request->u.ata.count = iocmd->u.request.u.ata.count; - } - - request->timeout = iocmd->u.request.timeout; - request->data = buf; - request->bytecount = iocmd->u.request.count; - request->transfersize = request->bytecount; - - if (iocmd->u.request.flags & ATA_CMD_CONTROL) - request->flags |= ATA_R_CONTROL; - if (iocmd->u.request.flags & ATA_CMD_READ) - request->flags |= ATA_R_READ; - if (iocmd->u.request.flags & ATA_CMD_WRITE) - request->flags |= ATA_R_WRITE; - - ata_queue_request(request); - - iocmd->u.request.u.ata.command = request->u.ata.command; - iocmd->u.request.u.ata.feature = request->u.ata.feature; - iocmd->u.request.u.ata.lba = request->u.ata.lba; - iocmd->u.request.u.ata.count = request->u.ata.count; - if (request->result) - iocmd->u.request.error = request->result; - else { - if (iocmd->u.request.flags & ATA_CMD_READ) - error = copyout(buf, - iocmd->u.request.data, iocmd->u.request.count); - else - error = 0; - } - free(buf, M_ATA); - ata_free_request(request); + else + error = ENXIO; break; case ATAREINIT: - if (!device || !(ch = device_get_softc(device))) { - error = ENXIO; - break; - } - error = ata_reinit(ch); - ata_start(ch); + error = ata_reinit(device); + ata_start(device); break; case ATAATTACH: - if (!device) { - error = ENXIO; - break; - } /* SOS should enable channel HW on controller XXX */ - error = ata_probe(device); - if (!error) - error = ata_attach(device); + error = ata_attach(device); break; case ATADETACH: - if (!device) { - error = ENXIO; - break; - } error = ata_detach(device); /* SOS should disable channel HW on controller XXX */ break; - -#ifdef DEV_ATARAID - case ATARAIDCREATE: - error = ata_raid_create(&iocmd->u.raid_setup); - break; - - case ATARAIDDELETE: - error = ata_raid_delete(iocmd->channel); - break; - - case ATARAIDSTATUS: - error = ata_raid_status(iocmd->channel, &iocmd->u.raid_status); - break; - - case ATARAIDADDSPARE: - error = ata_raid_addspare(iocmd->channel, iocmd->u.raid_spare.disk); - break; - - case ATARAIDREBUILD: - error = ata_raid_rebuild(iocmd->channel); - break; -#endif - } - PICKUP_GIANT(); - return error; -} - -/* - * device probe functions - */ -static int -ata_getparam(struct ata_device *atadev, u_int8_t command) -{ - struct ata_request *request; - int error = ENOMEM; - - if (!atadev->param) - atadev->param = malloc(sizeof(struct ata_params), M_ATA, M_NOWAIT); - if (atadev->param) { - request = ata_alloc_request(); - if (request) { - int retries = 2; - while (retries-- > 0) { - request->device = atadev; - request->timeout = 5; - request->retries = 0; - request->u.ata.command = command; - request->flags = (ATA_R_READ | ATA_R_IMMEDIATE); - request->data = (caddr_t)atadev->param; - request->bytecount = sizeof(struct ata_params); - request->donecount = 0; - request->transfersize = DEV_BSIZE; - ata_queue_request(request); - if (!(error = request->result)) - break; - } - ata_free_request(request); - } - if (!error && (isprint(atadev->param->model[0]) || - isprint(atadev->param->model[1]))) { - struct ata_params *atacap = atadev->param; -#if BYTE_ORDER == BIG_ENDIAN - int16_t *ptr; - - for (ptr = (int16_t *)atacap; - ptr < (int16_t *)atacap + sizeof(struct ata_params)/2; ptr++) { - *ptr = bswap16(*ptr); - } -#endif - 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) - ata_prtdev(atadev, - "pio=0x%02x wdma=0x%02x udma=0x%02x cable=%spin\n", - ata_pmode(atacap), ata_wmode(atacap), - ata_umode(atacap), - (atacap->hwres & ATA_CABLE_ID) ? "80":"40"); - } - else { - if (!error) - error = ENXIO; - if (atadev->param) { - free(atadev->param, M_ATA); - atadev->param = NULL; - } - } + default: + if (ata_ioctl_func) + error = ata_ioctl_func(iocmd); } return error; } static void -ata_identify_devices(struct ata_channel *ch) -{ - if (ch->devices & ATA_ATA_SLAVE) { - if (ata_getparam(&ch->device[SLAVE], ATA_ATA_IDENTIFY)) - ch->devices &= ~ATA_ATA_SLAVE; -#ifdef DEV_ATADISK - else - ch->device[SLAVE].attach = ad_attach; -#endif - } - if (ch->devices & ATA_ATAPI_SLAVE) { - if (ata_getparam(&ch->device[SLAVE], ATA_ATAPI_IDENTIFY)) - ch->devices &= ~ATA_ATAPI_SLAVE; - else { - ata_controlcmd(&ch->device[SLAVE], ATA_ATAPI_RESET, 0, 0, 0); - switch (ch->device[SLAVE].param->config & ATA_ATAPI_TYPE_MASK) { -#ifdef DEV_ATAPICD - case ATA_ATAPI_TYPE_CDROM: - ch->device[SLAVE].attach = acd_attach; - break; -#endif -#ifdef DEV_ATAPIFD - case ATA_ATAPI_TYPE_DIRECT: - ch->device[SLAVE].attach = afd_attach; - break; -#endif -#ifdef DEV_ATAPIST - case ATA_ATAPI_TYPE_TAPE: - ch->device[SLAVE].attach = ast_attach; - break; -#endif - } - } - } - if (ch->devices & ATA_ATA_MASTER) { - if (ata_getparam(&ch->device[MASTER], ATA_ATA_IDENTIFY)) - ch->devices &= ~ATA_ATA_MASTER; -#ifdef DEV_ATADISK - else - ch->device[MASTER].attach = ad_attach; -#endif - } - if (ch->devices & ATA_ATAPI_MASTER) { - if (ata_getparam(&ch->device[MASTER], ATA_ATAPI_IDENTIFY)) - ch->devices &= ~ATA_ATAPI_MASTER; - else { - ata_controlcmd(&ch->device[MASTER], ATA_ATAPI_RESET, 0, 0, 0); - switch (ch->device[MASTER].param->config & ATA_ATAPI_TYPE_MASK) { -#ifdef DEV_ATAPICD - case ATA_ATAPI_TYPE_CDROM: - ch->device[MASTER].attach = acd_attach; - break; -#endif -#ifdef DEV_ATAPIFD - case ATA_ATAPI_TYPE_DIRECT: - ch->device[MASTER].attach = afd_attach; - break; -#endif -#ifdef DEV_ATAPIST - case ATA_ATAPI_TYPE_TAPE: - ch->device[MASTER].attach = ast_attach; - break; -#endif - } - } - } - - /* setup basic transfer mode by setting PIO mode and DMA if supported */ - if (ch->device[MASTER].param) { - ch->device[MASTER].setmode(&ch->device[MASTER], ATA_PIO_MAX); - if ((((ch->devices & ATA_ATAPI_MASTER) && atapi_dma && - (ch->device[MASTER].param->config&ATA_DRQ_MASK) != ATA_DRQ_INTR && - ata_umode(ch->device[MASTER].param) >= ATA_UDMA2) || - ((ch->devices & ATA_ATA_MASTER) && ata_dma)) && ch->dma) - ch->device[MASTER].setmode(&ch->device[MASTER], ATA_DMA_MAX); - - } - if (ch->device[SLAVE].param) { - ch->device[SLAVE].setmode(&ch->device[SLAVE], ATA_PIO_MAX); - if ((((ch->devices & ATA_ATAPI_SLAVE) && atapi_dma && - (ch->device[SLAVE].param->config&ATA_DRQ_MASK) != ATA_DRQ_INTR && - ata_umode(ch->device[SLAVE].param) >= ATA_UDMA2) || - ((ch->devices & ATA_ATA_SLAVE) && ata_dma)) && ch->dma) - ch->device[SLAVE].setmode(&ch->device[SLAVE], ATA_DMA_MAX); - } -} - -static void ata_boot_attach(void) { struct ata_channel *ch; int ctlr; + /* release the hook that got us here, only needed during boot */ if (ata_delayed_attach) { config_intrhook_disestablish(ata_delayed_attach); free(ata_delayed_attach, M_TEMP); ata_delayed_attach = NULL; } - /* - * run through all ata devices and look for real ATA & ATAPI devices - * using the hints we found in the early probe, this avoids some of - * the delays probing of non-exsistent devices can cause. - */ - for (ctlr=0; ctlr<devclass_get_maxunit(ata_devclass); ctlr++) { - if (!(ch = devclass_get_softc(ata_devclass, ctlr))) - continue; - ata_identify_devices(ch); - if (ch->device[MASTER].attach) - ch->device[MASTER].attach(&ch->device[MASTER]); - if (ch->device[SLAVE].attach) - ch->device[SLAVE].attach(&ch->device[SLAVE]); -#ifdef DEV_ATAPICAM - atapi_cam_attach_bus(ch); -#endif + /* 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))) { + bus_generic_probe(ch->dev); + bus_generic_attach(ch->dev); + } } -#ifdef DEV_ATARAID - ata_raid_attach(); -#endif } /* * misc support functions */ -void -ata_udelay(int interval) -{ - if (interval < (1000000/hz) || ata_delayed_attach || ata_resuming) - DELAY(interval); - else - tsleep(&interval, PRIBIO, "ataslp", interval/(1000000/hz)); -} - -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); -} - -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; -} - -static void -bpack(int8_t *src, int8_t *dst, int len) +device_t +ata_add_child(driver_t *driver, device_t parent, struct ata_device *atadev, + const char *name, int unit) { - 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; + struct ata_channel *ch = device_get_softc(parent); + device_t child; + + if ((child = device_add_child(parent, name, unit))) { + char buffer[64]; + + device_set_driver(child, driver); + device_set_softc(child, atadev); + sprintf(buffer, "%.40s/%.8s", + atadev->param.model, atadev->param.revision); + device_set_desc_copy(child, buffer); + device_quiet(child); + atadev->dev = child; + atadev->max_iosize = DEV_BSIZE; + atadev->mode = ATA_PIO_MAX; + if ((atadev->param.config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) { + if (atapi_dma && ch->dma && + (atadev->param.config & ATA_DRQ_MASK) != ATA_DRQ_INTR && + ata_umode(&atadev->param) >= ATA_UDMA2) + atadev->mode = ATA_DMA_MAX; } - if (src[i] == ' ') { - blank = 1; - if (i == 0) - continue; + else { + if (ata_dma && ch->dma) + atadev->mode = ATA_DMA_MAX; } - dst[j++] = src[i]; } - if (j < len) - dst[j] = 0x00; + return child; } -int -ata_printf(struct ata_channel *ch, int device, const char * fmt, ...) +void +ata_identify(driver_t *driver, device_t parent, int type, const char *name) { - va_list ap; - int ret; + struct ata_channel *ch = device_get_softc(parent); + struct ata_device *master, *slave; + int master_res = EIO, slave_res = EIO, master_unit = -1, slave_unit = -1; - if (device == -1) - ret = printf("ata%d: ", device_get_unit(ch->dev)); - else { - if (ch->device[ATA_DEV(device)].name) - ret = printf("%s: ", ch->device[ATA_DEV(device)].name); - else - ret = printf("ata%d-%s: ", device_get_unit(ch->dev), - (device == ATA_MASTER) ? "master" : "slave"); + if (!(master = malloc(sizeof(struct ata_device), + M_ATA, M_NOWAIT | M_ZERO))) { + device_printf(parent, "out of memory\n"); + return; } - va_start(ap, fmt); - ret += vprintf(fmt, ap); - va_end(ap); - return ret; -} - -int -ata_prtdev(struct ata_device *atadev, const char * fmt, ...) -{ - va_list ap; - int ret; - - if (atadev->name) - ret = printf("%s: ", atadev->name); - else - ret = printf("ata%d-%s: ", device_get_unit(atadev->channel->dev), - (atadev->unit == ATA_MASTER) ? "master" : "slave"); - va_start(ap, fmt); - ret += vprintf(fmt, ap); - va_end(ap); - return ret; -} - -void -ata_set_name(struct ata_device *atadev, char *name, int lun) -{ - atadev->name = malloc(strlen(name) + 4, M_ATA, M_NOWAIT); - if (atadev->name) - sprintf(atadev->name, "%s%d", name, lun); -} + master->unit = ATA_MASTER; + if (!(slave = malloc(sizeof(struct ata_device), + M_ATA, M_NOWAIT | M_ZERO))) { + free(master, M_ATA); + device_printf(parent, "out of memory\n"); + return; + } + slave->unit = ATA_SLAVE; -void -ata_free_name(struct ata_device *atadev) -{ - if (atadev->name) - free(atadev->name, M_ATA); - atadev->name = NULL; -} + /* wait for the channel to be IDLE then grab it before touching HW */ + while (ATA_LOCKING(device_get_parent(parent),parent,ATA_LF_LOCK)!=ch->unit) + tsleep(ch, PRIBIO, "ataidnt2", 1); + while (1) { + 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, "ataidnt1", 1); + } -int -ata_get_lun(u_int32_t *map) -{ - int lun = ffs(~*map) - 1; + if (type < 0) { + if (ch->devices & ATA_ATA_SLAVE) + slave_res = ata_getparam(parent, slave, ATA_ATA_IDENTIFY); + if (ch->devices & ATA_ATA_MASTER) + master_res = ata_getparam(parent, master, ATA_ATA_IDENTIFY); +#ifdef ATA_STATIC_ID + master_unit = (device_get_unit(parent) << 1); + slave_unit = (device_get_unit(parent) << 1) + 1; +#endif + } + else { + if (ch->devices & ATA_ATAPI_SLAVE) + slave_res = ata_getparam(parent, slave, ATA_ATAPI_IDENTIFY); + if (ch->devices & ATA_ATAPI_MASTER) + master_res = ata_getparam(parent, master, ATA_ATAPI_IDENTIFY); + } - *map |= (1 << lun); - return lun; -} + if (master_res || + !(type < 0 || (master->param.config & ATA_ATAPI_TYPE_MASK) == type) || + !ata_add_child(driver, parent, master, name, master_unit)) + free(master, M_ATA); + + if (slave_res || + !(type < 0 || (slave->param.config & ATA_ATAPI_TYPE_MASK) == type) || + !ata_add_child(driver, parent, slave, name, slave_unit)) + free(slave, M_ATA); -int -ata_test_lun(u_int32_t *map, int lun) -{ - return (*map & (1 << lun)); + mtx_lock(&ch->state_mtx); + ch->state = ATA_IDLE; + mtx_unlock(&ch->state_mtx); + ATA_LOCKING(device_get_parent(parent), parent, ATA_LF_UNLOCK); } void -ata_free_lun(u_int32_t *map, int lun) +ata_udelay(int interval) { - *map &= ~(1 << lun); + /* for now just use DELAY, the timer/sleep subsytems are not there yet */ + if (1 || interval < (1000000/hz) || ata_delayed_attach) + DELAY(interval); + else + tsleep(&interval, PRIBIO, "ataslp", interval/(1000000/hz)); } char * ata_mode2str(int mode) { switch (mode) { - case ATA_PIO: return "BIOSPIO"; 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_DMA: return "BIOSDMA"; case ATA_WDMA0: return "WDMA0"; case ATA_WDMA1: return "WDMA1"; case ATA_WDMA2: return "WDMA2"; @@ -992,7 +698,11 @@ ata_mode2str(int mode) case ATA_UDMA5: return "UDMA100"; case ATA_UDMA6: return "UDMA133"; case ATA_SA150: return "SATA150"; - default: return "???"; + default: + if (mode & ATA_DMA_MASK) + return "BIOSDMA"; + else + return "BIOSPIO"; } } @@ -1060,44 +770,67 @@ ata_limit_mode(struct ata_device *atadev, int mode, int maxmode) 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_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_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)); + if (mode > ata_pmode(&atadev->param)) + return min(mode, ata_pmode(&atadev->param)); return mode; } -static void -ata_init(void) +/* + * module handeling + */ +static int +ata_module_event_handler(module_t mod, int what, void *arg) { - /* register controlling device */ - make_dev(&ata_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0600, "ata"); - - /* 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; - } - 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); + static struct cdev *atacdev; + + switch (what) { + case MOD_LOAD: + /* 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); + } + } + return 0; + + case MOD_UNLOAD: + /* deregister controlling device */ + destroy_dev(atacdev); + return 0; + + default: + return EOPNOTSUPP; } +} - /* register handler to flush write caches on shutdown */ - if ((EVENTHANDLER_REGISTER(shutdown_post_sync, ata_shutdown, - NULL, SHUTDOWN_PRI_DEFAULT)) == NULL) - printf("ata: shutdown event registration failed!\n"); +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); +static void +ata_init(void) +{ /* init our UMA zone for ATA requests */ ata_zone = uma_zcreate("ata_request", sizeof(struct ata_request), NULL, NULL, NULL, NULL, 0, 0); } + SYSINIT(atadev, SI_SUB_DRIVERS, SI_ORDER_SECOND, ata_init, NULL) diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index 6a9d099..72608e3 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,220 +29,235 @@ */ /* ATA register defines */ -#define ATA_DATA 0x00 /* data register */ - -#define ATA_ERROR 0x01 /* (R) error register */ -#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_MASK 0x0f /* error mask */ -#define ATA_SK_MASK 0xf0 /* sense key mask */ -#define ATA_SK_NO_SENSE 0x00 /* no specific sense key info */ -#define ATA_SK_RECOVERED_ERROR 0x10 /* command OK, data recovered */ -#define ATA_SK_NOT_READY 0x20 /* no access to drive */ -#define ATA_SK_MEDIUM_ERROR 0x30 /* non-recovered data error */ -#define ATA_SK_HARDWARE_ERROR 0x40 /* non-recoverable HW failure */ -#define ATA_SK_ILLEGAL_REQUEST 0x50 /* invalid command param(s) */ -#define ATA_SK_UNIT_ATTENTION 0x60 /* media changed */ -#define ATA_SK_DATA_PROTECT 0x70 /* write protect */ -#define ATA_SK_BLANK_CHECK 0x80 /* blank check */ -#define ATA_SK_VENDOR_SPECIFIC 0x90 /* vendor specific skey */ -#define ATA_SK_COPY_ABORTED 0xa0 /* copy aborted */ -#define ATA_SK_ABORTED_COMMAND 0xb0 /* command aborted, try again */ -#define ATA_SK_EQUAL 0xc0 /* equal */ -#define ATA_SK_VOLUME_OVERFLOW 0xd0 /* volume overflow */ -#define ATA_SK_MISCOMPARE 0xe0 /* data dont match the medium */ -#define ATA_SK_RESERVED 0xf0 - -#define ATA_FEATURE 0x01 /* (W) feature register */ -#define ATA_F_DMA 0x01 /* enable DMA */ -#define ATA_F_OVL 0x02 /* enable overlap */ - -#define ATA_COUNT 0x02 /* (W) sector count */ -#define ATA_IREASON 0x02 /* (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_SECTOR 0x03 /* sector # */ -#define ATA_CYL_LSB 0x04 /* cylinder# LSB */ -#define ATA_CYL_MSB 0x05 /* cylinder# MSB */ -#define ATA_DRIVE 0x06 /* Sector/Drive/Head register */ -#define ATA_D_LBA 0x40 /* use LBA addressing */ -#define ATA_D_IBM 0xa0 /* 512 byte sectors, ECC */ - -#define ATA_CMD 0x07 /* command register */ - -#define ATA_STATUS 0x07 /* status register */ -#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_ALTSTAT 0x08 /* alternate status register */ -#define ATA_ALTOFFSET 0x206 /* alternate registers offset */ -#define ATA_PCCARD_ALTOFFSET 0x0e /* do for PCCARD devices */ -#define ATA_PC98_ALTOFFSET 0x10c /* do for PC98 devices */ -#define ATA_A_IDS 0x02 /* disable interrupts */ -#define ATA_A_RESET 0x04 /* RESET controller */ -#define ATA_A_4BIT 0x08 /* 4 head bits */ +#define ATA_DATA 0x00 /* data register */ + +#define ATA_ERROR 0x01 /* (R) error register */ +#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_MASK 0x0f /* error mask */ +#define ATA_SK_MASK 0xf0 /* sense key mask */ +#define ATA_SK_NO_SENSE 0x00 /* no specific sense key info */ +#define ATA_SK_RECOVERED_ERROR 0x10 /* command OK, data recovered */ +#define ATA_SK_NOT_READY 0x20 /* no access to drive */ +#define ATA_SK_MEDIUM_ERROR 0x30 /* non-recovered data error */ +#define ATA_SK_HARDWARE_ERROR 0x40 /* non-recoverable HW failure */ +#define ATA_SK_ILLEGAL_REQUEST 0x50 /* invalid command param(s) */ +#define ATA_SK_UNIT_ATTENTION 0x60 /* media changed */ +#define ATA_SK_DATA_PROTECT 0x70 /* write protect */ +#define ATA_SK_BLANK_CHECK 0x80 /* blank check */ +#define ATA_SK_VENDOR_SPECIFIC 0x90 /* vendor specific skey */ +#define ATA_SK_COPY_ABORTED 0xa0 /* copy aborted */ +#define ATA_SK_ABORTED_COMMAND 0xb0 /* command aborted, try again */ +#define ATA_SK_EQUAL 0xc0 /* equal */ +#define ATA_SK_VOLUME_OVERFLOW 0xd0 /* volume overflow */ +#define ATA_SK_MISCOMPARE 0xe0 /* data dont match the medium */ +#define ATA_SK_RESERVED 0xf0 + +#define ATA_FEATURE 0x01 /* (W) feature register */ +#define ATA_F_DMA 0x01 /* enable DMA */ +#define ATA_F_OVL 0x02 /* enable overlap */ + +#define ATA_COUNT 0x02 /* (W) sector count */ +#define ATA_IREASON 0x02 /* (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_SECTOR 0x03 /* sector # */ +#define ATA_CYL_LSB 0x04 /* cylinder# LSB */ +#define ATA_CYL_MSB 0x05 /* cylinder# MSB */ +#define ATA_DRIVE 0x06 /* Sector/Drive/Head register */ +#define ATA_D_LBA 0x40 /* use LBA addressing */ +#define ATA_D_IBM 0xa0 /* 512 byte sectors, ECC */ + +#define ATA_CMD 0x07 /* command register */ + +#define ATA_STATUS 0x07 /* status register */ +#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_ALTSTAT 0x08 /* alternate status register */ +#define ATA_ALTOFFSET 0x206 /* alternate registers offset */ +#define ATA_PCCARD_ALTOFFSET 0x0e /* do for PCCARD devices */ +#define ATA_PC98_ALTOFFSET 0x10c /* do for PC98 devices */ +#define ATA_A_IDS 0x02 /* disable interrupts */ +#define ATA_A_RESET 0x04 /* RESET controller */ +#define ATA_A_4BIT 0x08 /* 4 head bits */ +#define ATA_A_HOB 0x80 /* High Order Byte enable */ /* ATAPI misc defines */ -#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 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 /* 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_ALTIOSIZE 0x01 -#define ATA_BMIOSIZE 0x08 -#define ATA_PC98_BANKIOSIZE 0x01 -#define ATA_IOADDR_RID 0 -#define ATA_ALTADDR_RID 1 -#define ATA_BMADDR_RID 0x20 -#define ATA_PC98_ALTADDR_RID 8 -#define ATA_PC98_BANKADDR_RID 9 - -#define ATA_IRQ_RID 0 -#define ATA_DEV(device) ((device == ATA_MASTER) ? 0 : 1) +#define ATA_PRIMARY 0x1f0 +#define ATA_SECONDARY 0x170 +#define ATA_PC98_BANK 0x432 +#define ATA_IOSIZE 0x08 +#define ATA_PC98_IOSIZE 0x10 +#define ATA_ALTIOSIZE 0x01 +#define ATA_BMIOSIZE 0x08 +#define ATA_PC98_BANKIOSIZE 0x01 +#define ATA_IOADDR_RID 0 +#define ATA_ALTADDR_RID 1 +#define ATA_BMADDR_RID 0x20 +#define ATA_PC98_ALTADDR_RID 8 +#define ATA_PC98_BANKADDR_RID 9 + +#define ATA_IRQ_RID 0 +#define ATA_DEV(device) ((device == ATA_MASTER) ? 0 : 1) /* busmaster DMA related defines */ -#define ATA_DMA_ENTRIES 256 -#define ATA_DMA_EOT 0x80000000 +#define ATA_DMA_ENTRIES 256 +#define ATA_DMA_EOT 0x80000000 -#define ATA_BMCMD_PORT 0x09 -#define ATA_BMCMD_START_STOP 0x01 -#define ATA_BMCMD_WRITE_READ 0x08 +#define ATA_BMCMD_PORT 0x09 +#define ATA_BMCMD_START_STOP 0x01 +#define ATA_BMCMD_WRITE_READ 0x08 -#define ATA_BMDEVSPEC_0 0x0a -#define ATA_BMSTAT_PORT 0x0b -#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_0 0x0a +#define ATA_BMSTAT_PORT 0x0b +#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 0x0c -#define ATA_BMDTP_PORT 0x0d +#define ATA_BMDEVSPEC_1 0x0c +#define ATA_BMDTP_PORT 0x0d -#define ATA_IDX_ADDR 0x0e -#define ATA_IDX_DATA 0x0f -#define ATA_MAX_RES 0x10 +#define ATA_IDX_ADDR 0x0e +#define ATA_IDX_DATA 0x0f +#define ATA_MAX_RES 0x10 -#define ATA_INTR_FLAGS (INTR_MPSAFE|INTR_TYPE_BIO|INTR_ENTROPY) -#define ATA_OP_CONTINUES 0 -#define ATA_OP_FINISHED 1 +#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 268435455 +#define ATA_MAX_28BIT_LBA 268435455 /* ATAPI request sense structure */ struct atapi_sense { - u_int8_t error_code :7; /* current or deferred errors */ - u_int8_t valid :1; /* follows ATAPI spec */ - u_int8_t segment; /* Segment number */ - u_int8_t sense_key :4; /* sense key */ - u_int8_t reserved2_4 :1; /* reserved */ - u_int8_t ili :1; /* incorrect length indicator */ - u_int8_t eom :1; /* end of medium */ - u_int8_t filemark :1; /* filemark */ - u_int32_t cmd_info __packed; /* cmd information */ - u_int8_t sense_length; /* additional sense len (n-7) */ - u_int32_t cmd_specific_info __packed; /* additional cmd spec info */ - u_int8_t asc; /* additional sense code */ - u_int8_t ascq; /* additional sense code qual */ - u_int8_t replaceable_unit_code; /* replaceable unit code */ - u_int8_t sk_specific :7; /* sense key specific */ - u_int8_t sksv :1; /* sense key specific info OK */ - u_int8_t sk_specific1; /* sense key specific */ - u_int8_t sk_specific2; /* sense key specific */ + u_int8_t error_code :7; /* current or deferred errors */ + u_int8_t valid :1; /* follows ATAPI spec */ + u_int8_t segment; /* Segment number */ + u_int8_t sense_key :4; /* sense key */ + u_int8_t reserved2_4 :1; /* reserved */ + u_int8_t ili :1; /* incorrect length indicator */ + u_int8_t eom :1; /* end of medium */ + u_int8_t filemark :1; /* filemark */ + u_int32_t cmd_info __packed; /* cmd information */ + u_int8_t sense_length; /* additional sense len (n-7) */ + u_int32_t cmd_specific_info __packed; /* additional cmd spec info */ + u_int8_t asc; /* additional sense code */ + u_int8_t ascq; /* additional sense code qual */ + u_int8_t replaceable_unit_code; /* replaceable unit code */ + u_int8_t sk_specific :7; /* sense key specific */ + u_int8_t sksv :1; /* sense key specific info OK */ + u_int8_t sk_specific1; /* sense key specific */ + u_int8_t sk_specific2; /* sense key specific */ }; -struct ata_request { - struct ata_device *device; /* ptr to device softc */ - void *driver; /* driver specific */ +/* structure used for composite atomic operations */ +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[32]; /* size must match maps above */ + caddr_t data_1; + caddr_t data_2; +}; +/* structure used to queue an ATA/ATAPI request */ +struct ata_request { + device_t dev; /* device handle */ union { struct { - u_int8_t command; /* command reg */ - u_int8_t feature; /* feature reg */ - u_int16_t count; /* count reg */ - u_int64_t lba; /* lba reg */ + u_int8_t command; /* command reg */ + u_int8_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_data; /* ATAPI request sense data */ - u_int8_t sense_key; /* ATAPI request sense key */ - u_int8_t sense_cmd; /* ATAPI saved command */ + u_int8_t ccb[16]; /* ATAPI command block */ + struct atapi_sense sense_data; /* ATAPI request sense data */ + u_int8_t sense_key; /* ATAPI request sense key */ + u_int8_t sense_cmd; /* ATAPI saved command */ } atapi; } u; - - u_int8_t status; /* ATA status */ - u_int8_t error; /* ATA error */ - u_int8_t dmastat; /* DMA status */ - - u_int32_t bytecount; /* bytes to transfer */ - u_int32_t transfersize; /* bytes pr transfer */ - u_int32_t donecount; /* bytes transferred */ - caddr_t data; /* pointer to data buf */ - int flags; -#define ATA_R_CONTROL 0x0001 -#define ATA_R_READ 0x0002 -#define ATA_R_WRITE 0x0004 -#define ATA_R_DMA 0x0008 - -#define ATA_R_ATAPI 0x0010 -#define ATA_R_QUIET 0x0020 -#define ATA_R_INTR_SEEN 0x0040 -#define ATA_R_TIMEOUT 0x0080 - -#define ATA_R_ORDERED 0x0100 -#define ATA_R_IMMEDIATE 0x0200 -#define ATA_R_REQUEUE 0x0400 - -#define ATA_R_DEBUG 0x1000 - - 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 */ - int result; /* result error code */ - struct task task; /* task management */ - struct bio *bio; /* bio for this request */ - TAILQ_ENTRY(ata_request) sequence; /* sequence management */ - TAILQ_ENTRY(ata_request) chain; /* list management */ + u_int32_t bytecount; /* bytes to transfer */ + u_int32_t transfersize; /* bytes pr transfer */ + caddr_t data; /* pointer to data buf */ + int flags; +#define ATA_R_CONTROL 0x00000001 +#define ATA_R_READ 0x00000002 +#define ATA_R_WRITE 0x00000004 +#define ATA_R_DMA 0x00000008 + +#define ATA_R_ATAPI 0x00000010 +#define ATA_R_QUIET 0x00000020 +#define ATA_R_INTR_SEEN 0x00000040 +#define ATA_R_TIMEOUT 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_DEBUG 0x10000000 + + u_int8_t status; /* ATA status */ + u_int8_t error; /* ATA error */ + u_int8_t dmastat; /* DMA status */ + 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 */ }; /* define this for debugging request processing */ -#if 0 +#if 1 #define ATA_DEBUG_RQ(request, string) \ { \ if (request->flags & ATA_R_DEBUG) \ - ata_prtdev(request->device, "req=%p %s " string "\n", \ - request, ata_cmd2str(request)); \ + device_printf(request->dev, "req=%p %s " string "\n", \ + request, ata_cmd2str(request)); \ } #else #define ATA_DEBUG_RQ(request, string) @@ -251,27 +266,19 @@ struct ata_request { /* structure describing an ATA/ATAPI device */ struct ata_device { - struct ata_channel *channel; - int unit; /* unit number */ -#define ATA_MASTER 0x00 -#define ATA_SLAVE 0x10 - - char *name; /* device name */ - struct ata_params *param; /* ata param structure */ - void *softc; /* ptr to softc for device */ - void (*attach)(struct ata_device *atadev); - void (*detach)(struct ata_device *atadev); - void (*config)(struct ata_device *atadev); - void (*start)(struct ata_device *atadev); - int flags; -#define ATA_D_USE_CHS 0x0001 -#define ATA_D_DETACHING 0x0002 -#define ATA_D_MEDIA_CHANGED 0x0004 -#define ATA_D_ENC_PRESENT 0x0008 - - int cmd; /* last cmd executed */ - int mode; /* transfermode */ - void (*setmode)(struct ata_device *atadev, int mode); + device_t dev; /* device handle */ + int unit; /* physical unit */ +#define ATA_MASTER 0x00 +#define ATA_SLAVE 0x10 + + struct ata_params param; /* ata param structure */ + int mode; /* current transfermode */ + u_int32_t max_iosize; /* max IO size */ + int cmd; /* last cmd executed */ + 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 */ @@ -286,28 +293,29 @@ struct ata_dmasetprd_args { int error; }; +struct ata_channel {}; /* structure holding DMA related information */ struct ata_dma { - bus_dma_tag_t dmatag; /* parent DMA tag */ - bus_dma_tag_t cdmatag; /* control DMA tag */ - bus_dmamap_t cdmamap; /* control DMA map */ - bus_dma_tag_t ddmatag; /* data DMA tag */ - bus_dmamap_t ddmamap; /* data DMA map */ - void *dmatab; /* DMA transfer table */ - bus_addr_t mdmatab; /* bus address of dmatab */ - bus_dma_tag_t wdmatag; /* workspace DMA tag */ - bus_dmamap_t wdmamap; /* workspace DMA map */ - u_int8_t *workspace; /* workspace */ - bus_addr_t wdmatab; /* bus address of dmatab */ - - u_int32_t alignment; /* DMA engine alignment */ - u_int32_t boundary; /* DMA engine boundary */ - u_int32_t max_iosize; /* DMA engine max IO size */ - u_int32_t cur_iosize; /* DMA engine current IO size */ - int flags; -#define ATA_DMA_READ 0x01 /* transaction is a read */ -#define ATA_DMA_LOADED 0x02 /* DMA tables etc loaded */ -#define ATA_DMA_ACTIVE 0x04 /* DMA transfer in progress */ + bus_dma_tag_t dmatag; /* parent DMA tag */ + 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 */ + 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 */ + + u_int32_t alignment; /* DMA engine alignment */ + u_int32_t boundary; /* DMA engine boundary */ + u_int32_t max_iosize; /* DMA engine max IO size */ + u_int32_t cur_iosize; /* DMA engine current IO size */ + int flags; +#define ATA_DMA_READ 0x01 /* transaction is a read */ +#define ATA_DMA_LOADED 0x02 /* DMA tables etc loaded */ +#define ATA_DMA_ACTIVE 0x04 /* DMA transfer in progress */ void (*alloc)(struct ata_channel *ch); void (*free)(struct ata_channel *ch); @@ -322,70 +330,59 @@ struct ata_dma { struct ata_lowlevel { int (*begin_transaction)(struct ata_request *request); int (*end_transaction)(struct ata_request *request); - void (*interrupt)(void *channel); void (*reset)(struct ata_channel *ch); int (*command)(struct ata_device *atadev, u_int8_t command, u_int64_t lba, u_int16_t count, u_int16_t feature); }; /* structure holding resources for an ATA channel */ struct ata_resource { - struct resource *res; - int offset; + struct resource *res; + int offset; }; /* structure describing an ATA channel */ struct ata_channel { - struct device *dev; /* device handle */ - int unit; /* channel number */ - 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_48BIT_ACTIVE 0x10 -#define ATA_IMMEDIATE_MODE 0x20 -#define ATA_HWGONE 0x40 - - struct ata_device device[2]; /* devices on this channel */ -#define MASTER 0x00 -#define SLAVE 0x01 - - int devices; /* what is present */ -#define ATA_ATA_MASTER 0x01 -#define ATA_ATA_SLAVE 0x02 -#define ATA_ATAPI_MASTER 0x04 -#define ATA_ATAPI_SLAVE 0x08 - - struct mtx state_mtx; /* state lock */ - int state; /* ATA channel state */ -#define ATA_IDLE 0x0000 -#define ATA_ACTIVE 0x0001 -#define ATA_INTERRUPT 0x0002 -#define ATA_TIMEOUT 0x0004 - - void (*reset)(struct ata_channel *); - int (*locking)(struct ata_channel *, int); -#define ATA_LF_LOCK 0x0001 -#define ATA_LF_UNLOCK 0x0002 -#define ATA_LF_WHICH 0x0004 - - struct mtx queue_mtx; /* queue lock */ - TAILQ_HEAD(, ata_request) ata_queue; /* head of ATA queue */ - struct ata_request *running; /* currently running request */ + device_t dev; /* device handle */ + int unit; /* physical channel */ + 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_48BIT_ACTIVE 0x08 + + int devices; /* what is present */ +#define ATA_ATA_MASTER 0x01 +#define ATA_ATA_SLAVE 0x02 +#define ATA_ATAPI_MASTER 0x04 +#define ATA_ATAPI_SLAVE 0x08 + + struct mtx state_mtx; /* state lock */ + int state; /* ATA channel state */ +#define ATA_IDLE 0x0000 +#define ATA_ACTIVE 0x0001 +#define ATA_STALL_QUEUE 0x0002 +#define ATA_TIMEOUT 0x0004 + + 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 */ }; /* 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 +#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_ioctl_func)(struct ata_cmd *iocmd); extern devclass_t ata_devclass; extern int ata_wc; @@ -394,16 +391,11 @@ extern int ata_wc; 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_identify(driver_t *driver, device_t parent, int type, const char *name); void ata_udelay(int interval); -int ata_printf(struct ata_channel *ch, int device, const char *fmt, ...) __printflike(3, 4); -int ata_prtdev(struct ata_device *atadev, const char *fmt, ...) __printflike(2, 3); -void ata_set_name(struct ata_device *atadev, char *name, int lun); -void ata_free_name(struct ata_device *atadev); -int ata_get_lun(u_int32_t *map); -int ata_test_lun(u_int32_t *map, int lun); -void ata_free_lun(u_int32_t *map, int lun); char *ata_mode2str(int mode); int ata_pmode(struct ata_params *ap); int ata_wmode(struct ata_params *ap); @@ -411,33 +403,28 @@ int ata_umode(struct ata_params *ap); int ata_limit_mode(struct ata_device *atadev, int mode, int maxmode); /* ata-queue.c: */ -int ata_reinit(struct ata_channel *ch); -void ata_start(struct ata_channel *ch); int ata_controlcmd(struct ata_device *atadev, u_int8_t command, u_int16_t feature, u_int64_t lba, u_int16_t count); int ata_atapicmd(struct ata_device *atadev, 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_catch_inflight(struct ata_channel *ch); -void ata_fail_requests(struct ata_channel *ch, struct ata_device *device); +void ata_fail_requests(struct ata_channel *ch, device_t dev); char *ata_cmd2str(struct ata_request *request); /* ata-lowlevel.c: */ void ata_generic_hw(struct ata_channel *ch); int ata_generic_command(struct ata_device *atadev, u_int8_t command, u_int64_t lba, u_int16_t count, u_int16_t feature); - -/* subdrivers */ -void ad_attach(struct ata_device *atadev); -void acd_attach(struct ata_device *atadev); -void afd_attach(struct ata_device *atadev); -void ast_attach(struct ata_device *atadev); -void atapi_cam_attach_bus(struct ata_channel *ch); -void atapi_cam_detach_bus(struct ata_channel *ch); -void atapi_cam_reinit_bus(struct ata_channel *ch); +int ata_getparam(device_t parent, struct ata_device *atadev, u_int8_t command); /* macros for alloc/free of ata_requests */ extern uma_zone_t ata_zone; #define ata_alloc_request() uma_zalloc(ata_zone, M_NOWAIT | M_ZERO) #define ata_free_request(request) uma_zfree(ata_zone, request) +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) \ diff --git a/sys/dev/ata/ata-card.c b/sys/dev/ata/ata-card.c index 0a6c8c6..a8aa985 100644 --- a/sys/dev/ata/ata-card.c +++ b/sys/dev/ata/ata-card.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -61,8 +61,6 @@ static const struct pccard_product ata_pccard_products[] = { {NULL} }; -MALLOC_DECLARE(M_ATA); - static int ata_pccard_match(device_t dev) { @@ -89,18 +87,6 @@ ata_pccard_match(device_t dev) } static int -ata_pccard_locknoop(struct ata_channel *ch, int type) -{ - return ch->unit; -} - -static void -ata_pccard_setmode(struct ata_device *atadev, int mode) -{ - atadev->mode = ata_limit_mode(atadev, mode, ATA_PIO_MAX); -} - -static int ata_pccard_probe(device_t dev) { struct ata_channel *ch = device_get_softc(dev); @@ -145,8 +131,6 @@ ata_pccard_probe(device_t dev) /* initialize softc for this channel */ ch->unit = 0; ch->flags |= (ATA_USE_16BIT | ATA_NO_SLAVE); - ch->locking = ata_pccard_locknoop; - ch->device[MASTER].setmode = ata_pccard_setmode; ata_generic_hw(ch); return ata_probe(dev); } @@ -157,8 +141,6 @@ ata_pccard_detach(device_t dev) struct ata_channel *ch = device_get_softc(dev); int i; - free(ch->device[MASTER].param, M_ATA); - ch->device[MASTER].param = NULL; ata_detach(dev); if (ch->r_io[ATA_ALTSTAT].res != ch->r_io[ATA_DATA].res) bus_release_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID, @@ -172,14 +154,14 @@ ata_pccard_detach(device_t dev) static device_method_t ata_pccard_methods[] = { /* device interface */ - DEVMETHOD(device_probe, pccard_compat_probe), - DEVMETHOD(device_attach, pccard_compat_attach), - DEVMETHOD(device_detach, ata_pccard_detach), - - /* Card interface */ - DEVMETHOD(card_compat_match, ata_pccard_match), - DEVMETHOD(card_compat_probe, ata_pccard_probe), - DEVMETHOD(card_compat_attach, ata_attach), + DEVMETHOD(device_probe, pccard_compat_probe), + DEVMETHOD(device_attach, pccard_compat_attach), + DEVMETHOD(device_detach, ata_pccard_detach), + + /* card interface */ + DEVMETHOD(card_compat_match, ata_pccard_match), + DEVMETHOD(card_compat_probe, ata_pccard_probe), + DEVMETHOD(card_compat_attach, ata_attach), { 0, 0 } }; @@ -190,3 +172,4 @@ static driver_t ata_pccard_driver = { }; DRIVER_MODULE(ata, pccard, ata_pccard_driver, ata_devclass, 0, 0); +MODULE_DEPEND(ata, ata, 1, 1, 1); diff --git a/sys/dev/ata/ata-cbus.c b/sys/dev/ata/ata-cbus.c index 5c39261..46b009c 100644 --- a/sys/dev/ata/ata-cbus.c +++ b/sys/dev/ata/ata-cbus.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2002 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 2002 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include <sys/rman.h> #include <isa/isavar.h> #include <dev/ata/ata-all.h> +#include <ata_if.h> /* local vars */ struct ata_cbus_controller { @@ -54,11 +55,10 @@ struct ata_cbus_controller { struct resource *bankio; struct resource *irq; void *ih; - void (*setmode)(struct ata_device *, int); - int (*locking)(struct ata_channel *, int); struct mtx bank_mtx; - int current_bank; + int locked_bank; int restart_bank; + int hardware_bank; struct { void (*function)(void *); void *argument; @@ -67,8 +67,7 @@ struct ata_cbus_controller { /* local prototypes */ static void ata_cbus_intr(void *); -static int ata_cbus_banking(struct ata_channel *, int); -static void ata_cbus_setmode(struct ata_device *, int); +static int ata_cbus_banking(device_t parent, device_t dev, int flags); static int ata_cbus_probe(device_t dev) @@ -162,10 +161,9 @@ ata_cbus_attach(device_t dev) } mtx_init(&ctlr->bank_mtx, "ATA cbus bank lock", NULL, MTX_DEF); - ctlr->current_bank = -1; + ctlr->hardware_bank = -1; + ctlr->locked_bank = -1; ctlr->restart_bank = -1; - ctlr->locking = ata_cbus_banking; - ctlr->setmode = ata_cbus_setmode;; if (!device_add_child(dev, "ata", 0)) return ENOMEM; @@ -229,41 +227,44 @@ ata_cbus_intr(void *data) int unit; for (unit = 0; unit < 2; unit++) { - if (!(ch = ctlr->interrupt[unit].argument)) - continue; - if (ch->locking(ch, ATA_LF_WHICH) == unit) + if (!(ch = ctlr->interrupt[unit].argument)) + continue; + if (ata_cbus_banking(device_get_parent(ch->dev), ch->dev, + ATA_LF_WHICH) == unit) ctlr->interrupt[unit].function(ch); } } static int -ata_cbus_banking(struct ata_channel *ch, int flags) +ata_cbus_banking(device_t parent, device_t dev, int flags) { - struct ata_cbus_controller *ctlr = - device_get_softc(device_get_parent(ch->dev)); + struct ata_cbus_controller *ctlr = device_get_softc(parent); + struct ata_channel *ch = device_get_softc(dev); int res; mtx_lock(&ctlr->bank_mtx); switch (flags) { case ATA_LF_LOCK: - if (ctlr->current_bank == -1) - ctlr->current_bank = ch->unit; - if (ctlr->current_bank == ch->unit) + if (ctlr->locked_bank == -1) + ctlr->locked_bank = ch->unit; + if (ctlr->locked_bank == ch->unit) { + ctlr->hardware_bank = ch->unit; ATA_OUTB(ctlr->bankio, 0, ch->unit); + } else ctlr->restart_bank = ch->unit; break; case ATA_LF_UNLOCK: - if (ctlr->current_bank == ch->unit) { - ctlr->current_bank = -1; + if (ctlr->locked_bank == ch->unit) { + ctlr->locked_bank = -1; if (ctlr->restart_bank != -1) { - if (ctlr->interrupt[ctlr->restart_bank].argument) { - mtx_unlock(&ctlr->bank_mtx); - ata_start(ctlr->interrupt[ctlr->restart_bank].argument); - mtx_lock(&ctlr->bank_mtx); + if ((ch = ctlr->interrupt[ctlr->restart_bank].argument)) { + ctlr->restart_bank = -1; + mtx_unlock(&ctlr->bank_mtx); + ata_start(ch->dev); + return -1; } - ctlr->restart_bank = -1; } } break; @@ -271,26 +272,24 @@ ata_cbus_banking(struct ata_channel *ch, int flags) case ATA_LF_WHICH: break; } - res = ctlr->current_bank; + res = ctlr->locked_bank; mtx_unlock(&ctlr->bank_mtx); return res; } -static void -ata_cbus_setmode(struct ata_device *atadev, int mode) -{ - atadev->mode = ata_limit_mode(atadev, mode, ATA_PIO_MAX); -} - static device_method_t ata_cbus_methods[] = { - /* device_interface */ - DEVMETHOD(device_probe, ata_cbus_probe), - DEVMETHOD(device_attach, ata_cbus_attach), + /* device interface */ + DEVMETHOD(device_probe, ata_cbus_probe), + DEVMETHOD(device_attach, ata_cbus_attach), +// DEVMETHOD(device_detach, ata_cbus_detach), /* bus methods */ - DEVMETHOD(bus_alloc_resource, ata_cbus_alloc_resource), - DEVMETHOD(bus_setup_intr, ata_cbus_setup_intr), - DEVMETHOD(bus_print_child, ata_cbus_print_child), + DEVMETHOD(bus_alloc_resource, ata_cbus_alloc_resource), + DEVMETHOD(bus_setup_intr, ata_cbus_setup_intr), + DEVMETHOD(bus_print_child, ata_cbus_print_child), + + /* ATA methods */ + DEVMETHOD(ata_locking, ata_cbus_banking), { 0, 0 } }; @@ -330,19 +329,17 @@ ata_cbussub_probe(device_t dev) /* initialize softc for this channel */ ch->flags |= ATA_USE_16BIT; - ch->locking = ctlr->locking; - ch->device[MASTER].setmode = ctlr->setmode; - ch->device[SLAVE].setmode = ctlr->setmode; ata_generic_hw(ch); return ata_probe(dev); } static device_method_t ata_cbussub_methods[] = { /* device interface */ - DEVMETHOD(device_probe, ata_cbussub_probe), - DEVMETHOD(device_attach, ata_attach), - DEVMETHOD(device_detach, ata_detach), - DEVMETHOD(device_resume, ata_resume), + DEVMETHOD(device_probe, ata_cbussub_probe), + DEVMETHOD(device_attach, ata_attach), + DEVMETHOD(device_detach, ata_detach), + DEVMETHOD(device_suspend, ata_suspend), + DEVMETHOD(device_resume, ata_resume), { 0, 0 } }; @@ -353,3 +350,4 @@ static driver_t ata_cbussub_driver = { }; DRIVER_MODULE(ata, atacbus, ata_cbussub_driver, ata_devclass, 0, 0); +MODULE_DEPEND(ata, ata, 1, 1, 1); diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c index 1e1735f..b87c1b3 100644 --- a/sys/dev/ata/ata-chipset.c +++ b/sys/dev/ata/ata-chipset.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -50,14 +50,7 @@ __FBSDID("$FreeBSD$"); #include <dev/pci/pcireg.h> #include <dev/ata/ata-all.h> #include <dev/ata/ata-pci.h> - -/* misc defines */ -#define GRANDPARENT(dev) device_get_parent(device_get_parent(dev)) -#define ATAPI_DEVICE(atadev) \ - ((atadev->unit == ATA_MASTER && \ - atadev->channel->devices & ATA_ATAPI_MASTER) ||\ - (atadev->unit == ATA_SLAVE && \ - atadev->channel->devices & ATA_ATAPI_SLAVE)) +#include <ata_if.h> /* local prototypes */ static int ata_generic_chipinit(device_t); @@ -120,12 +113,29 @@ static int ata_sis_chipinit(device_t); static void ata_sis_setmode(struct ata_device *, int); static int ata_check_80pin(struct ata_device *, int); static struct ata_chip_id *ata_find_chip(device_t, struct ata_chip_id *, int); -static struct ata_chip_id *ata_match_chip(device_t, struct ata_chip_id *); static int ata_setup_interrupt(device_t); static int ata_serialize(struct ata_channel *, int); static int ata_mode2idx(int); -/* generic or unknown ATA chipset init code */ + +static 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); +} + +static int +ata_atapi(struct ata_device *atadev) +{ + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); + + return ((atadev->unit == ATA_MASTER && ch->devices & ATA_ATAPI_MASTER) || + (atadev->unit == ATA_SLAVE && ch->devices & ATA_ATAPI_SLAVE)); +} + + +/* generic or unknown ATA chipset support functions */ int ata_generic_ident(device_t dev) { @@ -180,6 +190,8 @@ ata_generic_setmode(struct ata_device *atadev, int mode) atadev->mode = mode; } + +/* SATA support functions */ static void ata_sata_setmode(struct ata_device *atadev, int mode) { @@ -189,9 +201,9 @@ ata_sata_setmode(struct ata_device *atadev, int mode) * this works around the problems some devices has with the * Marvell 88SX8030 SATA->PATA converters and UDMA6/ATA133. */ - if (atadev->param->satacapabilities != 0x0000 && - atadev->param->satacapabilities != 0xffff) { - if (!ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, + if (atadev->param.satacapabilities != 0x0000 && + atadev->param.satacapabilities != 0xffff) { + if (!ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, ata_limit_mode(atadev, mode, ATA_UDMA6))) atadev->mode = ATA_SA150; } @@ -202,6 +214,33 @@ ata_sata_setmode(struct ata_device *atadev, int mode) } } +static void +ata_sata_connect(void *context, int dummy) +{ + struct ata_connect_task *tp = (struct ata_connect_task *)context; + device_t *children; + int nchildren, i; + + mtx_lock(&Giant); /* newbus suckage it needs Giant */ + if (tp->action == ATA_C_ATTACH) { + bus_generic_probe(tp->dev); + bus_generic_attach(tp->dev); + device_printf(tp->dev, "CONNECTED\n"); + } + if (tp->action == ATA_C_DETACH) { + if (!device_get_children(tp->dev, &children, &nchildren)) { + for (i = 0; i < nchildren; i++) + if (children[i]) + device_delete_child(tp->dev, children[i]); + free(children, M_TEMP); + } + device_printf(tp->dev, "DISCONNECTED\n"); + } + mtx_unlock(&Giant); /* suckage code dealt with, release Giant */ + free(tp, M_ATA); +} + + /* * Acard chipset support functions */ @@ -265,7 +304,9 @@ ata_acard_intr(void *data) for (unit = 0; unit < 2; unit++) { if (!(ch = ctlr->interrupt[unit].argument)) continue; - if (ctlr->chip->cfg1 == ATPOLD && ch->locking(ch, ATA_LF_WHICH) != unit) + if (ctlr->chip->cfg1 == ATPOLD && + ATA_LOCKING(device_get_parent(ch->dev), + ch->dev, ATA_LF_WHICH) != unit) continue; if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) { int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; @@ -286,30 +327,31 @@ ata_acard_intr(void *data) static void ata_acard_850_setmode(struct ata_device *atadev, int mode) { - device_t parent = device_get_parent(atadev->channel->dev); - struct ata_pci_controller *ctlr = device_get_softc(parent); - int devno = (atadev->channel->unit << 1) + ATA_DEV(atadev->unit); + device_t gparent = GRANDPARENT(atadev->dev); + struct ata_pci_controller *ctlr = device_get_softc(gparent); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); + int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); int error; mode = ata_limit_mode(atadev, mode, - ATAPI_DEVICE(atadev)?ATA_PIO_MAX:ctlr->chip->max_dma); + ata_atapi(atadev) ? ATA_PIO_MAX:ctlr->chip->max_dma); /* XXX missing WDMA0+1 + PIO modes */ if (mode >= ATA_WDMA2) { error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,mode); if (bootverbose) - ata_prtdev(atadev, "%ssetting %s on %s chip\n", - (error) ? "FAILURE " : "", - ata_mode2str(mode), ctlr->chip->text); + device_printf(atadev->dev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", + ata_mode2str(mode), ctlr->chip->text); if (!error) { - u_int8_t reg54 = pci_read_config(parent, 0x54, 1); + u_int8_t reg54 = pci_read_config(gparent, 0x54, 1); reg54 &= ~(0x03 << (devno << 1)); if (mode >= ATA_UDMA0) reg54 |= (((mode & ATA_MODE_MASK) + 1) << (devno << 1)); - pci_write_config(parent, 0x54, reg54, 1); - pci_write_config(parent, 0x4a, 0xa6, 1); - pci_write_config(parent, 0x40 + (devno << 1), 0x0301, 2); + pci_write_config(gparent, 0x54, reg54, 1); + pci_write_config(gparent, 0x4a, 0xa6, 1); + pci_write_config(gparent, 0x40 + (devno << 1), 0x0301, 2); atadev->mode = mode; return; } @@ -320,14 +362,15 @@ ata_acard_850_setmode(struct ata_device *atadev, int mode) static void ata_acard_86X_setmode(struct ata_device *atadev, int mode) { - device_t parent = device_get_parent(atadev->channel->dev); - struct ata_pci_controller *ctlr = device_get_softc(parent); - int devno = (atadev->channel->unit << 1) + ATA_DEV(atadev->unit); + device_t gparent = GRANDPARENT(atadev->dev); + struct ata_pci_controller *ctlr = device_get_softc(gparent); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); + int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); int error; mode = ata_limit_mode(atadev, mode, - ATAPI_DEVICE(atadev)?ATA_PIO_MAX:ctlr->chip->max_dma); + ata_atapi(atadev) ? ATA_PIO_MAX:ctlr->chip->max_dma); mode = ata_check_80pin(atadev, mode); @@ -335,18 +378,18 @@ ata_acard_86X_setmode(struct ata_device *atadev, int mode) if (mode >= ATA_WDMA2) { error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,mode); if (bootverbose) - ata_prtdev(atadev, "%ssetting %s on %s chip\n", - (error) ? "FAILURE " : "", - ata_mode2str(mode), ctlr->chip->text); + device_printf(atadev->dev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", + ata_mode2str(mode), ctlr->chip->text); if (!error) { - u_int16_t reg44 = pci_read_config(parent, 0x44, 2); + u_int16_t reg44 = pci_read_config(gparent, 0x44, 2); reg44 &= ~(0x000f << (devno << 2)); if (mode >= ATA_UDMA0) reg44 |= (((mode & ATA_MODE_MASK) + 1) << (devno << 2)); - pci_write_config(parent, 0x44, reg44, 2); - pci_write_config(parent, 0x4a, 0xa6, 1); - pci_write_config(parent, 0x40 + devno, 0x31, 1); + pci_write_config(gparent, 0x44, reg44, 2); + pci_write_config(gparent, 0x4a, 0xa6, 1); + pci_write_config(gparent, 0x40 + devno, 0x31, 1); atadev->mode = mode; return; } @@ -389,11 +432,16 @@ ata_ali_chipinit(device_t dev) return ENXIO; /* deactivate the ATAPI FIFO and enable ATAPI UDMA */ - pci_write_config(dev, 0x53, pci_read_config(dev, 0x53, 1) | 0x03, 1); + if (ctlr->chip->cfg2 & ALINEW) + pci_write_config(dev, 0x53, pci_read_config(dev, 0x53, 1) | 0x01, 1); + else + pci_write_config(dev, 0x53, + (pci_read_config(dev, 0x53, 1) & ~0x02) | 0x03, 1); /* enable cable detection and UDMA support on newer chips */ if (ctlr->chip->cfg2 & ALINEW) pci_write_config(dev, 0x4b, pci_read_config(dev, 0x4b, 1) | 0x09, 1); + ctlr->setmode = ata_ali_setmode; return 0; } @@ -401,18 +449,18 @@ ata_ali_chipinit(device_t dev) static void ata_ali_setmode(struct ata_device *atadev, int mode) { - device_t parent = device_get_parent(atadev->channel->dev); - struct ata_pci_controller *ctlr = device_get_softc(parent); - int devno = (atadev->channel->unit << 1) + ATA_DEV(atadev->unit); + device_t gparent = GRANDPARENT(atadev->dev); + struct ata_pci_controller *ctlr = device_get_softc(gparent); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); + int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); int error; mode = ata_limit_mode(atadev, mode, ctlr->chip->max_dma); if (ctlr->chip->cfg2 & ALINEW) { if (mode > ATA_UDMA2 && - pci_read_config(parent, 0x4a, 1) & (1 << atadev->channel->unit)) { - ata_prtdev(atadev, - "DMA limited to UDMA33, non-ATA66 cable or device\n"); + pci_read_config(gparent, 0x4a, 1) & (1 << ch->unit)) { + ata_print_cable(atadev->dev, "controller"); mode = ATA_UDMA2; } } @@ -421,11 +469,11 @@ ata_ali_setmode(struct ata_device *atadev, int mode) if (ctlr->chip->cfg2 & ALIOLD) { /* doesn't support ATAPI DMA on write */ - atadev->channel->flags |= ATA_ATAPI_DMA_RO; - if (atadev->channel->devices & ATA_ATAPI_MASTER && - atadev->channel->devices & ATA_ATAPI_SLAVE) { + ch->flags |= ATA_ATAPI_DMA_RO; + if (ch->devices & ATA_ATAPI_MASTER && ch->devices & ATA_ATAPI_SLAVE) { /* doesn't support ATAPI DMA on two ATAPI devices */ - ata_prtdev(atadev, "two atapi devices on this channel, no DMA\n"); + device_printf(atadev->dev, + "two atapi devices on this channel, no DMA\n"); mode = ata_limit_mode(atadev, mode, ATA_PIO_MAX); } } @@ -433,18 +481,18 @@ ata_ali_setmode(struct ata_device *atadev, int mode) error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); if (bootverbose) - ata_prtdev(atadev, "%ssetting %s on %s chip\n", + device_printf(atadev->dev, "%ssetting %s on %s chip\n", (error) ? "FAILURE " : "", ata_mode2str(mode), ctlr->chip->text); if (!error) { if (mode >= ATA_UDMA0) { u_int8_t udma[] = {0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x0f}; - u_int32_t word54 = pci_read_config(parent, 0x54, 4); + u_int32_t word54 = pci_read_config(gparent, 0x54, 4); word54 &= ~(0x000f000f << (devno << 2)); word54 |= (((udma[mode&ATA_MODE_MASK]<<16)|0x05)<<(devno<<2)); - pci_write_config(parent, 0x54, word54, 4); - pci_write_config(parent, 0x58 + (atadev->channel->unit << 2), + pci_write_config(gparent, 0x54, word54, 4); + pci_write_config(gparent, 0x58 + (ch->unit << 2), 0x00310001, 4); } else { @@ -452,9 +500,9 @@ ata_ali_setmode(struct ata_device *atadev, int mode) { 0x006d0003, 0x00580002, 0x00440001, 0x00330001, 0x00310001, 0x00440001, 0x00330001, 0x00310001}; - pci_write_config(parent, 0x54, pci_read_config(parent, 0x54, 4) & - ~(0x0008000f << (devno << 2)), 4); - pci_write_config(parent, 0x58 + (atadev->channel->unit << 2), + pci_write_config(gparent, 0x54, pci_read_config(gparent, 0x54, 4) & + ~(0x0008000f << (devno << 2)), 4); + pci_write_config(gparent, 0x58 + (ch->unit << 2), piotimings[ata_mode2idx(mode)], 4); } atadev->mode = mode; @@ -462,7 +510,7 @@ ata_ali_setmode(struct ata_device *atadev, int mode) } /* - * American Micro Devices (AMD) support functions + * American Micro Devices (AMD) chipset support functions */ int ata_amd_ident(device_t dev) @@ -470,10 +518,10 @@ ata_amd_ident(device_t dev) struct ata_pci_controller *ctlr = device_get_softc(dev); struct ata_chip_id *idx; static struct ata_chip_id ids[] = - {{ ATA_AMD756, 0x00, AMDNVIDIA, 0x00, ATA_UDMA4, "AMD 756" }, + {{ ATA_AMD756, 0x00, AMDNVIDIA, 0x00, ATA_UDMA4, "AMD 756" }, { ATA_AMD766, 0x00, AMDNVIDIA, AMDCABLE|AMDBUG, ATA_UDMA5, "AMD 766" }, - { ATA_AMD768, 0x00, AMDNVIDIA, AMDCABLE, ATA_UDMA5, "AMD 768" }, - { ATA_AMD8111, 0x00, AMDNVIDIA, AMDCABLE, ATA_UDMA6, "AMD 8111" }, + { ATA_AMD768, 0x00, AMDNVIDIA, AMDCABLE, ATA_UDMA5, "AMD 768" }, + { ATA_AMD8111, 0x00, AMDNVIDIA, AMDCABLE, ATA_UDMA6, "AMD 8111" }, { 0, 0, 0, 0, 0, 0}}; char buffer[64]; @@ -539,24 +587,24 @@ ata_cyrix_chipinit(device_t dev) static void ata_cyrix_setmode(struct ata_device *atadev, int mode) { - struct ata_channel *ch = atadev->channel; - int devno = (atadev->channel->unit << 1) + ATA_DEV(atadev->unit); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); + int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); u_int32_t piotiming[] = { 0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010 }; u_int32_t dmatiming[] = { 0x00077771, 0x00012121, 0x00002020 }; u_int32_t udmatiming[] = { 0x00921250, 0x00911140, 0x00911030 }; int error; - atadev->channel->dma->alignment = 16; - atadev->channel->dma->max_iosize = 126 * DEV_BSIZE; + ch->dma->alignment = 16; + ch->dma->max_iosize = 126 * DEV_BSIZE; mode = ata_limit_mode(atadev, mode, ATA_UDMA2); error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); if (bootverbose) - ata_prtdev(atadev, "%ssetting %s on Cyrix chip\n", - (error) ? "FAILURE " : "", ata_mode2str(mode)); + device_printf(atadev->dev, "%ssetting %s on Cyrix chip\n", + (error) ? "FAILURE " : "", ata_mode2str(mode)); if (!error) { if (mode >= ATA_UDMA0) { ATA_OUTL(ch->r_io[ATA_BMCMD_PORT].res, @@ -614,7 +662,8 @@ ata_cypress_chipinit(device_t dev) static void ata_cypress_setmode(struct ata_device *atadev, int mode) { - device_t parent = device_get_parent(atadev->channel->dev); + device_t gparent = GRANDPARENT(atadev->dev); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); int error; mode = ata_limit_mode(atadev, mode, ATA_WDMA2); @@ -623,10 +672,10 @@ ata_cypress_setmode(struct ata_device *atadev, int mode) if (mode == ATA_WDMA2) { error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,mode); if (bootverbose) - ata_prtdev(atadev, "%ssetting WDMA2 on Cypress chip\n", - error ? "FAILURE " : ""); + device_printf(atadev->dev, "%ssetting WDMA2 on Cypress chip\n", + error ? "FAILURE " : ""); if (!error) { - pci_write_config(parent, atadev->channel->unit?0x4e:0x4c,0x2020,2); + pci_write_config(gparent, ch->unit ? 0x4e : 0x4c, 0x2020, 2); atadev->mode = mode; return; } @@ -643,14 +692,15 @@ ata_highpoint_ident(device_t dev) struct ata_pci_controller *ctlr = device_get_softc(dev); struct ata_chip_id *idx; static struct ata_chip_id ids[] = - {{ ATA_HPT366, 0x05, HPT372, 0x00, ATA_UDMA6, "HighPoint HPT372" }, - { ATA_HPT366, 0x03, HPT370, 0x00, ATA_UDMA5, "HighPoint HPT370" }, - { ATA_HPT366, 0x02, HPT366, 0x00, ATA_UDMA4, "HighPoint HPT368" }, + {{ ATA_HPT374, 0x07, HPT374, 0x00, ATA_UDMA6, "HighPoint HPT374" }, + { ATA_HPT372, 0x02, HPT372, 0x00, ATA_UDMA6, "HighPoint HPT372N" }, + { ATA_HPT372, 0x01, HPT372, 0x00, ATA_UDMA6, "HighPoint HPT372" }, + { ATA_HPT371, 0x01, HPT372, 0x00, ATA_UDMA6, "HighPoint HPT371" }, + { ATA_HPT366, 0x05, HPT372, 0x00, ATA_UDMA6, "HighPoint HPT372" }, + { ATA_HPT366, 0x03, HPT370, 0x00, ATA_UDMA5, "HighPoint HPT370" }, + { ATA_HPT366, 0x02, HPT366, 0x00, ATA_UDMA4, "HighPoint HPT368" }, { ATA_HPT366, 0x00, HPT366, HPTOLD, ATA_UDMA4, "HighPoint HPT366" }, - { ATA_HPT372, 0x01, HPT372, 0x00, ATA_UDMA6, "HighPoint HPT372" }, - { ATA_HPT302, 0x01, HPT372, 0x00, ATA_UDMA6, "HighPoint HPT302" }, - { ATA_HPT371, 0x01, HPT372, 0x00, ATA_UDMA6, "HighPoint HPT371" }, - { ATA_HPT374, 0x07, HPT374, 0x00, ATA_UDMA6, "HighPoint HPT374" }, + { ATA_HPT302, 0x01, HPT372, 0x00, ATA_UDMA6, "HighPoint HPT302" }, { 0, 0, 0, 0, 0, 0}}; char buffer[64]; @@ -738,43 +788,50 @@ ata_highpoint_intr(void *data) static void ata_highpoint_setmode(struct ata_device *atadev, int mode) { - device_t parent = device_get_parent(atadev->channel->dev); - struct ata_pci_controller *ctlr = device_get_softc(parent); - int devno = (atadev->channel->unit << 1) + ATA_DEV(atadev->unit); + device_t gparent = GRANDPARENT(atadev->dev); + struct ata_pci_controller *ctlr = device_get_softc(gparent); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); + int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); int error; u_int32_t timings33[][4] = { - /* HPT366 HPT370 HPT372 HPT374 mode */ - { 0x40d0a7aa, 0x06914e57, 0x0d029d5e, 0x0ac1f48a }, /* PIO 0 */ - { 0x40d0a7a3, 0x06914e43, 0x0d029d26, 0x0ac1f465 }, /* PIO 1 */ - { 0x40d0a753, 0x06514e33, 0x0c829ca6, 0x0a81f454 }, /* PIO 2 */ - { 0x40c8a742, 0x06514e22, 0x0c829c84, 0x0a81f443 }, /* PIO 3 */ - { 0x40c8a731, 0x06514e21, 0x0c829c62, 0x0a81f442 }, /* PIO 4 */ - { 0x20c8a797, 0x26514e97, 0x2c82922e, 0x228082ea }, /* MWDMA 0 */ - { 0x20c8a732, 0x26514e33, 0x2c829266, 0x22808254 }, /* MWDMA 1 */ - { 0x20c8a731, 0x26514e21, 0x2c829262, 0x22808242 }, /* MWDMA 2 */ - { 0x10c8a731, 0x16514e31, 0x1c82dc62, 0x121882ea }, /* UDMA 0 */ - { 0x10cba731, 0x164d4e31, 0x1c9adc62, 0x12148254 }, /* UDMA 1 */ - { 0x10caa731, 0x16494e31, 0x1c91dc62, 0x120c8242 }, /* UDMA 2 */ - { 0x10cfa731, 0x166d4e31, 0x1c8edc62, 0x128c8242 }, /* UDMA 3 */ - { 0x10c9a731, 0x16454e31, 0x1c8ddc62, 0x12ac8242 }, /* UDMA 4 */ - { 0, 0x16454e31, 0x1c6ddc62, 0x12848242 }, /* UDMA 5 */ - { 0, 0, 0x1c81dc62, 0x12448242 } /* UDMA 6 */ + /* HPT366 HPT370 HPT372 HPT374 mode */ + { 0x40d0a7aa, 0x06914e57, 0x0d029d5e, 0x0ac1f48a }, /* PIO 0 */ + { 0x40d0a7a3, 0x06914e43, 0x0d029d26, 0x0ac1f465 }, /* PIO 1 */ + { 0x40d0a753, 0x06514e33, 0x0c829ca6, 0x0a81f454 }, /* PIO 2 */ + { 0x40c8a742, 0x06514e22, 0x0c829c84, 0x0a81f443 }, /* PIO 3 */ + { 0x40c8a731, 0x06514e21, 0x0c829c62, 0x0a81f442 }, /* PIO 4 */ + { 0x20c8a797, 0x26514e97, 0x2c82922e, 0x228082ea }, /* MWDMA 0 */ + { 0x20c8a732, 0x26514e33, 0x2c829266, 0x22808254 }, /* MWDMA 1 */ + { 0x20c8a731, 0x26514e21, 0x2c829262, 0x22808242 }, /* MWDMA 2 */ + { 0x10c8a731, 0x16514e31, 0x1c829c62, 0x121882ea }, /* UDMA 0 */ + { 0x10cba731, 0x164d4e31, 0x1c9a9c62, 0x12148254 }, /* UDMA 1 */ + { 0x10caa731, 0x16494e31, 0x1c929c62, 0x120c8242 }, /* UDMA 2 */ + { 0x10cfa731, 0x166d4e31, 0x1c8e9c62, 0x128c8242 }, /* UDMA 3 */ + { 0x10c9a731, 0x16454e31, 0x1c8a9c62, 0x12ac8242 }, /* UDMA 4 */ + { 0, 0x16454e31, 0x1c8a9c62, 0x12848242 }, /* UDMA 5 */ + { 0, 0, 0x1c869c62, 0x12808242 } /* UDMA 6 */ }; mode = ata_limit_mode(atadev, mode, ctlr->chip->max_dma); - if (ctlr->chip->cfg1 == HPT366 && ATAPI_DEVICE(atadev)) + if (ctlr->chip->cfg1 == HPT366 && ata_atapi(atadev)) mode = ata_limit_mode(atadev, mode, ATA_PIO_MAX); mode = ata_highpoint_check_80pin(atadev, mode); - error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); + /* + * most if not all HPT chips cant really handle that the device is + * running at ATA_UDMA6/ATA133 speed, so we cheat at set the device to + * a max of ATA_UDMA5/ATA100 to guard against suboptimal performance + */ + error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, + ata_limit_mode(atadev, mode, ATA_UDMA5)); if (bootverbose) - ata_prtdev(atadev, "%ssetting %s on HighPoint chip\n", - (error) ? "FAILURE " : "", ata_mode2str(mode)); + device_printf(atadev->dev, "%ssetting %s on HighPoint chip\n", + (error) ? "FAILURE " : "", ata_mode2str(mode)); if (!error) - pci_write_config(parent, 0x40 + (devno << 2), + pci_write_config(gparent, 0x40 + (devno << 2), timings33[ata_mode2idx(mode)][ctlr->chip->cfg1], 4); atadev->mode = mode; } @@ -782,25 +839,26 @@ ata_highpoint_setmode(struct ata_device *atadev, int mode) static int ata_highpoint_check_80pin(struct ata_device *atadev, int mode) { - device_t parent = device_get_parent(atadev->channel->dev); - struct ata_pci_controller *ctlr = device_get_softc(parent); + device_t gparent = GRANDPARENT(atadev->dev); + struct ata_pci_controller *ctlr = device_get_softc(gparent); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); u_int8_t reg, val, res; - if (ctlr->chip->cfg1 == HPT374 && pci_get_function(parent) == 1) { - reg = atadev->channel->unit ? 0x57 : 0x53; - val = pci_read_config(parent, reg, 1); - pci_write_config(parent, reg, val | 0x80, 1); + if (ctlr->chip->cfg1 == HPT374 && pci_get_function(gparent) == 1) { + reg = ch->unit ? 0x57 : 0x53; + val = pci_read_config(gparent, reg, 1); + pci_write_config(gparent, reg, val | 0x80, 1); } else { reg = 0x5b; - val = pci_read_config(parent, reg, 1); - pci_write_config(parent, reg, val & 0xfe, 1); + val = pci_read_config(gparent, reg, 1); + pci_write_config(gparent, reg, val & 0xfe, 1); } - res = pci_read_config(parent, 0x5a, 1) & (atadev->channel->unit ? 0x1:0x2); - pci_write_config(parent, reg, val, 1); + res = pci_read_config(gparent, 0x5a, 1) & (ch->unit ? 0x1:0x2); + pci_write_config(gparent, reg, val, 1); if (mode > ATA_UDMA2 && res) { - ata_prtdev(atadev,"DMA limited to UDMA33, non-ATA66 cable or device\n"); + ata_print_cable(atadev->dev, "controller"); mode = ATA_UDMA2; } return mode; @@ -920,7 +978,7 @@ ata_intel_reset(struct ata_channel *ch) { device_t parent = device_get_parent(ch->dev); struct ata_pci_controller *ctlr = device_get_softc(parent); - int mask, timeout = 100; + int mask, timeout; /* ICH6 has 4 SATA ports as master/slave on 2 channels so deal with pairs */ if (ctlr->chip->chipid == ATA_I82801FB_S1 || @@ -931,33 +989,37 @@ ata_intel_reset(struct ata_channel *ch) /* ICH5 in compat mode has SATA ports as master/slave on 1 channel */ if (pci_read_config(parent, 0x90, 1) & 0x04) mask = 0x0003; - else + else { mask = (0x0001 << ch->unit); + /* XXX SOS should be in intel_allocate when we grow it */ + ch->flags |= ATA_NO_SLAVE; + } } pci_write_config(parent, 0x92, pci_read_config(parent, 0x92, 2) & ~mask, 2); DELAY(10); pci_write_config(parent, 0x92, pci_read_config(parent, 0x92, 2) | mask, 2); - while (timeout--) { + /* wait up to 1 sec for "connect well" */ + for (timeout = 0; timeout < 100 ; timeout++) { + if (((pci_read_config(parent, 0x92, 2) & (mask << 4)) == (mask << 4)) && + (ATA_IDX_INB(ch, ATA_STATUS) != 0xff)) + break; ata_udelay(10000); - if ((pci_read_config(parent, 0x92, 2) & (mask << 4)) == (mask << 4)) { - ata_udelay(10000); - return; - } } } static void ata_intel_new_setmode(struct ata_device *atadev, int mode) { - device_t parent = device_get_parent(atadev->channel->dev); - struct ata_pci_controller *ctlr = device_get_softc(parent); - int devno = (atadev->channel->unit << 1) + ATA_DEV(atadev->unit); - u_int32_t reg40 = pci_read_config(parent, 0x40, 4); - u_int8_t reg44 = pci_read_config(parent, 0x44, 1); - u_int8_t reg48 = pci_read_config(parent, 0x48, 1); - u_int16_t reg4a = pci_read_config(parent, 0x4a, 2); - u_int16_t reg54 = pci_read_config(parent, 0x54, 2); + device_t gparent = GRANDPARENT(atadev->dev); + struct ata_pci_controller *ctlr = device_get_softc(gparent); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); + int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); + u_int32_t reg40 = pci_read_config(gparent, 0x40, 4); + u_int8_t reg44 = pci_read_config(gparent, 0x44, 1); + u_int8_t reg48 = pci_read_config(gparent, 0x48, 1); + u_int16_t reg4a = pci_read_config(gparent, 0x4a, 2); + u_int16_t reg54 = pci_read_config(gparent, 0x54, 2); u_int32_t mask40 = 0, new40 = 0; u_int8_t mask44 = 0, new44 = 0; int error; @@ -967,38 +1029,38 @@ ata_intel_new_setmode(struct ata_device *atadev, int mode) mode = ata_limit_mode(atadev, mode, ctlr->chip->max_dma); if ( mode > ATA_UDMA2 && !(reg54 & (0x10 << devno))) { - ata_prtdev(atadev,"DMA limited to UDMA33, non-ATA66 cable or device\n"); + ata_print_cable(atadev->dev, "controller"); mode = ATA_UDMA2; } error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); if (bootverbose) - ata_prtdev(atadev, "%ssetting %s on %s chip\n", - (error) ? "FAILURE " : "", - ata_mode2str(mode), ctlr->chip->text); + device_printf(atadev->dev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", + ata_mode2str(mode), ctlr->chip->text); if (error) return; if (mode >= ATA_UDMA0) { - pci_write_config(parent, 0x48, reg48 | (0x0001 << devno), 2); - pci_write_config(parent, 0x4a, (reg4a & ~(0x3 << (devno<<2))) | + pci_write_config(gparent, 0x48, reg48 | (0x0001 << devno), 2); + pci_write_config(gparent, 0x4a, (reg4a & ~(0x3 << (devno<<2))) | (0x01 + !(mode & 0x01)), 2); } else { - pci_write_config(parent, 0x48, reg48 & ~(0x0001 << devno), 2); - pci_write_config(parent, 0x4a, (reg4a & ~(0x3 << (devno << 2))), 2); + pci_write_config(gparent, 0x48, reg48 & ~(0x0001 << devno), 2); + pci_write_config(gparent, 0x4a, (reg4a & ~(0x3 << (devno << 2))), 2); } reg54 |= 0x0400; if (mode >= ATA_UDMA2) - pci_write_config(parent, 0x54, reg54 | (0x1 << devno), 2); + pci_write_config(gparent, 0x54, reg54 | (0x1 << devno), 2); else - pci_write_config(parent, 0x54, reg54 & ~(0x1 << devno), 2); + pci_write_config(gparent, 0x54, reg54 & ~(0x1 << devno), 2); if (mode >= ATA_UDMA5) - pci_write_config(parent, 0x54, reg54 | (0x1000 << devno), 2); + pci_write_config(gparent, 0x54, reg54 | (0x1000 << devno), 2); else - pci_write_config(parent, 0x54, reg54 & ~(0x1000 << devno), 2); + pci_write_config(gparent, 0x54, reg54 & ~(0x1000 << devno), 2); reg40 &= ~0x00ff00ff; reg40 |= 0x40774077; @@ -1012,14 +1074,14 @@ ata_intel_new_setmode(struct ata_device *atadev, int mode) new44 = ((timings[ata_mode2idx(mode)] & 0x30) >> 2) | (timings[ata_mode2idx(mode)] & 0x03); } - if (atadev->channel->unit) { + if (ch->unit) { mask40 <<= 16; new40 <<= 16; mask44 <<= 4; new44 <<= 4; } - pci_write_config(parent, 0x40, (reg40 & ~mask40) | new40, 4); - pci_write_config(parent, 0x44, (reg44 & ~mask44) | new44, 1); + pci_write_config(gparent, 0x40, (reg40 & ~mask40) | new40, 4); + pci_write_config(gparent, 0x44, (reg44 & ~mask44) | new44, 1); atadev->mode = mode; } @@ -1062,8 +1124,8 @@ ata_ite_chipinit(device_t dev) static void ata_ite_setmode(struct ata_device *atadev, int mode) { - device_t parent = device_get_parent(atadev->channel->dev); - struct ata_channel *ch = atadev->channel; + device_t gparent = GRANDPARENT(atadev->dev); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); int error; @@ -1071,9 +1133,9 @@ ata_ite_setmode(struct ata_device *atadev, int mode) mode = ata_limit_mode(atadev, mode, ATA_UDMA6); /* check the CBLID bits for 80 conductor cable detection */ - if (mode > ATA_UDMA2 && (pci_read_config(parent, 0x40, 2) & + if (mode > ATA_UDMA2 && (pci_read_config(gparent, 0x40, 2) & (ch->unit ? (1<<3) : (1<<2)))) { - ata_prtdev(atadev,"DMA limited to UDMA33, non-ATA66 cable or device\n"); + ata_print_cable(atadev->dev, "controller"); mode = ATA_UDMA2; } @@ -1081,8 +1143,8 @@ ata_ite_setmode(struct ata_device *atadev, int mode) error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); if (bootverbose) - ata_prtdev(atadev, "%s setting %s on ITE8212F chip\n", - (error) ? "failed" : "success", ata_mode2str(mode)); + device_printf(atadev->dev, "%s setting %s on ITE8212F chip\n", + (error) ? "failed" : "success", ata_mode2str(mode)); /* if the device accepted the mode change, setup the HW accordingly */ if (!error) { @@ -1091,12 +1153,12 @@ ata_ite_setmode(struct ata_device *atadev, int mode) { 0x44, 0x42, 0x31, 0x21, 0x11, 0xa2, 0x91 }; /* enable UDMA mode */ - pci_write_config(parent, 0x50, - pci_read_config(parent, 0x50, 1) & + pci_write_config(gparent, 0x50, + pci_read_config(gparent, 0x50, 1) & ~(1 << (devno + 3)), 1); /* set UDMA timing */ - pci_write_config(parent, + pci_write_config(gparent, 0x56 + (ch->unit << 2) + ATA_DEV(atadev->unit), udmatiming[mode & ATA_MODE_MASK], 1); } @@ -1105,19 +1167,20 @@ ata_ite_setmode(struct ata_device *atadev, int mode) { 0xaa, 0xa3, 0xa1, 0x33, 0x31, 0x88, 0x32, 0x31 }; /* disable UDMA mode */ - pci_write_config(parent, 0x50, - pci_read_config(parent, 0x50, 1) | + pci_write_config(gparent, 0x50, + pci_read_config(gparent, 0x50, 1) | (1 << (devno + 3)), 1); /* set active and recover timing (shared between master & slave) */ - if (pci_read_config(parent, 0x54 + (ch->unit << 2), 1) < + if (pci_read_config(gparent, 0x54 + (ch->unit << 2), 1) < chtiming[ata_mode2idx(mode)]) - pci_write_config(parent, 0x54 + (ch->unit << 2), - chtiming[ata_mode2idx(mode)], 1); + pci_write_config(gparent, 0x54 + (ch->unit << 2), + chtiming[ata_mode2idx(mode)], 1); } atadev->mode = mode; } } + /* * National chipset support functions */ @@ -1164,41 +1227,42 @@ ata_national_chipinit(device_t dev) static void ata_national_setmode(struct ata_device *atadev, int mode) { - device_t parent = device_get_parent(atadev->channel->dev); - int devno = (atadev->channel->unit << 1) + ATA_DEV(atadev->unit); + device_t gparent = GRANDPARENT(atadev->dev); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); + int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); u_int32_t piotiming[] = - { 0x9172d132, 0x21717121, 0x00803020, 0x20102010, 0x00100010, + { 0x9172d132, 0x21717121, 0x00803020, 0x20102010, 0x00100010, 0x00803020, 0x20102010, 0x00100010, 0x00100010, 0x00100010, 0x00100010 }; u_int32_t dmatiming[] = { 0x80077771, 0x80012121, 0x80002020 }; u_int32_t udmatiming[] = { 0x80921250, 0x80911140, 0x80911030 }; int error; - atadev->channel->dma->alignment = 16; - atadev->channel->dma->max_iosize = 126 * DEV_BSIZE; + ch->dma->alignment = 16; + ch->dma->max_iosize = 126 * DEV_BSIZE; mode = ata_limit_mode(atadev, mode, ATA_UDMA2); error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); if (bootverbose) - ata_prtdev(atadev, "%s setting %s on National chip\n", - (error) ? "failed" : "success", ata_mode2str(mode)); + device_printf(atadev->dev, "%s setting %s on National chip\n", + (error) ? "failed" : "success", ata_mode2str(mode)); if (!error) { if (mode >= ATA_UDMA0) { - pci_write_config(parent, 0x44 + (devno << 3), + pci_write_config(gparent, 0x44 + (devno << 3), udmatiming[mode & ATA_MODE_MASK], 4); } else if (mode >= ATA_WDMA0) { - pci_write_config(parent, 0x44 + (devno << 3), + pci_write_config(gparent, 0x44 + (devno << 3), dmatiming[mode & ATA_MODE_MASK], 4); } else { - pci_write_config(parent, 0x44 + (devno << 3), - pci_read_config(parent, 0x44 + (devno << 3), 4) | + pci_write_config(gparent, 0x44 + (devno << 3), + pci_read_config(gparent, 0x44 + (devno << 3), 4) | 0x80000000, 4); } - pci_write_config(parent, 0x40 + (devno << 3), + pci_write_config(gparent, 0x40 + (devno << 3), piotiming[ata_mode2idx(mode)], 4); atadev->mode = mode; } @@ -1218,8 +1282,14 @@ ata_nvidia_ident(device_t dev) { ATA_NFORCE2_MCP, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nVidia nForce2 MCP" }, { ATA_NFORCE3, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nVidia nForce3" }, { ATA_NFORCE3_PRO, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nVidia nForce3 Pro" }, + { ATA_NFORCE3_PRO_S1, 0, 0, 0, ATA_SA150, "nVidia nForce3 Pro" }, + { ATA_NFORCE3_PRO_S2, 0, 0, 0, ATA_SA150, "nVidia nForce3 Pro" }, { ATA_NFORCE3_MCP, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nVidia nForce3 MCP" }, + { ATA_NFORCE3_MCP_S1, 0, 0, 0, ATA_SA150, "nVidia nForce3 MCP" }, + { ATA_NFORCE3_MCP_S2, 0, 0, 0, ATA_SA150, "nVidia nForce3 MCP" }, { ATA_NFORCE4, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nVidia nForce4" }, + { ATA_NFORCE4_S1, 0, 0, 0, ATA_SA150, "nVidia nForce4" }, + { ATA_NFORCE4_S1, 0, 0, 0, ATA_SA150, "nVidia nForce4" }, { 0, 0, 0, 0, 0, 0}}; char buffer[64]; @@ -1241,38 +1311,52 @@ ata_nvidia_chipinit(device_t dev) if (ata_setup_interrupt(dev)) return ENXIO; - /* disable prefetch, postwrite */ - pci_write_config(dev, 0x51, pci_read_config(dev, 0x51, 1) & 0x0f, 1); - - ctlr->setmode = ata_via_family_setmode; + if (ctlr->chip->max_dma < ATA_SA150) { + /* disable prefetch, postwrite */ + pci_write_config(dev, 0x51, pci_read_config(dev, 0x51, 1) & 0x0f, 1); + ctlr->setmode = ata_via_family_setmode; + } + else { + /* we need hotplug and proper reset code as well XXX SOS */ + ctlr->setmode = ata_sata_setmode; + } return 0; } /* * Promise chipset support functions */ -#define ATA_PDC_APKT_OFFSET 0x00000010 -#define ATA_PDC_HPKT_OFFSET 0x00000040 -#define ATA_PDC_ASG_OFFSET 0x00000080 -#define ATA_PDC_LSG_OFFSET 0x000000c0 -#define ATA_PDC_HSG_OFFSET 0x00000100 -#define ATA_PDC_CHN_OFFSET 0x00000400 -#define ATA_PDC_BUF_BASE 0x00400000 -#define ATA_PDC_BUF_OFFSET 0x00100000 -#define ATA_PDC_MAX_HPKT 8 -#define ATA_PDC_WRITE_REG 0x00 -#define ATA_PDC_WRITE_CTL 0x0e -#define ATA_PDC_WRITE_END 0x08 -#define ATA_PDC_WAIT_NBUSY 0x10 -#define ATA_PDC_WAIT_READY 0x18 -#define ATA_PDC_1B 0x20 -#define ATA_PDC_2B 0x40 +#define ATA_PDC_APKT_OFFSET 0x00000010 +#define ATA_PDC_HPKT_OFFSET 0x00000040 +#define ATA_PDC_ASG_OFFSET 0x00000080 +#define ATA_PDC_LSG_OFFSET 0x000000c0 +#define ATA_PDC_HSG_OFFSET 0x00000100 +#define ATA_PDC_CHN_OFFSET 0x00000400 +#define ATA_PDC_BUF_BASE 0x00400000 +#define ATA_PDC_BUF_OFFSET 0x00100000 +#define ATA_PDC_MAX_HPKT 8 +#define ATA_PDC_WRITE_REG 0x00 +#define ATA_PDC_WRITE_CTL 0x0e +#define ATA_PDC_WRITE_END 0x08 +#define ATA_PDC_WAIT_NBUSY 0x10 +#define ATA_PDC_WAIT_READY 0x18 +#define ATA_PDC_1B 0x20 +#define ATA_PDC_2B 0x40 + +struct host_packet { +u_int32_t addr; + TAILQ_ENTRY(host_packet) chain; +}; struct ata_promise_sx4 { - struct mtx mtx; - u_int32_t array[ATA_PDC_MAX_HPKT]; - int head, tail; - int busy; + struct mtx mtx; +#if 0 + u_int32_t array[ATA_PDC_MAX_HPKT]; + int head, tail; +#else + TAILQ_HEAD(, host_packet) queue; +#endif + int busy; }; int @@ -1281,18 +1365,18 @@ ata_promise_ident(device_t dev) struct ata_pci_controller *ctlr = device_get_softc(dev); struct ata_chip_id *idx; static struct ata_chip_id ids[] = - {{ ATA_PDC20246, 0, PROLD, 0x00, ATA_UDMA2, "Promise PDC20246" }, - { ATA_PDC20262, 0, PRNEW, 0x00, ATA_UDMA4, "Promise PDC20262" }, - { ATA_PDC20263, 0, PRNEW, 0x00, ATA_UDMA4, "Promise PDC20263" }, - { ATA_PDC20265, 0, PRNEW, 0x00, ATA_UDMA5, "Promise PDC20265" }, - { ATA_PDC20267, 0, PRNEW, 0x00, ATA_UDMA5, "Promise PDC20267" }, - { ATA_PDC20268, 0, PRTX, PRTX4, ATA_UDMA5, "Promise PDC20268" }, - { ATA_PDC20269, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20269" }, - { ATA_PDC20270, 0, PRTX, PRTX4, ATA_UDMA5, "Promise PDC20270" }, - { ATA_PDC20271, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20271" }, - { ATA_PDC20275, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20275" }, - { ATA_PDC20276, 0, PRTX, PRSX6K, ATA_UDMA6, "Promise PDC20276" }, - { ATA_PDC20277, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20277" }, + {{ ATA_PDC20246, 0, PROLD, 0x00, ATA_UDMA2, "Promise PDC20246" }, + { ATA_PDC20262, 0, PRNEW, 0x00, ATA_UDMA4, "Promise PDC20262" }, + { ATA_PDC20263, 0, PRNEW, 0x00, ATA_UDMA4, "Promise PDC20263" }, + { ATA_PDC20265, 0, PRNEW, 0x00, ATA_UDMA5, "Promise PDC20265" }, + { ATA_PDC20267, 0, PRNEW, 0x00, ATA_UDMA5, "Promise PDC20267" }, + { ATA_PDC20268, 0, PRTX, PRTX4, ATA_UDMA5, "Promise PDC20268" }, + { ATA_PDC20269, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20269" }, + { ATA_PDC20270, 0, PRTX, PRTX4, ATA_UDMA5, "Promise PDC20270" }, + { ATA_PDC20271, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20271" }, + { ATA_PDC20275, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20275" }, + { ATA_PDC20276, 0, PRTX, PRSX6K, ATA_UDMA6, "Promise PDC20276" }, + { ATA_PDC20277, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20277" }, { ATA_PDC20318, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20318" }, { ATA_PDC20319, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20319" }, { ATA_PDC20371, 0, PRMIO, PRCMBO, ATA_SA150, "Promise PDC20371" }, @@ -1400,8 +1484,8 @@ ata_promise_chipinit(device_t dev) break; case PRMIO: -// if (ctlr->r_res1) -// bus_release_resource(dev, ctlr->r_type1, ctlr->r_rid1,ctlr->r_res1); +// if (ctlr->r_res1) +// bus_release_resource(dev, ctlr->r_type1, ctlr->r_rid1,ctlr->r_res1); ctlr->r_type1 = SYS_RES_MEMORY; ctlr->r_rid1 = PCIR_BAR(4); if (!(ctlr->r_res1 = bus_alloc_resource_any(dev, ctlr->r_type1, @@ -1411,43 +1495,25 @@ ata_promise_chipinit(device_t dev) ctlr->r_type2 = SYS_RES_MEMORY; ctlr->r_rid2 = PCIR_BAR(3); if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2, - &ctlr->r_rid2, RF_ACTIVE))) + &ctlr->r_rid2, RF_ACTIVE))){ + bus_release_resource(dev, ctlr->r_type1, ctlr->r_rid1,ctlr->r_res1); return ENXIO; - + } ctlr->reset = ata_promise_mio_reset; ctlr->dmainit = ata_promise_mio_dmainit; ctlr->allocate = ata_promise_mio_allocate; - switch (ctlr->chip->cfg2) { - case PRPATA: - ctlr->channels = ((ATA_INL(ctlr->r_res2, 0x48) & 0x01) > 0) + - ((ATA_INL(ctlr->r_res2, 0x48) & 0x02) > 0) + 2; - break; - - case PRCMBO: - ATA_OUTL(ctlr->r_res2, 0x06c, 0x000000ff); - ctlr->channels = ((ATA_INL(ctlr->r_res2, 0x48) & 0x02) > 0) + 3; - break; - - case PRSATA: - ATA_OUTL(ctlr->r_res2, 0x06c, 0x000000ff); - ctlr->channels = 4; - break; - - case PRCMBO2: - ATA_OUTL(ctlr->r_res2, 0x060, 0x000000ff); - ctlr->channels = 3; - break; - - case PRSATA2: - ATA_OUTL(ctlr->r_res2, 0x060, 0x000000ff); - ctlr->channels = 4; - break; - - case PRSX4X: { + if (ctlr->chip->cfg2 == PRSX4X) { struct ata_promise_sx4 *hpkt; u_int32_t dimm = ATA_INL(ctlr->r_res2, 0x000c0080); + if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, + ata_promise_sx4_intr, ctlr, &ctlr->handle))) { + device_printf(dev, "unable to setup interrupt\n"); + /* XXX SOS release resources */ + return ENXIO; + } + /* print info about cache memory */ device_printf(dev, "DIMM size %dMB @ 0x%08x%s\n", (((dimm >> 16) & 0xff)-((dimm >> 24) & 0xff)+1) << 4, @@ -1455,34 +1521,63 @@ ata_promise_chipinit(device_t dev) ATA_INL(ctlr->r_res2, 0x000c0088) & (1<<16) ? " ECC enabled" : "" ); + /* adjust cache memory parameters */ ATA_OUTL(ctlr->r_res2, 0x000c000c, (ATA_INL(ctlr->r_res2, 0x000c000c) & 0xffff0000)); - ctlr->driver = malloc(sizeof(struct ata_promise_sx4), - M_TEMP, M_NOWAIT | M_ZERO); - hpkt = ctlr->driver; + /* setup host packet controls */ + hpkt = malloc(sizeof(struct ata_promise_sx4), + M_TEMP, M_NOWAIT | M_ZERO); mtx_init(&hpkt->mtx, "ATA promise HPKT lock", NULL, MTX_DEF); - hpkt->busy = hpkt->head = hpkt->tail = 0; - - ctlr->channels = 4; - - if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, - ata_promise_sx4_intr, ctlr, &ctlr->handle))) { - device_printf(dev, "unable to setup interrupt\n"); - return ENXIO; - } + TAILQ_INIT(&hpkt->queue); + hpkt->busy = 0; //hpkt->head = hpkt->tail = 0; + device_set_ivars(dev, hpkt); + ctlr->channels = 4; return 0; - } } if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, ata_promise_mio_intr, ctlr, &ctlr->handle))) { device_printf(dev, "unable to setup interrupt\n"); + /* XXX SOS release resources */ return ENXIO; } - return 0; + + switch (ctlr->chip->cfg2) { + case PRPATA: + ctlr->channels = ((ATA_INL(ctlr->r_res2, 0x48) & 0x01) > 0) + + ((ATA_INL(ctlr->r_res2, 0x48) & 0x02) > 0) + 2; + break; + + case PRCMBO: + ATA_OUTL(ctlr->r_res2, 0x06c, 0x000000ff); + ctlr->channels = ((ATA_INL(ctlr->r_res2, 0x48) & 0x02) > 0) + 3; + break; + + case PRSATA: + ATA_OUTL(ctlr->r_res2, 0x06c, 0x000000ff); + ctlr->channels = 4; + break; + + case PRCMBO2: + ATA_OUTL(ctlr->r_res2, 0x060, 0x000000ff); + ctlr->channels = 3; + break; + + case PRSATA2: + ATA_OUTL(ctlr->r_res2, 0x060, 0x000000ff); + ctlr->channels = 4; + break; + + default: + /* XXX SOS release resources */ + return ENXIO; + } + default: + /* XXX SOS release resources */ + return ENXIO; } - return ENXIO; + return 0; } static int @@ -1500,11 +1595,13 @@ ata_promise_mio_allocate(device_t dev, struct ata_channel *ch) ch->r_io[ATA_ALTSTAT].offset = offset + 0x0238 + (ch->unit << 7); ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2; ch->flags |= ATA_USE_16BIT; + if ((ctlr->chip->cfg2 & (PRSATA | PRSATA2)) || ((ctlr->chip->cfg2 & (PRCMBO | PRCMBO2)) && ch->unit < 2)) ch->flags |= ATA_NO_SLAVE; + ata_generic_hw(ch); - if (ctlr->chip->cfg2 & PRSX4X) + if (offset) ch->hw.command = ata_promise_sx4_command; else ch->hw.command = ata_promise_mio_command; @@ -1516,26 +1613,74 @@ ata_promise_mio_intr(void *data) { struct ata_pci_controller *ctlr = data; struct ata_channel *ch; - u_int32_t vector = ATA_INL(ctlr->r_res2, 0x00040); - u_int32_t status = 0; + u_int32_t vector = 0, status = 0; int unit; - if (ctlr->chip->cfg2 & (PRSATA | PRCMBO)) { + switch (ctlr->chip->cfg2) { + case PRSATA: + case PRCMBO: + /* read and acknowledge interrupt(s) */ + vector = ATA_INL(ctlr->r_res2, 0x040); + + /* read and clear interface status */ status = ATA_INL(ctlr->r_res2, 0x06c); ATA_OUTL(ctlr->r_res2, 0x06c, status & 0x000000ff); - } - if (ctlr->chip->cfg2 & (PRSATA2 | PRCMBO2)) { + break; + + case PRSATA2: + case PRCMBO2: + /* read and acknowledge interrupt(s) */ + vector = ATA_INL(ctlr->r_res2, 0x040); ATA_OUTL(ctlr->r_res2, 0x040, vector & 0x0000ffff); + + /* read and clear interface status */ status = ATA_INL(ctlr->r_res2, 0x060); ATA_OUTL(ctlr->r_res2, 0x060, status & 0x000000ff); + break; } + for (unit = 0; unit < ctlr->channels; unit++) { - if (status & (0x00000011 << unit)) - if ((ch = ctlr->interrupt[unit].argument)) - ata_promise_mio_reset(ch); - if (vector & (1 << (unit + 1))) - if ((ch = ctlr->interrupt[unit].argument)) - ctlr->interrupt[unit].function(ch); + + if ((ch = ctlr->interrupt[unit].argument)) { + + /* check for and handle disconnect events */ + if (status & (0x00000001 << unit)) { + struct ata_connect_task *tp = (struct ata_connect_task *) + malloc(sizeof(struct ata_connect_task), + M_ATA, M_NOWAIT | M_ZERO); + + if (bootverbose) + device_printf(ch->dev, "DISCONNECT requested\n"); + tp->action = ATA_C_DETACH; + tp->dev = ch->dev; + TASK_INIT(&tp->task, 0, ata_sata_connect, tp); + taskqueue_enqueue(taskqueue_thread, &tp->task); + } + + /* check for and handle connect events */ + if (status & (0x00000010 << unit)) { + struct ata_connect_task *tp = (struct ata_connect_task *) + malloc(sizeof(struct ata_connect_task), + M_ATA, M_NOWAIT | M_ZERO); + + if (bootverbose) + device_printf(ch->dev, "CONNECT requested\n"); + + /* if we dont get "connect well" reset the channel */ + if (!(status & (0x00000100 << unit))) + ctlr->reset(ch); + + tp->action = ATA_C_ATTACH; + tp->dev = ch->dev; + TASK_INIT(&tp->task, 0, ata_sata_connect, tp); + taskqueue_enqueue(taskqueue_thread, &tp->task); + } + + /* active interrupt(s) need to call the interrupt handler */ + if (vector & (1 << (unit + 1))) + if ((ch = ctlr->interrupt[unit].argument)) + ctlr->interrupt[unit].function(ch); + } } } @@ -1596,6 +1741,40 @@ ata_promise_mio_dmainit(struct ata_channel *ch) } } +static int +ata_promise_connect(struct ata_channel *ch) +{ + struct ata_pci_controller *ctlr = + device_get_softc(device_get_parent(ch->dev)); + u_int32_t status; + int loop, retry; + + if ((ATA_INL(ctlr->r_res2, 0x408 + (ch->unit << 8)) & 0x07) == 0) { + status = ATA_INL(ctlr->r_res2, 0x400 + (ch->unit << 8)); + if ((status & 0x737) == 0x113 || (status & 0x737) == 0x123) + return 1; + } + for (retry = 0; retry < 10; retry++) { + for (loop = 0; loop < 10; loop++) { + ATA_OUTL(ctlr->r_res2, 0x408 + (ch->unit << 8), 1); + ata_udelay(100); + if ((ATA_INL(ctlr->r_res2, 0x408 + (ch->unit << 8)) & 0x07) == 1) + break; + } + ata_udelay(1000); + for (loop = 0; loop < 10; loop++) { + ATA_OUTL(ctlr->r_res2, 0x408 + (ch->unit << 8), 0); + ata_udelay(100); + if ((ATA_INL(ctlr->r_res2, 0x408 + (ch->unit << 8)) & 0x07) == 0) + break; + } + status = ATA_INL(ctlr->r_res2, 0x400 + (ch->unit << 8)); + if ((status & 0x737) == 0x113 || (status & 0x737) == 0x123) + return 1; + } + return 0; +} + static void ata_promise_mio_reset(struct ata_channel *ch) { @@ -1604,42 +1783,38 @@ ata_promise_mio_reset(struct ata_channel *ch) switch (ctlr->chip->cfg2) { case PRSX4X: { - struct ata_promise_sx4 *hpktp = ctlr->driver; + struct ata_promise_sx4 *hpktp = device_get_ivars(ctlr->dev); /* softreset channel ATA module */ ATA_OUTL(ctlr->r_res2, 0xc0260 + (ch->unit << 7), ch->unit + 1); - DELAY(1000); + ata_udelay(1000); ATA_OUTL(ctlr->r_res2, 0xc0260 + (ch->unit << 7), (ATA_INL(ctlr->r_res2, 0xc0260 + (ch->unit << 7)) & ~0x00003f9f) | (ch->unit + 1)); - /* softreset HOST module */ + /* softreset HOST module XXX SOS what about other outstandings */ mtx_lock(&hpktp->mtx); ATA_OUTL(ctlr->r_res2, 0xc012c, (ATA_INL(ctlr->r_res2, 0xc012c) & ~0x00000f9f) | (1 << 11)); DELAY(10); ATA_OUTL(ctlr->r_res2, 0xc012c, (ATA_INL(ctlr->r_res2, 0xc012c) & ~0x00000f9f)); + hpktp->busy = 0; mtx_unlock(&hpktp->mtx); - } - break; - - case PRCMBO: - case PRCMBO2: - /* softreset channel ATA module */ - ATA_OUTL(ctlr->r_res2, 0x0260 + (ch->unit << 7), (1 << 11)); - ata_udelay(10000); - ATA_OUTL(ctlr->r_res2, 0x0260 + (ch->unit << 7), - (ATA_INL(ctlr->r_res2, 0x0260 + (ch->unit << 7)) & - ~0x00003f9f) | (ch->unit + 1)); + } break; + case PRCMBO: case PRSATA: { u_int32_t status = 0; int timeout; - /* mask plug/unplug intr */ - ATA_OUTL(ctlr->r_res2, 0x06c, (0x00110000 << ch->unit)); + if ((ctlr->chip->cfg2 == PRSATA) || + ((ctlr->chip->cfg2 == PRCMBO) && (ch->unit < 2))) { + + /* mask plug/unplug intr */ + ATA_OUTL(ctlr->r_res2, 0x06c, (0x00110000 << ch->unit)); + } /* softreset channels ATA module */ ATA_OUTL(ctlr->r_res2, 0x0260 + (ch->unit << 7), (1 << 11)); @@ -1648,32 +1823,42 @@ ata_promise_mio_reset(struct ata_channel *ch) (ATA_INL(ctlr->r_res2, 0x0260 + (ch->unit << 7)) & ~0x00003f9f) | (ch->unit + 1)); - /* enable PHY XXX SOS */ - /* wait up to 1 sec for "connect well" */ - for (timeout = 0; timeout > 1000000 ; timeout += 100) { + if ((ctlr->chip->cfg2 == PRSATA) || + ((ctlr->chip->cfg2 == PRCMBO) && (ch->unit < 2))) { + + /* enable PHY and try to connect */ + ata_promise_connect(ch); + + /* wait up to 1 sec for "connect well" */ + for (timeout = 0; timeout < 100 ; timeout++) { status = ATA_INL(ctlr->r_res2, 0x400 + (ch->unit << 8)); + if (((status & 0x717) == 0x113) && + (ATA_IDX_INB(ch, ATA_STATUS) != 0xff)) + break; + ata_udelay(10000); + } + if (timeout >= 100) + device_printf(ch->dev, "connect status=%08x\n", status); - if ((status & 0x313) == 0x112) - break; - ata_udelay(10000); + /* reset and enable plug/unplug intr */ + ATA_OUTL(ctlr->r_res2, 0x06c, (0x00000011 << ch->unit)); + } } - if (timeout >= 1000000) - device_printf(ch->dev, "connect status=%08x\n", status); - - /* reset and enable plug/unplug intr */ - ATA_OUTL(ctlr->r_res2, 0x06c, (0x00000011 << ch->unit)); - } break; + case PRCMBO2: case PRSATA2: { u_int32_t status = 0; int timeout; - /* set portmultiplier port */ - ATA_OUTL(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f); + if ((ctlr->chip->cfg2 == PRSATA2) || + ((ctlr->chip->cfg2 == PRCMBO2) && (ch->unit < 2))) { + /* set portmultiplier port */ + ATA_OUTL(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f); - /* mask plug/unplug intr */ - ATA_OUTL(ctlr->r_res2, 0x060, (0x00110000 << ch->unit)); + /* mask plug/unplug intr */ + ATA_OUTL(ctlr->r_res2, 0x060, (0x00110000 << ch->unit)); + } /* softreset channels ATA module */ ATA_OUTL(ctlr->r_res2, 0x0260 + (ch->unit << 7), (1 << 11)); @@ -1682,28 +1867,34 @@ ata_promise_mio_reset(struct ata_channel *ch) (ATA_INL(ctlr->r_res2, 0x0260 + (ch->unit << 7)) & ~0x00003f9f) | (ch->unit + 1)); - /* enable PHY XXX SOS */ - /* set PHY mode to "improved" */ - ATA_OUTL(ctlr->r_res2, 0x414 + (ch->unit << 8), - (ATA_INL(ctlr->r_res2, 0x414 + (ch->unit << 8)) & - ~0x00000003) | 0x00000001); + if ((ctlr->chip->cfg2 == PRSATA2) || + ((ctlr->chip->cfg2 == PRCMBO2) && (ch->unit < 2))) { - /* wait up to 1 sec for "connect well" */ - for (timeout = 0; timeout > 1000000 ; timeout += 100) { - status = ATA_INL(ctlr->r_res2, 0x400 + (ch->unit << 8)); + /* set PHY mode to "improved" */ + ATA_OUTL(ctlr->r_res2, 0x414 + (ch->unit << 8), + (ATA_INL(ctlr->r_res2, 0x414 + (ch->unit << 8)) & + ~0x00000003) | 0x00000001); - if ((status & 0x737) == 0x113 || (status & 0x727) == 0x123) - break; - ata_udelay(10000); - } - if (timeout >= 1000000) - device_printf(ch->dev, "connect status=%08x\n", status); + /* enable PHY and try to connect */ + ata_promise_connect(ch); - /* reset and enable plug/unplug intr */ - ATA_OUTL(ctlr->r_res2, 0x060, (0x00000011 << ch->unit)); + /* wait up to 1 sec for "connect well" */ + for (timeout = 0; timeout < 100 ; timeout++) { + status = ATA_INL(ctlr->r_res2, 0x400 + (ch->unit << 8)); + if (((status & 0x737) == 0x113 || (status & 0x737) == 0x123) && + (ATA_IDX_INB(ch, ATA_STATUS) != 0xff)) + break; + ata_udelay(10000); + } + if (timeout >= 100) + device_printf(ch->dev, "connect status=%08x\n", status); + + /* reset and enable plug/unplug intr */ + ATA_OUTL(ctlr->r_res2, 0x060, (0x00000011 << ch->unit)); - /* set portmultiplier port */ - ATA_OUTL(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x00); + /* set portmultiplier port */ + ATA_OUTL(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x00); + } } break; } @@ -1713,30 +1904,29 @@ static int ata_promise_mio_command(struct ata_device *atadev, u_int8_t command, u_int64_t lba, u_int16_t count, u_int16_t feature) { - struct ata_pci_controller *ctlr = - device_get_softc(device_get_parent(atadev->channel->dev)); - u_int32_t *wordp = (u_int32_t *)atadev->channel->dma->workspace; + struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(atadev->dev)); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); + u_int32_t *wordp = (u_int32_t *)ch->dma->work; - ATA_OUTL(ctlr->r_res2, (atadev->channel->unit + 1) << 2, 0x00000001); + ATA_OUTL(ctlr->r_res2, (ch->unit + 1) << 2, 0x00000001); switch (command) { default: return ata_generic_command(atadev, command, lba, count, feature); case ATA_READ_DMA: - wordp[0] = htole32(0x04 | ((atadev->channel->unit+1)<<16) | (0x00<<24)); + wordp[0] = htole32(0x04 | ((ch->unit + 1) << 16) | (0x00 << 24)); break; case ATA_WRITE_DMA: - wordp[0] = htole32(0x00 | ((atadev->channel->unit+1)<<16) | (0x00<<24)); + wordp[0] = htole32(0x00 | ((ch->unit + 1) << 16) | (0x00 << 24)); break; } - wordp[1] = htole32(atadev->channel->dma->mdmatab); + wordp[1] = htole32(ch->dma->sg_bus); wordp[2] = 0; ata_promise_apkt((u_int8_t*)wordp, atadev, command, lba, count, feature); - ATA_OUTL(ctlr->r_res2, 0x0240 + (atadev->channel->unit << 7), - atadev->channel->dma->wdmatab); + ATA_OUTL(ctlr->r_res2, 0x0240 + (ch->unit << 7), ch->dma->work_bus); return 0; } @@ -1744,10 +1934,10 @@ static int ata_promise_sx4_command(struct ata_device *atadev, u_int8_t command, u_int64_t lba, u_int16_t count, u_int16_t feature) { - struct ata_channel *ch = atadev->channel; - struct ata_dma_prdentry *prd = ch->dma->dmatab; - struct ata_pci_controller *ctlr = - device_get_softc(device_get_parent(ch->dev)); + device_t gparent = GRANDPARENT(atadev->dev); + struct ata_pci_controller *ctlr = device_get_softc(gparent); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); + struct ata_dma_prdentry *prd = ch->dma->sg; caddr_t window = rman_get_virtual(ctlr->r_res1); u_int32_t *wordp; int i, idx, length = 0; @@ -1844,6 +2034,7 @@ static int ata_promise_apkt(u_int8_t *bytep, struct ata_device *atadev, u_int8_t command, u_int64_t lba, u_int16_t count, u_int16_t feature) { + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); int i = 12; bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_PDC_WAIT_NBUSY|ATA_DRIVE; @@ -1851,9 +2042,9 @@ ata_promise_apkt(u_int8_t *bytep, struct ata_device *atadev, u_int8_t command, bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_CTL; bytep[i++] = ATA_A_4BIT; - if ((lba >= ATA_MAX_28BIT_LBA || count > 256) && atadev->param && - (atadev->param->support.command2 & ATA_SUPPORT_ADDRESS48)) { - atadev->channel->flags |= ATA_48BIT_ACTIVE; + if ((lba >= ATA_MAX_28BIT_LBA || count > 256) && + (atadev->param.support.command2 & ATA_SUPPORT_ADDRESS48)) { + ch->flags |= ATA_48BIT_ACTIVE; if (command == ATA_READ_DMA) command = ATA_READ_DMA48; if (command == ATA_WRITE_DMA) @@ -1877,7 +2068,7 @@ ata_promise_apkt(u_int8_t *bytep, struct ata_device *atadev, u_int8_t command, bytep[i++] = ATA_D_LBA | atadev->unit; } else { - atadev->channel->flags &= ~ATA_48BIT_ACTIVE; + ch->flags &= ~ATA_48BIT_ACTIVE; bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_FEATURE; bytep[i++] = feature; bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_COUNT; @@ -1900,28 +2091,50 @@ ata_promise_apkt(u_int8_t *bytep, struct ata_device *atadev, u_int8_t command, static void ata_promise_queue_hpkt(struct ata_pci_controller *ctlr, u_int32_t hpkt) { - struct ata_promise_sx4 *hpktp = ctlr->driver; + struct ata_promise_sx4 *hpktp = device_get_ivars(ctlr->dev); mtx_lock(&hpktp->mtx); +#if 0 if (hpktp->tail == hpktp->head && !hpktp->busy) { ATA_OUTL(ctlr->r_res2, 0x000c0100, hpkt); hpktp->busy = 1; } else hpktp->array[(hpktp->head++) & (ATA_PDC_MAX_HPKT - 1)] = hpkt; +#else + if (hpktp->busy) { + struct host_packet *hp = + malloc(sizeof(struct host_packet), M_TEMP, M_NOWAIT | M_ZERO); + hp->addr = hpkt; + TAILQ_INSERT_TAIL(&hpktp->queue, hp, chain); + } + else { + hpktp->busy = 1; + ATA_OUTL(ctlr->r_res2, 0x000c0100, hpkt); + } +#endif mtx_unlock(&hpktp->mtx); } static void ata_promise_next_hpkt(struct ata_pci_controller *ctlr) { - struct ata_promise_sx4 *hpktp = ctlr->driver; + struct ata_promise_sx4 *hpktp = device_get_ivars(ctlr->dev); + struct host_packet *hp; mtx_lock(&hpktp->mtx); +#if 0 if (hpktp->tail != hpktp->head) { ATA_OUTL(ctlr->r_res2, 0x000c0100, hpktp->array[(hpktp->tail++) & (ATA_PDC_MAX_HPKT - 1)]); } +#else + if ((hp = TAILQ_FIRST(&hpktp->queue))) { + TAILQ_REMOVE(&hpktp->queue, hp, chain); + ATA_OUTL(ctlr->r_res2, 0x000c0100, hp->addr); + free(hp, M_TEMP); + } +#endif else hpktp->busy = 0; mtx_unlock(&hpktp->mtx); @@ -1995,7 +2208,7 @@ ata_promise_new_dmastart(struct ata_channel *ch) } ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) | (ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR))); - ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->mdmatab); + ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->sg_bus); ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, ((ch->dma->flags & ATA_DMA_READ) ? ATA_BMCMD_WRITE_READ : 0) | ATA_BMCMD_START_STOP); @@ -2036,26 +2249,27 @@ ata_promise_new_dmainit(struct ata_channel *ch) static void ata_promise_setmode(struct ata_device *atadev, int mode) { - device_t parent = device_get_parent(atadev->channel->dev); - struct ata_pci_controller *ctlr = device_get_softc(parent); - int devno = (atadev->channel->unit << 1) + ATA_DEV(atadev->unit); + device_t gparent = GRANDPARENT(atadev->dev); + struct ata_pci_controller *ctlr = device_get_softc(gparent); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); + int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); int error; u_int32_t timings33[][2] = { - /* PROLD PRNEW mode */ - { 0x004ff329, 0x004fff2f }, /* PIO 0 */ - { 0x004fec25, 0x004ff82a }, /* PIO 1 */ - { 0x004fe823, 0x004ff026 }, /* PIO 2 */ - { 0x004fe622, 0x004fec24 }, /* PIO 3 */ - { 0x004fe421, 0x004fe822 }, /* PIO 4 */ - { 0x004567f3, 0x004acef6 }, /* MWDMA 0 */ - { 0x004467f3, 0x0048cef6 }, /* MWDMA 1 */ - { 0x004367f3, 0x0046cef6 }, /* MWDMA 2 */ - { 0x004367f3, 0x0046cef6 }, /* UDMA 0 */ - { 0x004247f3, 0x00448ef6 }, /* UDMA 1 */ - { 0x004127f3, 0x00436ef6 }, /* UDMA 2 */ - { 0, 0x00424ef6 }, /* UDMA 3 */ - { 0, 0x004127f3 }, /* UDMA 4 */ - { 0, 0x004127f3 } /* UDMA 5 */ + /* PROLD PRNEW mode */ + { 0x004ff329, 0x004fff2f }, /* PIO 0 */ + { 0x004fec25, 0x004ff82a }, /* PIO 1 */ + { 0x004fe823, 0x004ff026 }, /* PIO 2 */ + { 0x004fe622, 0x004fec24 }, /* PIO 3 */ + { 0x004fe421, 0x004fe822 }, /* PIO 4 */ + { 0x004567f3, 0x004acef6 }, /* MWDMA 0 */ + { 0x004467f3, 0x0048cef6 }, /* MWDMA 1 */ + { 0x004367f3, 0x0046cef6 }, /* MWDMA 2 */ + { 0x004367f3, 0x0046cef6 }, /* UDMA 0 */ + { 0x004247f3, 0x00448ef6 }, /* UDMA 1 */ + { 0x004127f3, 0x00436ef6 }, /* UDMA 2 */ + { 0, 0x00424ef6 }, /* UDMA 3 */ + { 0, 0x004127f3 }, /* UDMA 4 */ + { 0, 0x004127f3 } /* UDMA 5 */ }; mode = ata_limit_mode(atadev, mode, ctlr->chip->max_dma); @@ -2063,22 +2277,20 @@ ata_promise_setmode(struct ata_device *atadev, int mode) switch (ctlr->chip->cfg1) { case PROLD: case PRNEW: - if (mode > ATA_UDMA2 && (pci_read_config(parent, 0x50, 2) & - (atadev->channel->unit ? 1 << 11 : 1 << 10))) { - ata_prtdev(atadev, - "DMA limited to UDMA33, non-ATA66 cable or device\n"); + if (mode > ATA_UDMA2 && (pci_read_config(gparent, 0x50, 2) & + (ch->unit ? 1 << 11 : 1 << 10))) { + ata_print_cable(atadev->dev, "controller"); mode = ATA_UDMA2; } - if (ATAPI_DEVICE(atadev) && mode > ATA_PIO_MAX) + if (ata_atapi(atadev) && mode > ATA_PIO_MAX) mode = ata_limit_mode(atadev, mode, ATA_PIO_MAX); break; case PRTX: - ATA_IDX_OUTB(atadev->channel, ATA_BMDEVSPEC_0, 0x0b); + ATA_IDX_OUTB(ch, ATA_BMDEVSPEC_0, 0x0b); if (mode > ATA_UDMA2 && - ATA_IDX_INB(atadev->channel, ATA_BMDEVSPEC_1) & 0x04) { - ata_prtdev(atadev, - "DMA limited to UDMA33, non-ATA66 cable or device\n"); + ATA_IDX_INB(ch, ATA_BMDEVSPEC_1) & 0x04) { + ata_print_cable(atadev->dev, "controller"); mode = ATA_UDMA2; } break; @@ -2087,9 +2299,8 @@ ata_promise_setmode(struct ata_device *atadev, int mode) if (mode > ATA_UDMA2 && (ATA_INL(ctlr->r_res2, (ctlr->chip->cfg2 & PRSX4X ? 0x000c0260 : 0x0260) + - (atadev->channel->unit << 7)) & 0x01000000)) { - ata_prtdev(atadev, - "DMA limited to UDMA33, non-ATA66 cable or device\n"); + (ch->unit << 7)) & 0x01000000)) { + ata_print_cable(atadev->dev, "controller"); mode = ATA_UDMA2; } break; @@ -2098,12 +2309,12 @@ ata_promise_setmode(struct ata_device *atadev, int mode) error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); if (bootverbose) - ata_prtdev(atadev, "%ssetting %s on %s chip\n", - (error) ? "FAILURE " : "", - ata_mode2str(mode), ctlr->chip->text); + device_printf(atadev->dev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", + ata_mode2str(mode), ctlr->chip->text); if (!error) { if (ctlr->chip->cfg1 < PRTX) - pci_write_config(parent, 0x60 + (devno << 2), + pci_write_config(gparent, 0x60 + (devno << 2), timings33[ctlr->chip->cfg1][ata_mode2idx(mode)],4); atadev->mode = mode; } @@ -2174,9 +2385,10 @@ ata_serverworks_chipinit(device_t dev) static void ata_serverworks_setmode(struct ata_device *atadev, int mode) { - device_t parent = device_get_parent(atadev->channel->dev); - struct ata_pci_controller *ctlr = device_get_softc(parent); - int devno = (atadev->channel->unit << 1) + ATA_DEV(atadev->unit); + device_t gparent = GRANDPARENT(atadev->dev); + struct ata_pci_controller *ctlr = device_get_softc(gparent); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); + int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); int offset = (devno ^ 0x01) << 3; int error; u_int8_t piotimings[] = { 0x5d, 0x47, 0x34, 0x22, 0x20, 0x34, 0x22, 0x20, @@ -2190,39 +2402,39 @@ ata_serverworks_setmode(struct ata_device *atadev, int mode) error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); if (bootverbose) - ata_prtdev(atadev, "%ssetting %s on %s chip\n", - (error) ? "FAILURE " : "", - ata_mode2str(mode), ctlr->chip->text); + device_printf(atadev->dev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", + ata_mode2str(mode), ctlr->chip->text); if (!error) { if (mode >= ATA_UDMA0) { - pci_write_config(parent, 0x56, - (pci_read_config(parent, 0x56, 2) & + pci_write_config(gparent, 0x56, + (pci_read_config(gparent, 0x56, 2) & ~(0xf << (devno << 2))) | ((mode & ATA_MODE_MASK) << (devno << 2)), 2); - pci_write_config(parent, 0x54, - pci_read_config(parent, 0x54, 1) | + pci_write_config(gparent, 0x54, + pci_read_config(gparent, 0x54, 1) | (0x01 << devno), 1); - pci_write_config(parent, 0x44, - (pci_read_config(parent, 0x44, 4) & + pci_write_config(gparent, 0x44, + (pci_read_config(gparent, 0x44, 4) & ~(0xff << offset)) | (dmatimings[2] << offset), 4); } else if (mode >= ATA_WDMA0) { - pci_write_config(parent, 0x54, - pci_read_config(parent, 0x54, 1) & + pci_write_config(gparent, 0x54, + pci_read_config(gparent, 0x54, 1) & ~(0x01 << devno), 1); - pci_write_config(parent, 0x44, - (pci_read_config(parent, 0x44, 4) & + pci_write_config(gparent, 0x44, + (pci_read_config(gparent, 0x44, 4) & ~(0xff << offset)) | (dmatimings[mode & ATA_MODE_MASK] << offset),4); } else - pci_write_config(parent, 0x54, - pci_read_config(parent, 0x54, 1) & + pci_write_config(gparent, 0x54, + pci_read_config(gparent, 0x54, 1) & ~(0x01 << devno), 1); - pci_write_config(parent, 0x40, - (pci_read_config(parent, 0x40, 4) & + pci_write_config(gparent, 0x40, + (pci_read_config(gparent, 0x40, 4) & ~(0xff << offset)) | (piotimings[ata_mode2idx(mode)] << offset), 4); atadev->mode = mode; @@ -2230,7 +2442,7 @@ ata_serverworks_setmode(struct ata_device *atadev, int mode) } /* - * Silicon Image (former CMD) chipset support functions + * Silicon Image Inc. (SiI) (former CMD) chipset support functions */ int ata_sii_ident(device_t dev) @@ -2238,18 +2450,18 @@ ata_sii_ident(device_t dev) struct ata_pci_controller *ctlr = device_get_softc(dev); struct ata_chip_id *idx; static struct ata_chip_id ids[] = - {{ ATA_SII3114, 0x00, SIIMEMIO, SII4CH, ATA_SA150, "SiI 3114" }, - { ATA_SII3512, 0x02, SIIMEMIO, 0, ATA_SA150, "SiI 3512" }, - { ATA_SII3112, 0x02, SIIMEMIO, 0, ATA_SA150, "SiI 3112" }, - { ATA_SII3112_1, 0x02, SIIMEMIO, 0, ATA_SA150, "SiI 3112" }, - { ATA_SII3512, 0x00, SIIMEMIO, SIIBUG, ATA_SA150, "SiI 3512" }, - { ATA_SII3112, 0x00, SIIMEMIO, SIIBUG, ATA_SA150, "SiI 3112" }, - { ATA_SII3112_1, 0x00, SIIMEMIO, SIIBUG, ATA_SA150, "SiI 3112" }, + {{ ATA_SII3114, 0x00, SIIMEMIO, SII4CH, ATA_SA150, "SiI 3114" }, + { ATA_SII3512, 0x02, SIIMEMIO, 0, ATA_SA150, "SiI 3512" }, + { ATA_SII3112, 0x02, SIIMEMIO, 0, ATA_SA150, "SiI 3112" }, + { ATA_SII3112_1, 0x02, SIIMEMIO, 0, ATA_SA150, "SiI 3112" }, + { ATA_SII3512, 0x00, SIIMEMIO, SIIBUG, ATA_SA150, "SiI 3512" }, + { ATA_SII3112, 0x00, SIIMEMIO, SIIBUG, ATA_SA150, "SiI 3112" }, + { ATA_SII3112_1, 0x00, SIIMEMIO, SIIBUG, ATA_SA150, "SiI 3112" }, { ATA_SII0680, 0x00, SIIMEMIO, SIISETCLK, ATA_UDMA6, "SiI 0680" }, - { ATA_CMD649, 0x00, 0, SIIINTR, ATA_UDMA5, "CMD 649" }, - { ATA_CMD648, 0x00, 0, SIIINTR, ATA_UDMA4, "CMD 648" }, - { ATA_CMD646, 0x07, 0, 0, ATA_UDMA2, "CMD 646U2" }, - { ATA_CMD646, 0x00, 0, 0, ATA_WDMA2, "CMD 646" }, + { ATA_CMD649, 0x00, 0, SIIINTR, ATA_UDMA5, "CMD 649" }, + { ATA_CMD648, 0x00, 0, SIIINTR, ATA_UDMA4, "CMD 648" }, + { ATA_CMD646, 0x07, 0, 0, ATA_UDMA2, "CMD 646U2" }, + { ATA_CMD646, 0x00, 0, 0, ATA_WDMA2, "CMD 646" }, { 0, 0, 0, 0, 0, 0}}; char buffer[64]; @@ -2297,14 +2509,19 @@ ata_sii_chipinit(device_t dev) ctlr->chip->text); } - /* enable interrupt as BIOS might not */ - pci_write_config(dev, 0x8a, (pci_read_config(dev, 0x8a, 1) & 0x3f), 1); - + /* if we have 4 channels enable the second set */ if (ctlr->chip->cfg2 & SII4CH) { ATA_OUTL(ctlr->r_res2, 0x0200, 0x00000002); ctlr->channels = 4; } + /* enable PCI interrupt as BIOS might not */ + pci_write_config(dev, 0x8a, (pci_read_config(dev, 0x8a, 1) & 0x3f), 1); + + /* dont block interrupts from any channel */ + pci_write_config(dev, 0x48, + (pci_read_config(dev, 0x48, 4) & ~0x03c00000), 4); + ctlr->allocate = ata_sii_allocate; if (ctlr->chip->max_dma >= ATA_SA150) { ctlr->reset = ata_sii_reset; @@ -2360,14 +2577,18 @@ ata_sii_allocate(device_t dev, struct ata_channel *ch) ch->r_io[ATA_BMDEVSPEC_1].offset = 0x100 + (unit01 << 7) + (unit10 << 8); ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2; - if (ctlr->chip->max_dma >= ATA_SA150) + if (ctlr->chip->max_dma >= ATA_SA150) { ch->flags |= ATA_NO_SLAVE; + /* enable PHY state change interrupt */ + ATA_OUTL(ctlr->r_res2, 0x148 + (unit01 << 7) + (unit10 << 8),(1 << 16)); + } + if ((ctlr->chip->cfg2 & SIIBUG) && ch->dma) { + /* work around errata in early chips */ ch->dma->boundary = 16 * DEV_BSIZE; ch->dma->max_iosize = 15 * DEV_BSIZE; } - ata_generic_hw(ch); return 0; @@ -2376,10 +2597,37 @@ ata_sii_allocate(device_t dev, struct ata_channel *ch) static void ata_sii_reset(struct ata_channel *ch) { - ATA_IDX_OUTL(ch, ATA_BMDEVSPEC_1, 0x00000001); - DELAY(25000); - ATA_IDX_OUTL(ch, ATA_BMDEVSPEC_1, 0x00000000); - ata_udelay(1000000); + struct ata_pci_controller *ctlr = + device_get_softc(device_get_parent(ch->dev)); + int offset = ((ch->unit & 1) << 7) + ((ch->unit & 2) << 8); + u_int32_t status = 0, error; + int timeout; + + /* disable PHY state change interrupt */ + ATA_OUTL(ctlr->r_res2, 0x148 + offset, ~(1 << 16)); + + /* flip reset bit */ + ATA_OUTL(ctlr->r_res2, 0x100 + offset, 0x00000001); + ata_udelay(25000); + ATA_OUTL(ctlr->r_res2, 0x100 + offset, 0x00000000); + + /* enable PHY and try to connect XXX SOS */ + /* wait up to 1 sec for "connect well" */ + for (timeout = 0; timeout < 100 ; timeout++) { + status = ATA_INL(ctlr->r_res2, 0x104 + offset); + if (((status & 0x717) == 0x113) && ATA_IDX_INB(ch, ATA_STATUS) != 0xff) + break; + ata_udelay(10000); + } + if (timeout >= 100) + device_printf(ch->dev, "connect status=%08x\n", status); + + /* clear error register */ + error = ATA_INL(ctlr->r_res2, 0x108 + offset); + ATA_OUTL(ctlr->r_res2, 0x108 + offset, error); + + /* enable PHY state change interrupt */ + ATA_OUTL(ctlr->r_res2, 0x148 + offset, (1 << 16)); } static void @@ -2393,6 +2641,39 @@ ata_sii_intr(void *data) for (unit = 0; unit < ctlr->channels; unit++) { if (!(ch = ctlr->interrupt[unit].argument)) continue; + + /* check for PHY related interrupts on SATA capable HW */ + if (ctlr->chip->max_dma >= ATA_SA150) { + int offset = ((ch->unit & 1) << 7) + ((ch->unit & 2) << 8); + u_int32_t status = ATA_INL(ctlr->r_res2, 0x104 + offset); + u_int32_t error = ATA_INL(ctlr->r_res2, 0x108 + offset); + + if (error) { + /* clear error bits/interrupt */ + ATA_OUTL(ctlr->r_res2, 0x108 + offset, error); + + /* if we have a connection "surprise" deal with it */ + if (error & (1 << 16)) { + struct ata_connect_task *tp = (struct ata_connect_task *) + malloc(sizeof(struct ata_connect_task), + M_ATA, M_NOWAIT | M_ZERO); + + if ((status & 0x717) == 0x113) { + device_printf(ch->dev, "CONNECT requested\n"); + tp->action = ATA_C_ATTACH; + } + else { + device_printf(ch->dev, "DISCONNECT requested\n"); + tp->action = ATA_C_DETACH; + } + tp->dev = ch->dev; + TASK_INIT(&tp->task, 0, ata_sata_connect, tp); + taskqueue_enqueue(taskqueue_thread, &tp->task); + } + } + } + + /* any drive action to take care of ? */ if (ATA_IDX_INB(ch, ATA_BMDEVSPEC_0) & 0x08) { if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) { int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; @@ -2404,6 +2685,7 @@ ata_sii_intr(void *data) } ctlr->interrupt[unit].function(ch); } + } } @@ -2464,21 +2746,21 @@ ata_cmd_old_intr(void *data) static void ata_sii_setmode(struct ata_device *atadev, int mode) { - device_t parent = device_get_parent(atadev->channel->dev); - struct ata_pci_controller *ctlr = device_get_softc(parent); - int rego = (atadev->channel->unit << 4) + (ATA_DEV(atadev->unit) << 1); - int mreg = atadev->channel->unit ? 0x84 : 0x80; + device_t gparent = GRANDPARENT(atadev->dev); + struct ata_pci_controller *ctlr = device_get_softc(gparent); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); + int rego = (ch->unit << 4) + (ATA_DEV(atadev->unit) << 1); + int mreg = ch->unit ? 0x84 : 0x80; int mask = 0x03 << (ATA_DEV(atadev->unit) << 2); - int mval = pci_read_config(parent, mreg, 1) & ~mask; + int mval = pci_read_config(gparent, mreg, 1) & ~mask; int error; mode = ata_limit_mode(atadev, mode, ctlr->chip->max_dma); if (ctlr->chip->cfg2 & SIISETCLK) { - if (mode > ATA_UDMA2 && (pci_read_config(parent, 0x79, 1) & - (atadev->channel->unit ? 0x02 : 0x01))) { - ata_prtdev(atadev, - "DMA limited to UDMA33, non-ATA66 cable or device\n"); + if (mode > ATA_UDMA2 && (pci_read_config(gparent, 0x79, 1) & + (ch->unit ? 0x02 : 0x01))) { + ata_print_cable(atadev->dev, "controller"); mode = ATA_UDMA2; } } @@ -2488,9 +2770,9 @@ ata_sii_setmode(struct ata_device *atadev, int mode) error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); if (bootverbose) - ata_prtdev(atadev, "%ssetting %s on %s chip\n", - (error) ? "FAILURE " : "", - ata_mode2str(mode), ctlr->chip->text); + device_printf(atadev->dev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", + ata_mode2str(mode), ctlr->chip->text); if (error) return; @@ -2498,10 +2780,10 @@ ata_sii_setmode(struct ata_device *atadev, int mode) u_int8_t udmatimings[] = { 0xf, 0xb, 0x7, 0x5, 0x3, 0x2, 0x1 }; u_int8_t ureg = 0xac + rego; - pci_write_config(parent, mreg, + pci_write_config(gparent, mreg, mval | (0x03 << (ATA_DEV(atadev->unit) << 2)), 1); - pci_write_config(parent, ureg, - (pci_read_config(parent, ureg, 1) & ~0x3f) | + pci_write_config(gparent, ureg, + (pci_read_config(gparent, ureg, 1) & ~0x3f) | udmatimings[mode & ATA_MODE_MASK], 1); } @@ -2509,18 +2791,18 @@ ata_sii_setmode(struct ata_device *atadev, int mode) u_int8_t dreg = 0xa8 + rego; u_int16_t dmatimings[] = { 0x2208, 0x10c2, 0x10c1 }; - pci_write_config(parent, mreg, + pci_write_config(gparent, mreg, mval | (0x02 << (ATA_DEV(atadev->unit) << 2)), 1); - pci_write_config(parent, dreg, dmatimings[mode & ATA_MODE_MASK], 2); + pci_write_config(gparent, dreg, dmatimings[mode & ATA_MODE_MASK], 2); } else { u_int8_t preg = 0xa4 + rego; u_int16_t piotimings[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 }; - pci_write_config(parent, mreg, + pci_write_config(gparent, mreg, mval | (0x01 << (ATA_DEV(atadev->unit) << 2)), 1); - pci_write_config(parent, preg, piotimings[mode & ATA_MODE_MASK], 2); + pci_write_config(gparent, preg, piotimings[mode & ATA_MODE_MASK], 2); } atadev->mode = mode; } @@ -2528,9 +2810,10 @@ ata_sii_setmode(struct ata_device *atadev, int mode) static void ata_cmd_setmode(struct ata_device *atadev, int mode) { - device_t parent = device_get_parent(atadev->channel->dev); - struct ata_pci_controller *ctlr = device_get_softc(parent); - int devno = (atadev->channel->unit << 1) + ATA_DEV(atadev->unit); + device_t gparent = GRANDPARENT(atadev->dev); + struct ata_pci_controller *ctlr = device_get_softc(gparent); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); + int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); int error; mode = ata_limit_mode(atadev, mode, ctlr->chip->max_dma); @@ -2540,38 +2823,38 @@ ata_cmd_setmode(struct ata_device *atadev, int mode) error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); if (bootverbose) - ata_prtdev(atadev, "%ssetting %s on %s chip\n", - (error) ? "FAILURE " : "", - ata_mode2str(mode), ctlr->chip->text); + device_printf(atadev->dev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", + ata_mode2str(mode), ctlr->chip->text); if (!error) { int treg = 0x54 + ((devno < 3) ? (devno << 1) : 7); - int ureg = atadev->channel->unit ? 0x7b : 0x73; + int ureg = ch->unit ? 0x7b : 0x73; - if (mode >= ATA_UDMA0) { + if (mode >= ATA_UDMA0) { int udmatimings[][2] = { { 0x31, 0xc2 }, { 0x21, 0x82 }, { 0x11, 0x42 }, { 0x25, 0x8a }, { 0x15, 0x4a }, { 0x05, 0x0a } }; - u_int8_t umode = pci_read_config(parent, ureg, 1); + u_int8_t umode = pci_read_config(gparent, ureg, 1); umode &= ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca); umode |= udmatimings[mode & ATA_MODE_MASK][ATA_DEV(atadev->unit)]; - pci_write_config(parent, ureg, umode, 1); + pci_write_config(gparent, ureg, umode, 1); } else if (mode >= ATA_WDMA0) { int dmatimings[] = { 0x87, 0x32, 0x3f }; - pci_write_config(parent, treg, dmatimings[mode & ATA_MODE_MASK], 1); - pci_write_config(parent, ureg, - pci_read_config(parent, ureg, 1) & + pci_write_config(gparent, treg, dmatimings[mode & ATA_MODE_MASK], 1); + pci_write_config(gparent, ureg, + pci_read_config(gparent, ureg, 1) & ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca), 1); } else { int piotimings[] = { 0xa9, 0x57, 0x44, 0x32, 0x3f }; - pci_write_config(parent, treg, + pci_write_config(gparent, treg, piotimings[(mode & ATA_MODE_MASK) - ATA_PIO0], 1); - pci_write_config(parent, ureg, - pci_read_config(parent, ureg, 1) & + pci_write_config(gparent, ureg, + pci_read_config(gparent, ureg, 1) & ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca), 1); } atadev->mode = mode; @@ -2579,7 +2862,7 @@ ata_cmd_setmode(struct ata_device *atadev, int mode) } /* - * SiS chipset support functions + * Silicon Integrated Systems Corp. (SiS) chipset support functions */ int ata_sis_ident(device_t dev) @@ -2587,7 +2870,9 @@ ata_sis_ident(device_t dev) struct ata_pci_controller *ctlr = device_get_softc(dev); struct ata_chip_id *idx; static struct ata_chip_id ids[] = - {{ ATA_SIS964_S,0x00, SISSATA, 0, ATA_SA150, "SiS 964" }, /* south */ + {{ ATA_SIS181, 0x00, SISSATA, 0, ATA_SA150, "SiS 181" }, /* south */ + { ATA_SIS180, 0x00, SISSATA, 0, ATA_SA150, "SiS 180" }, /* south */ + { ATA_SIS965, 0x00, SIS133NEW, 0, ATA_UDMA6, "SiS 965" }, /* south */ { ATA_SIS964, 0x00, SIS133NEW, 0, ATA_UDMA6, "SiS 964" }, /* south */ { ATA_SIS963, 0x00, SIS133NEW, 0, ATA_UDMA6, "SiS 963" }, /* south */ { ATA_SIS962, 0x00, SIS133NEW, 0, ATA_UDMA6, "SiS 962" }, /* south */ @@ -2697,26 +2982,25 @@ ata_sis_chipinit(device_t dev) static void ata_sis_setmode(struct ata_device *atadev, int mode) { - device_t parent = device_get_parent(atadev->channel->dev); - struct ata_pci_controller *ctlr = device_get_softc(parent); - int devno = (atadev->channel->unit << 1) + ATA_DEV(atadev->unit); + device_t gparent = GRANDPARENT(atadev->dev); + struct ata_pci_controller *ctlr = device_get_softc(gparent); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); + int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); int error; mode = ata_limit_mode(atadev, mode, ctlr->chip->max_dma); if (ctlr->chip->cfg1 == SIS133NEW) { if (mode > ATA_UDMA2 && - pci_read_config(parent, atadev->channel->unit?0x52:0x50,2)&0x8000){ - ata_prtdev(atadev, - "DMA limited to UDMA33, non-ATA66 cable or device\n"); + pci_read_config(gparent, ch->unit ? 0x52 : 0x50,2) & 0x8000) { + ata_print_cable(atadev->dev, "controller"); mode = ATA_UDMA2; } } else { if (mode > ATA_UDMA2 && - pci_read_config(parent, 0x48, 1)&(atadev->channel->unit?0x20:0x10)){ - ata_prtdev(atadev, - "DMA limited to UDMA33, non-ATA66 cable or device\n"); + pci_read_config(gparent, 0x48, 1)&(ch->unit ? 0x20 : 0x10)) { + ata_print_cable(atadev->dev, "controller"); mode = ATA_UDMA2; } } @@ -2724,9 +3008,9 @@ ata_sis_setmode(struct ata_device *atadev, int mode) error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); if (bootverbose) - ata_prtdev(atadev, "%ssetting %s on %s chip\n", - (error) ? "FAILURE " : "", - ata_mode2str(mode), ctlr->chip->text); + device_printf(atadev->dev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", + ata_mode2str(mode), ctlr->chip->text); if (!error) { switch (ctlr->chip->cfg1) { case SIS133NEW: { @@ -2736,8 +3020,8 @@ ata_sis_setmode(struct ata_device *atadev, int mode) 0x0509347c, 0x0509325c, 0x0509323c, 0x0509322c, 0x0509321c}; u_int32_t reg; - reg = (pci_read_config(parent, 0x57, 1)&0x40?0x70:0x40)+(devno<<2); - pci_write_config(parent, reg, timings[ata_mode2idx(mode)], 4); + reg = (pci_read_config(gparent, 0x57, 1)&0x40?0x70:0x40)+(devno<<2); + pci_write_config(gparent, reg, timings[ata_mode2idx(mode)], 4); break; } case SIS133OLD: { @@ -2747,7 +3031,7 @@ ata_sis_setmode(struct ata_device *atadev, int mode) u_int16_t reg = 0x40 + (devno << 1); - pci_write_config(parent, reg, timings[ata_mode2idx(mode)], 2); + pci_write_config(gparent, reg, timings[ata_mode2idx(mode)], 2); break; } case SIS100NEW: { @@ -2756,7 +3040,7 @@ ata_sis_setmode(struct ata_device *atadev, int mode) 0x0031, 0x8b31, 0x8731, 0x8531, 0x8431, 0x8231, 0x8131 }; u_int16_t reg = 0x40 + (devno << 1); - pci_write_config(parent, reg, timings[ata_mode2idx(mode)], 2); + pci_write_config(gparent, reg, timings[ata_mode2idx(mode)], 2); break; } case SIS100OLD: @@ -2767,7 +3051,7 @@ ata_sis_setmode(struct ata_device *atadev, int mode) 0x0301, 0xf301, 0xd301, 0xb301, 0xa301, 0x9301, 0x8301 }; u_int16_t reg = 0x40 + (devno << 1); - pci_write_config(parent, reg, timings[ata_mode2idx(mode)], 2); + pci_write_config(gparent, reg, timings[ata_mode2idx(mode)], 2); break; } } @@ -2775,7 +3059,7 @@ ata_sis_setmode(struct ata_device *atadev, int mode) } } -/* VIA chipsets */ +/* VIA Technologies Inc. chipset support functions */ int ata_via_ident(device_t dev) { @@ -2797,8 +3081,8 @@ ata_via_ident(device_t dev) { ATA_VIA8237, 0x00, VIA133, 0x00, ATA_UDMA6, "VIA 8237" }, { 0, 0, 0, 0, 0, 0 }}; static struct ata_chip_id new_ids[] = - {{ ATA_VIA6410, 0x00, 0x00, 0x00, ATA_UDMA6, "VIA 6410" }, - { ATA_VIA6420, 0x00, 0x00, 0x00, ATA_SA150, "VIA 6420" }, + {{ ATA_VIA6410, 0x00, 0x00, 0x00, ATA_UDMA6, "VIA 6410" }, + { ATA_VIA6420, 0x00, 0x00, 0x00, ATA_SA150, "VIA 6420" }, { 0, 0, 0, 0, 0, 0 }}; char buffer[64]; @@ -2835,7 +3119,7 @@ ata_via_chipinit(device_t dev) /* prepare for ATA-66 on the 82C686a and 82C596b */ if (ctlr->chip->cfg2 & VIACLK) - pci_write_config(dev, 0x50, 0x030b030b, 4); + pci_write_config(dev, 0x50, 0x030b030b, 4); /* the southbridge might need the data corruption fix */ if (ctlr->chip->cfg2 & VIABUG) @@ -2892,17 +3176,18 @@ ata_via_southbridge_fixup(device_t dev) static void ata_via_family_setmode(struct ata_device *atadev, int mode) { - device_t parent = device_get_parent(atadev->channel->dev); - struct ata_pci_controller *ctlr = device_get_softc(parent); + device_t gparent = GRANDPARENT(atadev->dev); + struct ata_pci_controller *ctlr = device_get_softc(gparent); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); u_int8_t timings[] = { 0xa8, 0x65, 0x42, 0x22, 0x20, 0x42, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; int modes[][7] = { - { 0xc2, 0xc1, 0xc0, 0x00, 0x00, 0x00, 0x00 }, /* VIA ATA33 */ - { 0xee, 0xec, 0xea, 0xe9, 0xe8, 0x00, 0x00 }, /* VIA ATA66 */ - { 0xf7, 0xf6, 0xf4, 0xf2, 0xf1, 0xf0, 0x00 }, /* VIA ATA100 */ - { 0xf7, 0xf7, 0xf6, 0xf4, 0xf2, 0xf1, 0xf0 }, /* VIA ATA133 */ - { 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6, 0xc7 }}; /* AMD/nVIDIA */ - int devno = (atadev->channel->unit << 1) + ATA_DEV(atadev->unit); + { 0xc2, 0xc1, 0xc0, 0x00, 0x00, 0x00, 0x00 }, /* VIA ATA33 */ + { 0xee, 0xec, 0xea, 0xe9, 0xe8, 0x00, 0x00 }, /* VIA ATA66 */ + { 0xf7, 0xf6, 0xf4, 0xf2, 0xf1, 0xf0, 0x00 }, /* VIA ATA100 */ + { 0xf7, 0xf7, 0xf6, 0xf4, 0xf2, 0xf1, 0xf0 }, /* VIA ATA133 */ + { 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6, 0xc7 }}; /* AMD/nVIDIA */ + int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); int reg = 0x53 - devno; int error; @@ -2910,9 +3195,8 @@ ata_via_family_setmode(struct ata_device *atadev, int mode) if (ctlr->chip->cfg2 & AMDCABLE) { if (mode > ATA_UDMA2 && - !(pci_read_config(parent, 0x42, 1) & (1 << devno))) { - ata_prtdev(atadev, - "DMA limited to UDMA33, non-ATA66 cable or device\n"); + !(pci_read_config(gparent, 0x42, 1) & (1 << devno))) { + ata_print_cable(atadev->dev, "controller"); mode = ATA_UDMA2; } } @@ -2923,25 +3207,37 @@ ata_via_family_setmode(struct ata_device *atadev, int mode) reg += 0x10; if (ctlr->chip->cfg1 != VIA133) - pci_write_config(parent, reg - 0x08, timings[ata_mode2idx(mode)], 1); + pci_write_config(gparent, reg - 0x08, timings[ata_mode2idx(mode)], 1); error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); if (bootverbose) - ata_prtdev(atadev, "%ssetting %s on %s chip\n", - (error) ? "FAILURE " : "", ata_mode2str(mode), - ctlr->chip->text); + device_printf(atadev->dev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", ata_mode2str(mode), + ctlr->chip->text); if (!error) { if (mode >= ATA_UDMA0) - pci_write_config(parent, reg, + pci_write_config(gparent, reg, modes[ctlr->chip->cfg1][mode & ATA_MODE_MASK], 1); else - pci_write_config(parent, reg, 0x8b, 1); + pci_write_config(gparent, reg, 0x8b, 1); atadev->mode = mode; } } /* misc functions */ +struct ata_chip_id * +ata_match_chip(device_t dev, struct ata_chip_id *index) +{ + while (index->chipid != 0) { + if (pci_get_devid(dev) == index->chipid && + pci_get_revid(dev) >= index->chiprev) + return index; + index++; + } + return NULL; +} + static struct ata_chip_id * ata_find_chip(device_t dev, struct ata_chip_id *index, int slot) { @@ -2967,18 +3263,6 @@ ata_find_chip(device_t dev, struct ata_chip_id *index, int slot) return NULL; } -static struct ata_chip_id * -ata_match_chip(device_t dev, struct ata_chip_id *index) -{ - while (index->chipid != 0) { - if (pci_get_devid(dev) == index->chipid && - pci_get_revid(dev) >= index->chiprev) - return index; - index++; - } - return NULL; -} - static int ata_setup_interrupt(device_t dev) { @@ -3001,9 +3285,9 @@ ata_setup_interrupt(device_t dev) } struct ata_serialize { - struct mtx locked_mtx; - int locked_ch; - int restart_ch; + struct mtx locked_mtx; + int locked_ch; + int restart_ch; }; static int @@ -3016,16 +3300,16 @@ ata_serialize(struct ata_channel *ch, int flags) int res; if (!inited) { - ctlr->driver = malloc(sizeof(struct ata_serialize), + serial = malloc(sizeof(struct ata_serialize), M_TEMP, M_NOWAIT | M_ZERO); - serial = ctlr->driver; mtx_init(&serial->locked_mtx, "ATA serialize lock", NULL, MTX_DEF); serial->locked_ch = -1; serial->restart_ch = -1; + device_set_ivars(ctlr->dev, serial); inited = 1; } else - serial = ctlr->driver; + serial = device_get_ivars(ctlr->dev); mtx_lock(&serial->locked_mtx); switch (flags) { @@ -3037,17 +3321,17 @@ ata_serialize(struct ata_channel *ch, int flags) break; case ATA_LF_UNLOCK: - if (serial->locked_ch == ch->unit) { - serial->locked_ch = -1; - if (serial->restart_ch != -1) { - if (ctlr->interrupt[serial->restart_ch].argument) { - mtx_unlock(&serial->locked_mtx); - ata_start(ctlr->interrupt[serial->restart_ch].argument); - mtx_lock(&serial->locked_mtx); - } - serial->restart_ch = -1; - } - } + if (serial->locked_ch == ch->unit) { + serial->locked_ch = -1; + if (serial->restart_ch != -1) { + if ((ch = ctlr->interrupt[serial->restart_ch].argument)) { + serial->restart_ch = -1; + mtx_unlock(&serial->locked_mtx); + ata_start(ch->dev); + return -1; + } + } + } break; case ATA_LF_WHICH: @@ -3061,8 +3345,8 @@ ata_serialize(struct ata_channel *ch, int flags) static int ata_check_80pin(struct ata_device *atadev, int mode) { - if (mode > ATA_UDMA2 && !(atadev->param->hwres & ATA_CABLE_ID)) { - ata_prtdev(atadev,"DMA limited to UDMA33, non-ATA66 cable or device\n"); + if (mode > ATA_UDMA2 && !(atadev->param.hwres & ATA_CABLE_ID)) { + ata_print_cable(atadev->dev, "device"); mode = ATA_UDMA2; } return mode; diff --git a/sys/dev/ata/ata-commands.h b/sys/dev/ata/ata-commands.h index ea27d68..4a6320b 100644 --- a/sys/dev/ata/ata-commands.h +++ b/sys/dev/ata/ata-commands.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,101 +29,102 @@ */ /* ATA commands */ -#define ATA_NOP 0x00 /* NOP command */ -#define ATA_NF_FLUSHQUEUE 0x00 /* flush queued cmd's */ -#define ATA_NF_AUTOPOLL 0x01 /* start autopoll function */ -#define ATA_ATAPI_RESET 0x08 /* reset ATAPI device */ -#define ATA_READ 0x20 /* read command */ -#define ATA_READ48 0x24 /* read command */ -#define ATA_READ_DMA48 0x25 /* read w/DMA command */ -#define ATA_READ_DMA_QUEUED48 0x26 /* read w/DMA QUEUED command */ -#define ATA_READ_MUL48 0x29 /* read multi command */ -#define ATA_WRITE 0x30 /* write command */ -#define ATA_WRITE48 0x34 /* write command */ -#define ATA_WRITE_DMA48 0x35 /* write w/DMA command */ -#define ATA_WRITE_DMA_QUEUED48 0x36 /* write w/DMA QUEUED command */ -#define ATA_WRITE_MUL48 0x39 /* write multi command */ -#define ATA_READ_FPDMA_QUEUED 0x60 /* read w/DMA NCQ */ -#define ATA_WRITE_FPDMA_QUEUED 0x61 /* write w/DMA NCQ */ -#define ATA_PACKET_CMD 0xa0 /* packet command */ -#define ATA_ATAPI_IDENTIFY 0xa1 /* get ATAPI params*/ -#define ATA_SERVICE 0xa2 /* service command */ -#define ATA_READ_MUL 0xc4 /* read multi command */ -#define ATA_WRITE_MUL 0xc5 /* write multi command */ -#define ATA_SET_MULTI 0xc6 /* set multi size command */ -#define ATA_READ_DMA_QUEUED 0xc7 /* read w/DMA QUEUED command */ -#define ATA_READ_DMA 0xc8 /* read w/DMA command */ -#define ATA_WRITE_DMA 0xca /* write w/DMA command */ -#define ATA_WRITE_DMA_QUEUED 0xcc /* write w/DMA QUEUED command */ -#define ATA_SLEEP 0xe6 /* sleep command */ -#define ATA_FLUSHCACHE 0xe7 /* flush cache to disk */ -#define ATA_FLUSHCACHE48 0xea /* flush cache to disk */ -#define ATA_ATA_IDENTIFY 0xec /* get ATA params */ -#define ATA_SETFEATURES 0xef /* features command */ -#define ATA_SF_SETXFER 0x03 /* set transfer mode */ -#define ATA_SF_ENAB_WCACHE 0x02 /* enable write cache */ -#define ATA_SF_DIS_WCACHE 0x82 /* disable write cache */ -#define ATA_SF_ENAB_RCACHE 0xaa /* enable readahead cache */ -#define ATA_SF_DIS_RCACHE 0x55 /* disable readahead cache */ -#define ATA_SF_ENAB_RELIRQ 0x5d /* enable release interrupt */ -#define ATA_SF_DIS_RELIRQ 0xdd /* disable release interrupt */ -#define ATA_SF_ENAB_SRVIRQ 0x5e /* enable service interrupt */ -#define ATA_SF_DIS_SRVIRQ 0xde /* disable service interrupt */ +#define ATA_NOP 0x00 /* NOP command */ +#define ATA_NF_FLUSHQUEUE 0x00 /* flush queued cmd's */ +#define ATA_NF_AUTOPOLL 0x01 /* start autopoll function */ +#define ATA_DEVICE_RESET 0x08 /* reset ATAPI device */ +#define ATA_READ 0x20 /* read command */ +#define ATA_READ48 0x24 /* read command */ +#define ATA_READ_DMA48 0x25 /* read w/DMA command */ +#define ATA_READ_DMA_QUEUED48 0x26 /* read w/DMA QUEUED command */ +#define ATA_READ_MUL48 0x29 /* read multi command */ +#define ATA_WRITE 0x30 /* write command */ +#define ATA_WRITE48 0x34 /* write command */ +#define ATA_WRITE_DMA48 0x35 /* write w/DMA command */ +#define ATA_WRITE_DMA_QUEUED48 0x36 /* write w/DMA QUEUED command */ +#define ATA_WRITE_MUL48 0x39 /* write multi command */ +#define ATA_READ_FPDMA_QUEUED 0x60 /* read w/DMA NCQ */ +#define ATA_WRITE_FPDMA_QUEUED 0x61 /* write w/DMA NCQ */ +#define ATA_SEEK 0x70 /* seek */ +#define ATA_PACKET_CMD 0xa0 /* packet command */ +#define ATA_ATAPI_IDENTIFY 0xa1 /* get ATAPI params*/ +#define ATA_SERVICE 0xa2 /* service command */ +#define ATA_READ_MUL 0xc4 /* read multi command */ +#define ATA_WRITE_MUL 0xc5 /* write multi command */ +#define ATA_SET_MULTI 0xc6 /* set multi size command */ +#define ATA_READ_DMA_QUEUED 0xc7 /* read w/DMA QUEUED command */ +#define ATA_READ_DMA 0xc8 /* read w/DMA command */ +#define ATA_WRITE_DMA 0xca /* write w/DMA command */ +#define ATA_WRITE_DMA_QUEUED 0xcc /* write w/DMA QUEUED command */ +#define ATA_SLEEP 0xe6 /* sleep command */ +#define ATA_FLUSHCACHE 0xe7 /* flush cache to disk */ +#define ATA_FLUSHCACHE48 0xea /* flush cache to disk */ +#define ATA_ATA_IDENTIFY 0xec /* get ATA params */ +#define ATA_SETFEATURES 0xef /* features command */ +#define ATA_SF_SETXFER 0x03 /* set transfer mode */ +#define ATA_SF_ENAB_WCACHE 0x02 /* enable write cache */ +#define ATA_SF_DIS_WCACHE 0x82 /* disable write cache */ +#define ATA_SF_ENAB_RCACHE 0xaa /* enable readahead cache */ +#define ATA_SF_DIS_RCACHE 0x55 /* disable readahead cache */ +#define ATA_SF_ENAB_RELIRQ 0x5d /* enable release interrupt */ +#define ATA_SF_DIS_RELIRQ 0xdd /* disable release interrupt */ +#define ATA_SF_ENAB_SRVIRQ 0x5e /* enable service interrupt */ +#define ATA_SF_DIS_SRVIRQ 0xde /* disable service interrupt */ /* ATAPI commands */ -#define ATAPI_TEST_UNIT_READY 0x00 /* check if device is ready */ -#define ATAPI_REZERO 0x01 /* rewind */ -#define ATAPI_REQUEST_SENSE 0x03 /* get sense data */ -#define ATAPI_FORMAT 0x04 /* format unit */ -#define ATAPI_READ 0x08 /* read data */ -#define ATAPI_WRITE 0x0a /* write data */ -#define ATAPI_WEOF 0x10 /* write filemark */ -#define ATAPI_WF_WRITE 0x01 -#define ATAPI_SPACE 0x11 /* space command */ -#define ATAPI_SP_FM 0x01 -#define ATAPI_SP_EOD 0x03 -#define ATAPI_MODE_SELECT 0x15 /* mode select */ -#define ATAPI_ERASE 0x19 /* erase */ -#define ATAPI_MODE_SENSE 0x1a /* mode sense */ -#define ATAPI_START_STOP 0x1b /* start/stop unit */ -#define ATAPI_SS_LOAD 0x01 -#define ATAPI_SS_RETENSION 0x02 -#define ATAPI_SS_EJECT 0x04 -#define ATAPI_PREVENT_ALLOW 0x1e /* media removal */ -#define ATAPI_READ_FORMAT_CAPACITIES 0x23 /* get format capacities */ -#define ATAPI_READ_CAPACITY 0x25 /* get volume capacity */ -#define ATAPI_READ_BIG 0x28 /* read data */ -#define ATAPI_WRITE_BIG 0x2a /* write data */ -#define ATAPI_LOCATE 0x2b /* locate to position */ -#define ATAPI_READ_POSITION 0x34 /* read position */ -#define ATAPI_SYNCHRONIZE_CACHE 0x35 /* flush buf, close channel */ -#define ATAPI_WRITE_BUFFER 0x3b /* write device buffer */ -#define ATAPI_READ_BUFFER 0x3c /* read device buffer */ -#define ATAPI_READ_SUBCHANNEL 0x42 /* get subchannel info */ -#define ATAPI_READ_TOC 0x43 /* get table of contents */ -#define ATAPI_PLAY_10 0x45 /* play by lba */ -#define ATAPI_PLAY_MSF 0x47 /* play by MSF address */ -#define ATAPI_PLAY_TRACK 0x48 /* play by track number */ -#define ATAPI_PAUSE 0x4b /* pause audio operation */ -#define ATAPI_READ_DISK_INFO 0x51 /* get disk info structure */ -#define ATAPI_READ_TRACK_INFO 0x52 /* get track info structure */ -#define ATAPI_RESERVE_TRACK 0x53 /* reserve track */ -#define ATAPI_SEND_OPC_INFO 0x54 /* send OPC structurek */ -#define ATAPI_MODE_SELECT_BIG 0x55 /* set device parameters */ -#define ATAPI_REPAIR_TRACK 0x58 /* repair track */ -#define ATAPI_READ_MASTER_CUE 0x59 /* read master CUE info */ -#define ATAPI_MODE_SENSE_BIG 0x5a /* get device parameters */ -#define ATAPI_CLOSE_TRACK 0x5b /* close track/session */ -#define ATAPI_READ_BUFFER_CAPACITY 0x5c /* get buffer capicity */ -#define ATAPI_SEND_CUE_SHEET 0x5d /* send CUE sheet */ -#define ATAPI_BLANK 0xa1 /* blank the media */ -#define ATAPI_SEND_KEY 0xa3 /* send DVD key structure */ -#define ATAPI_REPORT_KEY 0xa4 /* get DVD key structure */ -#define ATAPI_PLAY_12 0xa5 /* play by lba */ -#define ATAPI_LOAD_UNLOAD 0xa6 /* changer control command */ -#define ATAPI_READ_STRUCTURE 0xad /* get DVD structure */ -#define ATAPI_PLAY_CD 0xb4 /* universal play command */ -#define ATAPI_SET_SPEED 0xbb /* set drive speed */ -#define ATAPI_MECH_STATUS 0xbd /* get changer status */ -#define ATAPI_READ_CD 0xbe /* read data */ -#define ATAPI_POLL_DSC 0xff /* poll DSC status bit */ +#define ATAPI_TEST_UNIT_READY 0x00 /* check if device is ready */ +#define ATAPI_REZERO 0x01 /* rewind */ +#define ATAPI_REQUEST_SENSE 0x03 /* get sense data */ +#define ATAPI_FORMAT 0x04 /* format unit */ +#define ATAPI_READ 0x08 /* read data */ +#define ATAPI_WRITE 0x0a /* write data */ +#define ATAPI_WEOF 0x10 /* write filemark */ +#define ATAPI_WF_WRITE 0x01 +#define ATAPI_SPACE 0x11 /* space command */ +#define ATAPI_SP_FM 0x01 +#define ATAPI_SP_EOD 0x03 +#define ATAPI_MODE_SELECT 0x15 /* mode select */ +#define ATAPI_ERASE 0x19 /* erase */ +#define ATAPI_MODE_SENSE 0x1a /* mode sense */ +#define ATAPI_START_STOP 0x1b /* start/stop unit */ +#define ATAPI_SS_LOAD 0x01 +#define ATAPI_SS_RETENSION 0x02 +#define ATAPI_SS_EJECT 0x04 +#define ATAPI_PREVENT_ALLOW 0x1e /* media removal */ +#define ATAPI_READ_FORMAT_CAPACITIES 0x23 /* get format capacities */ +#define ATAPI_READ_CAPACITY 0x25 /* get volume capacity */ +#define ATAPI_READ_BIG 0x28 /* read data */ +#define ATAPI_WRITE_BIG 0x2a /* write data */ +#define ATAPI_LOCATE 0x2b /* locate to position */ +#define ATAPI_READ_POSITION 0x34 /* read position */ +#define ATAPI_SYNCHRONIZE_CACHE 0x35 /* flush buf, close channel */ +#define ATAPI_WRITE_BUFFER 0x3b /* write device buffer */ +#define ATAPI_READ_BUFFER 0x3c /* read device buffer */ +#define ATAPI_READ_SUBCHANNEL 0x42 /* get subchannel info */ +#define ATAPI_READ_TOC 0x43 /* get table of contents */ +#define ATAPI_PLAY_10 0x45 /* play by lba */ +#define ATAPI_PLAY_MSF 0x47 /* play by MSF address */ +#define ATAPI_PLAY_TRACK 0x48 /* play by track number */ +#define ATAPI_PAUSE 0x4b /* pause audio operation */ +#define ATAPI_READ_DISK_INFO 0x51 /* get disk info structure */ +#define ATAPI_READ_TRACK_INFO 0x52 /* get track info structure */ +#define ATAPI_RESERVE_TRACK 0x53 /* reserve track */ +#define ATAPI_SEND_OPC_INFO 0x54 /* send OPC structurek */ +#define ATAPI_MODE_SELECT_BIG 0x55 /* set device parameters */ +#define ATAPI_REPAIR_TRACK 0x58 /* repair track */ +#define ATAPI_READ_MASTER_CUE 0x59 /* read master CUE info */ +#define ATAPI_MODE_SENSE_BIG 0x5a /* get device parameters */ +#define ATAPI_CLOSE_TRACK 0x5b /* close track/session */ +#define ATAPI_READ_BUFFER_CAPACITY 0x5c /* get buffer capicity */ +#define ATAPI_SEND_CUE_SHEET 0x5d /* send CUE sheet */ +#define ATAPI_BLANK 0xa1 /* blank the media */ +#define ATAPI_SEND_KEY 0xa3 /* send DVD key structure */ +#define ATAPI_REPORT_KEY 0xa4 /* get DVD key structure */ +#define ATAPI_PLAY_12 0xa5 /* play by lba */ +#define ATAPI_LOAD_UNLOAD 0xa6 /* changer control command */ +#define ATAPI_READ_STRUCTURE 0xad /* get DVD structure */ +#define ATAPI_PLAY_CD 0xb4 /* universal play command */ +#define ATAPI_SET_SPEED 0xbb /* set drive speed */ +#define ATAPI_MECH_STATUS 0xbd /* get changer status */ +#define ATAPI_READ_CD 0xbe /* read data */ +#define ATAPI_POLL_DSC 0xff /* poll DSC status bit */ diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c index 2a338c6..9183645 100644 --- a/sys/dev/ata/ata-disk.c +++ b/sys/dev/ata/ata-disk.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/ata.h> #include <sys/kernel.h> +#include <sys/module.h> #include <sys/malloc.h> #include <sys/bio.h> #include <sys/bus.h> @@ -52,287 +53,225 @@ __FBSDID("$FreeBSD$"); #include <dev/ata/ata-pci.h> #include <dev/ata/ata-disk.h> #include <dev/ata/ata-raid.h> +#include <ata_if.h> /* prototypes */ -static void ad_detach(struct ata_device *); -static void ad_config(struct ata_device *); -static void ad_start(struct ata_device *); +static void ad_init(device_t); static void ad_done(struct ata_request *); -static disk_open_t adopen; -static disk_strategy_t adstrategy; -static dumper_t addump; -void ad_print(struct ad_softc *); +static void ad_describe(device_t dev); static int ad_version(u_int16_t); +static disk_strategy_t ad_strategy; +static dumper_t ad_dump; -/* internal vars */ +/* local vars */ static MALLOC_DEFINE(M_AD, "AD driver", "ATA disk driver"); -static u_int32_t adp_lun_map = 0; -void -ad_attach(struct ata_device *atadev) +static void +ad_identify(driver_t *driver, device_t parent) { + ata_identify(driver, parent, -1, "ad"); +} + +static int +ad_probe(device_t dev) +{ + return 0; +} + +static int +ad_attach(device_t dev) +{ + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_device *atadev = device_get_softc(dev); struct ad_softc *adp; u_int32_t lbasize; u_int64_t lbasize48; + /* check that we have a virgin disk to attach */ + if (device_get_ivars(dev)) + return EEXIST; + if (!(adp = malloc(sizeof(struct ad_softc), M_AD, M_NOWAIT | M_ZERO))) { - ata_prtdev(atadev, "FAILURE - could not allocate driver storage\n"); - atadev->attach = NULL; - return; + device_printf(dev, "out of memory\n"); + device_set_softc(dev, NULL); + free(atadev, M_ATA); + return ENOMEM; } - atadev->softc = adp; - adp->device = atadev; - -#ifdef ATA_STATIC_ID - adp->lun = (device_get_unit(atadev->channel->dev)<<1)+ATA_DEV(atadev->unit); -#else - adp->lun = ata_get_lun(&adp_lun_map); -#endif - ata_set_name(atadev, "ad", adp->lun); - adp->heads = atadev->param->heads; - adp->sectors = atadev->param->sectors; - adp->total_secs = atadev->param->cylinders * adp->heads * adp->sectors; -#ifdef PC98 - /* - * During the BOOT process, the PC-98 BIOS sets fake geometry of - * xxxx/8/17 of the disk using 'INITIALIZE DEVICE PARAMETER (91h)' - * command. After this command, all access to the drive must be done - * via the new, fake geometry, rather than the old, native format. - * With ATA/ATAPI-6 or later, these parameters are obsolete, but - * PC-98s are still using them. - * - * This only really matters when we're talking to disks using CHS - * mode, not LBA mode. The CHS mode disks are still relatively - * common in these machines, so that case must be addressed. - * - * (ITF sets new CHS geometry to initialized disks.) - * - * obsolete54[0]: current cylinder - * obsolete54[1]: current heads - * obsolete54[2]: current sectors - * obsolete54[3-4]: current capacities(multiplied above 3 values) - */ - /* Get CHS geometry from set by Initialize Device Parameters command. */ - if ((atadev->param->atavalid & ATA_FLAG_54_58) || - (atadev->param->obsolete54[0] != 0 && - atadev->param->obsolete54[1] != 0 && - atadev->param->obsolete54[2] != 0)) { - adp->heads = atadev->param->obsolete54[1]; - adp->sectors = atadev->param->obsolete54[2]; - adp->total_secs = *(u_int32_t*)&(atadev->param->obsolete54[3]); - } -#endif - - mtx_init(&adp->queue_mtx, "ATA disk bioqueue lock", NULL, MTX_DEF); - bioq_init(&adp->queue); + device_set_ivars(dev, adp); - lbasize = (u_int32_t)atadev->param->lba_size_1 | - ((u_int32_t)atadev->param->lba_size_2 << 16); + if (atadev->param.atavalid & ATA_FLAG_54_58) { + adp->heads = atadev->param.current_heads; + adp->sectors = atadev->param.current_sectors; + adp->total_secs = (u_int32_t)atadev->param.current_size_1 | + ((u_int32_t)atadev->param.current_size_2 << 16); + } + else { + adp->heads = atadev->param.heads; + adp->sectors = atadev->param.sectors; + adp->total_secs = atadev->param.cylinders * adp->heads * adp->sectors; + } + lbasize = (u_int32_t)atadev->param.lba_size_1 | + ((u_int32_t)atadev->param.lba_size_2 << 16); /* does this device need oldstyle CHS addressing */ - if (!ad_version(atadev->param->version_major) || !lbasize) + if (!ad_version(atadev->param.version_major) || !lbasize) atadev->flags |= ATA_D_USE_CHS; /* use the 28bit LBA size if valid or bigger than the CHS mapping */ - if (atadev->param->cylinders == 16383 || adp->total_secs < lbasize) + if (atadev->param.cylinders == 16383 || adp->total_secs < lbasize) adp->total_secs = lbasize; - lbasize48 = ((u_int64_t)atadev->param->lba_size48_1) | - ((u_int64_t)atadev->param->lba_size48_2 << 16) | - ((u_int64_t)atadev->param->lba_size48_3 << 32) | - ((u_int64_t)atadev->param->lba_size48_4 << 48); - /* use the 48bit LBA size if valid */ - if ((atadev->param->support.command2 & ATA_SUPPORT_ADDRESS48) && + lbasize48 = ((u_int64_t)atadev->param.lba_size48_1) | + ((u_int64_t)atadev->param.lba_size48_2 << 16) | + ((u_int64_t)atadev->param.lba_size48_3 << 32) | + ((u_int64_t)atadev->param.lba_size48_4 << 48); + if ((atadev->param.support.command2 & ATA_SUPPORT_ADDRESS48) && lbasize48 > ATA_MAX_28BIT_LBA) adp->total_secs = lbasize48; - /* setup the function ptrs */ - atadev->detach = ad_detach; - atadev->config = ad_config; - atadev->start = ad_start; + /* init device parameters */ + ad_init(dev); - /* config device features */ - ad_config(atadev); + /* announce we are here */ + ad_describe(dev); - /* lets create the disk device */ + /* create the disk device */ adp->disk = disk_alloc(); - adp->disk->d_open = adopen; - adp->disk->d_strategy = adstrategy; - adp->disk->d_dump = addump; + adp->disk->d_strategy = ad_strategy; + adp->disk->d_dump = ad_dump; adp->disk->d_name = "ad"; - adp->disk->d_drv1 = adp; - if (atadev->channel->dma) - adp->disk->d_maxsize = atadev->channel->dma->max_iosize; + adp->disk->d_drv1 = dev; + if (ch->dma) + adp->disk->d_maxsize = ch->dma->max_iosize; else adp->disk->d_maxsize = DFLTPHYS; adp->disk->d_sectorsize = DEV_BSIZE; adp->disk->d_mediasize = DEV_BSIZE * (off_t)adp->total_secs; adp->disk->d_fwsectors = adp->sectors; adp->disk->d_fwheads = adp->heads; - adp->disk->d_unit = adp->lun; + adp->disk->d_unit = device_get_unit(dev); disk_create(adp->disk, DISK_VERSION); - - /* announce we are here */ - ad_print(adp); - -#ifdef DEV_ATARAID - ata_raiddisk_attach(adp); -#endif + device_add_child(dev, "subdisk", device_get_unit(dev)); + bus_generic_attach(dev); + return 0; } -static void -ad_detach(struct ata_device *atadev) +static int +ad_detach(device_t dev) { - struct ad_softc *adp = atadev->softc; + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_device *atadev = device_get_softc(dev); + struct ad_softc *adp = device_get_ivars(dev); + device_t *children; + int nchildren, i; + + /* check that we have a valid disk to detach */ + if (!device_get_ivars(dev)) + return ENXIO; + + /* 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); + } -#ifdef DEV_ATARAID - if (adp->flags & AD_F_RAID_SUBDISK) - ata_raiddisk_detach(adp); -#endif + /* detroy disk from the system so we dont get any further requests */ disk_destroy(adp->disk); - ata_prtdev(atadev, "WARNING - removed from configuration\n"); - mtx_lock(&adp->queue_mtx); - bioq_flush(&adp->queue, NULL, ENXIO); - mtx_unlock(&adp->queue_mtx); - mtx_destroy(&adp->queue_mtx); - ata_free_name(atadev); - ata_free_lun(&adp_lun_map, adp->lun); - atadev->attach = NULL; - atadev->detach = NULL; - atadev->start = NULL; - atadev->softc = NULL; - atadev->flags = 0; + + /* fail requests on the queue and any thats "in flight" for this device */ + ata_fail_requests(ch, dev); + + /* dont leave anything behind */ + device_set_ivars(dev, NULL); free(adp, M_AD); + device_set_softc(dev, NULL); + free(atadev, M_ATA); + return 0; } static void -ad_config(struct ata_device *atadev) +ad_shutdown(device_t dev) { - struct ad_softc *adp = atadev->softc; - - /* enable read caching */ - ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_ENAB_RCACHE, 0, 0); - - /* enable write caching if enabled */ - if (ata_wc) - ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_ENAB_WCACHE, 0, 0); - else - ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_DIS_WCACHE, 0, 0); - - /* use multiple sectors/interrupt if device supports it */ - adp->max_iosize = DEV_BSIZE; - if (ad_version(atadev->param->version_major)) { - int secsperint = max(1, min(atadev->param->sectors_intr, 16)); + struct ata_device *atadev = device_get_softc(dev); - if (!ata_controlcmd(atadev, ATA_SET_MULTI, 0, 0, secsperint)) - adp->max_iosize = secsperint * DEV_BSIZE; - } + if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE) + ata_controlcmd(atadev, ATA_FLUSHCACHE, 0, 0, 0); } static int -adopen(struct disk *dp) +ad_reinit(device_t dev) { - struct ad_softc *adp = dp->d_drv1; + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_device *atadev = device_get_softc(dev); - if (adp == NULL || adp->device->flags & ATA_D_DETACHING) - return ENXIO; + /* if detach pending flag set, return error */ + + if (((atadev->unit == ATA_MASTER) && !(ch->devices & ATA_ATA_MASTER)) || + ((atadev->unit == ATA_SLAVE) && !(ch->devices & ATA_ATA_SLAVE))) { + return 1; + } + ad_init(dev); return 0; } static void -adstrategy(struct bio *bp) -{ - struct ad_softc *adp = bp->bio_disk->d_drv1; - - mtx_lock(&adp->queue_mtx); - bioq_disksort(&adp->queue, bp); - mtx_unlock(&adp->queue_mtx); - ata_start(adp->device->channel); -} - -static void -ad_start(struct ata_device *atadev) +ad_strategy(struct bio *bp) { - struct ad_softc *adp = atadev->softc; - struct bio *bp; + device_t dev = bp->bio_disk->d_drv1; + struct ata_device *atadev = device_get_softc(dev); struct ata_request *request; - /* remove request from drive queue */ - mtx_lock(&adp->queue_mtx); - bp = bioq_first(&adp->queue); - if (!bp) { - mtx_unlock(&adp->queue_mtx); - return; - } - bioq_remove(&adp->queue, bp); - mtx_unlock(&adp->queue_mtx); - if (adp->device->flags & ATA_D_DETACHING) { - biofinish(bp, NULL, ENXIO); - return; - } - if (!(request = ata_alloc_request())) { - ata_prtdev(atadev, "FAILURE - out of memory in start\n"); + device_printf(dev, "FAILURE - out of memory in start\n"); biofinish(bp, NULL, ENOMEM); return; } /* setup request */ - request->device = atadev; + request->dev = dev; request->bio = bp; request->callback = ad_done; request->timeout = 5; request->retries = 2; request->data = bp->bio_data; request->bytecount = bp->bio_bcount; - - /* convert LBA contents if this is an old non-LBA device */ - if (atadev->flags & ATA_D_USE_CHS) { - int sector = (bp->bio_pblkno % adp->sectors) + 1; - int cylinder = bp->bio_pblkno / (adp->sectors * adp->heads); - int head = (bp->bio_pblkno % - (adp->sectors * adp->heads)) / adp->sectors; - - request->u.ata.lba = - (sector & 0xff) | (cylinder & 0xffff) << 8 | (head & 0xf) << 24; - } - else - request->u.ata.lba = bp->bio_pblkno; - + request->u.ata.lba = bp->bio_pblkno; request->u.ata.count = request->bytecount / DEV_BSIZE; - request->transfersize = min(bp->bio_bcount, adp->max_iosize); + request->transfersize = min(bp->bio_bcount, atadev->max_iosize); switch (bp->bio_cmd) { case BIO_READ: - request->flags |= ATA_R_READ; + request->flags = ATA_R_READ; if (atadev->mode >= ATA_DMA) { request->u.ata.command = ATA_READ_DMA; request->flags |= ATA_R_DMA; } - else if (adp->max_iosize > DEV_BSIZE) + else if (atadev->max_iosize > DEV_BSIZE) request->u.ata.command = ATA_READ_MUL; else request->u.ata.command = ATA_READ; - break; case BIO_WRITE: - request->flags |= ATA_R_WRITE; + request->flags = ATA_R_WRITE; if (atadev->mode >= ATA_DMA) { request->u.ata.command = ATA_WRITE_DMA; request->flags |= ATA_R_DMA; } - else if (adp->max_iosize > DEV_BSIZE) + else if (atadev->max_iosize > DEV_BSIZE) request->u.ata.command = ATA_WRITE_MUL; else request->u.ata.command = ATA_WRITE; break; default: - ata_prtdev(atadev, "FAILURE - unknown BIO operation\n"); + device_printf(dev, "FAILURE - unknown BIO operation\n"); ata_free_request(request); biofinish(bp, NULL, EIO); return; } + request->flags |= ATA_R_ORDERED; ata_queue_request(request); } @@ -350,25 +289,28 @@ ad_done(struct ata_request *request) } static int -addump(void *arg, void *virtual, vm_offset_t physical, +ad_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length) { - struct ata_request request; struct disk *dp = arg; - struct ad_softc *adp = dp->d_drv1; + device_t dev = dp->d_drv1; + struct ata_device *atadev = device_get_softc(dev); + struct ad_softc *adp = device_get_ivars(dev); + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_request request; if (!adp) return ENXIO; bzero(&request, sizeof(struct ata_request)); - request.device = adp->device; + request.dev = dev; if (length) { request.data = virtual; request.bytecount = length; - request.transfersize = min(length, adp->max_iosize); + request.transfersize = min(length, atadev->max_iosize); request.flags = ATA_R_WRITE; - if (adp->max_iosize > DEV_BSIZE) + if (atadev->max_iosize > DEV_BSIZE) request.u.ata.command = ATA_WRITE_MUL; else request.u.ata.command = ATA_WRITE; @@ -379,13 +321,10 @@ addump(void *arg, void *virtual, vm_offset_t physical, request.u.ata.command = ATA_FLUSHCACHE; request.flags = ATA_R_CONTROL; } - - if (request.device->channel-> - hw.begin_transaction(&request) == ATA_OP_CONTINUES) { + if (ch->hw.begin_transaction(&request) == ATA_OP_CONTINUES) { do { DELAY(20); - } while (request.device->channel-> - hw.end_transaction(&request) == ATA_OP_CONTINUES); + } while (ch->hw.end_transaction(&request) == ATA_OP_CONTINUES); ata_finish(&request); } if (request.status & ATA_S_ERROR) @@ -393,43 +332,75 @@ addump(void *arg, void *virtual, vm_offset_t physical, return 0; } +static void +ad_init(device_t dev) +{ + struct ata_device *atadev = device_get_softc(dev); + + ATA_SETMODE(GRANDPARENT(dev), dev); + + /* enable read caching */ + ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_ENAB_RCACHE, 0, 0); + + /* enable write caching if enabled */ + if (ata_wc) + ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_ENAB_WCACHE, 0, 0); + else + ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_DIS_WCACHE, 0, 0); + + /* use multiple sectors/interrupt if device supports it */ + if (ad_version(atadev->param.version_major)) { + int secsperint = max(1, min(atadev->param.sectors_intr, 16)); + + if (!ata_controlcmd(atadev, ATA_SET_MULTI, 0, 0, secsperint)) + atadev->max_iosize = secsperint * DEV_BSIZE; + } + else + atadev->max_iosize = DEV_BSIZE; +} + void -ad_print(struct ad_softc *adp) +ad_describe(device_t dev) { - if (bootverbose) { - ata_prtdev(adp->device, "<%.40s/%.8s> ATA-%d disk at ata%d-%s\n", - adp->device->param->model, adp->device->param->revision, - ad_version(adp->device->param->version_major), - device_get_unit(adp->device->channel->dev), - (adp->device->unit == ATA_MASTER) ? "master" : "slave"); - - ata_prtdev(adp->device, - "%lluMB (%llu sectors), %llu C, %u H, %u S, %u B\n", - (unsigned long long)(adp->total_secs / - ((1024L*1024L)/DEV_BSIZE)), - (unsigned long long)adp->total_secs, - (unsigned long long)(adp->total_secs / - (adp->heads * adp->sectors)), - adp->heads, adp->sectors, DEV_BSIZE); - - ata_prtdev(adp->device, "%d secs/int, %d depth queue, %s%s\n", - adp->max_iosize / DEV_BSIZE, adp->num_tags + 1, - (adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "", - ata_mode2str(adp->device->mode)); + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_device *atadev = device_get_softc(dev); + struct ad_softc *adp = device_get_ivars(dev); + u_int8_t *marker, vendor[64], product[64]; + + /* try to seperate the ATA model string into vendor and model parts */ + if ((marker = index(atadev->param.model, ' ')) || + (marker = index(atadev->param.model, '-'))) { + int len = (marker - atadev->param.model); + + strncpy(vendor, atadev->param.model, len); + vendor[len++] = 0; + strcat(vendor, " "); + strncpy(product, atadev->param.model + len, 40 - len); + vendor[40 - len] = 0; } else { - ata_prtdev(adp->device, - "%lluMB <%.40s/%.8s> [%lld/%d/%d] at ata%d-%s %s%s\n", - (unsigned long long)(adp->total_secs / - ((1024L * 1024L) / DEV_BSIZE)), - adp->device->param->model, adp->device->param->revision, - (unsigned long long)(adp->total_secs / - (adp->heads * adp->sectors)), - adp->heads, adp->sectors, - device_get_unit(adp->device->channel->dev), - (adp->device->unit == ATA_MASTER) ? "master" : "slave", - (adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "", - ata_mode2str(adp->device->mode)); + if (!strncmp(atadev->param.model, "ST", 2)) + strcpy(vendor, "Seagate "); + else + strcpy(vendor, ""); + strncpy(product, atadev->param.model, 40); + } + + device_printf(dev, "%lluMB <%s%s %.8s> at ata%d-%s %s%s\n", + (unsigned long long)(adp->total_secs / (1048576 / DEV_BSIZE)), + vendor, product, atadev->param.revision, + device_get_unit(ch->dev), + (atadev->unit == ATA_MASTER) ? "master" : "slave", + (adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "", + ata_mode2str(atadev->mode)); + if (bootverbose) { + device_printf(dev, "%llu sectors [%lldC/%dH/%dS] " + "%d sectors/interrupt %d depth queue\n", + (unsigned long long)adp->total_secs, + (unsigned long long)(adp->total_secs / + (adp->heads * adp->sectors)), + adp->heads, adp->sectors, atadev->max_iosize / DEV_BSIZE, + adp->num_tags + 1); } } @@ -445,3 +416,45 @@ ad_version(u_int16_t version) return bit; return 0; } + +static device_method_t ad_methods[] = { + /* device interface */ + DEVMETHOD(device_identify, ad_identify), + DEVMETHOD(device_probe, ad_probe), + DEVMETHOD(device_attach, ad_attach), + DEVMETHOD(device_detach, ad_detach), + DEVMETHOD(device_shutdown, ad_shutdown), + + /* ATA methods */ + DEVMETHOD(ata_reinit, ad_reinit), + + { 0, 0 } +}; + +static driver_t ad_driver = { + "ad", + ad_methods, + sizeof(struct ad_softc) +}; + +devclass_t ad_devclass; + +static int +ad_modevent(module_t mod, int what, void *arg) +{ + device_t *devs; + int ndevs, i; + + if (what == MOD_UNLOAD) { + if (!devclass_get_devices(ad_devclass, &devs, &ndevs) && devs) { + for (i = 0; i < ndevs; i++) + device_delete_child(device_get_parent(devs[i]), devs[i]); + free(devs, M_TEMP); + } + } + return 0; +} + +DRIVER_MODULE(ad, ata, ad_driver, ad_devclass, ad_modevent, NULL); +MODULE_VERSION(ad, 1); +MODULE_DEPEND(ad, ata, 1, 1, 1); diff --git a/sys/dev/ata/ata-disk.h b/sys/dev/ata/ata-disk.h index c24c4ae..cbfc4a65 100644 --- a/sys/dev/ata/ata-disk.h +++ b/sys/dev/ata/ata-disk.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,22 +30,20 @@ /* structure describing an ATA disk */ struct ad_softc { - struct ata_device *device; /* ptr to device softc */ - int lun; /* logical unit number */ - u_int64_t total_secs; /* total # of sectors (LBA) */ - u_int8_t heads; - u_int8_t sectors; - u_int32_t transfersize; /* size of each transfer */ - int num_tags; /* number of tags supported */ - int max_iosize; /* max transfer HW supports */ - int flags; /* drive flags */ -#define AD_F_LABELLING 0x0001 -#define AD_F_CHS_USED 0x0002 -#define AD_F_32B_ENABLED 0x0004 -#define AD_F_TAG_ENABLED 0x0008 -#define AD_F_RAID_SUBDISK 0x0010 + u_int64_t total_secs; /* total # of sectors (LBA) */ + u_int8_t heads; + u_int8_t sectors; + u_int32_t transfersize; /* size of each transfer */ + int num_tags; /* number of tags supported */ + int flags; /* drive flags */ +#define AD_F_LABELLING 0x0001 +#define AD_F_CHS_USED 0x0002 +#define AD_F_32B_ENABLED 0x0004 +#define AD_F_TAG_ENABLED 0x0008 +#define AD_F_RAID_SUBDISK 0x0010 - struct mtx queue_mtx; /* bio queue lock */ - struct bio_queue_head queue; /* head of request queue */ - struct disk *disk; /* disklabel/slice stuff */ + struct disk *disk; /* disklabel/slice stuff */ }; + +extern devclass_t ad_devclass; + diff --git a/sys/dev/ata/ata-dma.c b/sys/dev/ata/ata-dma.c index 974fb7d..98e35a1 100644 --- a/sys/dev/ata/ata-dma.c +++ b/sys/dev/ata/ata-dma.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -57,8 +57,8 @@ static int ata_dmaunload(struct ata_channel *); static MALLOC_DEFINE(M_ATADMA, "ATA DMA", "ATA driver DMA"); /* misc defines */ -#define MAXTABSZ PAGE_SIZE -#define MAXWSPCSZ PAGE_SIZE +#define MAXTABSZ PAGE_SIZE +#define MAXWSPCSZ PAGE_SIZE struct ata_dc_cb_args { bus_addr_t maddr; @@ -104,51 +104,51 @@ ata_dmaalloc(struct ata_channel *ch) if (bus_dma_tag_create(ch->dma->dmatag, PAGE_SIZE, PAGE_SIZE, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MAXTABSZ, 1, MAXTABSZ, - 0, NULL, NULL, &ch->dma->cdmatag)) + 0, NULL, NULL, &ch->dma->sg_tag)) goto error; if (bus_dma_tag_create(ch->dma->dmatag,ch->dma->alignment,ch->dma->boundary, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 256 * DEV_BSIZE, ATA_DMA_ENTRIES, ch->dma->max_iosize, - BUS_DMA_ALLOCNOW, NULL, NULL, &ch->dma->ddmatag)) + BUS_DMA_ALLOCNOW, NULL, NULL, &ch->dma->data_tag)) goto error; - if (bus_dmamem_alloc(ch->dma->cdmatag, (void **)&ch->dma->dmatab, 0, - &ch->dma->cdmamap)) + if (bus_dmamem_alloc(ch->dma->sg_tag, (void **)&ch->dma->sg, 0, + &ch->dma->sg_map)) goto error; - if (bus_dmamap_load(ch->dma->cdmatag, ch->dma->cdmamap, ch->dma->dmatab, + if (bus_dmamap_load(ch->dma->sg_tag, ch->dma->sg_map, ch->dma->sg, MAXTABSZ, ata_dmasetupc_cb, &ccba, 0) || ccba.error) { - bus_dmamem_free(ch->dma->cdmatag, ch->dma->dmatab, ch->dma->cdmamap); + bus_dmamem_free(ch->dma->sg_tag, ch->dma->sg, ch->dma->sg_map); goto error; } - ch->dma->mdmatab = ccba.maddr; + ch->dma->sg_bus = ccba.maddr; - if (bus_dmamap_create(ch->dma->ddmatag, 0, &ch->dma->ddmamap)) + if (bus_dmamap_create(ch->dma->data_tag, 0, &ch->dma->data_map)) goto error; if (bus_dma_tag_create(ch->dma->dmatag, PAGE_SIZE, PAGE_SIZE, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MAXWSPCSZ, 1, MAXWSPCSZ, - 0, NULL, NULL, &ch->dma->wdmatag)) + 0, NULL, NULL, &ch->dma->work_tag)) goto error; - if (bus_dmamem_alloc(ch->dma->wdmatag, (void **)&ch->dma->workspace, 0, - &ch->dma->wdmamap)) + if (bus_dmamem_alloc(ch->dma->work_tag, (void **)&ch->dma->work, 0, + &ch->dma->work_map)) goto error; - if (bus_dmamap_load(ch->dma->wdmatag, ch->dma->wdmamap, ch->dma->workspace, + if (bus_dmamap_load(ch->dma->work_tag, ch->dma->work_map,ch->dma->work, MAXWSPCSZ, ata_dmasetupc_cb, &ccba, 0) || ccba.error) { - bus_dmamem_free(ch->dma->wdmatag, ch->dma->workspace, ch->dma->wdmamap); + bus_dmamem_free(ch->dma->work_tag,ch->dma->work, ch->dma->work_map); goto error; } - ch->dma->wdmatab = ccba.maddr; + ch->dma->work_bus = ccba.maddr; return; error: - ata_printf(ch, -1, "WARNING - DMA allocation failed, disabling DMA\n"); + device_printf(ch->dev, "WARNING - DMA allocation failed, disabling DMA\n"); ata_dmafree(ch); free(ch->dma, M_ATADMA); ch->dma = NULL; @@ -157,35 +157,35 @@ error: static void ata_dmafree(struct ata_channel *ch) { - if (ch->dma->wdmatab) { - bus_dmamap_unload(ch->dma->wdmatag, ch->dma->wdmamap); - bus_dmamem_free(ch->dma->wdmatag, ch->dma->workspace, ch->dma->wdmamap); - ch->dma->wdmatab = 0; - ch->dma->wdmamap = NULL; - ch->dma->workspace = NULL; + if (ch->dma->work_bus) { + bus_dmamap_unload(ch->dma->work_tag, ch->dma->work_map); + bus_dmamem_free(ch->dma->work_tag, ch->dma->work, ch->dma->work_map); + ch->dma->work_bus = 0; + ch->dma->work_map = NULL; + ch->dma->work = NULL; } - if (ch->dma->wdmatag) { - bus_dma_tag_destroy(ch->dma->wdmatag); - ch->dma->wdmatag = NULL; + if (ch->dma->work_tag) { + bus_dma_tag_destroy(ch->dma->work_tag); + ch->dma->work_tag = NULL; } - if (ch->dma->mdmatab) { - bus_dmamap_unload(ch->dma->cdmatag, ch->dma->cdmamap); - bus_dmamem_free(ch->dma->cdmatag, ch->dma->dmatab, ch->dma->cdmamap); - ch->dma->mdmatab = 0; - ch->dma->cdmamap = NULL; - ch->dma->dmatab = NULL; + if (ch->dma->sg_bus) { + bus_dmamap_unload(ch->dma->sg_tag, ch->dma->sg_map); + bus_dmamem_free(ch->dma->sg_tag, ch->dma->sg, ch->dma->sg_map); + ch->dma->sg_bus = 0; + ch->dma->sg_map = NULL; + ch->dma->sg = NULL; } - if (ch->dma->ddmamap) { - bus_dmamap_destroy(ch->dma->ddmatag, ch->dma->ddmamap); - ch->dma->ddmamap = NULL; + if (ch->dma->data_map) { + bus_dmamap_destroy(ch->dma->data_tag, ch->dma->data_map); + ch->dma->data_map = NULL; } - if (ch->dma->cdmatag) { - bus_dma_tag_destroy(ch->dma->cdmatag); - ch->dma->cdmatag = NULL; + if (ch->dma->sg_tag) { + bus_dma_tag_destroy(ch->dma->sg_tag); + ch->dma->sg_tag = NULL; } - if (ch->dma->ddmatag) { - bus_dma_tag_destroy(ch->dma->ddmatag); - ch->dma->ddmatag = NULL; + if (ch->dma->data_tag) { + bus_dma_tag_destroy(ch->dma->data_tag); + ch->dma->data_tag = NULL; } if (ch->dma->dmatag) { bus_dma_tag_destroy(ch->dma->dmatag); @@ -213,38 +213,41 @@ ata_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) static int ata_dmaload(struct ata_device *atadev, caddr_t data, int32_t count, int dir) { - struct ata_channel *ch = atadev->channel; + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); struct ata_dmasetprd_args cba; if (ch->dma->flags & ATA_DMA_LOADED) { - ata_prtdev(atadev, "FAILURE - already active DMA on this device\n"); + device_printf(atadev->dev, + "FAILURE - already active DMA on this device\n"); return -1; } if (!count) { - ata_prtdev(atadev, "FAILURE - zero length DMA transfer attempted\n"); + device_printf(atadev->dev, + "FAILURE - zero length DMA transfer attempted\n"); return -1; } if (((uintptr_t)data & (ch->dma->alignment - 1)) || (count & (ch->dma->alignment - 1))) { - ata_prtdev(atadev, "FAILURE - non aligned DMA transfer attempted\n"); + device_printf(atadev->dev, + "FAILURE - non aligned DMA transfer attempted\n"); return -1; } if (count > ch->dma->max_iosize) { - ata_prtdev(atadev, - "FAILURE - oversized DMA transfer attempted %d > %d\n", - count, ch->dma->max_iosize); + device_printf(atadev->dev, + "FAILURE - oversized DMA transfer attempted %d > %d\n", + count, ch->dma->max_iosize); return -1; } - cba.dmatab = ch->dma->dmatab; + cba.dmatab = ch->dma->sg; - bus_dmamap_sync(ch->dma->cdmatag, ch->dma->cdmamap, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(ch->dma->sg_tag, ch->dma->sg_map, BUS_DMASYNC_PREWRITE); - if (bus_dmamap_load(ch->dma->ddmatag, ch->dma->ddmamap, data, count, + if (bus_dmamap_load(ch->dma->data_tag, ch->dma->data_map, data, count, ch->dma->setprd, &cba, 0) || cba.error) return -1; - bus_dmamap_sync(ch->dma->ddmatag, ch->dma->ddmamap, + bus_dmamap_sync(ch->dma->data_tag, ch->dma->data_map, dir ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); ch->dma->cur_iosize = count; @@ -255,12 +258,12 @@ ata_dmaload(struct ata_device *atadev, caddr_t data, int32_t count, int dir) int ata_dmaunload(struct ata_channel *ch) { - bus_dmamap_sync(ch->dma->cdmatag, ch->dma->cdmamap, BUS_DMASYNC_POSTWRITE); + bus_dmamap_sync(ch->dma->sg_tag, ch->dma->sg_map, BUS_DMASYNC_POSTWRITE); - bus_dmamap_sync(ch->dma->ddmatag, ch->dma->ddmamap, + bus_dmamap_sync(ch->dma->data_tag, ch->dma->data_map, (ch->dma->flags & ATA_DMA_READ) != 0 ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(ch->dma->ddmatag, ch->dma->ddmamap); + bus_dmamap_unload(ch->dma->data_tag, ch->dma->data_map); ch->dma->cur_iosize = 0; ch->dma->flags &= ~ATA_DMA_LOADED; diff --git a/sys/dev/ata/ata-isa.c b/sys/dev/ata/ata-isa.c index 4fadd2d..c15a2d3 100644 --- a/sys/dev/ata/ata-isa.c +++ b/sys/dev/ata/ata-isa.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,28 +49,16 @@ __FBSDID("$FreeBSD$"); /* local vars */ static struct isa_pnp_id ata_ids[] = { - {0x0006d041, "Generic ESDI/IDE/ATA controller"}, /* PNP0600 */ - {0x0106d041, "Plus Hardcard II"}, /* PNP0601 */ - {0x0206d041, "Plus Hardcard IIXL/EZ"}, /* PNP0602 */ - {0x0306d041, "Generic ATA"}, /* PNP0603 */ + {0x0006d041, "Generic ESDI/IDE/ATA controller"}, /* PNP0600 */ + {0x0106d041, "Plus Hardcard II"}, /* PNP0601 */ + {0x0206d041, "Plus Hardcard IIXL/EZ"}, /* PNP0602 */ + {0x0306d041, "Generic ATA"}, /* PNP0603 */ /* PNP0680 */ - {0x8006d041, "Standard bus mastering IDE hard disk controller"}, + {0x8006d041, "Standard bus mastering IDE hard disk controller"}, {0} }; static int -ata_isa_locknoop(struct ata_channel *ch, int type) -{ - return ch->unit; -} - -static void -ata_isa_setmode(struct ata_device *atadev, int mode) -{ - atadev->mode = ata_limit_mode(atadev, mode, ATA_PIO_MAX); -} - -static int ata_isa_probe(device_t dev) { struct ata_channel *ch = device_get_softc(dev); @@ -115,18 +103,16 @@ ata_isa_probe(device_t dev) /* initialize softc for this channel */ ch->unit = 0; ch->flags |= ATA_USE_16BIT; - ch->locking = ata_isa_locknoop; - ch->device[MASTER].setmode = ata_isa_setmode; - ch->device[SLAVE].setmode = ata_isa_setmode; ata_generic_hw(ch); return ata_probe(dev); } static device_method_t ata_isa_methods[] = { /* device interface */ - DEVMETHOD(device_probe, ata_isa_probe), - DEVMETHOD(device_attach, ata_attach), - DEVMETHOD(device_resume, ata_resume), + DEVMETHOD(device_probe, ata_isa_probe), + DEVMETHOD(device_attach, ata_attach), + DEVMETHOD(device_suspend, ata_suspend), + DEVMETHOD(device_resume, ata_resume), { 0, 0 } }; @@ -137,3 +123,4 @@ static driver_t ata_isa_driver = { }; DRIVER_MODULE(ata, isa, ata_isa_driver, ata_devclass, 0, 0); +MODULE_DEPEND(ata, ata, 1, 1, 1); diff --git a/sys/dev/ata/ata-lowlevel.c b/sys/dev/ata/ata-lowlevel.c index aec3b05..bb9d9e0 100644 --- a/sys/dev/ata/ata-lowlevel.c +++ b/sys/dev/ata/ata-lowlevel.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,9 +32,11 @@ __FBSDID("$FreeBSD$"); #include "opt_ata.h" #include <sys/param.h> #include <sys/systm.h> -#include <sys/ata.h> #include <sys/kernel.h> +#include <sys/endian.h> +#include <sys/ata.h> #include <sys/conf.h> +#include <sys/ctype.h> #include <sys/bus.h> #include <sys/sema.h> #include <sys/taskqueue.h> @@ -42,17 +44,108 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <sys/rman.h> #include <dev/ata/ata-all.h> +#include <dev/ata/ata-commands.h> +#include <dev/ata/ata-pci.h> +#include <ata_if.h> /* prototypes */ static int ata_begin_transaction(struct ata_request *); static int ata_end_transaction(struct ata_request *); static void ata_generic_reset(struct ata_channel *); -static int ata_wait(struct ata_device *, u_int8_t); +static int ata_wait(struct ata_channel *ch, struct ata_device *, u_int8_t); static void ata_pio_read(struct ata_request *, int); static void ata_pio_write(struct ata_request *, int); +static void bswap(int8_t *, int); +static void btrim(int8_t *, int); +static void bpack(int8_t *, int8_t *, int); + +/* get device parameter page from device */ +int +ata_getparam(device_t parent, struct ata_device *atadev, u_int8_t command) +{ + struct ata_channel *ch = device_get_softc(parent); + int error = 0, retry = 0; + + do { + if (retry++ > 4) { + if (bootverbose) + printf("ata%d-%s: %s-identify retries exceeded\n", ch->unit, + atadev->unit == ATA_MASTER ? "master" : "slave", + command == ATA_ATAPI_IDENTIFY ? "ATAPI" : "ATA"); + error = ENXIO; + break; + } + + /* select device */ + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | atadev->unit); + + /* disable interrupt */ + ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_4BIT | ATA_A_IDS); + + /* ready to issue command ? */ + if ((error = ata_wait(ch, atadev, 0)) < 0) { + printf("ata%d-%s: timeout sending %s-identify error=%d\n", + device_get_unit(parent), + atadev->unit == ATA_MASTER ? "master" : "slave", + command == ATA_ATAPI_IDENTIFY ? "ATAPI" : "ATA", error); + error = ENXIO; + break; + } + + /* select device */ + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | atadev->unit); + + /* issue command */ + ATA_IDX_OUTB(ch, ATA_CMD, command); + + } while (ata_wait(ch, atadev, ATA_S_DRQ)); + + if (!error) { + ATA_IDX_INSW_STRM(ch, ATA_DATA, (void *)&atadev->param, + sizeof(struct ata_params)/sizeof(int16_t)); + ATA_IDX_INB(ch, ATA_STATUS); + } + + if (!error && (isprint(atadev->param.model[0]) || + isprint(atadev->param.model[1]))) { + struct ata_params *atacap = &atadev->param; +#if BYTE_ORDER == BIG_ENDIAN + int16_t *ptr; + + for (ptr = (int16_t *)atacap; + ptr < (int16_t *)atacap + sizeof(struct ata_params)/2; ptr++) { + *ptr = bswap16(*ptr); + } +#endif + 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", + ch->unit, atadev->unit == ATA_MASTER ? "master":"slave", + ata_mode2str(ata_pmode(atacap)), + ata_mode2str(ata_wmode(atacap)), + ata_mode2str(ata_umode(atacap)), + (atacap->hwres & ATA_CABLE_ID) ? "80":"40"); + } + else { + if (!error) + error = ENXIO; + } -/* local vars */ -static int atadebug = 0; + return error; +} /* * low level ATA functions @@ -70,14 +163,8 @@ ata_generic_hw(struct ata_channel *ch) static int ata_begin_transaction(struct ata_request *request) { - struct ata_channel *ch = request->device->channel; - - /* safetybelt for HW that went away */ - if (!request->device->param || request->device->channel->flags&ATA_HWGONE) { - request->retries = 0; - request->result = ENXIO; - return ATA_OP_FINISHED; - } + struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_device *atadev = device_get_softc(request->dev); ATA_DEBUG_RQ(request, "begin transaction"); @@ -96,17 +183,17 @@ ata_begin_transaction(struct ata_request *request) int write = (request->flags & ATA_R_WRITE); /* issue command */ - if (ch->hw.command(request->device, request->u.ata.command, + if (ch->hw.command(atadev, request->u.ata.command, request->u.ata.lba, request->u.ata.count, request->u.ata.feature)) { - ata_prtdev(request->device, "error issueing %s command\n", + device_printf(request->dev, "error issueing %s command\n", ata_cmd2str(request)); request->result = EIO; break; } /* device reset doesn't interrupt */ - if (request->u.ata.command == ATA_ATAPI_RESET) { + if (request->u.ata.command == ATA_DEVICE_RESET) { int timeout = 1000000; do { DELAY(10); @@ -119,9 +206,9 @@ ata_begin_transaction(struct ata_request *request) /* if write command output the data */ if (write) { - if (ata_wait(request->device, + if (ata_wait(ch, atadev, (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) { - ata_prtdev(request->device,"timeout waiting for write DRQ"); + device_printf(request->dev,"timeout waiting for write DRQ"); request->result = EIO; break; } @@ -133,18 +220,18 @@ ata_begin_transaction(struct ata_request *request) /* ATA DMA data transfer commands */ case ATA_R_DMA: /* check sanity, setup SG list and DMA engine */ - if (ch->dma->load(request->device, request->data, request->bytecount, + if (ch->dma->load(atadev, request->data, request->bytecount, request->flags & ATA_R_READ)) { - ata_prtdev(request->device, "setting up DMA failed\n"); + device_printf(request->dev, "setting up DMA failed\n"); request->result = EIO; break; } /* issue command */ - if (ch->hw.command(request->device, request->u.ata.command, + if (ch->hw.command(atadev, request->u.ata.command, request->u.ata.lba, request->u.ata.count, request->u.ata.feature)) { - ata_prtdev(request->device, "error issueing %s command\n", + device_printf(request->dev, "error issueing %s command\n", ata_cmd2str(request)); request->result = EIO; break; @@ -152,7 +239,7 @@ ata_begin_transaction(struct ata_request *request) /* start DMA engine */ if (ch->dma->start(ch)) { - ata_prtdev(request->device, "error starting DMA\n"); + device_printf(request->dev, "error starting DMA\n"); request->result = EIO; break; } @@ -162,8 +249,7 @@ ata_begin_transaction(struct ata_request *request) case ATA_R_ATAPI: /* is this just a POLL DSC command ? */ if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) { - ATA_IDX_OUTB(ch, ATA_DRIVE, - ATA_D_IBM | request->device->unit); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | atadev->unit); DELAY(10); if (!(ATA_IDX_INB(ch, ATA_ALTSTAT)&ATA_S_DSC)) request->result = EBUSY; @@ -171,15 +257,15 @@ ata_begin_transaction(struct ata_request *request) } /* start ATAPI operation */ - if (ch->hw.command(request->device, ATA_PACKET_CMD, + if (ch->hw.command(atadev, ATA_PACKET_CMD, request->transfersize << 8, 0, 0)) { - ata_prtdev(request->device, "error issuing ATA PACKET command\n"); + device_printf(request->dev, "error issuing ATA PACKET command\n"); request->result = EIO; break; } /* command interrupt device ? just return and wait for interrupt */ - if ((request->device->param->config & ATA_DRQ_MASK) == ATA_DRQ_INTR) + if ((atadev->param.config & ATA_DRQ_MASK) == ATA_DRQ_INTR) return ATA_OP_CONTINUES; /* wait for ready to write ATAPI command block */ @@ -195,8 +281,7 @@ ata_begin_transaction(struct ata_request *request) DELAY(20); } if (timeout <= 0) { - ata_prtdev(request->device, - "timeout waiting for ATAPI ready\n"); + device_printf(request->dev,"timeout waiting for ATAPI ready\n"); request->result = EIO; break; } @@ -208,15 +293,14 @@ ata_begin_transaction(struct ata_request *request) /* output actual command block */ ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (int16_t *)request->u.atapi.ccb, - (request->device->param->config & ATA_PROTO_MASK) == + (atadev->param.config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12 ? 6 : 8); return ATA_OP_CONTINUES; case ATA_R_ATAPI|ATA_R_DMA: /* is this just a POLL DSC command ? */ if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) { - ATA_IDX_OUTB(ch, ATA_DRIVE, - ATA_D_IBM | request->device->unit); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | atadev->unit); DELAY(10); if (!(ATA_IDX_INB(ch, ATA_ALTSTAT)&ATA_S_DSC)) request->result = EBUSY; @@ -224,18 +308,16 @@ ata_begin_transaction(struct ata_request *request) } /* check sanity, setup SG list and DMA engine */ - if (ch->dma->load(request->device, - request->data, - request->bytecount, - request->flags & ATA_R_READ)) { - ata_prtdev(request->device, "setting up DMA failed\n"); + if (ch->dma->load(atadev, request->data, request->bytecount, + request->flags & ATA_R_READ)) { + device_printf(request->dev, "setting up DMA failed\n"); request->result = EIO; break; } /* start ATAPI operation */ - if (ch->hw.command(request->device, ATA_PACKET_CMD, 0, 0, ATA_F_DMA)) { - ata_prtdev(request->device, "error issuing ATAPI packet command\n"); + if (ch->hw.command(atadev, ATA_PACKET_CMD, 0, 0, ATA_F_DMA)) { + device_printf(request->dev, "error issuing ATAPI packet command\n"); request->result = EIO; break; } @@ -253,7 +335,7 @@ ata_begin_transaction(struct ata_request *request) DELAY(20); } if (timeout <= 0) { - ata_prtdev(request->device,"timeout waiting for ATAPI ready\n"); + device_printf(request->dev,"timeout waiting for ATAPI ready\n"); request->result = EIO; break; } @@ -265,7 +347,7 @@ ata_begin_transaction(struct ata_request *request) /* output actual command block */ ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (int16_t *)request->u.atapi.ccb, - (request->device->param->config & ATA_PROTO_MASK) == + (atadev->param.config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12 ? 6 : 8); /* start DMA engine */ @@ -285,7 +367,8 @@ ata_begin_transaction(struct ata_request *request) static int ata_end_transaction(struct ata_request *request) { - struct ata_channel *ch = request->device->channel; + struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_device *atadev = device_get_softc(request->dev); int length; ATA_DEBUG_RQ(request, "end transaction"); @@ -297,9 +380,11 @@ ata_end_transaction(struct ata_request *request) /* ATA PIO data transfer and control commands */ default: - /* XXX Doesn't handle the non-PIO case. */ + + /* on timeouts we have no data or anything so just return */ if (request->flags & ATA_R_TIMEOUT) - return ATA_OP_FINISHED; + //return ATA_OP_FINISHED; + break; /* on control commands read back registers to the request struct */ if (request->flags & ATA_R_CONTROL) { @@ -307,21 +392,30 @@ ata_end_transaction(struct ata_request *request) request->u.ata.lba = ATA_IDX_INB(ch, ATA_SECTOR) | (ATA_IDX_INB(ch, ATA_CYL_LSB) << 8) | (ATA_IDX_INB(ch, ATA_CYL_MSB) << 16) | - ((ATA_IDX_INB(ch, ATA_DRIVE) & 0x0f) << 24); + ((ATA_IDX_INB(ch, ATA_DRIVE) & 0x0f) << 24); } /* if we got an error we are done with the HW */ if (request->status & ATA_S_ERROR) { request->error = ATA_IDX_INB(ch, ATA_ERROR); - return ATA_OP_FINISHED; + //return ATA_OP_FINISHED; + break; } /* are we moving data ? */ if (request->flags & (ATA_R_READ | ATA_R_WRITE)) { /* if read data get it */ - if (request->flags & ATA_R_READ) + if (request->flags & ATA_R_READ) { + if (ata_wait(ch, atadev, + (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) { + device_printf(request->dev, "timeout waiting for read DRQ"); + request->result = EIO; + //return ATA_OP_FINISHED; + break; + } ata_pio_read(request, request->transfersize); + } /* update how far we've gotten */ request->donecount += request->transfersize; @@ -334,19 +428,17 @@ ata_end_transaction(struct ata_request *request) min((request->bytecount - request->donecount), request->transfersize); - /* clear interrupt seen flag as we need to wait again */ - request->flags &= ~ATA_R_INTR_SEEN; - /* if data write command, output the data */ if (request->flags & ATA_R_WRITE) { /* if we get an error here we are done with the HW */ - if (ata_wait(request->device, + if (ata_wait(ch, atadev, (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) { - ata_prtdev(request->device, - "timeout waiting for write DRQ"); + device_printf(request->dev, + "timeout waiting for write DRQ"); request->status = ATA_IDX_INB(ch, ATA_STATUS); - return ATA_OP_FINISHED; + //return ATA_OP_FINISHED; + break; } /* output data and return waiting for new interrupt */ @@ -360,7 +452,8 @@ ata_end_transaction(struct ata_request *request) } } /* done with HW */ - return ATA_OP_FINISHED; + //return ATA_OP_FINISHED; + break; /* ATA DMA data transfer commands */ case ATA_R_DMA: @@ -374,19 +467,25 @@ ata_end_transaction(struct ata_request *request) request->error = ATA_IDX_INB(ch, ATA_ERROR); else if (request->dmastat & ATA_BMSTAT_ERROR) request->status |= ATA_S_ERROR; - else + else if (!(request->flags & ATA_R_TIMEOUT)) request->donecount = request->bytecount; /* release SG list etc */ ch->dma->unload(ch); /* done with HW */ - return ATA_OP_FINISHED; + //return ATA_OP_FINISHED; + break; /* ATAPI PIO commands */ case ATA_R_ATAPI: length = ATA_IDX_INB(ch, ATA_CYL_LSB)|(ATA_IDX_INB(ch, ATA_CYL_MSB)<<8); + /* on timeouts we have no data or anything so just return */ + if (request->flags & ATA_R_TIMEOUT) + //return ATA_OP_FINISHED; + break; + switch ((ATA_IDX_INB(ch, ATA_IREASON) & (ATA_I_CMD | ATA_I_IN)) | (request->status & ATA_S_DRQ)) { @@ -395,12 +494,13 @@ ata_end_transaction(struct ata_request *request) DELAY(10); if (!(request->status & ATA_S_DRQ)) { - ata_prtdev(request->device, "command interrupt without DRQ\n"); + device_printf(request->dev, "command interrupt without DRQ\n"); request->status = ATA_S_ERROR; - return ATA_OP_FINISHED; + //return ATA_OP_FINISHED; + break; } ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (int16_t *)request->u.atapi.ccb, - (request->device->param->config & + (atadev->param.config & ATA_PROTO_MASK)== ATA_PROTO_ATAPI_12 ? 6 : 8); /* return wait for interrupt */ return ATA_OP_CONTINUES; @@ -408,10 +508,11 @@ ata_end_transaction(struct ata_request *request) case ATAPI_P_WRITE: if (request->flags & ATA_R_READ) { request->status = ATA_S_ERROR; - ata_prtdev(request->device, - "%s trying to write on read buffer\n", + device_printf(request->dev, + "%s trying to write on read buffer\n", ata_cmd2str(request)); - return ATA_OP_FINISHED; + //return ATA_OP_FINISHED; + break; } ata_pio_write(request, length); request->donecount += length; @@ -425,10 +526,11 @@ ata_end_transaction(struct ata_request *request) case ATAPI_P_READ: if (request->flags & ATA_R_WRITE) { request->status = ATA_S_ERROR; - ata_prtdev(request->device, - "%s trying to read on write buffer\n", + device_printf(request->dev, + "%s trying to read on write buffer\n", ata_cmd2str(request)); - return ATA_OP_FINISHED; + //return ATA_OP_FINISHED; + break; } ata_pio_read(request, length); request->donecount += length; @@ -440,9 +542,9 @@ ata_end_transaction(struct ata_request *request) return ATA_OP_CONTINUES; case ATAPI_P_DONEDRQ: - ata_prtdev(request->device, - "WARNING - %s DONEDRQ non conformant device\n", - ata_cmd2str(request)); + device_printf(request->dev, + "WARNING - %s DONEDRQ non conformant device\n", + ata_cmd2str(request)); if (request->flags & ATA_R_READ) { ata_pio_read(request, length); request->donecount += length; @@ -459,15 +561,17 @@ ata_end_transaction(struct ata_request *request) case ATAPI_P_DONE: if (request->status & (ATA_S_ERROR | ATA_S_DWF)) request->error = ATA_IDX_INB(ch, ATA_ERROR); - return ATA_OP_FINISHED; + //return ATA_OP_FINISHED; + break; default: - ata_prtdev(request->device, "unknown transfer phase\n"); + device_printf(request->dev, "unknown transfer phase\n"); request->status = ATA_S_ERROR; } /* done with HW */ - return ATA_OP_FINISHED; + //return ATA_OP_FINISHED; + break; /* ATAPI DMA commands */ case ATA_R_ATAPI|ATA_R_DMA: @@ -481,39 +585,44 @@ ata_end_transaction(struct ata_request *request) request->error = ATA_IDX_INB(ch, ATA_ERROR); else if (request->dmastat & ATA_BMSTAT_ERROR) request->status |= ATA_S_ERROR; - else + else if (!(request->flags & ATA_R_TIMEOUT)) request->donecount = request->bytecount; /* release SG list etc */ ch->dma->unload(ch); /* done with HW */ - return ATA_OP_FINISHED; + //return ATA_OP_FINISHED; + break; } + + /* disable interrupt */ + //ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_4BIT | ATA_A_IDS); + + return ATA_OP_FINISHED; } /* must be called with ATA channel locked */ static void ata_generic_reset(struct ata_channel *ch) { - u_int8_t err = 0, lsb = 0, msb = 0, ostat0, ostat1; - u_int8_t stat0 = 0, stat1 = 0; + u_int8_t ostat0 = 0, stat0 = 0, ostat1 = 0, stat1 = 0; + u_int8_t err = 0, lsb = 0, msb = 0; int mask = 0, timeout; /* if DMA functionality present stop it */ if (ch->dma) { - if (ch->dma->stop) - ch->dma->stop(ch); - if (ch->dma->flags & ATA_DMA_LOADED) - ch->dma->unload(ch); + if (ch->dma->stop) + ch->dma->stop(ch); + if (ch->dma->flags & ATA_DMA_LOADED) + ch->dma->unload(ch); } /* reset host end of channel (if supported) */ - if (ch->reset) - ch->reset(ch); + ATA_RESET(device_get_parent(ch->dev), ch->dev); /* do we have any signs of ATA/ATAPI HW being present ? */ - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_MASTER); DELAY(10); ostat0 = ATA_IDX_INB(ch, ATA_STATUS); if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) { @@ -521,12 +630,11 @@ ata_generic_reset(struct ata_channel *ch) mask |= 0x01; } - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); - DELAY(10); - ostat1 = ATA_IDX_INB(ch, ATA_STATUS); - /* in some setups we dont want to test for a slave */ if (!(ch->flags & ATA_NO_SLAVE)) { + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_SLAVE); + DELAY(10); + ostat1 = ATA_IDX_INB(ch, ATA_STATUS); if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) { stat1 = ATA_S_BUSY; mask |= 0x02; @@ -534,8 +642,8 @@ ata_generic_reset(struct ata_channel *ch) } if (bootverbose) - ata_printf(ch, -1, "reset tp1 mask=%02x ostat0=%02x ostat1=%02x\n", - mask, ostat0, ostat1); + device_printf(ch->dev, "reset tp1 mask=%02x ostat0=%02x ostat1=%02x\n", + mask, ostat0, ostat1); /* if nothing showed up there is no need to get any further */ /* SOS is that too strong?, we just might loose devices here XXX */ @@ -544,7 +652,7 @@ ata_generic_reset(struct ata_channel *ch) return; /* reset (both) devices on this channel */ - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_MASTER); DELAY(10); ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS | ATA_A_RESET); ata_udelay(10000); @@ -554,17 +662,19 @@ ata_generic_reset(struct ata_channel *ch) /* wait for BUSY to go inactive */ for (timeout = 0; timeout < 310; timeout++) { - if (stat0 & ATA_S_BUSY) { + if ((mask & 0x01) && (stat0 & ATA_S_BUSY)) { ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); DELAY(10); - err = ATA_IDX_INB(ch, ATA_ERROR); + err = ATA_IDX_INB(ch, ATA_ERROR); lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); msb = ATA_IDX_INB(ch, ATA_CYL_MSB); stat0 = ATA_IDX_INB(ch, ATA_STATUS); if (bootverbose) - ata_printf(ch, ATA_MASTER, - "stat=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n", - stat0, err, lsb, msb); + device_printf(ch->dev, + "stat0=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n", + stat0, err, lsb, msb); + if (stat0 == err && lsb == err && msb == err && timeout > 10) + mask &= ~0x01; if (!(stat0 & ATA_S_BUSY)) { if ((err & 0x7f) == ATA_E_ILI) { if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) { @@ -574,22 +684,25 @@ ata_generic_reset(struct ata_channel *ch) ch->devices |= ATA_ATA_MASTER; } } - else if ((stat0 & 0x4f) && err == lsb && err == msb) { + else if ((stat0 & 0x0f) && err == lsb && err == msb) { stat0 |= ATA_S_BUSY; } } } - if (!((mask == 0x03) && (stat0 & ATA_S_BUSY)) && (stat1 & ATA_S_BUSY)) { + + if ((mask & 0x02) && (stat1 & ATA_S_BUSY)) { ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); DELAY(10); - err = ATA_IDX_INB(ch, ATA_ERROR); + err = ATA_IDX_INB(ch, ATA_ERROR); lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); msb = ATA_IDX_INB(ch, ATA_CYL_MSB); stat1 = ATA_IDX_INB(ch, ATA_STATUS); if (bootverbose) - ata_printf(ch, ATA_SLAVE, - " stat=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n", - stat1, err, lsb, msb); + device_printf(ch->dev, + "stat1=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n", + stat1, err, lsb, msb); + if (stat1 == err && lsb == err && msb == err && timeout > 10) + mask &= ~0x02; if (!(stat1 & ATA_S_BUSY)) { if ((err & 0x7f) == ATA_E_ILI) { if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) { @@ -599,44 +712,39 @@ ata_generic_reset(struct ata_channel *ch) ch->devices |= ATA_ATA_SLAVE; } } - else if ((stat1 & 0x4f) && err == lsb && err == msb) { - stat1 |= ATA_S_BUSY; + else if ((stat0 & 0x0f) && err == lsb && err == msb) { + stat0 |= ATA_S_BUSY; } } } - if (mask == 0x01) /* wait for master only */ - if (!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 5) || - (stat0 == err && lsb == err && msb == err && timeout > 5)) + + if (mask == 0x00) /* nothing to wait for */ + break; + if (mask == 0x01) /* wait for master only */ + if (!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 10)) break; - if (mask == 0x02) /* wait for slave only */ - if (!(stat1 & ATA_S_BUSY) || (stat1 == 0xff && timeout > 5) || - (stat1 == err && lsb == err && msb == err && timeout > 5)) + if (mask == 0x02) /* wait for slave only */ + if (!(stat1 & ATA_S_BUSY) || (stat1 == 0xff && timeout > 10)) break; - if (mask == 0x03) { /* wait for both master & slave */ + if (mask == 0x03) { /* wait for both master & slave */ if (!(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY)) break; - if ((stat0 == 0xff && timeout > 5) || - (stat0 == err && lsb == err && msb == err && timeout > 5)) + if ((stat0 == 0xff) && (timeout > 20)) mask &= ~0x01; - if ((stat1 == 0xff && timeout > 5) || - (stat1 == err && lsb == err && msb == err && timeout > 5)) + if ((stat1 == 0xff) && (timeout > 20)) mask &= ~0x02; } - if (mask == 0 && !(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY)) - break; - ata_udelay(100000); } if (bootverbose) - ata_printf(ch, -1, - "reset tp2 stat0=%02x stat1=%02x devices=0x%b\n", - stat0, stat1, ch->devices, - "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER"); + device_printf(ch->dev, "reset tp2 stat0=%02x stat1=%02x devices=0x%b\n", + stat0, stat1, ch->devices, + "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER"); } static int -ata_wait(struct ata_device *atadev, u_int8_t mask) +ata_wait(struct ata_channel *ch, struct ata_device *atadev, u_int8_t mask) { u_int8_t status; int timeout = 0; @@ -645,21 +753,19 @@ ata_wait(struct ata_device *atadev, u_int8_t mask) /* wait 5 seconds for device to get !BUSY */ while (timeout < 5000000) { - status = ATA_IDX_INB(atadev->channel, ATA_STATUS); + status = ATA_IDX_INB(ch, ATA_ALTSTAT); - /* if drive fails status, reselect the drive just to be sure */ + /* if drive fails status, reselect the drive and try again */ if (status == 0xff) { - ata_prtdev(atadev, "WARNING no status, reselecting device\n"); - ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit); - DELAY(10); - status = ATA_IDX_INB(atadev->channel, ATA_STATUS); - if (status == 0xff) - return -1; + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | atadev->unit); + timeout += 1000; + DELAY(1000); + continue; } /* are we done ? */ if (!(status & ATA_S_BUSY)) - break; + break; if (timeout > 1000) { timeout += 1000; @@ -669,50 +775,46 @@ ata_wait(struct ata_device *atadev, u_int8_t mask) timeout += 10; DELAY(10); } - } - if (timeout >= 5000000) - return -1; - if (!mask) - return (status & ATA_S_ERROR); + } + if (timeout >= 5000000) + return -2; + if (!mask) + return (status & ATA_S_ERROR); DELAY(1); - /* wait 50 msec for bits wanted */ + /* wait 50 msec for bits wanted */ timeout = 5000; - while (timeout--) { - status = ATA_IDX_INB(atadev->channel, ATA_STATUS); + while (timeout--) { + status = ATA_IDX_INB(ch, ATA_ALTSTAT); if ((status & mask) == mask) - return (status & ATA_S_ERROR); - DELAY (10); - } - return -1; + return (status & ATA_S_ERROR); + DELAY(10); + } + return -3; } int ata_generic_command(struct ata_device *atadev, u_int8_t command, - u_int64_t lba, u_int16_t count, u_int16_t feature) + u_int64_t lba, u_int16_t count, u_int16_t feature) { - if (atadebug) - ata_prtdev(atadev, "ata_command: addr=%04lx, command=%02x, " - "lba=%jd, count=%d, feature=%d\n", - rman_get_start(atadev->channel->r_io[ATA_DATA].res), - command, (intmax_t)lba, count, feature); + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); /* select device */ - ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | atadev->unit); /* ready to issue command ? */ - if (ata_wait(atadev, 0) < 0) { - ata_prtdev(atadev, "timeout sending command=%02x\n", command); + if (ata_wait(ch, atadev, 0) < 0) { + device_printf(atadev->dev, "timeout sending command=%02x\n", command); return -1; } /* enable interrupt */ - ATA_IDX_OUTB(atadev->channel, ATA_ALTSTAT, ATA_A_4BIT); + ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_4BIT); /* only use 48bit addressing if needed (avoid bugs and overhead) */ - if ((lba >= ATA_MAX_28BIT_LBA || count > 256) && atadev->param && - atadev->param->support.command2 & ATA_SUPPORT_ADDRESS48) { + if ((lba >= ATA_MAX_28BIT_LBA || count > 256) && + atadev->param.support.command2 & ATA_SUPPORT_ADDRESS48) { /* translate command into 48bit version */ switch (command) { @@ -735,39 +837,54 @@ ata_generic_command(struct ata_device *atadev, u_int8_t command, case ATA_FLUSHCACHE: command = ATA_FLUSHCACHE48; break; default: - ata_prtdev(atadev, "can't translate cmd to 48bit version\n"); + device_printf(atadev->dev,"can't translate cmd to 48bit version\n"); return -1; } - ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, (feature>>8) & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, feature & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_COUNT, (count>>8) & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_COUNT, count & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, (lba>>24) & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, lba & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>32) & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>8) & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>40) & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>16) & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_LBA | atadev->unit); - atadev->channel->flags |= ATA_48BIT_ACTIVE; + ATA_IDX_OUTB(ch, ATA_FEATURE, (feature>>8) & 0xff); + ATA_IDX_OUTB(ch, ATA_FEATURE, feature & 0xff); + ATA_IDX_OUTB(ch, ATA_COUNT, (count>>8) & 0xff); + ATA_IDX_OUTB(ch, ATA_COUNT, count & 0xff); + ATA_IDX_OUTB(ch, ATA_SECTOR, (lba>>24) & 0xff); + ATA_IDX_OUTB(ch, ATA_SECTOR, lba & 0xff); + ATA_IDX_OUTB(ch, ATA_CYL_LSB, (lba>>32) & 0xff); + ATA_IDX_OUTB(ch, ATA_CYL_LSB, (lba>>8) & 0xff); + ATA_IDX_OUTB(ch, ATA_CYL_MSB, (lba>>40) & 0xff); + ATA_IDX_OUTB(ch, ATA_CYL_MSB, (lba>>16) & 0xff); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_LBA | atadev->unit); + ch->flags |= ATA_48BIT_ACTIVE; } else { - ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, feature); - ATA_IDX_OUTB(atadev->channel, ATA_COUNT, count); - ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, lba & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>8) & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>16) & 0xff); - if (atadev->flags & ATA_D_USE_CHS) - ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, - ATA_D_IBM | atadev->unit | ((lba>>24) & 0xf)); - else - ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, - ATA_D_IBM | ATA_D_LBA | atadev->unit|((lba>>24)&0xf)); - atadev->channel->flags &= ~ATA_48BIT_ACTIVE; + ATA_IDX_OUTB(ch, ATA_FEATURE, feature); + ATA_IDX_OUTB(ch, ATA_COUNT, count); + if (atadev->flags & ATA_D_USE_CHS) { + int heads, sectors; + + if (atadev->param.atavalid & ATA_FLAG_54_58) { + heads = atadev->param.current_heads; + sectors = atadev->param.current_sectors; + } + else { + heads = atadev->param.heads; + sectors = atadev->param.sectors; + } + ATA_IDX_OUTB(ch, ATA_SECTOR, (lba % sectors) + 1); + ATA_IDX_OUTB(ch, ATA_CYL_LSB, (lba / (sectors * heads))); + ATA_IDX_OUTB(ch, ATA_CYL_MSB, (lba / (sectors * heads)) >> 8); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | atadev->unit | + (((lba % (sectors * heads)) / sectors) & 0xf)); + } + else { + ATA_IDX_OUTB(ch, ATA_SECTOR, lba & 0xff); + ATA_IDX_OUTB(ch, ATA_CYL_LSB, (lba>>8) & 0xff); + ATA_IDX_OUTB(ch, ATA_CYL_MSB, (lba>>16) & 0xff); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | atadev->unit | + ((lba>>24) & 0x0f)); + } + ch->flags &= ~ATA_48BIT_ACTIVE; } /* issue command to controller */ - ATA_IDX_OUTB(atadev->channel, ATA_CMD, command); + ATA_IDX_OUTB(ch, ATA_CMD, command); return 0; } @@ -775,8 +892,8 @@ ata_generic_command(struct ata_device *atadev, u_int8_t command, static void ata_pio_read(struct ata_request *request, int length) { + struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); int size = min(request->transfersize, length); - struct ata_channel *ch = request->device->channel; int resid; if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t))) @@ -789,7 +906,7 @@ ata_pio_read(struct ata_request *request, int length) size / sizeof(int32_t)); if (request->transfersize < length) { - ata_prtdev(request->device, "WARNING - %s read data overrun %d>%d\n", + device_printf(request->dev, "WARNING - %s read data overrun %d>%d\n", ata_cmd2str(request), length, request->transfersize); for (resid = request->transfersize; resid < length; resid += sizeof(int16_t)) @@ -800,8 +917,8 @@ ata_pio_read(struct ata_request *request, int length) static void ata_pio_write(struct ata_request *request, int length) { + struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); int size = min(request->transfersize, length); - struct ata_channel *ch = request->device->channel; int resid; if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t))) @@ -814,10 +931,54 @@ ata_pio_write(struct ata_request *request, int length) size / sizeof(int32_t)); if (request->transfersize < length) { - ata_prtdev(request->device, "WARNING - %s write data underrun %d>%d\n", + device_printf(request->dev, "WARNING - %s write data underrun %d>%d\n", ata_cmd2str(request), length, request->transfersize); for (resid = request->transfersize; resid < length; resid += sizeof(int16_t)) ATA_IDX_OUTW(ch, ATA_DATA, 0); } } + +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); +} + +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; +} + +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; +} diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c index 747ba41..523ee8e 100644 --- a/sys/dev/ata/ata-pci.c +++ b/sys/dev/ata/ata-pci.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/kernel.h> #include <sys/module.h> +#include <sys/ata.h> #include <sys/bus.h> #include <sys/malloc.h> #include <sys/sema.h> @@ -50,17 +51,17 @@ __FBSDID("$FreeBSD$"); #include <dev/pci/pcireg.h> #include <dev/ata/ata-all.h> #include <dev/ata/ata-pci.h> +#include <ata_if.h> /* local vars */ static MALLOC_DEFINE(M_ATAPCI, "ATA PCI", "ATA driver PCI"); /* misc defines */ -#define IOMASK 0xfffffffc +#define IOMASK 0xfffffffc /* prototypes */ -static int ata_pci_allocate(device_t, struct ata_channel *); +static int ata_pci_allocate(device_t dev, struct ata_channel *ch); static void ata_pci_dmainit(struct ata_channel *); -static int ata_pci_locknoop(struct ata_channel *, int); int ata_legacy(device_t dev) @@ -71,7 +72,7 @@ ata_legacy(device_t dev) (PCIP_STORAGE_IDE_MODEPRIM | PCIP_STORAGE_IDE_MODESEC))); } -static int +int ata_pci_probe(device_t dev) { if (pci_get_class(dev) != PCIC_STORAGE) @@ -164,7 +165,7 @@ ata_pci_probe(device_t dev) return ENXIO; } -static int +int ata_pci_attach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); @@ -178,7 +179,7 @@ ata_pci_attach(device_t dev) ctlr->channels = 1; ctlr->allocate = ata_pci_allocate; ctlr->dmainit = ata_pci_dmainit; - ctlr->locking = ata_pci_locknoop; + ctlr->dev = dev; /* if needed try to enable busmastering */ cmd = pci_read_config(dev, PCIR_COMMAND, 2); @@ -209,24 +210,24 @@ ata_pci_attach(device_t dev) } device_add_child(dev, "ata", devclass_find_free_unit(ata_devclass, 2)); } - return bus_generic_attach(dev); + bus_generic_attach(dev); + return 0; } -static int +int ata_pci_detach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - struct ata_channel *ch; - int unit; + device_t *children; + int nchildren, i; - /* mark HW as gone, we dont want to issue commands to HW no longer there */ - for (unit = 0; unit < ctlr->channels; unit++) { - if ((ch = ctlr->interrupt[unit].argument)) - ch->flags |= ATA_HWGONE; + /* detach & delete all children */ + if (!device_get_children(dev, &children, &nchildren)) { + for (i = 0; i < nchildren; i++) + device_delete_child(dev, children[i]); + free(children, M_TEMP); } - bus_generic_detach(dev); - if (ctlr->r_irq) { bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle); bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ctlr->r_irq); @@ -239,19 +240,7 @@ ata_pci_detach(device_t dev) return 0; } -static int -ata_pci_print_child(device_t dev, device_t child) -{ - struct ata_channel *ch = device_get_softc(child); - int retval = 0; - - retval += bus_print_child_header(dev, child); - retval += printf(": channel #%d", ch->unit); - retval += bus_print_child_footer(dev, child); - return retval; -} - -static struct resource * +struct resource * ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { @@ -307,7 +296,7 @@ ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid, return 0; } -static int +int ata_pci_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { @@ -348,7 +337,7 @@ ata_pci_release_resource(device_t dev, device_t child, int type, int rid, return EINVAL; } -static int +int ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_intr_t *function, void *argument, void **cookiep) @@ -373,7 +362,7 @@ ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, } } -static int +int ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie) { @@ -435,12 +424,46 @@ ata_pci_allocate(device_t dev, struct ata_channel *ch) return 0; } +static void +ata_pci_setmode(device_t parent, device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(parent); + struct ata_device *atadev = device_get_softc(dev); + int mode = atadev->mode; + + ctlr->setmode(atadev, ATA_PIO_MAX); + if (mode >= ATA_DMA) + ctlr->setmode(atadev, mode); +} + +static int +ata_pci_locking(device_t parent, device_t dev, int mode) +{ + struct ata_pci_controller *ctlr = device_get_softc(parent); + struct ata_channel *ch = device_get_softc(dev); + + if (ctlr->locking) + return ctlr->locking(ch, mode); + else + return ch->unit; +} + +static void +ata_pci_reset(device_t parent, device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(parent); + struct ata_channel *ch = device_get_softc(dev); + + if (ctlr->reset) + ctlr->reset(ch); +} + static int ata_pci_dmastart(struct ata_channel *ch) { ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) | (ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR))); - ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->mdmatab); + ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->sg_bus); ch->dma->flags |= ATA_DMA_ACTIVE; ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, (ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_WRITE_READ) | @@ -472,41 +495,41 @@ ata_pci_dmainit(struct ata_channel *ch) } } -static int -ata_pci_locknoop(struct ata_channel *ch, int flags) -{ - return ch->unit; -} - static device_method_t ata_pci_methods[] = { /* device interface */ - DEVMETHOD(device_probe, ata_pci_probe), - DEVMETHOD(device_attach, ata_pci_attach), - DEVMETHOD(device_detach, ata_pci_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), + DEVMETHOD(device_probe, ata_pci_probe), + DEVMETHOD(device_attach, ata_pci_attach), + DEVMETHOD(device_detach, ata_pci_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), /* bus methods */ - DEVMETHOD(bus_print_child, ata_pci_print_child), - DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource), - DEVMETHOD(bus_release_resource, ata_pci_release_resource), - DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), - DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_setup_intr, ata_pci_setup_intr), - DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr), + DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource), + DEVMETHOD(bus_release_resource, ata_pci_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_setup_intr, ata_pci_setup_intr), + DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr), + + /* ATA methods */ + DEVMETHOD(ata_setmode, ata_pci_setmode), + DEVMETHOD(ata_locking, ata_pci_locking), + DEVMETHOD(ata_reset, ata_pci_reset), { 0, 0 } }; +devclass_t atapci_devclass; + static driver_t ata_pci_driver = { "atapci", ata_pci_methods, sizeof(struct ata_pci_controller), }; -static devclass_t ata_pci_devclass; - -DRIVER_MODULE(atapci, pci, ata_pci_driver, ata_pci_devclass, 0, 0); +DRIVER_MODULE(atapci, pci, ata_pci_driver, atapci_devclass, 0, 0); +MODULE_VERSION(atapci, 1); +MODULE_DEPEND(atapci, ata, 1, 1, 1); static int ata_channel_probe(device_t dev) @@ -514,6 +537,7 @@ ata_channel_probe(device_t dev) struct ata_channel *ch = device_get_softc(dev); device_t *children; int count, i; + char buffer[32]; /* take care of green memory */ bzero(ch, sizeof(struct ata_channel)); @@ -526,6 +550,9 @@ ata_channel_probe(device_t dev) } free(children, M_TEMP); + sprintf(buffer, "ATA channel %d", ch->unit); + device_set_desc_copy(dev, buffer); + return ata_probe(dev); } @@ -536,11 +563,6 @@ ata_channel_attach(device_t dev) struct ata_channel *ch = device_get_softc(dev); int error; - ch->device[MASTER].setmode = ctlr->setmode; - ch->device[SLAVE].setmode = ctlr->setmode; - ch->locking = ctlr->locking; - ch->reset = ctlr->reset; - if (ctlr->r_res1) ctlr->dmainit(ch); if (ch->dma) @@ -569,15 +591,16 @@ ata_channel_detach(device_t dev) static device_method_t ata_channel_methods[] = { /* device interface */ - DEVMETHOD(device_probe, ata_channel_probe), - DEVMETHOD(device_attach, ata_channel_attach), - DEVMETHOD(device_detach, ata_channel_detach), - DEVMETHOD(device_suspend, ata_suspend), - DEVMETHOD(device_resume, ata_resume), + DEVMETHOD(device_probe, ata_channel_probe), + DEVMETHOD(device_attach, ata_channel_attach), + DEVMETHOD(device_detach, ata_channel_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), { 0, 0 } }; -static driver_t ata_channel_driver = { +driver_t ata_channel_driver = { "ata", ata_channel_methods, sizeof(struct ata_channel), diff --git a/sys/dev/ata/ata-pci.h b/sys/dev/ata/ata-pci.h index 5189e70..be15b38 100644 --- a/sys/dev/ata/ata-pci.h +++ b/sys/dev/ata/ata-pci.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003, 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 2003 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,306 +30,321 @@ /* structure holding chipset config info */ struct ata_chip_id { - u_int32_t chipid; - u_int8_t chiprev; - int cfg1; - int cfg2; - u_int8_t max_dma; - char *text; + u_int32_t chipid; + u_int8_t chiprev; + int cfg1; + int cfg2; + u_int8_t max_dma; + char *text; }; /* structure describing a PCI ATA controller */ struct ata_pci_controller { - int r_type1; - int r_rid1; - struct resource *r_res1; - int r_type2; - int r_rid2; - struct resource *r_res2; - struct resource *r_irq; - void *handle; - struct ata_chip_id *chip; - int channels; - int (*chipinit)(device_t); - int (*allocate)(device_t, struct ata_channel *); - void (*reset)(struct ata_channel *); - void (*dmainit)(struct ata_channel *); - void (*setmode)(struct ata_device *, int); - int (*locking)(struct ata_channel *, int); + device_t dev; + int r_type1; + int r_rid1; + struct resource *r_res1; + int r_type2; + int r_rid2; + struct resource *r_res2; + struct resource *r_irq; + void *handle; + struct ata_chip_id *chip; + int channels; + int (*chipinit)(device_t); + int (*allocate)(device_t, struct ata_channel *); + int (*locking)(struct ata_channel *, int); + void (*reset)(struct ata_channel *); + void (*dmainit)(struct ata_channel *); + void (*setmode)(struct ata_device *, int); struct { - void (*function)(void *); - void *argument; - } interrupt[8]; /* SOS max ch# for now XXX */ - void *driver; + void (*function)(void *); + void *argument; + } interrupt[8]; /* SOS max ch# for now XXX */ +}; + +/* structure for SATA connection update hotplug/hotswap support */ +struct ata_connect_task { + struct task task; + device_t dev; + int action; +#define ATA_C_ATTACH 1 +#define ATA_C_DETACH 2 }; /* defines for known chipset PCI id's */ -#define ATA_ACARD_ID 0x1191 -#define ATA_ATP850 0x00021191 -#define ATA_ATP850A 0x00041191 -#define ATA_ATP850R 0x00051191 -#define ATA_ATP860A 0x00061191 -#define ATA_ATP860R 0x00071191 -#define ATA_ATP865A 0x00081191 -#define ATA_ATP865R 0x00091191 - -#define ATA_AMD_ID 0x1022 -#define ATA_AMD755 0x74011022 -#define ATA_AMD756 0x74091022 -#define ATA_AMD766 0x74111022 -#define ATA_AMD768 0x74411022 -#define ATA_AMD8111 0x74691022 - -#define ATA_ACER_LABS_ID 0x10b9 -#define ATA_ALI_5229 0x522910b9 - -#define ATA_CENATEK_ID 0x16ca -#define ATA_CENATEK_ROCKET 0x000116ca - -#define ATA_CYRIX_ID 0x1078 -#define ATA_CYRIX_5530 0x01021078 - -#define ATA_CYPRESS_ID 0x1080 -#define ATA_CYPRESS_82C693 0xc6931080 - -#define ATA_DEC_21150 0x00221011 -#define ATA_DEC_21150_1 0x00231011 - -#define ATA_HIGHPOINT_ID 0x1103 -#define ATA_HPT366 0x00041103 -#define ATA_HPT372 0x00051103 -#define ATA_HPT302 0x00061103 -#define ATA_HPT371 0x00071103 -#define ATA_HPT374 0x00081103 - -#define ATA_INTEL_ID 0x8086 -#define ATA_I960RM 0x09628086 -#define ATA_I82371FB 0x12308086 -#define ATA_I82371SB 0x70108086 -#define ATA_I82371AB 0x71118086 -#define ATA_I82443MX 0x71998086 -#define ATA_I82451NX 0x84ca8086 -#define ATA_I82372FB 0x76018086 -#define ATA_I82801AB 0x24218086 -#define ATA_I82801AA 0x24118086 -#define ATA_I82801BA 0x244a8086 -#define ATA_I82801BA_1 0x244b8086 -#define ATA_I82801CA 0x248a8086 -#define ATA_I82801CA_1 0x248b8086 -#define ATA_I82801DB 0x24cb8086 -#define ATA_I82801DB_1 0x24ca8086 -#define ATA_I82801EB 0x24db8086 -#define ATA_I82801EB_S1 0x24d18086 -#define ATA_I82801EB_R1 0x24df8086 -#define ATA_I6300ESB 0x25a28086 -#define ATA_I6300ESB_S1 0x25a38086 -#define ATA_I6300ESB_R1 0x25b08086 -#define ATA_I82801FB 0x266f8086 -#define ATA_I82801FB_S1 0x26518086 -#define ATA_I82801FB_R1 0x26528086 - -#define ATA_ITE_ID 0x1283 -#define ATA_IT8212F 0x82121283 - -#define ATA_MICRON_ID 0x1042 -#define ATA_MICRON_RZ1000 0x10001042 -#define ATA_MICRON_RZ1001 0x10011042 - -#define ATA_NATIONAL_ID 0x100b -#define ATA_SC1100 0x0502100b - -#define ATA_NVIDIA_ID 0x10de -#define ATA_NFORCE1 0x01bc10de -#define ATA_NFORCE2 0x006510de -#define ATA_NFORCE2_MCP 0x008510de -#define ATA_NFORCE3 0x00d510de -#define ATA_NFORCE3_PRO 0x00e510de -#define ATA_NFORCE3_PRO_S1 0x00e310de -#define ATA_NFORCE3_PRO_S2 0x00ee10de -#define ATA_NFORCE3_MCP 0x003510de -#define ATA_NFORCE3_MCP_S1 0x003610de -#define ATA_NFORCE3_MCP_S2 0x003e10de -#define ATA_NFORCE4 0x005310de -#define ATA_NFORCE4_S1 0x005410de -#define ATA_NFORCE4_S2 0x005510de - - -#define ATA_PROMISE_ID 0x105a -#define ATA_PDC20246 0x4d33105a -#define ATA_PDC20262 0x4d38105a -#define ATA_PDC20263 0x0d38105a -#define ATA_PDC20265 0x0d30105a -#define ATA_PDC20267 0x4d30105a -#define ATA_PDC20268 0x4d68105a -#define ATA_PDC20269 0x4d69105a -#define ATA_PDC20270 0x6268105a -#define ATA_PDC20271 0x6269105a -#define ATA_PDC20275 0x1275105a -#define ATA_PDC20276 0x5275105a -#define ATA_PDC20277 0x7275105a -#define ATA_PDC20318 0x3318105a -#define ATA_PDC20319 0x3319105a -#define ATA_PDC20371 0x3371105a -#define ATA_PDC20375 0x3375105a -#define ATA_PDC20376 0x3376105a -#define ATA_PDC20377 0x3377105a -#define ATA_PDC20378 0x3373105a -#define ATA_PDC20379 0x3372105a -#define ATA_PDC20571 0x3571105a -#define ATA_PDC20575 0x3d75105a -#define ATA_PDC20579 0x3574105a -#define ATA_PDC20580 0x3570105a -#define ATA_PDC40518 0x3d18105a -#define ATA_PDC20617 0x6617105a -#define ATA_PDC20618 0x6626105a -#define ATA_PDC20619 0x6629105a -#define ATA_PDC20620 0x6620105a -#define ATA_PDC20621 0x6621105a -#define ATA_PDC20622 0x6622105a - -#define ATA_SERVERWORKS_ID 0x1166 -#define ATA_ROSB4_ISA 0x02001166 -#define ATA_ROSB4 0x02111166 -#define ATA_CSB5 0x02121166 -#define ATA_CSB6 0x02131166 -#define ATA_CSB6_1 0x02171166 - -#define ATA_SILICON_IMAGE_ID 0x1095 -#define ATA_SII3114 0x31141095 -#define ATA_SII3512 0x35121095 -#define ATA_SII3112 0x31121095 -#define ATA_SII3112_1 0x02401095 -#define ATA_SII0680 0x06801095 -#define ATA_CMD646 0x06461095 -#define ATA_CMD648 0x06481095 -#define ATA_CMD649 0x06491095 - -#define ATA_SIS_ID 0x1039 -#define ATA_SISSOUTH 0x00081039 -#define ATA_SIS5511 0x55111039 -#define ATA_SIS5513 0x55131039 -#define ATA_SIS5517 0x55171039 -#define ATA_SIS5518 0x55181039 -#define ATA_SIS5571 0x55711039 -#define ATA_SIS5591 0x55911039 -#define ATA_SIS5596 0x55961039 -#define ATA_SIS5597 0x55971039 -#define ATA_SIS5598 0x55981039 -#define ATA_SIS5600 0x56001039 -#define ATA_SIS530 0x05301039 -#define ATA_SIS540 0x05401039 -#define ATA_SIS550 0x05501039 -#define ATA_SIS620 0x06201039 -#define ATA_SIS630 0x06301039 -#define ATA_SIS635 0x06351039 -#define ATA_SIS633 0x06331039 -#define ATA_SIS640 0x06401039 -#define ATA_SIS645 0x06451039 -#define ATA_SIS646 0x06461039 -#define ATA_SIS648 0x06481039 -#define ATA_SIS650 0x06501039 -#define ATA_SIS651 0x06511039 -#define ATA_SIS652 0x06521039 -#define ATA_SIS655 0x06551039 -#define ATA_SIS658 0x06581039 -#define ATA_SIS661 0x06611039 -#define ATA_SIS730 0x07301039 -#define ATA_SIS733 0x07331039 -#define ATA_SIS735 0x07351039 -#define ATA_SIS740 0x07401039 -#define ATA_SIS745 0x07451039 -#define ATA_SIS746 0x07461039 -#define ATA_SIS748 0x07481039 -#define ATA_SIS750 0x07501039 -#define ATA_SIS751 0x07511039 -#define ATA_SIS752 0x07521039 -#define ATA_SIS755 0x07551039 -#define ATA_SIS961 0x09611039 -#define ATA_SIS962 0x09621039 -#define ATA_SIS963 0x09631039 -#define ATA_SIS964 0x09641039 -#define ATA_SIS964_S 0x01801039 - -#define ATA_VIA_ID 0x1106 -#define ATA_VIA82C571 0x05711106 -#define ATA_VIA82C586 0x05861106 -#define ATA_VIA82C596 0x05961106 -#define ATA_VIA82C686 0x06861106 -#define ATA_VIA8231 0x82311106 -#define ATA_VIA8233 0x30741106 -#define ATA_VIA8233A 0x31471106 -#define ATA_VIA8233C 0x31091106 -#define ATA_VIA8235 0x31771106 -#define ATA_VIA8237 0x32271106 -#define ATA_VIA8361 0x31121106 -#define ATA_VIA8363 0x03051106 -#define ATA_VIA8371 0x03911106 -#define ATA_VIA8662 0x31021106 -#define ATA_VIA6410 0x31641106 -#define ATA_VIA6420 0x31491106 +#define ATA_ACARD_ID 0x1191 +#define ATA_ATP850 0x00021191 +#define ATA_ATP850A 0x00041191 +#define ATA_ATP850R 0x00051191 +#define ATA_ATP860A 0x00061191 +#define ATA_ATP860R 0x00071191 +#define ATA_ATP865A 0x00081191 +#define ATA_ATP865R 0x00091191 + +#define ATA_AMD_ID 0x1022 +#define ATA_AMD755 0x74011022 +#define ATA_AMD756 0x74091022 +#define ATA_AMD766 0x74111022 +#define ATA_AMD768 0x74411022 +#define ATA_AMD8111 0x74691022 + +#define ATA_ACER_LABS_ID 0x10b9 +#define ATA_ALI_5229 0x522910b9 + +#define ATA_CENATEK_ID 0x16ca +#define ATA_CENATEK_ROCKET 0x000116ca + +#define ATA_CYRIX_ID 0x1078 +#define ATA_CYRIX_5530 0x01021078 + +#define ATA_CYPRESS_ID 0x1080 +#define ATA_CYPRESS_82C693 0xc6931080 + +#define ATA_DEC_21150 0x00221011 +#define ATA_DEC_21150_1 0x00231011 + +#define ATA_HIGHPOINT_ID 0x1103 +#define ATA_HPT366 0x00041103 +#define ATA_HPT372 0x00051103 +#define ATA_HPT302 0x00061103 +#define ATA_HPT371 0x00071103 +#define ATA_HPT374 0x00081103 + +#define ATA_INTEL_ID 0x8086 +#define ATA_I960RM 0x09628086 +#define ATA_I82371FB 0x12308086 +#define ATA_I82371SB 0x70108086 +#define ATA_I82371AB 0x71118086 +#define ATA_I82443MX 0x71998086 +#define ATA_I82451NX 0x84ca8086 +#define ATA_I82372FB 0x76018086 +#define ATA_I82801AB 0x24218086 +#define ATA_I82801AA 0x24118086 +#define ATA_I82801BA 0x244a8086 +#define ATA_I82801BA_1 0x244b8086 +#define ATA_I82801CA 0x248a8086 +#define ATA_I82801CA_1 0x248b8086 +#define ATA_I82801DB 0x24cb8086 +#define ATA_I82801DB_1 0x24ca8086 +#define ATA_I82801EB 0x24db8086 +#define ATA_I82801EB_S1 0x24d18086 +#define ATA_I82801EB_R1 0x24df8086 +#define ATA_I6300ESB 0x25a28086 +#define ATA_I6300ESB_S1 0x25a38086 +#define ATA_I6300ESB_R1 0x25b08086 +#define ATA_I82801FB 0x266f8086 +#define ATA_I82801FB_S1 0x26518086 +#define ATA_I82801FB_R1 0x26528086 + +#define ATA_ITE_ID 0x1283 +#define ATA_IT8212F 0x82121283 + +#define ATA_MICRON_ID 0x1042 +#define ATA_MICRON_RZ1000 0x10001042 +#define ATA_MICRON_RZ1001 0x10011042 + +#define ATA_NATIONAL_ID 0x100b +#define ATA_SC1100 0x0502100b + +#define ATA_NVIDIA_ID 0x10de +#define ATA_NFORCE1 0x01bc10de +#define ATA_NFORCE2 0x006510de +#define ATA_NFORCE2_MCP 0x008510de +#define ATA_NFORCE3 0x00d510de +#define ATA_NFORCE3_PRO 0x00e510de +#define ATA_NFORCE3_PRO_S1 0x00e310de +#define ATA_NFORCE3_PRO_S2 0x00ee10de +#define ATA_NFORCE3_MCP 0x003510de +#define ATA_NFORCE3_MCP_S1 0x003610de +#define ATA_NFORCE3_MCP_S2 0x003e10de +#define ATA_NFORCE4 0x005310de +#define ATA_NFORCE4_S1 0x005410de +#define ATA_NFORCE4_S2 0x005510de + + +#define ATA_PROMISE_ID 0x105a +#define ATA_PDC20246 0x4d33105a +#define ATA_PDC20262 0x4d38105a +#define ATA_PDC20263 0x0d38105a +#define ATA_PDC20265 0x0d30105a +#define ATA_PDC20267 0x4d30105a +#define ATA_PDC20268 0x4d68105a +#define ATA_PDC20269 0x4d69105a +#define ATA_PDC20270 0x6268105a +#define ATA_PDC20271 0x6269105a +#define ATA_PDC20275 0x1275105a +#define ATA_PDC20276 0x5275105a +#define ATA_PDC20277 0x7275105a +#define ATA_PDC20318 0x3318105a +#define ATA_PDC20319 0x3319105a +#define ATA_PDC20371 0x3371105a +#define ATA_PDC20375 0x3375105a +#define ATA_PDC20376 0x3376105a +#define ATA_PDC20377 0x3377105a +#define ATA_PDC20378 0x3373105a +#define ATA_PDC20379 0x3372105a +#define ATA_PDC20571 0x3571105a +#define ATA_PDC20575 0x3d75105a +#define ATA_PDC20579 0x3574105a +#define ATA_PDC20580 0x3570105a +#define ATA_PDC40518 0x3d18105a +#define ATA_PDC20617 0x6617105a +#define ATA_PDC20618 0x6626105a +#define ATA_PDC20619 0x6629105a +#define ATA_PDC20620 0x6620105a +#define ATA_PDC20621 0x6621105a +#define ATA_PDC20622 0x6622105a + +#define ATA_SERVERWORKS_ID 0x1166 +#define ATA_ROSB4_ISA 0x02001166 +#define ATA_ROSB4 0x02111166 +#define ATA_CSB5 0x02121166 +#define ATA_CSB6 0x02131166 +#define ATA_CSB6_1 0x02171166 + +#define ATA_SILICON_IMAGE_ID 0x1095 +#define ATA_SII3114 0x31141095 +#define ATA_SII3512 0x35121095 +#define ATA_SII3112 0x31121095 +#define ATA_SII3112_1 0x02401095 +#define ATA_SII0680 0x06801095 +#define ATA_CMD646 0x06461095 +#define ATA_CMD648 0x06481095 +#define ATA_CMD649 0x06491095 + +#define ATA_SIS_ID 0x1039 +#define ATA_SISSOUTH 0x00081039 +#define ATA_SIS5511 0x55111039 +#define ATA_SIS5513 0x55131039 +#define ATA_SIS5517 0x55171039 +#define ATA_SIS5518 0x55181039 +#define ATA_SIS5571 0x55711039 +#define ATA_SIS5591 0x55911039 +#define ATA_SIS5596 0x55961039 +#define ATA_SIS5597 0x55971039 +#define ATA_SIS5598 0x55981039 +#define ATA_SIS5600 0x56001039 +#define ATA_SIS530 0x05301039 +#define ATA_SIS540 0x05401039 +#define ATA_SIS550 0x05501039 +#define ATA_SIS620 0x06201039 +#define ATA_SIS630 0x06301039 +#define ATA_SIS635 0x06351039 +#define ATA_SIS633 0x06331039 +#define ATA_SIS640 0x06401039 +#define ATA_SIS645 0x06451039 +#define ATA_SIS646 0x06461039 +#define ATA_SIS648 0x06481039 +#define ATA_SIS650 0x06501039 +#define ATA_SIS651 0x06511039 +#define ATA_SIS652 0x06521039 +#define ATA_SIS655 0x06551039 +#define ATA_SIS658 0x06581039 +#define ATA_SIS661 0x06611039 +#define ATA_SIS730 0x07301039 +#define ATA_SIS733 0x07331039 +#define ATA_SIS735 0x07351039 +#define ATA_SIS740 0x07401039 +#define ATA_SIS745 0x07451039 +#define ATA_SIS746 0x07461039 +#define ATA_SIS748 0x07481039 +#define ATA_SIS750 0x07501039 +#define ATA_SIS751 0x07511039 +#define ATA_SIS752 0x07521039 +#define ATA_SIS755 0x07551039 +#define ATA_SIS961 0x09611039 +#define ATA_SIS962 0x09621039 +#define ATA_SIS963 0x09631039 +#define ATA_SIS964 0x09641039 +#define ATA_SIS965 0x09641039 +#define ATA_SIS180 0x01801039 +#define ATA_SIS181 0x01811039 + +#define ATA_VIA_ID 0x1106 +#define ATA_VIA82C571 0x05711106 +#define ATA_VIA82C586 0x05861106 +#define ATA_VIA82C596 0x05961106 +#define ATA_VIA82C686 0x06861106 +#define ATA_VIA8231 0x82311106 +#define ATA_VIA8233 0x30741106 +#define ATA_VIA8233A 0x31471106 +#define ATA_VIA8233C 0x31091106 +#define ATA_VIA8235 0x31771106 +#define ATA_VIA8237 0x32271106 +#define ATA_VIA8361 0x31121106 +#define ATA_VIA8363 0x03051106 +#define ATA_VIA8371 0x03911106 +#define ATA_VIA8662 0x31021106 +#define ATA_VIA6410 0x31641106 +#define ATA_VIA6420 0x31491106 /* chipset setup related defines */ -#define ATPOLD 1 - -#define ALIOLD 0x01 -#define ALINEW 0x02 - -#define HPT366 0 -#define HPT370 1 -#define HPT372 2 -#define HPT374 3 -#define HPTOLD 0x01 - -#define PROLD 0 -#define PRNEW 1 -#define PRTX 2 -#define PRMIO 3 -#define PRTX4 0x01 -#define PRSX4X 0x02 -#define PRSX6K 0x04 -#define PRPATA 0x08 -#define PRCMBO 0x10 -#define PRCMBO2 0x20 -#define PRSATA 0x40 -#define PRSATA2 0x80 - -#define SWKS33 0 -#define SWKS66 1 -#define SWKS100 2 - -#define SIIMEMIO 1 -#define SIIINTR 0x01 -#define SIISETCLK 0x02 -#define SIIBUG 0x04 -#define SII4CH 0x08 - -#define SIS_SOUTH 1 -#define SISSATA 2 -#define SIS133NEW 3 -#define SIS133OLD 4 -#define SIS100NEW 5 -#define SIS100OLD 6 -#define SIS66 7 -#define SIS33 8 - -#define VIA33 0 -#define VIA66 1 -#define VIA100 2 -#define VIA133 3 -#define AMDNVIDIA 4 -#define AMDCABLE 0x01 -#define AMDBUG 0x02 -#define NVIDIA 0x04 -#define VIACLK 0x08 -#define VIABUG 0x10 - -/* global prototypes */ -int ata_legacy(device_t); +#define ATPOLD 1 -void ata_dmainit(struct ata_channel *); -int ata_dmastart(struct ata_channel *, caddr_t, int32_t, int); -int ata_dmastop(struct ata_channel *); +#define ALIOLD 0x01 +#define ALINEW 0x02 + +#define HPT366 0 +#define HPT370 1 +#define HPT372 2 +#define HPT374 3 +#define HPTOLD 0x01 + +#define PROLD 0 +#define PRNEW 1 +#define PRTX 2 +#define PRMIO 3 +#define PRTX4 0x01 +#define PRSX4X 0x02 +#define PRSX6K 0x04 +#define PRPATA 0x08 +#define PRCMBO 0x10 +#define PRCMBO2 0x20 +#define PRSATA 0x40 +#define PRSATA2 0x80 +#define SWKS33 0 +#define SWKS66 1 +#define SWKS100 2 + +#define SIIMEMIO 1 +#define SIIINTR 0x01 +#define SIISETCLK 0x02 +#define SIIBUG 0x04 +#define SII4CH 0x08 + +#define SIS_SOUTH 1 +#define SISSATA 2 +#define SIS133NEW 3 +#define SIS133OLD 4 +#define SIS100NEW 5 +#define SIS100OLD 6 +#define SIS66 7 +#define SIS33 8 + +#define VIA33 0 +#define VIA66 1 +#define VIA100 2 +#define VIA133 3 +#define AMDNVIDIA 4 +#define AMDCABLE 0x01 +#define AMDBUG 0x02 +#define NVIDIA 0x04 +#define VIACLK 0x08 +#define VIABUG 0x10 + +/* global prototypes ata-pci.c */ +int ata_pci_probe(device_t dev); +int ata_pci_attach(device_t dev); +int ata_pci_detach(device_t dev); +struct resource * ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags); +int ata_pci_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r); +int ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_intr_t *function, void *argument, void **cookiep); + int ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie); +extern driver_t ata_channel_driver; + +/* global prototypes ata-chipset.c */ int ata_generic_ident(device_t); int ata_acard_ident(device_t); int ata_ali_ident(device_t); @@ -346,3 +361,8 @@ int ata_serverworks_ident(device_t); int ata_sii_ident(device_t); int ata_sis_ident(device_t); int ata_via_ident(device_t); +int ata_legacy(device_t); +struct ata_chip_id *ata_match_chip(device_t, struct ata_chip_id *); + +/* global prototypes ata-dma.c */ +void ata_dmainit(struct ata_channel *); diff --git a/sys/dev/ata/ata-queue.c b/sys/dev/ata/ata-queue.c index 8800230..603e85d 100644 --- a/sys/dev/ata/ata-queue.c +++ b/sys/dev/ata/ata-queue.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,16 +43,18 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <sys/rman.h> #include <dev/ata/ata-all.h> +#include <ata_if.h> /* prototypes */ static void ata_completed(void *, int); static void ata_timeout(struct ata_request *); +static void ata_sort_queue(struct ata_channel *ch, struct ata_request *request); static char *ata_skey2str(u_int8_t); void ata_queue_request(struct ata_request *request) { - struct ata_channel *ch = request->device->channel; + struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); /* mark request as virgin */ request->result = request->status = request->error = 0; @@ -61,16 +63,13 @@ ata_queue_request(struct ata_request *request) if (!request->callback && !(request->flags & ATA_R_REQUEUE)) sema_init(&request->done, 0, "ATA request done"); - /* in IMMEDIATE_MODE we dont queue but call HW directly */ - /* used only during reinit for getparm and config */ - if ((ch->flags & ATA_IMMEDIATE_MODE) && - (request->flags & (ATA_R_CONTROL | ATA_R_IMMEDIATE))) { + /* in ATA_STALL_QUEUE state we call HW directly (used only during reinit) */ + if ((ch->state & ATA_STALL_QUEUE) && (request->flags & ATA_R_CONTROL)) { /* arm timeout */ if (!dumping) callout_reset(&request->callout, request->timeout * hz, (timeout_t*)ata_timeout, request); - /* kick HW into action */ ch->running = request; if (ch->hw.begin_transaction(request) == ATA_OP_FINISHED) { @@ -84,13 +83,15 @@ ata_queue_request(struct ata_request *request) else { /* put request on the locked queue at the specified location */ mtx_lock(&ch->queue_mtx); - if (request->flags & ATA_R_IMMEDIATE) + if (request->flags & ATA_R_AT_HEAD) TAILQ_INSERT_HEAD(&ch->ata_queue, request, chain); + else if (request->flags & ATA_R_ORDERED) + ata_sort_queue(ch, request); else TAILQ_INSERT_TAIL(&ch->ata_queue, request, chain); mtx_unlock(&ch->queue_mtx); ATA_DEBUG_RQ(request, "queued"); - ata_start(ch); + ata_start(ch->dev); } /* if this is a requeued request callback/sleep has been setup */ @@ -100,7 +101,12 @@ ata_queue_request(struct ata_request *request) /* if this is not a callback wait until request is completed */ if (!request->callback) { ATA_DEBUG_RQ(request, "wait for completition"); - sema_wait(&request->done); + while (sema_timedwait(&request->done, request->timeout * hz * 4)) { + device_printf(request->dev, + "req=%p %s semaphore timeout !! DANGER Will Robinson !!\n", + request, ata_cmd2str(request)); + ata_start(ch->dev); + } sema_destroy(&request->done); } } @@ -113,13 +119,13 @@ ata_controlcmd(struct ata_device *atadev, u_int8_t command, u_int16_t feature, int error = ENOMEM; if (request) { - request->device = atadev; + request->dev = atadev->dev; request->u.ata.command = command; request->u.ata.lba = lba; request->u.ata.count = count; request->u.ata.feature = feature; request->flags = ATA_R_CONTROL; - request->timeout = 5; + request->timeout = 1; request->retries = 0; ata_queue_request(request); error = request->result; @@ -136,8 +142,8 @@ ata_atapicmd(struct ata_device *atadev, u_int8_t *ccb, caddr_t data, int error = ENOMEM; if (request) { - request->device = atadev; - if ((atadev->param->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) + request->dev = atadev->dev; + if ((atadev->param.config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) bcopy(ccb, request->u.atapi.ccb, 12); else bcopy(ccb, request->u.atapi.ccb, 16); @@ -154,47 +160,58 @@ ata_atapicmd(struct ata_device *atadev, u_int8_t *ccb, caddr_t data, } void -ata_start(struct ata_channel *ch) +ata_start(device_t dev) { + struct ata_channel *ch = device_get_softc(dev); struct ata_request *request; - - /* if in immediate mode, just skip start requests (stall queue) */ - if (ch->flags & ATA_IMMEDIATE_MODE) - return; - - /* if we dont have any work, ask the subdriver(s) */ - mtx_lock(&ch->queue_mtx); - if (TAILQ_EMPTY(&ch->ata_queue)) { - mtx_unlock(&ch->queue_mtx); - if (ch->device[MASTER].start) - ch->device[MASTER].start(&ch->device[MASTER]); - if (ch->device[SLAVE].start) - ch->device[SLAVE].start(&ch->device[SLAVE]); - mtx_lock(&ch->queue_mtx); - } + struct ata_composite *cptr; + int dependencies = 0; /* if we have a request on the queue try to get it running */ + mtx_lock(&ch->queue_mtx); if ((request = TAILQ_FIRST(&ch->ata_queue))) { /* we need the locking function to get the lock for this channel */ - if (ch->locking(ch, ATA_LF_LOCK) == ch->unit) { + if (ATA_LOCKING(device_get_parent(dev), dev, ATA_LF_LOCK) == ch->unit) { + + /* check for composite dependencies */ + if ((cptr = request->composite)) { + mtx_lock(&cptr->lock); + if ((request->flags & ATA_R_WRITE) && + (cptr->wr_depend & cptr->rd_done) != cptr->wr_depend) { + dependencies = 1; + } + mtx_unlock(&cptr->lock); + } - /* check for the right state */ + /* check we are int the right state and has no dependencies */ mtx_lock(&ch->state_mtx); - if (ch->state == ATA_IDLE) { + if (ch->state == ATA_IDLE && !dependencies) { ATA_DEBUG_RQ(request, "starting"); +#if 0 + if (request->sequence_count) + request = request->sequence[--request->sequence_count]; + else +#else TAILQ_REMOVE(&ch->ata_queue, request, chain); +#endif ch->running = request; ch->state = ATA_ACTIVE; + + /* if we are the freezing point release it */ + if (ch->freezepoint == request) + ch->freezepoint = NULL; + + /* arm timeout for this request */ if (!dumping) callout_reset(&request->callout, request->timeout * hz, (timeout_t*)ata_timeout, request); if (ch->hw.begin_transaction(request) == ATA_OP_FINISHED) { ch->running = NULL; ch->state = ATA_IDLE; - mtx_unlock(&ch->queue_mtx); mtx_unlock(&ch->state_mtx); - ch->locking(ch, ATA_LF_UNLOCK); + mtx_unlock(&ch->queue_mtx); + ATA_LOCKING(device_get_parent(dev), dev, ATA_LF_UNLOCK); ata_finish(request); return; } @@ -208,25 +225,26 @@ ata_start(struct ata_channel *ch) void ata_finish(struct ata_request *request) { - struct ata_channel *ch = request->device->channel; + struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); - /* schedule it for completition */ - if (ch->flags & ATA_IMMEDIATE_MODE) { + /* if in STALL_QUEUE state or request is ATA_R_DIRECT call complete now */ + if ((ch->state & ATA_STALL_QUEUE) || (request->flags & ATA_R_DIRECT)) { ATA_DEBUG_RQ(request, "finish directly"); ata_completed(request, 0); } else { - if (!dumping) + /* reset timeout and put on the proper taskqueue for completition */ + if (!dumping && !(request->flags & ATA_R_TIMEOUT)) callout_reset(&request->callout, request->timeout * hz, (timeout_t*)ata_timeout, request); - if (request->bio && !(request->flags & ATA_R_TIMEOUT)) { + if (request->bio && !(request->flags & (ATA_R_THREAD | ATA_R_TIMEOUT))){ ATA_DEBUG_RQ(request, "finish bio_taskqueue"); bio_taskqueue(request->bio, (bio_task_t *)ata_completed, request); } else { TASK_INIT(&request->task, 0, ata_completed, request); - ATA_DEBUG_RQ(request, "finish taskqueue_thread"); - taskqueue_enqueue(taskqueue_thread, &request->task); + ATA_DEBUG_RQ(request, "finish taskqueue_swi"); + taskqueue_enqueue(taskqueue_swi, &request->task); } } } @@ -235,7 +253,9 @@ static void ata_completed(void *context, int dummy) { struct ata_request *request = (struct ata_request *)context; - struct ata_channel *ch = request->device->channel; + struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_device *atadev = device_get_softc(request->dev); + struct ata_composite *composite; ATA_DEBUG_RQ(request, "completed entered"); @@ -245,21 +265,25 @@ ata_completed(void *context, int dummy) * if reinit succeeds, retries still permit and device didn't * get removed by the reinit, reinject request */ - if (!ata_reinit(ch) && request->retries-- > 0 - && request->device->param){ + if (!ata_reinit(ch->dev) && request->dev && (request->retries-- > 0)) { request->flags &= ~(ATA_R_TIMEOUT | ATA_R_DEBUG); - request->flags |= (ATA_R_IMMEDIATE | ATA_R_REQUEUE); - request->donecount = 0; + request->flags |= (ATA_R_AT_HEAD | ATA_R_REQUEUE); ATA_DEBUG_RQ(request, "completed reinject"); ata_queue_request(request); return; } /* nothing more to try so finish with error */ - if (!(request->flags & ATA_R_QUIET)) - ata_prtdev(request->device, - "FAILURE - %s timed out\n", - ata_cmd2str(request)); + if (!(request->flags & ATA_R_QUIET)) { + if (request->dev) { + device_printf(request->dev, + "FAILURE - %s timed out", + ata_cmd2str(request)); + if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) + printf(" LBA=%llu", (unsigned long long)request->u.ata.lba); + printf("\n"); + } + } if (!request->result) request->result = EIO; } @@ -269,9 +293,9 @@ ata_completed(void *context, int dummy) /* if this is a soft ECC error warn about it */ if ((request->status & (ATA_S_CORR | ATA_S_ERROR)) == ATA_S_CORR) { - ata_prtdev(request->device, - "WARNING - %s soft error (ECC corrected)", - ata_cmd2str(request)); + device_printf(request->dev, + "WARNING - %s soft error (ECC corrected)", + ata_cmd2str(request)); if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) printf(" LBA=%llu", (unsigned long long)request->u.ata.lba); printf("\n"); @@ -280,13 +304,13 @@ ata_completed(void *context, int dummy) /* if this is a UDMA CRC error, retry request */ if (request->flags & ATA_R_DMA && request->error & ATA_E_ICRC) { if (request->retries-- > 0) { - ata_prtdev(request->device, - "WARNING - %s UDMA ICRC error (retrying request)", - ata_cmd2str(request)); + device_printf(request->dev, + "WARNING - %s UDMA ICRC error (retrying request)", + ata_cmd2str(request)); if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) printf(" LBA=%llu", (unsigned long long)request->u.ata.lba); printf("\n"); - request->flags |= (ATA_R_IMMEDIATE | ATA_R_REQUEUE); + request->flags |= (ATA_R_AT_HEAD | ATA_R_REQUEUE); ata_queue_request(request); return; } @@ -299,14 +323,15 @@ ata_completed(void *context, int dummy) default: if (!request->result && request->status & ATA_S_ERROR) { if (!(request->flags & ATA_R_QUIET)) { - ata_prtdev(request->device, - "FAILURE - %s status=%b error=%b", - ata_cmd2str(request), - request->status, "\20\10BUSY\7READY\6DMA_READY" - "\5DSC\4DRQ\3CORRECTABLE\2INDEX\1ERROR", - request->error, "\20\10ICRC\7UNCORRECTABLE" - "\6MEDIA_CHANGED\5NID_NOT_FOUND\4MEDIA_CHANGE_REQEST" - "\3ABORTED\2NO_MEDIA\1ILLEGAL_LENGTH"); + device_printf(request->dev, + "FAILURE - %s status=%b error=%b", + ata_cmd2str(request), + request->status, "\20\10BUSY\7READY\6DMA_READY" + "\5DSC\4DRQ\3CORRECTABLE\2INDEX\1ERROR", + request->error, "\20\10ICRC\7UNCORRECTABLE" + "\6MEDIA_CHANGED\5NID_NOT_FOUND" + "\4MEDIA_CHANGE_REQEST" + "\3ABORTED\2NO_MEDIA\1ILLEGAL_LENGTH"); if ((request->flags & ATA_R_DMA) && (request->dmastat & ATA_BMSTAT_ERROR)) printf(" dma=0x%02x", request->dmastat); @@ -314,8 +339,6 @@ ata_completed(void *context, int dummy) printf(" LBA=%llu", (unsigned long long)request->u.ata.lba); printf("\n"); } - - /* SOS this could be more precise ? XXX */ request->result = EIO; } break; @@ -330,7 +353,7 @@ ata_completed(void *context, int dummy) if (request->error & ATA_SK_MASK && request->u.atapi.ccb[0] != ATAPI_REQUEST_SENSE) { static u_int8_t ccb[16] = { ATAPI_REQUEST_SENSE, 0, 0, 0, - sizeof(struct atapi_sense), + sizeof(struct atapi_sense), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; request->u.atapi.sense_key = request->error; @@ -341,7 +364,7 @@ ata_completed(void *context, int dummy) request->transfersize = sizeof(struct atapi_sense); request->timeout = 5; request->flags &= (ATA_R_ATAPI | ATA_R_QUIET); - request->flags |= (ATA_R_READ | ATA_R_IMMEDIATE | ATA_R_REQUEUE); + request->flags |= (ATA_R_READ | ATA_R_AT_HEAD | ATA_R_REQUEUE); ATA_DEBUG_RQ(request, "autoissue request sense"); ata_queue_request(request); return; @@ -349,8 +372,8 @@ ata_completed(void *context, int dummy) switch (request->u.atapi.sense_key & ATA_SK_MASK) { case ATA_SK_RECOVERED_ERROR: - ata_prtdev(request->device, "WARNING - %s recovered error\n", - ata_cmd2str(request)); + device_printf(request->dev, "WARNING - %s recovered error\n", + ata_cmd2str(request)); /* FALLTHROUGH */ case ATA_SK_NO_SENSE: @@ -362,7 +385,7 @@ ata_completed(void *context, int dummy) break; case ATA_SK_UNIT_ATTENTION: - request->device->flags |= ATA_D_MEDIA_CHANGED; + atadev->flags |= ATA_D_MEDIA_CHANGED; request->result = EIO; break; @@ -371,12 +394,12 @@ ata_completed(void *context, int dummy) if (request->flags & ATA_R_QUIET) break; - ata_prtdev(request->device, - "FAILURE - %s %s asc=0x%02x ascq=0x%02x ", - ata_cmd2str(request), ata_skey2str( - (request->u.atapi.sense_key & ATA_SK_MASK) >> 4), - request->u.atapi.sense_data.asc, - request->u.atapi.sense_data.ascq); + device_printf(request->dev, + "FAILURE - %s %s asc=0x%02x ascq=0x%02x ", + ata_cmd2str(request), ata_skey2str( + (request->u.atapi.sense_key & ATA_SK_MASK) >> 4), + request->u.atapi.sense_data.asc, + request->u.atapi.sense_data.ascq); if (request->u.atapi.sense_data.sksv) printf("sks=0x%02x 0x%02x 0x%02x ", request->u.atapi.sense_data.sk_specific, @@ -395,29 +418,50 @@ ata_completed(void *context, int dummy) ATA_DEBUG_RQ(request, "completed callback/wakeup"); + /* if we are part of a composite operation update progress */ + if ((composite = request->composite)) { + int index = 0; + + mtx_lock(&composite->lock); + if (request->flags & ATA_R_READ) + composite->rd_done |= (1 << request->this); + if (request->flags & ATA_R_WRITE) + composite->wr_done |= (1 << request->this); + + if (composite->wr_depend && + (composite->rd_done & composite->wr_depend)==composite->wr_depend && + (composite->wr_needed & (~composite->wr_done))) { + index = ((composite->wr_needed & (~composite->wr_done))) - 1; + } + mtx_unlock(&composite->lock); + if (index) + ata_start(device_get_parent(composite->request[index]->dev)); + } + /* get results back to the initiator */ if (request->callback) (request->callback)(request); else sema_post(&request->done); - ata_start(ch); + ata_start(ch->dev); } static void ata_timeout(struct ata_request *request) { - struct ata_channel *ch = request->device->channel; + struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); mtx_lock(&ch->state_mtx); + //request->flags |= ATA_R_DEBUG; ATA_DEBUG_RQ(request, "timeout"); /* if interrupt has been seen, shout and just rearm timeout */ if (request->flags & ATA_R_INTR_SEEN) { - ata_prtdev(request->device, - "WARNING - %s interrupt was seen but timeout fired", - ata_cmd2str(request)); + device_printf(request->dev, + "WARNING - %s interrupt was seen but timeout fired", + ata_cmd2str(request)); if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) printf(" LBA=%llu", (unsigned long long)request->u.ata.lba); printf("\n"); @@ -431,29 +475,29 @@ ata_timeout(struct ata_request *request) } /* - * if we are waiting for a command to complete set ATA_TIMEOUT so - * we wont loose the race with an eventual interrupt arriving late + * grap and hold the state lock so we wont loose the race with + * an eventual interrupt arriving late */ - if (ch->state == ATA_ACTIVE) { + if (ch->state == ATA_ACTIVE || ch->state == ATA_STALL_QUEUE) { request->flags |= ATA_R_TIMEOUT; - ch->state = ATA_TIMEOUT; - ch->running = NULL; if (!(request->flags & ATA_R_QUIET) && request->retries > 0) { - ata_prtdev(request->device, - "TIMEOUT - %s retrying (%d retr%s left)", - ata_cmd2str(request), request->retries, - request->retries == 1 ? "y" : "ies"); + device_printf(request->dev, + "TIMEOUT - %s retrying (%d retr%s left)", + ata_cmd2str(request), request->retries, + request->retries == 1 ? "y" : "ies"); if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) printf(" LBA=%llu", (unsigned long long)request->u.ata.lba); printf("\n"); } ch->hw.end_transaction(request); + ch->state |= ATA_TIMEOUT; mtx_unlock(&ch->state_mtx); + ATA_LOCKING(device_get_parent(ch->dev), ch->dev, ATA_LF_UNLOCK); ata_finish(request); } else { mtx_unlock(&ch->state_mtx); - ata_prtdev(request->device, "timeout state=%d unexpected\n", ch->state); + device_printf(request->dev, "timeout state=%d unexpected\n", ch->state); } } @@ -468,33 +512,32 @@ ata_catch_inflight(struct ata_channel *ch) mtx_unlock(&ch->state_mtx); if (request) { - callout_drain(&request->callout); - ata_prtdev(request->device, - "WARNING - %s requeued due to channel reset", - ata_cmd2str(request)); - if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) - printf(" LBA=%llu", (unsigned long long)request->u.ata.lba); - printf("\n"); - request->flags |= ATA_R_REQUEUE; - ata_queue_request(request); + callout_drain(&request->callout); + 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=%llu", (unsigned long long)request->u.ata.lba); + printf("\n"); + request->flags |= ATA_R_REQUEUE; + ata_queue_request(request); } } void -ata_fail_requests(struct ata_channel *ch, struct ata_device *device) +ata_fail_requests(struct ata_channel *ch, device_t dev) { struct ata_request *request; - /* fail all requests queued on this channel */ + /* fail all requests queued on this channel for device dev if !NULL */ mtx_lock(&ch->queue_mtx); while ((request = TAILQ_FIRST(&ch->ata_queue))) { - if (!device || request->device == device) { + if (!dev || request->dev == dev) { TAILQ_REMOVE(&ch->ata_queue, request, chain); + mtx_unlock(&ch->queue_mtx); request->result = ENXIO; - if (request->callback) - (request->callback)(request); - else - sema_post(&request->done); + ata_finish(request); + mtx_lock(&ch->queue_mtx); } } mtx_unlock(&ch->queue_mtx); @@ -505,14 +548,86 @@ ata_fail_requests(struct ata_channel *ch, struct ata_device *device) mtx_unlock(&ch->state_mtx); /* if we have a request "in flight" fail it as well */ - if (request && (!device || request->device == device)) { + if (request && (!dev || request->dev == dev)) { callout_drain(&request->callout); request->result = ENXIO; - if (request->callback) - (request->callback)(request); - else - sema_post(&request->done); + ata_finish(request); + } +} + +static u_int64_t +ata_get_lba(struct ata_request *request) +{ + if (request->flags & ATA_R_ATAPI) { + switch (request->u.atapi.ccb[0]) { + case ATAPI_READ_BIG: + case ATAPI_WRITE_BIG: + case ATAPI_READ_CD: + return (request->u.atapi.ccb[5]) | (request->u.atapi.ccb[4]<<8) | + (request->u.atapi.ccb[3]<<16)|(request->u.atapi.ccb[2]<<24); + case ATAPI_READ: + case ATAPI_WRITE: + return (request->u.atapi.ccb[4]) | (request->u.atapi.ccb[3]<<8) | + (request->u.atapi.ccb[2]<<16); + default: + return 0; + } } + else + return request->u.ata.lba; +} + +static void +ata_sort_queue(struct ata_channel *ch, struct ata_request *request) +{ + struct ata_request *this, *next; + + this = TAILQ_FIRST(&ch->ata_queue); + + /* if the queue is empty just insert */ + if (!this) { + if (request->composite) + ch->freezepoint = request; + TAILQ_INSERT_TAIL(&ch->ata_queue, request, chain); + return; + } + + /* dont sort frozen parts of the queue */ + if (ch->freezepoint) + this = ch->freezepoint; + + /* if position is less than head we add after tipping point */ + if (ata_get_lba(request) < ata_get_lba(this)) { + while ((next = TAILQ_NEXT(this, chain))) { + + /* have we reached the tipping point */ + if (ata_get_lba(next) < ata_get_lba(this)) { + + /* sort the insert */ + do { + if (ata_get_lba(request) < ata_get_lba(next)) + break; + this = next; + } while ((next = TAILQ_NEXT(this, chain))); + break; + } + this = next; + } + } + + /* we are after head so sort the insert before tipping point */ + else { + while ((next = TAILQ_NEXT(this, chain))) { + if (ata_get_lba(next) < ata_get_lba(this) || + ata_get_lba(request) < ata_get_lba(next)) + break; + this = next; + } + } + + if (request->composite) + ch->freezepoint = request; + TAILQ_INSERT_AFTER(&ch->ata_queue, this, request, chain); } char * @@ -579,7 +694,7 @@ ata_cmd2str(struct ata_request *request) else { switch (request->u.ata.command) { case 0x00: return ("NOP"); - case 0x08: return ("ATAPI_RESET"); + case 0x08: return ("DEVICE_RESET"); case 0x20: return ("READ"); case 0x24: return ("READ48"); case 0x25: return ("READ_DMA48"); @@ -590,6 +705,7 @@ ata_cmd2str(struct ata_request *request) case 0x35: return ("WRITE_DMA48"); case 0x36: return ("WRITE_DMA_QUEUED48"); case 0x39: return ("WRITE_MUL48"); + case 0x70: return ("SEEK"); case 0xa0: return ("PACKET_CMD"); case 0xa1: return ("ATAPI_IDENTIFY"); case 0xa2: return ("SERVICE"); @@ -612,7 +728,7 @@ ata_cmd2str(struct ata_request *request) case 0xaa: return ("SETFEATURES ENABLE RCACHE"); case 0x55: return ("SETFEATURES DISABLE RCACHE"); } - sprintf(buffer, "SETFEATURES 0x%02x", request->u.ata.feature); + sprintf(buffer, "SETFEATURES 0x%02x", request->u.ata.feature); return buffer; } } diff --git a/sys/dev/ata/ata-raid.c b/sys/dev/ata/ata-raid.c index 4edaa79..ab9d902 100644 --- a/sys/dev/ata/ata-raid.c +++ b/sys/dev/ata/ata-raid.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 2000 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,274 +34,781 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/ata.h> #include <sys/kernel.h> -#include <sys/proc.h> #include <sys/malloc.h> +#include <sys/module.h> +#include <sys/endian.h> #include <sys/bio.h> #include <sys/bus.h> #include <sys/conf.h> #include <sys/disk.h> #include <sys/cons.h> -#include <sys/unistd.h> -#include <sys/kthread.h> #include <sys/sema.h> #include <sys/taskqueue.h> #include <vm/uma.h> #include <machine/bus.h> #include <sys/rman.h> -#include <geom/geom_disk.h> #include <dev/pci/pcivar.h> -#include <dev/pci/pcireg.h> +#include <geom/geom_disk.h> #include <dev/ata/ata-all.h> -#include <dev/ata/ata-pci.h> #include <dev/ata/ata-disk.h> #include <dev/ata/ata-raid.h> +#include <dev/ata/ata-pci.h> +#include <ata_if.h> + +/* prototypes */ +static void ata_raid_done(struct ata_request *request); +static void ata_raid_config_changed(struct ar_softc *rdp, int writeback); +static int ata_raid_status(int array, struct raid_status *status); +static int ata_raid_create(struct raid_setup *setup); +static int ata_raid_delete(int array); +static int ata_raid_addspare(int array, int spare); +static int ata_raid_rebuild(int array); +static int ata_raid_read_metadata(device_t subdisk); +static int ata_raid_write_metadata(struct ar_softc *rdp); +static int ata_raid_adaptec_read_meta(device_t dev, struct ar_softc **raidp); +static int ata_raid_hptv2_read_meta(device_t dev, struct ar_softc **raidp); +static int ata_raid_hptv2_write_meta(struct ar_softc *rdp); +static int ata_raid_hptv3_read_meta(device_t dev, struct ar_softc **raidp); +//static int ata_raid_hptv3_write_meta(struct ar_softc *rdp); +static int ata_raid_intel_read_meta(device_t dev, struct ar_softc **raidp); +static int ata_raid_ite_read_meta(device_t dev, struct ar_softc **raidp); +static int ata_raid_lsiv2_read_meta(device_t dev, struct ar_softc **raidp); +static int ata_raid_lsiv3_read_meta(device_t dev, struct ar_softc **raidp); +static int ata_raid_promise_read_meta(device_t dev, struct ar_softc **raidp, int native); +static int ata_raid_promise_write_meta(struct ar_softc *rdp); +static int ata_raid_sii_read_meta(device_t dev, struct ar_softc **raidp); +static struct ata_request *ata_raid_init_request(struct ar_softc *rdp, struct bio *bio); +static int ata_raid_send_request(struct ata_request *request); +static int ata_raid_rw(device_t dev, u_int64_t lba, void *data, u_int bcount, int flags); +static char * ata_raid_format(struct ar_softc *rdp); +static char * ata_raid_type(struct ar_softc *rdp); +static char * ata_raid_flags(struct ar_softc *rdp); + +/* debugging only */ +static void ata_raid_print_meta(struct ar_softc *meta); +static void ata_raid_adaptec_print_meta(struct adaptec_raid_conf *meta); +static void ata_raid_hptv2_print_meta(struct hptv2_raid_conf *meta); +static void ata_raid_hptv3_print_meta(struct hptv3_raid_conf *meta); +static void ata_raid_intel_print_meta(struct intel_raid_conf *meta); +static void ata_raid_ite_print_meta(struct ite_raid_conf *meta); +static void ata_raid_lsiv2_print_meta(struct lsiv2_raid_conf *meta); +static void ata_raid_lsiv3_print_meta(struct lsiv3_raid_conf *meta); +static void ata_raid_promise_print_meta(struct promise_raid_conf *meta); +static void ata_raid_sii_print_meta(struct sii_raid_conf *meta); + +/* internal vars */ +static struct ar_softc *ata_raid_arrays[MAX_ARRAYS]; +static MALLOC_DEFINE(M_AR, "AR driver", "ATA PseudoRAID driver"); +static devclass_t ata_raid_sub_devclass; +static int testing = 0; /* device structures */ -static disk_strategy_t arstrategy; -static dumper_t ardump; +static disk_strategy_t ata_raid_strategy; +//static dumper_t ata_raid_dump; -/* prototypes */ -static void ar_attach_raid(struct ar_softc *, int); -static void ar_done(struct bio *); -static void ar_config_changed(struct ar_softc *, int); -static void ar_rebuild(void *); -static int ar_highpoint_read_conf(struct ad_softc *, struct ar_softc **); -static int ar_highpoint_write_conf(struct ar_softc *); -static int ar_lsi_read_conf(struct ad_softc *, struct ar_softc **); -static int ar_lsi_write_conf(struct ar_softc *); -static int ar_promise_read_conf(struct ad_softc *, struct ar_softc **, int); -static int ar_promise_write_conf(struct ar_softc *); -static int ar_rw(struct ad_softc *, u_int32_t, int, caddr_t, int); -static struct ata_device *ar_locate_disk(int); -static void ar_print_conf(struct ar_softc *); - -/* internal vars */ -static struct ar_softc **ar_table = NULL; -static MALLOC_DEFINE(M_AR, "AR driver", "ATA RAID driver"); - -#define AR_REBUILD_SIZE 128 - -int -ata_raiddisk_attach(struct ad_softc *adp) +static void +ata_raid_attach(struct ar_softc *rdp, int update) { - struct ar_softc *rdp; - int array, disk; + int disk; - if (ar_table) { - for (array = 0; array < MAX_ARRAYS; array++) { - if (!(rdp = ar_table[array]) || !rdp->flags) - continue; - - for (disk = 0; disk < rdp->total_disks; disk++) { - if ((rdp->disks[disk].flags & AR_DF_ASSIGNED) && - rdp->disks[disk].device == adp->device) { - ata_prtdev(rdp->disks[disk].device, - "inserted into ar%d disk%d as spare\n", - array, disk); - rdp->disks[disk].flags |= (AR_DF_PRESENT | AR_DF_SPARE); - AD_SOFTC(rdp->disks[disk])->flags |= AD_F_RAID_SUBDISK; - ar_config_changed(rdp, 1); - return 1; + mtx_init(&rdp->lock, "ATA PseudoRAID metadata lock", NULL, MTX_DEF); + ata_raid_config_changed(rdp, update); + + /* sanitize arrays total_size % (width * interleave) == 0 */ + rdp->total_sectors = (rdp->total_sectors / (rdp->interleave * rdp->width)) * + (rdp->interleave * rdp->width); + rdp->disk = disk_alloc(); + rdp->disk->d_strategy = ata_raid_strategy; + //rdp->disk->d_dump = ata_raid_dump; + rdp->disk->d_name = "ar"; + rdp->disk->d_sectorsize = DEV_BSIZE; + rdp->disk->d_mediasize = (off_t)rdp->total_sectors * DEV_BSIZE; + rdp->disk->d_fwsectors = rdp->sectors; + rdp->disk->d_fwheads = rdp->heads; + rdp->disk->d_maxsize = 128 * DEV_BSIZE; + rdp->disk->d_drv1 = rdp; + rdp->disk->d_unit = rdp->lun; + disk_create(rdp->disk, DISK_VERSION); + + printf("ar%d: %lluMB <%s %s array> status: %s\n", rdp->lun, + (unsigned long long)(rdp->total_sectors / ((1024L*1024L)/DEV_BSIZE)), + ata_raid_format(rdp), ata_raid_type(rdp), ata_raid_flags(rdp)); + + if (testing || bootverbose) + printf("ar%d: %llu sectors [%dC/%dH/%dS] <%s> subdisks defined as:\n", + rdp->lun, (unsigned long long)rdp->total_sectors, + rdp->cylinders, rdp->heads, rdp->sectors, rdp->name); + + for (disk = 0; disk < rdp->total_disks; disk++) { + printf("ar%d: disk%d ", rdp->lun, disk); + if (rdp->disks[disk].dev) { + if (rdp->disks[disk].flags & AR_DF_PRESENT) { + /* status of this disk in the array */ + if (rdp->disks[disk].flags & AR_DF_ONLINE) + printf("READY "); + else if (rdp->disks[disk].flags & AR_DF_SPARE) + printf("SPARE "); + else + printf("FREE "); + + /* what type of disk is this in the array */ + switch (rdp->type) { + case AR_T_RAID1: + case AR_T_RAID01: + if (disk < rdp->width) + printf("(master) "); + else + printf("(mirror) "); } + + /* which physical disk is used */ + printf("using %s at ata%d-%s\n", + device_get_nameunit(rdp->disks[disk].dev), + device_get_unit(device_get_parent(rdp->disks[disk].dev)), + (((struct ata_device *) + device_get_softc(rdp->disks[disk].dev))->unit == + ATA_MASTER) ? "master" : "slave"); } + else if (rdp->disks[disk].flags & AR_DF_ASSIGNED) + printf("DOWN\n"); + else + printf("INVALID no RAID config on this subdisk\n"); } + else + printf("DOWN no device found for this subdisk\n"); } +} - if (!ar_table) - ar_table = malloc(sizeof(struct ar_soft *) * MAX_ARRAYS, - M_AR, M_NOWAIT | M_ZERO); - if (!ar_table) { - ata_prtdev(adp->device, "no memory for ATA raid array\n"); - return 0; +static int +ata_raid_ioctl(struct ata_cmd *iocmd) +{ + int error = EOPNOTSUPP; + + switch (iocmd->cmd) { + case ATARAIDSTATUS: + error = ata_raid_status(iocmd->channel, &iocmd->u.raid_status); + break; + + case ATARAIDCREATE: + error = ata_raid_create(&iocmd->u.raid_setup); + break; + + case ATARAIDDELETE: + error = ata_raid_delete(iocmd->channel); + break; + + case ATARAIDADDSPARE: + error = ata_raid_addspare(iocmd->channel, iocmd->u.raid_spare.disk); + break; + + case ATARAIDREBUILD: + error = ata_raid_rebuild(iocmd->channel); + break; } + return error; +} - switch(pci_get_vendor(device_get_parent(adp->device->channel->dev))) { - case ATA_PROMISE_ID: - /* test RAID bit in PCI reg XXX */ - return (ar_promise_read_conf(adp, ar_table, 0)); +static void +ata_raid_strategy(struct bio *bp) +{ + struct ar_softc *rdp = bp->bio_disk->d_drv1; + struct ata_request *request; + caddr_t data; + u_int64_t blkno, lba, blk = 0; + int count, chunk, drv, par = 0, change = 0; - case ATA_HIGHPOINT_ID: - return (ar_highpoint_read_conf(adp, ar_table)); + if (!(rdp->status & AR_S_READY) || + (bp->bio_cmd != BIO_READ && bp->bio_cmd != BIO_WRITE)) { + biofinish(bp, NULL, EIO); + return; + } - case ATA_SILICON_IMAGE_ID: - return (ar_lsi_read_conf(adp, ar_table)); + bp->bio_resid = bp->bio_bcount; + for (count = howmany(bp->bio_bcount, DEV_BSIZE), + blkno = bp->bio_pblkno, data = bp->bio_data; + count > 0; + count -= chunk, blkno += chunk, data += (chunk * DEV_BSIZE)) { - default: - return (ar_promise_read_conf(adp, ar_table, 1)); - } - return 0; -} + switch (rdp->type) { + case AR_T_JBOD: + case AR_T_RAID1: + drv = 0; + lba = blkno; + chunk = count; + break; + + case AR_T_SPAN: + drv = 0; + lba = blkno; + while (lba >= rdp->disks[drv].sectors) + lba -= rdp->disks[drv++].sectors; + chunk = min(rdp->disks[drv].sectors - lba, count); + break; + + case AR_T_RAID0: + case AR_T_RAID01: + chunk = blkno % rdp->interleave; + drv = (blkno / rdp->interleave) % rdp->width; + lba = (((blkno/rdp->interleave)/rdp->width)*rdp->interleave)+chunk; + chunk = min(count, rdp->interleave - chunk); + break; -int -ata_raiddisk_detach(struct ad_softc *adp) -{ - struct ar_softc *rdp; - int array, disk; + case AR_T_RAID5: + drv = (blkno / rdp->interleave) % (rdp->width - 1); + par = rdp->width - 1 - + (blkno / (rdp->interleave * (rdp->width - 1))) % rdp->width; + if (drv >= par) + drv++; + lba = ((blkno/rdp->interleave)/(rdp->width-1))*(rdp->interleave) + + ((blkno%(rdp->interleave*(rdp->width-1)))%rdp->interleave); + chunk = min(count, rdp->interleave - (lba % rdp->interleave)); + break; + + default: + printf("ar%d: unknown array type in ata_raid_strategy\n", rdp->lun); + biofinish(bp, NULL, EIO); + return; + } + + /* offset on all but "first on HPTv2" */ + if (!(drv == 0 && rdp->format == AR_F_HPTV2_RAID)) + lba += rdp->offset_sectors; + + if (!(request = ata_raid_init_request(rdp, bp))) { + biofinish(bp, NULL, EIO); + return; + } + request->data = data; + request->bytecount = chunk * DEV_BSIZE; + request->u.ata.lba = lba; + request->u.ata.count = request->bytecount / DEV_BSIZE; + + switch (rdp->type) { + case AR_T_JBOD: + case AR_T_SPAN: + case AR_T_RAID0: + if (((rdp->disks[drv].flags & (AR_DF_PRESENT|AR_DF_ONLINE)) == + (AR_DF_PRESENT|AR_DF_ONLINE) && !rdp->disks[drv].dev)) { + rdp->disks[drv].flags &= ~AR_DF_ONLINE; + ata_raid_config_changed(rdp, 1); + ata_free_request(request); + biofinish(bp, NULL, EIO); + return; + } + request->this = drv; + request->dev = rdp->disks[request->this].dev; + ata_raid_send_request(request); + break; + + case AR_T_RAID1: + case AR_T_RAID01: + if ((rdp->disks[drv].flags & + (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) && + !rdp->disks[drv].dev) { + rdp->disks[drv].flags &= ~AR_DF_ONLINE; + change = 1; + } + if ((rdp->disks[drv + rdp->width].flags & + (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) && + !rdp->disks[drv + rdp->width].dev) { + rdp->disks[drv + rdp->width].flags &= ~AR_DF_ONLINE; + change = 1; + } + if (change) + ata_raid_config_changed(rdp, 1); + if (!(rdp->status & AR_S_READY)) { + ata_free_request(request); + biofinish(bp, NULL, EIO); + return; + } + + if (rdp->status & AR_S_REBUILDING) + blk = ((lba / rdp->interleave) * rdp->width) * rdp->interleave + + (rdp->interleave * (drv % rdp->width)) + + lba % rdp->interleave;; - if (ar_table) { - for (array = 0; array < MAX_ARRAYS; array++) { - if (!(rdp = ar_table[array]) || !rdp->flags) - continue; - for (disk = 0; disk < rdp->total_disks; disk++) { - if (rdp->disks[disk].device == adp->device) { - ata_prtdev(rdp->disks[disk].device, - "deleted from ar%d disk%d\n", array, disk); - rdp->disks[disk].flags &= ~(AR_DF_PRESENT | AR_DF_ONLINE); - AD_SOFTC(rdp->disks[disk])->flags &= ~AD_F_RAID_SUBDISK; - rdp->disks[disk].device = NULL; - ar_config_changed(rdp, 1); - return 1; + if (bp->bio_cmd == BIO_READ) { + int src_online = + (rdp->disks[drv].flags & AR_DF_ONLINE); + int mir_online = + (rdp->disks[drv+rdp->width].flags & AR_DF_ONLINE); + + /* if mirror gone or close to last access on source */ + if (!mir_online || + ((src_online) && + bp->bio_pblkno >= + (rdp->disks[drv].last_lba - AR_PROXIMITY) && + bp->bio_pblkno <= + (rdp->disks[drv].last_lba + AR_PROXIMITY))) { + rdp->toggle = 0; + } + /* if source gone or close to last access on mirror */ + else if (!src_online || + ((mir_online) && + bp->bio_pblkno >= + (rdp->disks[drv+rdp->width].last_lba-AR_PROXIMITY) && + bp->bio_pblkno <= + (rdp->disks[drv+rdp->width].last_lba+AR_PROXIMITY))) { + drv += rdp->width; + rdp->toggle = 1; + } + /* not close to any previous access, toggle */ + else { + if (rdp->toggle) + rdp->toggle = 0; + else { + drv += rdp->width; + rdp->toggle = 1; + } + } + + if ((rdp->status & AR_S_REBUILDING) && + (blk <= rdp->rebuild_lba) && + ((blk + chunk) > rdp->rebuild_lba)) { + struct ata_composite *composite; + struct ata_request *rebuild; + int this; + + /* figure out what part to rebuild */ + if (drv < rdp->width) + this = drv + rdp->width; + else + this = drv - rdp->width; + + /* do we have a spare to rebuild on ? */ + if (rdp->disks[this].flags & AR_DF_SPARE) { + if ((composite = malloc(sizeof(struct ata_composite), + M_AR, M_NOWAIT | M_ZERO))) { + if ((rebuild = ata_alloc_request())) { + rdp->rebuild_lba = blk + chunk; + bcopy(request, rebuild, + sizeof(struct ata_request)); + rebuild->this = this; + rebuild->dev = rdp->disks[this].dev; + rebuild->flags &= ~ATA_R_READ; + rebuild->flags |= ATA_R_WRITE; + mtx_init(&composite->lock, + "ATA PseudoRAID rebuild lock", + NULL, MTX_DEF); + composite->rd_needed |= (1 << drv); + composite->wr_depend |= (1 << drv); + composite->wr_needed |= (1 << this); + composite->request[drv] = request; + composite->request[this] = rebuild; + request->composite = composite; + rebuild->composite = composite; + ata_raid_send_request(rebuild); + } + else { + free(composite, M_AR); + printf("DOH! ata_alloc_request failed!\n"); + } + } + else + printf("DOH! composite malloc failed!\n"); + } + else if (rdp->disks[this].flags & AR_DF_ONLINE) { + /* + * if we got here we are a chunk of a RAID01 that + * does not need a rebuild, but we need to increment + * the rebuild_lba address to get the rebuild to + * move to the next chunk correctly + */ + rdp->rebuild_lba = blk + chunk; + } + else + printf("DOH! we didn't find the rebuild part\n"); + } + } + if (bp->bio_cmd == BIO_WRITE) { + if ((rdp->disks[drv+rdp->width].flags & AR_DF_ONLINE) || + ((rdp->status & AR_S_REBUILDING) && + (rdp->disks[drv+rdp->width].flags & AR_DF_SPARE) && + ((blk < rdp->rebuild_lba) || + ((blk <= rdp->rebuild_lba) && + ((blk + chunk) > rdp->rebuild_lba))))) { + if ((rdp->disks[drv].flags & AR_DF_ONLINE) || + ((rdp->status & AR_S_REBUILDING) && + (rdp->disks[drv].flags & AR_DF_SPARE) && + ((blk < rdp->rebuild_lba) || + ((blk <= rdp->rebuild_lba) && + ((blk + chunk) > rdp->rebuild_lba))))) { + struct ata_request *mirror; + struct ata_composite *composite; + int this = drv + rdp->width; + + if ((composite = malloc(sizeof(struct ata_composite), + M_AR, M_NOWAIT | M_ZERO)) && + (mirror = ata_alloc_request())) { + rdp->rebuild_lba = blk + chunk; + bcopy(request, mirror, sizeof(struct ata_request)); + mirror->this = this; + mirror->dev = rdp->disks[this].dev; + mtx_init(&composite->lock, + "ATA PseudoRAID mirror lock", + NULL, MTX_DEF); + composite->wr_needed |= (1 << drv); + composite->wr_needed |= (1 << this); + composite->request[drv] = request; + composite->request[this] = mirror; + request->composite = composite; + mirror->composite = composite; + ata_raid_send_request(mirror); + rdp->disks[this].last_lba = bp->bio_pblkno + chunk; + } + } + else + drv += rdp->width; + } + } + request->this = drv; + request->dev = rdp->disks[request->this].dev; + ata_raid_send_request(request); + rdp->disks[request->this].last_lba = bp->bio_pblkno + chunk; + break; + + case AR_T_RAID5: + if (((rdp->disks[drv].flags & (AR_DF_PRESENT|AR_DF_ONLINE)) == + (AR_DF_PRESENT|AR_DF_ONLINE) && !rdp->disks[drv].dev)) { + rdp->disks[drv].flags &= ~AR_DF_ONLINE; + change = 1; + } + if (((rdp->disks[par].flags & (AR_DF_PRESENT|AR_DF_ONLINE)) == + (AR_DF_PRESENT|AR_DF_ONLINE) && !rdp->disks[par].dev)) { + rdp->disks[par].flags &= ~AR_DF_ONLINE; + change = 1; + } + if (change) + ata_raid_config_changed(rdp, 1); + if (!(rdp->status & AR_S_READY)) { + ata_free_request(request); + biofinish(bp, NULL, EIO); + return; + } + if (rdp->status & AR_S_DEGRADED) { + /* do the XOR game if possible */ + } + else { + request->this = drv; + request->dev = rdp->disks[request->this].dev; + if (bp->bio_cmd == BIO_READ) { + ata_raid_send_request(request); + } + if (bp->bio_cmd == BIO_WRITE) { + ata_raid_send_request(request); + // sikre at læs-modify-skriv til hver disk er atomarisk. + // par kopi af request + // læse orgdata fra drv + // skriv nydata til drv + // læse parorgdata fra par + // skriv orgdata xor parorgdata xor nydata til par } } + break; + + default: + printf("ar%d: unknown array type in ata_raid_strategy\n", rdp->lun); } } - return 0; } -void -ata_raid_attach() +static void +ata_raid_done(struct ata_request *request) { - struct ar_softc *rdp; - int array; + struct ar_softc *rdp = request->driver; + struct ata_composite *composite = NULL; + struct bio *bp = request->bio; + int i, mirror, finished = 0; + + switch (rdp->type) { + case AR_T_JBOD: + case AR_T_SPAN: + case AR_T_RAID0: + if (request->result) { + rdp->disks[request->this].flags &= ~AR_DF_ONLINE; + ata_raid_config_changed(rdp, 1); + bp->bio_error = request->result; + finished = 1; + } + else { + bp->bio_resid -= request->donecount; + if (bp->bio_resid == 0) + finished = 1; + } + break; - if (!ar_table) - return; + case AR_T_RAID1: + case AR_T_RAID01: + if (request->this < rdp->width) + mirror = request->this + rdp->width; + else + mirror = request->this - rdp->width; + if (request->result) { + rdp->disks[request->this].flags &= ~AR_DF_ONLINE; + ata_raid_config_changed(rdp, 1); + } + if (rdp->status & AR_S_READY) { + u_int64_t blk = 0; - for (array = 0; array < MAX_ARRAYS; array++) { - if (!(rdp = ar_table[array]) || !rdp->flags) - continue; - if (bootverbose) - ar_print_conf(rdp); - ar_attach_raid(rdp, 0); + if (rdp->status & AR_S_REBUILDING) + blk = ((request->u.ata.lba / rdp->interleave) * rdp->width) * + rdp->interleave + (rdp->interleave * + (request->this % rdp->width)) + + request->u.ata.lba % rdp->interleave; + + if (bp->bio_cmd == BIO_READ) { + + /* is this a rebuild composite */ + if ((composite = request->composite)) { + mtx_lock(&composite->lock); + + /* handle the read part of a rebuild composite */ + if (request->flags & ATA_R_READ) { + + /* if read failed array is now broken */ + if (request->result) { + rdp->disks[request->this].flags &= ~AR_DF_ONLINE; + ata_raid_config_changed(rdp, 1); + bp->bio_error = request->result; + rdp->rebuild_lba = blk; + finished = 1; + } + + /* good data, update how far we've gotten */ + else { + bp->bio_resid -= request->donecount; + if (bp->bio_resid == 0) { + if (composite->wr_done & (1 << mirror)) + finished = 1; + } + } + } + + /* handle the write part of a rebuild composite */ + else if (request->flags & ATA_R_WRITE) { + if (composite->rd_done & (1 << mirror)) { + if (request->result) { + printf("DOH! rebuild failed\n"); /* XXX SOS */ + rdp->rebuild_lba = blk; + } + if (bp->bio_resid == 0) + finished = 1; + } + } + mtx_unlock(&composite->lock); + } + + /* if read failed retry on the mirror */ + else if (request->result) { + request->dev = rdp->disks[mirror].dev; + ata_raid_send_request(request); + return; + } + + /* we have good data */ + else { + bp->bio_resid -= request->donecount; + if (bp->bio_resid == 0) + finished = 1; + } + } + else if (bp->bio_cmd == BIO_WRITE) { + /* do we have a mirror or rebuild to deal with ? */ + if ((composite = request->composite)) { + mtx_lock(&composite->lock); + if (composite->wr_done & (1 << mirror)) { + if (request->result) { + if (composite->request[mirror]->result) { + printf("DOH! all disks failed and got here\n"); + bp->bio_error = EIO; + } + if (rdp->status & AR_S_REBUILDING) { + rdp->rebuild_lba = blk; + printf("DOH! rebuild failed\n"); /* XXX SOS */ + } + bp->bio_resid -= + composite->request[mirror]->donecount; + } + else + bp->bio_resid -= request->donecount; + if (bp->bio_resid == 0) + finished = 1; + } + mtx_unlock(&composite->lock); + } + /* no mirror we are done */ + else { + bp->bio_resid -= request->donecount; + if (bp->bio_resid == 0) + finished = 1; + } + } + } + else + biofinish(bp, NULL, request->result); + break; + + case AR_T_RAID5: + if (request->result) { + rdp->disks[request->this].flags &= ~AR_DF_ONLINE; + ata_raid_config_changed(rdp, 1); + if (rdp->status & AR_S_READY) { + if (bp->bio_cmd == BIO_READ) { + /* do the XOR game to recover data */ + } + if (bp->bio_cmd == BIO_WRITE) { + /* if the parity failed we're OK sortof */ + /* otherwise wee need to do the XOR long dance */ + } + finished = 1; + } + else + biofinish(bp, NULL, request->result); + } + else { + // did we have an XOR game going ?? + bp->bio_resid -= request->donecount; + if (bp->bio_resid == 0) + finished = 1; + } + break; + + default: + printf("ar%d: unknown array type in ata_raid_done\n", rdp->lun); + } + + if (finished) + biodone(bp); + + if (composite) { + if (finished) { + /* we are done with this composite, free all resources */ + for (i = 0; i < 32; i++) { + if (composite->rd_needed & (1 << i) || + composite->wr_needed & (1 << i)) { + ata_free_request(composite->request[i]); + } + } + mtx_destroy(&composite->lock); + free(composite, M_AR); + } } + else + ata_free_request(request); } static void -ar_attach_raid(struct ar_softc *rdp, int update) +ata_raid_config_changed(struct ar_softc *rdp, int writeback) { - int disk; + int disk, count, status; - ar_config_changed(rdp, update); - rdp->disk = disk_alloc(); - rdp->disk->d_strategy = arstrategy; - rdp->disk->d_dump = ardump; - rdp->disk->d_name = "ar"; - rdp->disk->d_sectorsize = DEV_BSIZE; - rdp->disk->d_mediasize = (off_t)rdp->total_sectors * DEV_BSIZE; - rdp->disk->d_fwsectors = rdp->sectors; - rdp->disk->d_fwheads = rdp->heads; - rdp->disk->d_maxsize = 128 * DEV_BSIZE; - rdp->disk->d_drv1 = rdp; - rdp->disk->d_unit = rdp->lun; - rdp->disk->d_flags = DISKFLAG_NEEDSGIANT; - disk_create(rdp->disk, DISK_VERSION); + mtx_lock(&rdp->lock); + /* set default all working mode */ + status = rdp->status; + rdp->status &= ~AR_S_DEGRADED; + rdp->status |= AR_S_READY; - printf("ar%d: %lluMB <ATA ", rdp->lun, (unsigned long long) - (rdp->total_sectors / ((1024L * 1024L) / DEV_BSIZE))); - switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) { - case AR_F_RAID0: - printf("RAID0 "); break; - case AR_F_RAID1: - printf("RAID1 "); break; - case AR_F_SPAN: - printf("SPAN "); break; - case (AR_F_RAID0 | AR_F_RAID1): - printf("RAID0+1 "); break; - default: - printf("unknown 0x%x> ", rdp->flags); - return; + /* make sure all lost drives are accounted for */ + for (disk = 0; disk < rdp->total_disks; disk++) { + if (!(rdp->disks[disk].flags & AR_DF_PRESENT)) + rdp->disks[disk].flags &= ~AR_DF_ONLINE; } - printf("array> [%d/%d/%d] status: ", - rdp->cylinders, rdp->heads, rdp->sectors); - switch (rdp->flags & (AR_F_DEGRADED | AR_F_READY)) { - case AR_F_READY: - printf("READY"); + + /* depending on RAID type figure out our health status */ + switch (rdp->type) { + case AR_T_JBOD: + case AR_T_SPAN: + case AR_T_RAID0: + for (disk = 0; disk < rdp->total_disks; disk++) + if (!(rdp->disks[disk].flags & AR_DF_ONLINE)) + rdp->status &= ~AR_S_READY; break; - case (AR_F_DEGRADED | AR_F_READY): - printf("DEGRADED"); + + case AR_T_RAID1: + case AR_T_RAID01: + for (disk = 0; disk < rdp->width; disk++) { + if (!(rdp->disks[disk].flags & AR_DF_ONLINE) && + !(rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE)) { + rdp->status &= ~AR_S_READY; + } + else if (((rdp->disks[disk].flags & AR_DF_ONLINE) && + !(rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE)) || + (!(rdp->disks[disk].flags & AR_DF_ONLINE) && + (rdp->disks [disk + rdp->width].flags & AR_DF_ONLINE))) { + rdp->status |= AR_S_DEGRADED; + } + } break; - default: - printf("BROKEN"); + + case AR_T_RAID5: + for (count = 0, disk = 0; disk < rdp->total_disks; disk++) { + if (!(rdp->disks[disk].flags & AR_DF_ONLINE)) + count++; + } + if (count) { + if (count > 1) + rdp->status &= ~AR_S_READY; + else + rdp->status |= AR_S_DEGRADED; + } break; + default: + rdp->status &= ~AR_S_READY; } - printf(" subdisks:\n"); - for (disk = 0; disk < rdp->total_disks; disk++) { - if (rdp->disks[disk].device && - AD_SOFTC(rdp->disks[disk])->flags & AD_F_RAID_SUBDISK) { - if (rdp->disks[disk].flags & AR_DF_PRESENT) { - if (rdp->disks[disk].flags & AR_DF_ONLINE) - printf(" disk%d READY ", disk); - else if (rdp->disks[disk].flags & AR_DF_SPARE) - printf(" disk%d SPARE ", disk); - else - printf(" disk%d FREE ", disk); - printf("on %s at ata%d-%s\n", rdp->disks[disk].device->name, - device_get_unit(rdp->disks[disk].device->channel->dev), - (rdp->disks[disk].device->unit == ATA_MASTER) ? - "master" : "slave"); - } - else if (rdp->disks[disk].flags & AR_DF_ASSIGNED) - printf(" disk%d DOWN\n", disk); + + if (rdp->status != status) { + if (!(rdp->status & AR_S_READY)) { + printf("ar%d: FAILURE - %s array broken\n", + rdp->lun, ata_raid_type(rdp)); + } + else if (rdp->status & AR_S_DEGRADED) { + if (rdp->type & (AR_T_RAID1 | AR_T_RAID01)) + printf("ar%d: WARNING - mirror", rdp->lun); else - printf(" disk%d INVALID no RAID config on this disk\n", disk); + printf("ar%d: WARNING - parity", rdp->lun); + printf(" protection lost. %s array in DEGRADED mode\n", + ata_raid_type(rdp)); } - else - printf(" disk%d DOWN no device found for this disk\n", disk); } + mtx_unlock(&rdp->lock); + if (writeback) + ata_raid_write_metadata(rdp); + } -int -ata_raid_addspare(int array, int disk) +static int +ata_raid_status(int array, struct raid_status *status) { struct ar_softc *rdp; - struct ata_device *atadev; int i; - - if (!ar_table || !(rdp = ar_table[array])) - return ENXIO; - if (!(rdp->flags & AR_F_RAID1)) - return EPERM; - if (rdp->flags & AR_F_REBUILDING) - return EBUSY; - if (!(rdp->flags & AR_F_DEGRADED) || !(rdp->flags & AR_F_READY)) + + if (!(rdp = ata_raid_arrays[array])) return ENXIO; - + + status->type = rdp->type; + status->total_disks = rdp->total_disks; for (i = 0; i < rdp->total_disks; i++ ) { - if (((rdp->disks[i].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) == - (AR_DF_PRESENT | AR_DF_ONLINE)) && rdp->disks[i].device) - continue; - if ((atadev = ar_locate_disk(disk))) { - if (((struct ad_softc*)(atadev->softc))->flags & AD_F_RAID_SUBDISK) - return EBUSY; - rdp->disks[i].device = atadev; - rdp->disks[i].flags |= (AR_DF_PRESENT|AR_DF_ASSIGNED|AR_DF_SPARE); - AD_SOFTC(rdp->disks[i])->flags |= AD_F_RAID_SUBDISK; - ata_prtdev(rdp->disks[i].device, - "inserted into ar%d disk%d as spare\n", array, i); - ar_config_changed(rdp, 1); - return 0; - } + if ((rdp->disks[i].flags & AR_DF_PRESENT) && rdp->disks[i].dev) + status->disks[i] = device_get_unit(rdp->disks[i].dev); + else + status->disks[i] = -1; } - return ENXIO; + status->interleave = rdp->interleave; + status->status = rdp->status; + status->progress = 100 * rdp->rebuild_lba / rdp->total_sectors; + return 0; } -int +static int ata_raid_create(struct raid_setup *setup) { - struct ata_device *atadev; struct ar_softc *rdp; + device_t subdisk; int array, disk; int ctlr = 0, disk_size = 0, total_disks = 0; - if (!ar_table) - ar_table = malloc(sizeof(struct ar_soft *) * MAX_ARRAYS, - M_AR, M_NOWAIT | M_ZERO); - if (!ar_table) { - printf("ar: no memory for ATA raid array\n"); - return 0; - } for (array = 0; array < MAX_ARRAYS; array++) { - if (!ar_table[array]) + if (!ata_raid_arrays[array]) break; } if (array >= MAX_ARRAYS) @@ -309,60 +816,80 @@ ata_raid_create(struct raid_setup *setup) if (!(rdp = (struct ar_softc*)malloc(sizeof(struct ar_softc), M_AR, M_NOWAIT | M_ZERO))) { - printf("ar%d: failed to allocate raid config storage\n", array); + printf("ar%d: no memory for metadata storage\n", array); return ENOMEM; } for (disk = 0; disk < setup->total_disks; disk++) { - if ((atadev = ar_locate_disk(setup->disks[disk]))) { - rdp->disks[disk].device = atadev; - if (AD_SOFTC(rdp->disks[disk])->flags & AD_F_RAID_SUBDISK) { + if ((subdisk = devclass_get_device(ata_raid_sub_devclass, + setup->disks[disk]))) { + struct ata_raid_subdisk *ars = device_get_softc(subdisk); + + /* is device already assigned to another array ? */ + if (ars->raid) { setup->disks[disk] = -1; free(rdp, M_AR); return EBUSY; } + rdp->disks[disk].dev = device_get_parent(subdisk); - switch(pci_get_vendor(device_get_parent( - rdp->disks[disk].device->channel->dev))) { + switch (pci_get_vendor(GRANDPARENT(rdp->disks[disk].dev))) { case ATA_HIGHPOINT_ID: - ctlr |= AR_F_HIGHPOINT_RAID; - rdp->disks[disk].disk_sectors = - AD_SOFTC(rdp->disks[disk])->total_secs; + /* + * we need some way to decide if it should be v2 or v3 + * for now just use v2 since the v3 BIOS knows how to + * handle that as well. + */ + ctlr = AR_F_HPTV2_RAID; + rdp->disks[disk].sectors = HPTV3_LBA(rdp->disks[disk].dev); break; - case ATA_SILICON_IMAGE_ID: - ctlr |= AR_F_LSI_RAID; - rdp->disks[disk].disk_sectors = - AD_SOFTC(rdp->disks[disk])->total_secs - 4208; /* SOS */ + case ATA_ITE_ID: + ctlr = AR_F_ITE_RAID; + rdp->disks[disk].sectors = ITE_LBA(rdp->disks[disk].dev); break; - default: - ctlr |= AR_F_FREEBSD_RAID; - /* FALLTHROUGH */ + case 0: /* XXX SOS cover up for bug in our PCI code */ + case ATA_PROMISE_ID: + ctlr = AR_F_PROMISE_RAID; + rdp->disks[disk].sectors = PR_LBA(rdp->disks[disk].dev); + break; - case ATA_PROMISE_ID: - ctlr |= AR_F_PROMISE_RAID; - rdp->disks[disk].disk_sectors = - PR_LBA(AD_SOFTC(rdp->disks[disk])); + default: + /* XXX SOS + * right, so here we are, we have an ATA chip and we want + * to create a RAID and store the metadata. + * we need to find a way to tell what kind of metadata this + * hardware's BIOS might be using (good ideas are welcomed) + * for now we just use our own native FreeBSD format. + * the only way to get support for the BIOS format is to + * setup the RAID from there, in that case we pickup the + * metadata format from the disks (if we support it). + */ + printf("WARNING!! - using FreeBSD PsuedoRAID metadata " + "since BIOS format is unknown on this hardware.\n" + "If that is not what you want, use the BIOS to " + "create the array\n"); + ctlr = AR_F_FREEBSD_RAID; + rdp->disks[disk].sectors = PR_LBA(rdp->disks[disk].dev); break; } - if ((rdp->flags & - (AR_F_PROMISE_RAID | AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID)) && - (rdp->flags & - (AR_F_PROMISE_RAID | AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID)) != - (ctlr & - (AR_F_PROMISE_RAID | AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID))) { + /* we need all disks to be of the same format */ + if ((rdp->format & AR_F_FORMAT_MASK) && + (rdp->format & AR_F_FORMAT_MASK) != (ctlr & AR_F_FORMAT_MASK)) { free(rdp, M_AR); return EXDEV; } else - rdp->flags |= ctlr; + rdp->format = ctlr; + /* use the smallest disk of the lots size */ + /* gigabyte boundry ??? XXX SOS */ if (disk_size) - disk_size = min(rdp->disks[disk].disk_sectors, disk_size); + disk_size = min(rdp->disks[disk].sectors, disk_size); else - disk_size = rdp->disks[disk].disk_sectors; + disk_size = rdp->disks[disk].sectors; rdp->disks[disk].flags = (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE); @@ -374,1577 +901,2705 @@ ata_raid_create(struct raid_setup *setup) return ENXIO; } } - if (!total_disks) { + + if (total_disks != setup->total_disks) { free(rdp, M_AR); return ENODEV; } switch (setup->type) { - case 1: - rdp->flags |= AR_F_RAID0; + case AR_T_JBOD: + case AR_T_SPAN: + case AR_T_RAID0: break; - case 2: - rdp->flags |= AR_F_RAID1; + + case AR_T_RAID1: if (total_disks != 2) { free(rdp, M_AR); return EPERM; } break; - case 3: - rdp->flags |= (AR_F_RAID0 | AR_F_RAID1); + + case AR_T_RAID01: if (total_disks % 2 != 0) { free(rdp, M_AR); return EPERM; } break; - case 4: - rdp->flags |= AR_F_SPAN; - break; - } - for (disk = 0; disk < total_disks; disk++) - AD_SOFTC(rdp->disks[disk])->flags |= AD_F_RAID_SUBDISK; + case AR_T_RAID5: + if (total_disks < 3) { + free(rdp, M_AR); + return EPERM; + } + break; + default: + free(rdp, M_AR); + return EOPNOTSUPP; + } + rdp->type = setup->type; rdp->lun = array; - if (rdp->flags & AR_F_RAID0) { + if (rdp->type == AR_T_RAID0 || rdp->type == AR_T_RAID01 || + rdp->type == AR_T_RAID5) { int bit = 0; while (setup->interleave >>= 1) bit++; - if (rdp->flags & AR_F_HIGHPOINT_RAID) - rdp->interleave = min(max(32, 1 << bit), 128); - if (rdp->flags & AR_F_LSI_RAID) - rdp->interleave = min(max(2, 1 << bit), 4096); - if (rdp->flags & AR_F_PROMISE_RAID) - rdp->interleave = min(max(2, 1 << bit), 2048); + rdp->interleave = 1 << bit; } + rdp->offset_sectors = 0; + + /* values that depend on metadata format */ + switch (rdp->format) { + case AR_F_ADAPTEC_RAID: + rdp->interleave = min(max(32, rdp->interleave), 128); /*+*/ + break; + + case AR_F_INTEL_RAID: + rdp->interleave = min(max(8, rdp->interleave), 256); /*+*/ + break; + + case AR_F_ITE_RAID: + rdp->interleave = min(max(2, rdp->interleave), 128); /*+*/ + break; + + case AR_F_SII_RAID: + rdp->interleave = min(max(8, rdp->interleave), 256); /*+*/ + break; + + case AR_F_HPTV2_RAID: + rdp->interleave = min(max(8, rdp->interleave), 128); /*+*/ + rdp->offset_sectors = HPTV2_LBA(x) + 1; + break; + + case AR_F_HPTV3_RAID: + rdp->interleave = min(max(32, rdp->interleave), 4096); /*+*/ + break; + + case AR_F_LSIV2_RAID: + rdp->interleave = min(max(2, rdp->interleave), 4096); + break; + + case AR_F_LSIV3_RAID: + rdp->interleave = min(max(2, rdp->interleave), 256); + break; + + case AR_F_PROMISE_RAID: + rdp->interleave = min(max(2, rdp->interleave), 2048); /*+*/ + break; + } + rdp->total_disks = total_disks; - rdp->width = total_disks / ((rdp->flags & AR_F_RAID1) ? 2 : 1); - rdp->total_sectors = disk_size * rdp->width; + rdp->width = total_disks / (rdp->type & (AR_RAID1 | AR_T_RAID01) ? 2 : 1); + rdp->total_sectors = disk_size * (rdp->width - (rdp->type == AR_RAID5)); rdp->heads = 255; rdp->sectors = 63; rdp->cylinders = rdp->total_sectors / (255 * 63); - if (rdp->flags & AR_F_PROMISE_RAID) { - rdp->offset = 0; - rdp->reserved = 63; - } - if (rdp->flags & AR_F_HIGHPOINT_RAID) { - rdp->offset = HPT_LBA + 1; - rdp->reserved = HPT_LBA + 1; - } - rdp->lock_start = rdp->lock_end = 0xffffffff; - rdp->flags |= AR_F_READY; + rdp->rebuild_lba = 0; + rdp->status |= AR_S_READY; - ar_table[array] = rdp; -#if 0 - /* kick off rebuild here */ - if (setup->type == 2) { - rdp->disks[1].flags &= ~AR_DF_ONLINE; - rdp->disks[1].flags |= AR_DF_SPARE; + /* we are committed to this array, grap the subdisks */ + for (disk = 0; disk < setup->total_disks; disk++) { + if ((subdisk = devclass_get_device(ata_raid_sub_devclass, + setup->disks[disk]))) { + struct ata_raid_subdisk *ars = device_get_softc(subdisk); + + ars->raid = rdp; + ars->disk_number = disk; + } } -#endif - ar_attach_raid(rdp, 1); - ata_raid_rebuild(array); + ata_raid_attach(rdp, 1); + ata_raid_arrays[array] = rdp; setup->unit = array; return 0; } -int +static int ata_raid_delete(int array) { - struct ar_softc *rdp; + struct ar_softc *rdp; + device_t subdisk; int disk; - if (!ar_table) { - printf("ar: no memory for ATA raid array\n"); - return 0; - } - if (!(rdp = ar_table[array])) + if (!(rdp = ata_raid_arrays[array])) return ENXIO; - - rdp->flags &= ~AR_F_READY; + + rdp->status &= ~AR_S_READY; + disk_destroy(rdp->disk); + for (disk = 0; disk < rdp->total_disks; disk++) { - if ((rdp->disks[disk].flags&AR_DF_PRESENT) && rdp->disks[disk].device) { - AD_SOFTC(rdp->disks[disk])->flags &= ~AD_F_RAID_SUBDISK; -/* SOS - ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_GREEN); - XXX */ + if ((rdp->disks[disk].flags & AR_DF_PRESENT) && rdp->disks[disk].dev) { + if ((subdisk = devclass_get_device(ata_raid_sub_devclass, + device_get_unit(rdp->disks[disk].dev)))) { + struct ata_raid_subdisk *ars = device_get_softc(subdisk); + + if (ars->raid != rdp) /* XXX SOS */ + device_printf(subdisk, "DOH! this disk doesn't belong\n"); + if (ars->disk_number != disk) /* XXX SOS */ + device_printf(subdisk, "DOH! this disk number is wrong\n"); + ars->raid = NULL; + ars->disk_number = -1; + } rdp->disks[disk].flags = 0; } } - - if (rdp->flags & AR_F_HIGHPOINT_RAID) - ar_highpoint_write_conf(rdp); - if (rdp->flags & AR_F_LSI_RAID) - ar_lsi_write_conf(rdp); - if (rdp->flags & AR_F_PROMISE_RAID) - ar_promise_write_conf(rdp); - - disk_destroy(rdp->disk); + ata_raid_write_metadata(rdp); /* wipe the metadata instead? XXX SOS */ + ata_raid_arrays[array] = NULL; free(rdp, M_AR); - ar_table[array] = NULL; return 0; } -int -ata_raid_status(int array, struct raid_status *status) +static int +ata_raid_addspare(int array, int spare) { - struct ar_softc *rdp; - int i; + struct ar_softc *rdp; + device_t subdisk; + int disk; - if (!ar_table || !(rdp = ar_table[array])) + if (!(rdp = ata_raid_arrays[array])) + return ENXIO; + if (!(rdp->status & AR_S_DEGRADED) || !(rdp->status & AR_S_READY)) return ENXIO; + if (rdp->status & AR_S_REBUILDING) + return EBUSY; + switch (rdp->type) { + case AR_T_RAID1: + case AR_T_RAID01: + case AR_T_RAID5: + for (disk = 0; disk < rdp->total_disks; disk++ ) { + + if (((rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) == + (AR_DF_PRESENT | AR_DF_ONLINE)) && rdp->disks[disk].dev) + continue; - switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) { - case AR_F_RAID0: - status->type = AR_RAID0; - break; - case AR_F_RAID1: - status->type = AR_RAID1; - break; - case AR_F_RAID0 | AR_F_RAID1: - status->type = AR_RAID0 | AR_RAID1; - break; - case AR_F_SPAN: - status->type = AR_SPAN; - break; - } - status->total_disks = rdp->total_disks; - for (i = 0; i < rdp->total_disks; i++ ) { - if ((rdp->disks[i].flags & AR_DF_PRESENT) && rdp->disks[i].device) - status->disks[i] = AD_SOFTC(rdp->disks[i])->lun; - else - status->disks[i] = -1; - } - status->interleave = rdp->interleave; - status->status = 0; - if (rdp->flags & AR_F_READY) - status->status |= AR_READY; - if (rdp->flags & AR_F_DEGRADED) - status->status |= AR_DEGRADED; - if (rdp->flags & AR_F_REBUILDING) { - status->status |= AR_REBUILDING; - status->progress = 100*rdp->lock_start/(rdp->total_sectors/rdp->width); + if ((subdisk = devclass_get_device(ata_raid_sub_devclass, spare ))){ + struct ata_raid_subdisk *ars = device_get_softc(subdisk); + + if (ars->raid) + return EBUSY; + + /* validate size etc etc XXX SOS */ + ars->raid = rdp; + ars->disk_number = disk; + rdp->disks[disk].dev = device_get_parent(subdisk); + rdp->disks[disk].flags = + (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_SPARE); + + device_printf(rdp->disks[disk].dev, + "inserted into ar%d disk%d as spare\n", + rdp->lun, disk); + ata_raid_config_changed(rdp, 1); + return 0; + } + } + return ENXIO; + + default: + return EPERM; } - return 0; } - -int + +static int ata_raid_rebuild(int array) { - struct ar_softc *rdp; + struct ar_softc *rdp; + int disk, count; - if (!ar_table || !(rdp = ar_table[array])) + if (!(rdp = ata_raid_arrays[array])) return ENXIO; - if (rdp->flags & AR_F_REBUILDING) - return EBUSY; - return kthread_create(ar_rebuild, rdp, &rdp->pid, RFNOWAIT, 0, - "rebuilding ar%d", array); -} - -static int -ardump(void *arg, void *virtual, vm_offset_t physical, - off_t offset, size_t length) -{ - struct ar_softc *rdp; - struct disk *dp, *ap; - vm_offset_t pdata; - caddr_t vdata; - int blkno, count, chunk, error1, error2, lba, lbs, tmplba; - int drv = 0; - - dp = arg; - rdp = dp->d_drv1; - if (!rdp || !(rdp->flags & AR_F_READY)) + /* XXX SOS we should lock the rdp softc here */ + if (!(rdp->status & AR_S_DEGRADED) || !(rdp->status & AR_S_READY)) return ENXIO; - - if (length == 0) { - for (drv = 0; drv < rdp->total_disks; drv++) { - if (rdp->disks[drv].flags & AR_DF_ONLINE) { - ap = AD_SOFTC(rdp->disks[drv])->disk; - (void) ap->d_dump(ap, NULL, 0, 0, 0); + if (rdp->status & AR_S_REBUILDING) + return EBUSY; + + switch (rdp->type) { + case AR_T_RAID1: + case AR_T_RAID01: + case AR_T_RAID5: + for (count = 0, disk = 0; disk < rdp->total_disks; disk++ ) { + if (((rdp->disks[disk].flags & + (AR_DF_PRESENT|AR_DF_ASSIGNED|AR_DF_ONLINE|AR_DF_SPARE)) == + (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_SPARE)) && + rdp->disks[disk].dev) { + count++; } } - return 0; - } - - blkno = offset / DEV_BSIZE; - vdata = virtual; - pdata = physical; - - for (count = howmany(length, DEV_BSIZE); count > 0; - count -= chunk, blkno += chunk, vdata += (chunk * DEV_BSIZE), - pdata += (chunk * DEV_BSIZE)) { - switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) { - case AR_F_SPAN: - lba = blkno; - while (lba >= AD_SOFTC(rdp->disks[drv])->total_secs-rdp->reserved) - lba -= AD_SOFTC(rdp->disks[drv++])->total_secs-rdp->reserved; - chunk = min(AD_SOFTC(rdp->disks[drv])->total_secs-rdp->reserved-lba, - count); - break; - - case AR_F_RAID0: - case AR_F_RAID0 | AR_F_RAID1: - tmplba = blkno / rdp->interleave; - chunk = blkno % rdp->interleave; - if (blkno >= (rdp->total_sectors / (rdp->interleave * rdp->width)) * - (rdp->interleave * rdp->width) ) { - lbs = (rdp->total_sectors - - ((rdp->total_sectors / (rdp->interleave * rdp->width)) * - (rdp->interleave * rdp->width))) / rdp->width; - drv = (blkno - - ((rdp->total_sectors / (rdp->interleave * rdp->width)) * - (rdp->interleave * rdp->width))) / lbs; - lba = ((tmplba / rdp->width) * rdp->interleave) + - (blkno - ((tmplba / rdp->width) * rdp->interleave)) % lbs; - chunk = min(count, lbs); - } - else { - drv = tmplba % rdp->width; - lba = ((tmplba / rdp->width) * rdp->interleave) + chunk; - chunk = min(count, rdp->interleave - chunk); - } - break; - - case AR_F_RAID1: - drv = 0; - lba = blkno; - chunk = count; - break; - - default: - printf("ar%d: unknown array type in ardump\n", rdp->lun); - return EIO; - } - - if (drv > 0) - lba += rdp->offset; - - switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) { - case AR_F_SPAN: - case AR_F_RAID0: - if (rdp->disks[drv].flags & AR_DF_ONLINE) { - ap = AD_SOFTC(rdp->disks[drv])->disk; - error1 = ap->d_dump(ap, vdata, pdata, - (off_t) lba * DEV_BSIZE, - chunk * DEV_BSIZE); - } else - error1 = EIO; - if (error1) - return error1; - break; - - case AR_F_RAID1: - case AR_F_RAID0 | AR_F_RAID1: - if ((rdp->disks[drv].flags & AR_DF_ONLINE) || - ((rdp->flags & AR_F_REBUILDING) && - (rdp->disks[drv].flags & AR_DF_SPARE))) { - ap = AD_SOFTC(rdp->disks[drv])->disk; - error1 = ap->d_dump(ap, vdata, pdata, - (off_t) lba * DEV_BSIZE, - chunk * DEV_BSIZE); - } else - error1 = EIO; - if ((rdp->disks[drv + rdp->width].flags & AR_DF_ONLINE) || - ((rdp->flags & AR_F_REBUILDING) && - (rdp->disks[drv + rdp->width].flags & AR_DF_SPARE))) { - ap = AD_SOFTC(rdp->disks[drv + rdp->width])->disk; - error2 = ap->d_dump(ap, vdata, pdata, - (off_t) lba * DEV_BSIZE, - chunk * DEV_BSIZE); - } else - error2 = EIO; - if (error1 && error2) - return error1; - break; - - default: - printf("ar%d: unknown array type in ardump\n", rdp->lun); - return EIO; + if (count) { + rdp->rebuild_lba = 0; + rdp->status |= AR_S_REBUILDING; + return 0; } + return EIO; + + default: + return EPERM; } - return 0; } -static void -arstrategy(struct bio *bp) +static int +ata_raid_read_metadata(device_t subdisk) { - struct ar_softc *rdp = bp->bio_disk->d_drv1; - int blkno, count, chunk, lba, lbs, tmplba; - int drv = 0, change = 0; - caddr_t data; - - if (!(rdp->flags & AR_F_READY)) { - bp->bio_flags |= BIO_ERROR; - bp->bio_error = EIO; - biodone(bp); - return; - } - - bp->bio_resid = bp->bio_bcount; - blkno = bp->bio_pblkno; - data = bp->bio_data; - for (count = howmany(bp->bio_bcount, DEV_BSIZE); count > 0; - count -= chunk, blkno += chunk, data += (chunk * DEV_BSIZE)) { - struct ar_buf *buf1, *buf2; - - switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) { - case AR_F_SPAN: - lba = blkno; - while (lba >= AD_SOFTC(rdp->disks[drv])->total_secs-rdp->reserved) - lba -= AD_SOFTC(rdp->disks[drv++])->total_secs-rdp->reserved; - chunk = min(AD_SOFTC(rdp->disks[drv])->total_secs-rdp->reserved-lba, - count); - break; - - case AR_F_RAID0: - case AR_F_RAID0 | AR_F_RAID1: - tmplba = blkno / rdp->interleave; - chunk = blkno % rdp->interleave; - if (blkno >= (rdp->total_sectors / (rdp->interleave * rdp->width)) * - (rdp->interleave * rdp->width) ) { - lbs = (rdp->total_sectors - - ((rdp->total_sectors / (rdp->interleave * rdp->width)) * - (rdp->interleave * rdp->width))) / rdp->width; - drv = (blkno - - ((rdp->total_sectors / (rdp->interleave * rdp->width)) * - (rdp->interleave * rdp->width))) / lbs; - lba = ((tmplba / rdp->width) * rdp->interleave) + - (blkno - ((tmplba / rdp->width) * rdp->interleave)) % lbs; - chunk = min(count, lbs); - } - else { - drv = tmplba % rdp->width; - lba = ((tmplba / rdp->width) * rdp->interleave) + chunk; - chunk = min(count, rdp->interleave - chunk); - } + devclass_t pci_devclass = devclass_find("pci"); + devclass_t devclass=device_get_devclass(GRANDPARENT(GRANDPARENT(subdisk))); + + /* prioritize vendor native metadata layout if possible */ + if (devclass == pci_devclass) { + switch (pci_get_vendor(GRANDPARENT(device_get_parent(subdisk)))) { + case ATA_HIGHPOINT_ID: + if (ata_raid_hptv3_read_meta(subdisk, ata_raid_arrays)) + return 0; + if (ata_raid_hptv2_read_meta(subdisk, ata_raid_arrays)) + return 0; break; - case AR_F_RAID1: - drv = 0; - lba = blkno; - chunk = count; + case ATA_INTEL_ID: + if (ata_raid_intel_read_meta(subdisk, ata_raid_arrays)) + return 0; break; - default: - printf("ar%d: unknown array type in arstrategy\n", rdp->lun); - bp->bio_flags |= BIO_ERROR; - bp->bio_error = EIO; - biodone(bp); - return; - } - - buf1 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT | M_ZERO); /* XXX */ - buf1->bp.bio_pblkno = lba; - if ((buf1->drive = drv) > 0) - buf1->bp.bio_pblkno += rdp->offset; - buf1->bp.bio_driver1 = (void *)rdp; - buf1->bp.bio_bcount = chunk * DEV_BSIZE; - buf1->bp.bio_data = data; - buf1->bp.bio_cmd = bp->bio_cmd; - buf1->bp.bio_flags = bp->bio_flags; - buf1->bp.bio_done = ar_done; - buf1->org = bp; - - switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) { - case AR_F_SPAN: - case AR_F_RAID0: - if ((rdp->disks[buf1->drive].flags & - (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) && - !rdp->disks[buf1->drive].device->softc) { - rdp->disks[buf1->drive].flags &= ~AR_DF_ONLINE; - ar_config_changed(rdp, 1); - free(buf1, M_AR); - bp->bio_flags |= BIO_ERROR; - bp->bio_error = EIO; - biodone(bp); - return; - } - buf1->bp.bio_disk = AD_SOFTC(rdp->disks[buf1->drive])->disk; - AR_STRATEGY((struct bio *)buf1); + case ATA_ITE_ID: + if (ata_raid_ite_read_meta(subdisk, ata_raid_arrays)) + return 0; break; - case AR_F_RAID1: - case AR_F_RAID0 | AR_F_RAID1: - if (rdp->flags & AR_F_REBUILDING && bp->bio_cmd == BIO_WRITE) { - if ((bp->bio_pblkno >= rdp->lock_start && - bp->bio_pblkno < rdp->lock_end) || - ((bp->bio_pblkno + chunk) > rdp->lock_start && - (bp->bio_pblkno + chunk) <= rdp->lock_end)) { - tsleep(rdp, PRIBIO, "arwait", 0); - } - } - if ((rdp->disks[buf1->drive].flags & - (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) && - !rdp->disks[buf1->drive].device->softc) { - rdp->disks[buf1->drive].flags &= ~AR_DF_ONLINE; - change = 1; - } - if ((rdp->disks[buf1->drive + rdp->width].flags & - (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) && - !rdp->disks[buf1->drive + rdp->width].device->softc) { - rdp->disks[buf1->drive + rdp->width].flags &= ~AR_DF_ONLINE; - change = 1; - } - if (change) - ar_config_changed(rdp, 1); - - if (!(rdp->flags & AR_F_READY)) { - free(buf1, M_AR); - bp->bio_flags |= BIO_ERROR; - bp->bio_error = EIO; - biodone(bp); - return; - } - if (bp->bio_cmd == BIO_READ) { - int src_online = - (rdp->disks[buf1->drive].flags & AR_DF_ONLINE); - int mir_online = - (rdp->disks[buf1->drive+rdp->width].flags & AR_DF_ONLINE); - - /* if mirror gone or close to last access on source */ - if (!mir_online || - ((src_online) && - buf1->bp.bio_pblkno >= - (rdp->disks[buf1->drive].last_lba - AR_PROXIMITY) && - buf1->bp.bio_pblkno <= - (rdp->disks[buf1->drive].last_lba + AR_PROXIMITY))) { - rdp->flags &= ~AR_F_TOGGLE; - } - /* if source gone or close to last access on mirror */ - else if (!src_online || - ((mir_online) && - buf1->bp.bio_pblkno >= - (rdp->disks[buf1->drive + rdp->width].last_lba - - AR_PROXIMITY) && - buf1->bp.bio_pblkno <= - (rdp->disks[buf1->drive + rdp->width].last_lba + - AR_PROXIMITY))) { - buf1->drive = buf1->drive + rdp->width; - rdp->flags |= AR_F_TOGGLE; - } - /* not close to any previous access, toggle */ - else { - if (rdp->flags & AR_F_TOGGLE) - rdp->flags &= ~AR_F_TOGGLE; - else { - buf1->drive = buf1->drive + rdp->width; - rdp->flags |= AR_F_TOGGLE; - } - } - } - if (bp->bio_cmd == BIO_WRITE) { - if ((rdp->disks[buf1->drive+rdp->width].flags & AR_DF_ONLINE) || - ((rdp->flags & AR_F_REBUILDING) && - (rdp->disks[buf1->drive+rdp->width].flags & AR_DF_SPARE) && - buf1->bp.bio_pblkno < rdp->lock_start)) { - if ((rdp->disks[buf1->drive].flags & AR_DF_ONLINE) || - ((rdp->flags & AR_F_REBUILDING) && - (rdp->disks[buf1->drive].flags & AR_DF_SPARE) && - buf1->bp.bio_pblkno < rdp->lock_start)) { - buf2 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT); /* XXX */ - bcopy(buf1, buf2, sizeof(struct ar_buf)); - buf1->mirror = buf2; - buf2->mirror = buf1; - buf2->drive = buf1->drive + rdp->width; - buf2->bp.bio_disk = - AD_SOFTC(rdp->disks[buf2->drive])->disk; - AR_STRATEGY((struct bio *)buf2); - rdp->disks[buf2->drive].last_lba = - buf2->bp.bio_pblkno + chunk; - } - else - buf1->drive = buf1->drive + rdp->width; - } - } - buf1->bp.bio_disk = AD_SOFTC(rdp->disks[buf1->drive])->disk; - AR_STRATEGY((struct bio *)buf1); - rdp->disks[buf1->drive].last_lba = buf1->bp.bio_pblkno + chunk; + case 0: /* XXX SOS cover up for bug in our PCI code */ + case ATA_PROMISE_ID: + if (ata_raid_promise_read_meta(subdisk, ata_raid_arrays, 0)) + return 0; break; - default: - printf("ar%d: unknown array type in arstrategy\n", rdp->lun); + case ATA_SILICON_IMAGE_ID: + if (ata_raid_sii_read_meta(subdisk, ata_raid_arrays)) + return 0; + break; } } -} + + /* handle controllers that have multiple layout possibilities */ + /* NOTE: the order of these are not insignificant */ -static void -ar_done(struct bio *bp) -{ - struct ar_softc *rdp = (struct ar_softc *)bp->bio_driver1; - struct ar_buf *buf = (struct ar_buf *)bp; - - switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) { - case AR_F_SPAN: - case AR_F_RAID0: - if (buf->bp.bio_flags & BIO_ERROR) { - rdp->disks[buf->drive].flags &= ~AR_DF_ONLINE; - ar_config_changed(rdp, 1); - buf->org->bio_flags |= BIO_ERROR; - buf->org->bio_error = EIO; - biodone(buf->org); - } - else { - buf->org->bio_resid -= buf->bp.bio_bcount; - if (buf->org->bio_resid == 0) - biodone(buf->org); - } - break; + /* Adaptec HostRAID */ + if (ata_raid_adaptec_read_meta(subdisk, ata_raid_arrays)) + return 0; - case AR_F_RAID1: - case AR_F_RAID0 | AR_F_RAID1: - if (buf->bp.bio_flags & BIO_ERROR) { - rdp->disks[buf->drive].flags &= ~AR_DF_ONLINE; - ar_config_changed(rdp, 1); - if (rdp->flags & AR_F_READY) { - if (buf->bp.bio_cmd == BIO_READ) { - if (buf->drive < rdp->width) - buf->drive = buf->drive + rdp->width; - else - buf->drive = buf->drive - rdp->width; - buf->bp.bio_disk = AD_SOFTC(rdp->disks[buf->drive])->disk; - buf->bp.bio_flags = buf->org->bio_flags; - buf->bp.bio_error = 0; - AR_STRATEGY((struct bio *)buf); - return; - } - if (buf->bp.bio_cmd == BIO_WRITE) { - if (buf->flags & AB_F_DONE) { - buf->org->bio_resid -= buf->bp.bio_bcount; - if (buf->org->bio_resid == 0) - biodone(buf->org); - } - else - buf->mirror->flags |= AB_F_DONE; - } - } - else { - buf->org->bio_flags |= BIO_ERROR; - buf->org->bio_error = EIO; - biodone(buf->org); - } - } - else { - if (buf->bp.bio_cmd == BIO_WRITE) { - if (buf->mirror && !(buf->flags & AB_F_DONE)){ - buf->mirror->flags |= AB_F_DONE; - break; - } - } - buf->org->bio_resid -= buf->bp.bio_bcount; - if (buf->org->bio_resid == 0) - biodone(buf->org); - } - break; - - default: - printf("ar%d: unknown array type in ar_done\n", rdp->lun); - } - free(buf, M_AR); + /* LSILogic v3 and v2 */ + if (ata_raid_lsiv3_read_meta(subdisk, ata_raid_arrays)) + return 0; + if (ata_raid_lsiv2_read_meta(subdisk, ata_raid_arrays)) + return 0; + + /* if none of the above matched, try FreeBSD native format */ + return ata_raid_promise_read_meta(subdisk, ata_raid_arrays, 1); } -static void -ar_config_changed(struct ar_softc *rdp, int writeback) +static int +ata_raid_write_metadata(struct ar_softc *rdp) { - int disk, flags; + switch (rdp->format) { + case AR_F_FREEBSD_RAID: + case AR_F_PROMISE_RAID: + return ata_raid_promise_write_meta(rdp); + + case AR_F_HPTV3_RAID: + case AR_F_HPTV2_RAID: + /* + * always write HPT v2 metadata, the v3 BIOS knows it as well. + * this is handy since we cannot know what version BIOS is on there + */ + return ata_raid_hptv2_write_meta(rdp); +#if 0 + case AR_F_HPTV3_RAID: + return ata_raid_hptv3_write_meta(rdp); - flags = rdp->flags; - rdp->flags |= AR_F_READY; - rdp->flags &= ~AR_F_DEGRADED; + case AR_F_ADAPTEC_RAID: + return ata_raid_adaptec_write_meta(rdp); - for (disk = 0; disk < rdp->total_disks; disk++) - if (!(rdp->disks[disk].flags & AR_DF_PRESENT)) - rdp->disks[disk].flags &= ~AR_DF_ONLINE; + case ATA_INTEL_ID: + return ata_raid_intel_write_meta(rdp); - for (disk = 0; disk < rdp->total_disks; disk++) { - switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) { - case AR_F_SPAN: - case AR_F_RAID0: - if (!(rdp->disks[disk].flags & AR_DF_ONLINE)) { - rdp->flags &= ~AR_F_READY; - printf("ar%d: ERROR - array broken\n", rdp->lun); - } - break; + case ATA_ITE_ID: + return ata_raid_ite_write_meta(rdp); - case AR_F_RAID1: - case AR_F_RAID0 | AR_F_RAID1: - if (disk < rdp->width) { - if (!(rdp->disks[disk].flags & AR_DF_ONLINE) && - !(rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE)) { - rdp->flags &= ~AR_F_READY; - printf("ar%d: ERROR - array broken\n", rdp->lun); - } - else if (((rdp->disks[disk].flags & AR_DF_ONLINE) && - !(rdp->disks - [disk + rdp->width].flags & AR_DF_ONLINE))|| - (!(rdp->disks[disk].flags & AR_DF_ONLINE) && - (rdp->disks - [disk + rdp->width].flags & AR_DF_ONLINE))) { - rdp->flags |= AR_F_DEGRADED; - if (!(flags & AR_F_DEGRADED)) - printf("ar%d: WARNING - mirror lost\n", rdp->lun); - } - } - break; - } - if ((rdp->disks[disk].flags&AR_DF_PRESENT) && rdp->disks[disk].device) { -/* SOS - if (rdp->disks[disk].flags & AR_DF_ONLINE) - ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_GREEN); - else - ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_RED); - XXX */ - } - } - if (writeback) { - if (rdp->flags & AR_F_HIGHPOINT_RAID) - ar_highpoint_write_conf(rdp); - if (rdp->flags & AR_F_LSI_RAID) - ar_lsi_write_conf(rdp); - if (rdp->flags & AR_F_PROMISE_RAID) - ar_promise_write_conf(rdp); + case AR_F_LSIV2_RAID: + return ata_raid_lsiv2_write_meta(rdp); + + case AR_F_LSIV3_RAID: + return ata_raid_lsiv3_write_meta(rdp); + + case ATA_SILICON_IMAGE_ID: + return ata_raid_sii_write_meta(rdp); +#endif + default: + printf("ar%d: writing of %s metadata is NOT supported yet\n", + rdp->lun, ata_raid_format(rdp)); } + return -1; } -static void -ar_rebuild(void *arg) +/* Adaptec HostRAID Metadata */ +static int +ata_raid_adaptec_read_meta(device_t dev, struct ar_softc **raidp) { - struct ar_softc *rdp = arg; - int disk, s, count = 0, error = 0; - caddr_t buffer; + struct ata_raid_subdisk *ars = device_get_softc(dev); + device_t parent = device_get_parent(dev); + struct adaptec_raid_conf *meta; + struct ar_softc *raid; + int array, disk, retval = 0; - mtx_lock(&Giant); - if ((rdp->flags & (AR_F_READY|AR_F_DEGRADED)) != (AR_F_READY|AR_F_DEGRADED)) - kthread_exit(EEXIST); + if (!(meta = (struct adaptec_raid_conf *) + malloc(sizeof(struct adaptec_raid_conf), M_AR, M_NOWAIT | M_ZERO))) + return ENOMEM; - for (disk = 0; disk < rdp->total_disks; disk++) { - if (((rdp->disks[disk].flags&(AR_DF_PRESENT|AR_DF_ONLINE|AR_DF_SPARE))== - (AR_DF_PRESENT | AR_DF_SPARE)) && rdp->disks[disk].device) { - if (AD_SOFTC(rdp->disks[disk])->total_secs < - rdp->disks[disk].disk_sectors) { - ata_prtdev(rdp->disks[disk].device, - "disk capacity too small for this RAID config\n"); -#if 0 - rdp->disks[disk].flags &= ~AR_DF_SPARE; - AD_SOFTC(rdp->disks[disk])->flags &= ~AD_F_RAID_SUBDISK; -#endif - continue; - } -/* SOS - ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_ORANGE); - XXX */ - count++; - } + if (ata_raid_rw(parent, ADP_LBA(parent), + meta, sizeof(struct adaptec_raid_conf), ATA_R_READ)) { + if (testing || bootverbose) + device_printf(parent, "Adaptec read metadata failed\n"); + goto adaptec_out; } - if (!count) - kthread_exit(ENODEV); - /* setup start conditions */ - s = splbio(); - rdp->lock_start = 0; - rdp->lock_end = rdp->lock_start + AR_REBUILD_SIZE; - rdp->flags |= AR_F_REBUILDING; - splx(s); - buffer = malloc(AR_REBUILD_SIZE * DEV_BSIZE, M_AR, M_NOWAIT | M_ZERO); /* XXX */ + /* check if this is a Adaptec RAID struct */ + if (meta->magic_0 != ADP_MAGIC_0 || meta->magic_3 != ADP_MAGIC_3) { + if (testing || bootverbose) + device_printf(parent, "Adaptec check1 failed\n"); + goto adaptec_out; + } - /* now go copy entire disk(s) */ - while (rdp->lock_end < (rdp->total_sectors / rdp->width)) { - int size = min(AR_REBUILD_SIZE, - (rdp->total_sectors / rdp->width) - rdp->lock_end); + if (testing || bootverbose) + ata_raid_adaptec_print_meta(meta); - for (disk = 0; disk < rdp->width; disk++) { - struct ad_softc *adp; - - if (((rdp->disks[disk].flags & AR_DF_ONLINE) && - (rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE)) || - ((rdp->disks[disk].flags & AR_DF_ONLINE) && - !(rdp->disks[disk + rdp->width].flags & AR_DF_SPARE)) || - ((rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE) && - !(rdp->disks[disk].flags & AR_DF_SPARE))) - continue; + /* now convert Adaptec metadata into our generic form */ + for (array = 0; array < MAX_ARRAYS; array++) { + if (!raidp[array]) { + raidp[array] = + (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, + M_NOWAIT | M_ZERO); + if (!raidp[array]) { + device_printf(parent, "failed to allocate metadata storage\n"); + goto adaptec_out; + } + } + raid = raidp[array]; + if (raid->format && (raid->format != AR_F_ADAPTEC_RAID)) + continue; - if (rdp->disks[disk].flags & AR_DF_ONLINE) - adp = AD_SOFTC(rdp->disks[disk]); - else - adp = AD_SOFTC(rdp->disks[disk + rdp->width]); - if ((error = ar_rw(adp, rdp->lock_start, - size * DEV_BSIZE, buffer, AR_READ | AR_WAIT))) - break; + if (raid->magic_0 && raid->magic_0 != meta->configs[0].magic_0) + continue; - if (rdp->disks[disk].flags & AR_DF_ONLINE) - adp = AD_SOFTC(rdp->disks[disk + rdp->width]); - else - adp = AD_SOFTC(rdp->disks[disk]); - if ((error = ar_rw(adp, rdp->lock_start, - size * DEV_BSIZE, buffer, AR_WRITE | AR_WAIT))) + if (!meta->generation || be32toh(meta->generation) > raid->generation) { + switch (meta->configs[0].type) { + case ADP_T_RAID0: + raid->magic_0 = meta->configs[0].magic_0; + raid->type = AR_T_RAID0; + raid->interleave = 1 << (meta->configs[0].stripe_shift >> 1); + raid->width = be16toh(meta->configs[0].total_disks); + break; + + case ADP_T_RAID1: + raid->magic_0 = meta->configs[0].magic_0; + raid->type = AR_T_RAID1; + raid->width = be16toh(meta->configs[0].total_disks) / 2; break; + + default: + device_printf(parent, "Adaptec unknown RAID type 0x%02x\n", + meta->configs[0].type); + free(raidp[array], M_AR); + raidp[array] = NULL; + goto adaptec_out; + } + + raid->format = AR_F_ADAPTEC_RAID; + raid->generation = be32toh(meta->generation); + raid->total_disks = be16toh(meta->configs[0].total_disks); + raid->total_sectors = be32toh(meta->configs[0].sectors); + raid->heads = 255; + raid->sectors = 63; + raid->cylinders = raid->total_sectors / (63 * 255); + raid->offset_sectors = 0; + raid->rebuild_lba = 0; + raid->lun = array; + strncpy(raid->name, meta->configs[0].name, + min(sizeof(raid->name), sizeof(meta->configs[0].name))); + + /* clear out any old info */ + if (raid->generation) { + for (disk = 0; disk < raid->total_disks; disk++) { + raid->disks[disk].dev = NULL; + raid->disks[disk].flags = 0; + } + } } - if (error) { - wakeup(rdp); - free(buffer, M_AR); - kthread_exit(error); - } - s = splbio(); - rdp->lock_start = rdp->lock_end; - rdp->lock_end = rdp->lock_start + size; - splx(s); - wakeup(rdp); - sprintf(rdp->pid->p_comm, "rebuilding ar%d %lld%%", rdp->lun, - (unsigned long long)(100 * rdp->lock_start / - (rdp->total_sectors / rdp->width))); - } - free(buffer, M_AR); - for (disk = 0; disk < rdp->total_disks; disk++) { - if ((rdp->disks[disk].flags&(AR_DF_PRESENT|AR_DF_ONLINE|AR_DF_SPARE))== - (AR_DF_PRESENT | AR_DF_SPARE)) { - rdp->disks[disk].flags &= ~AR_DF_SPARE; - rdp->disks[disk].flags |= (AR_DF_ASSIGNED | AR_DF_ONLINE); - } - } - s = splbio(); - rdp->lock_start = 0xffffffff; - rdp->lock_end = 0xffffffff; - rdp->flags &= ~AR_F_REBUILDING; - splx(s); - ar_config_changed(rdp, 1); - kthread_exit(0); + if (be32toh(meta->generation) >= raid->generation) { + struct ata_device *atadev = device_get_softc(parent); + struct ata_channel *ch = device_get_softc(GRANDPARENT(dev)); + int disk_number = (ch->unit << !(ch->flags & ATA_NO_SLAVE)) + + (atadev->unit == ATA_MASTER ? 0 : 1); + + raid->disks[disk_number].dev = parent; + raid->disks[disk_number].sectors = + be32toh(meta->configs[disk_number + 1].sectors); + raid->disks[disk_number].flags = + (AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED); + ars->raid = raid; + ars->disk_number = disk_number; + retval = 1; + } + break; + } + +adaptec_out: + free(meta, M_AR); + return retval; } +/* Highpoint V2 RocketRAID Metadata */ static int -ar_highpoint_read_conf(struct ad_softc *adp, struct ar_softc **raidp) +ata_raid_hptv2_read_meta(device_t dev, struct ar_softc **raidp) { - struct highpoint_raid_conf *info; + struct ata_raid_subdisk *ars = device_get_softc(dev); + device_t parent = device_get_parent(dev); + struct hptv2_raid_conf *meta; struct ar_softc *raid = NULL; int array, disk_number = 0, retval = 0; - if (!(info = (struct highpoint_raid_conf *) - malloc(sizeof(struct highpoint_raid_conf), M_AR, M_NOWAIT | M_ZERO))) - return retval; + if (!(meta = (struct hptv2_raid_conf *) + malloc(sizeof(struct hptv2_raid_conf), M_AR, M_NOWAIT | M_ZERO))) + return ENOMEM; - if (ar_rw(adp, HPT_LBA, sizeof(struct highpoint_raid_conf), - (caddr_t)info, AR_READ | AR_WAIT)) { - if (bootverbose) - printf("ar: HighPoint read conf failed\n"); - goto highpoint_out; + if (ata_raid_rw(parent, HPTV2_LBA(parent), + meta, sizeof(struct hptv2_raid_conf), ATA_R_READ)) { + if (testing || bootverbose) + device_printf(parent, "HighPoint (v2) read metadata failed\n"); + goto hptv2_out; } - /* check if this is a HighPoint RAID struct */ - if (info->magic != HPT_MAGIC_OK && info->magic != HPT_MAGIC_BAD) { - if (bootverbose) - printf("ar: HighPoint check1 failed\n"); - goto highpoint_out; + /* check if this is a HighPoint v2 RAID struct */ + if (meta->magic != HPTV2_MAGIC_OK && meta->magic != HPTV2_MAGIC_BAD) { + if (testing || bootverbose) + device_printf(parent, "HighPoint (v2) check1 failed\n"); + goto hptv2_out; } /* is this disk defined, or an old leftover/spare ? */ - if (!info->magic_0) { - if (bootverbose) - printf("ar: HighPoint check2 failed\n"); - goto highpoint_out; + if (!meta->magic_0) { + if (testing || bootverbose) + device_printf(parent, "HighPoint (v2) check2 failed\n"); + goto hptv2_out; } - /* now convert HighPoint config info into our generic form */ + if (testing || bootverbose) + ata_raid_hptv2_print_meta(meta); + + /* now convert HighPoint (v2) metadata into our generic form */ for (array = 0; array < MAX_ARRAYS; array++) { if (!raidp[array]) { raidp[array] = - (struct ar_softc*)malloc(sizeof(struct ar_softc), M_AR, - M_NOWAIT | M_ZERO); + (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, + M_NOWAIT | M_ZERO); if (!raidp[array]) { - printf("ar%d: failed to allocate raid config storage\n", array); - goto highpoint_out; + device_printf(parent, "failed to allocate metadata storage\n"); + goto hptv2_out; } } raid = raidp[array]; - if (raid->flags & (AR_F_PROMISE_RAID | AR_F_LSI_RAID)) + if (raid->format && (raid->format != AR_F_HPTV2_RAID)) continue; - switch (info->type) { - case HPT_T_RAID0: - if ((info->order & (HPT_O_RAID0|HPT_O_OK))==(HPT_O_RAID0|HPT_O_OK)) + switch (meta->type) { + case HPTV2_T_RAID0: + if ((meta->order & (HPTV2_O_RAID0|HPTV2_O_OK)) == + (HPTV2_O_RAID0|HPTV2_O_OK)) goto highpoint_raid1; - if (info->order & (HPT_O_RAID0 | HPT_O_RAID1)) + if (meta->order & (HPTV2_O_RAID0 | HPTV2_O_RAID1)) goto highpoint_raid01; - if (raid->magic_0 && raid->magic_0 != info->magic_0) + if (raid->magic_0 && raid->magic_0 != meta->magic_0) continue; - raid->magic_0 = info->magic_0; - raid->flags |= AR_F_RAID0; - raid->interleave = 1 << info->stripe_shift; - disk_number = info->disk_number; - if (!(info->order & HPT_O_OK)) - info->magic = 0; /* mark bad */ + raid->magic_0 = meta->magic_0; + raid->type = AR_T_RAID0; + raid->interleave = 1 << meta->stripe_shift; + disk_number = meta->disk_number; + if (!(meta->order & HPTV2_O_OK)) + meta->magic = 0; /* mark bad */ break; - case HPT_T_RAID1: + case HPTV2_T_RAID1: highpoint_raid1: - if (raid->magic_0 && raid->magic_0 != info->magic_0) + if (raid->magic_0 && raid->magic_0 != meta->magic_0) continue; - raid->magic_0 = info->magic_0; - raid->flags |= AR_F_RAID1; - disk_number = (info->disk_number > 0); + raid->magic_0 = meta->magic_0; + raid->type = AR_T_RAID1; + disk_number = (meta->disk_number > 0); break; - case HPT_T_RAID01_RAID0: + case HPTV2_T_RAID01_RAID0: highpoint_raid01: - if (info->order & HPT_O_RAID0) { - if ((raid->magic_0 && raid->magic_0 != info->magic_0) || - (raid->magic_1 && raid->magic_1 != info->magic_1)) + if (meta->order & HPTV2_O_RAID0) { + if ((raid->magic_0 && raid->magic_0 != meta->magic_0) || + (raid->magic_1 && raid->magic_1 != meta->magic_1)) continue; - raid->magic_0 = info->magic_0; - raid->magic_1 = info->magic_1; - raid->flags |= (AR_F_RAID0 | AR_F_RAID1); - raid->interleave = 1 << info->stripe_shift; - disk_number = info->disk_number; + raid->magic_0 = meta->magic_0; + raid->magic_1 = meta->magic_1; + raid->type = AR_T_RAID01; + raid->interleave = 1 << meta->stripe_shift; + disk_number = meta->disk_number; } else { - if (raid->magic_1 && raid->magic_1 != info->magic_1) + if (raid->magic_1 && raid->magic_1 != meta->magic_1) continue; - raid->magic_1 = info->magic_1; - raid->flags |= (AR_F_RAID0 | AR_F_RAID1); - raid->interleave = 1 << info->stripe_shift; - disk_number = info->disk_number + info->array_width; - if (!(info->order & HPT_O_RAID1)) - info->magic = 0; /* mark bad */ + raid->magic_1 = meta->magic_1; + raid->type = AR_T_RAID01; + raid->interleave = 1 << meta->stripe_shift; + disk_number = meta->disk_number + meta->array_width; + if (!(meta->order & HPTV2_O_RAID1)) + meta->magic = 0; /* mark bad */ } break; - case HPT_T_SPAN: - if (raid->magic_0 && raid->magic_0 != info->magic_0) + case HPTV2_T_SPAN: + if (raid->magic_0 && raid->magic_0 != meta->magic_0) continue; - raid->magic_0 = info->magic_0; - raid->flags |= AR_F_SPAN; - disk_number = info->disk_number; + raid->magic_0 = meta->magic_0; + raid->type = AR_T_SPAN; + disk_number = meta->disk_number; break; default: - printf("ar%d: HighPoint unknown RAID type 0x%02x\n", - array, info->type); + device_printf(parent, "Highpoint (v2) unknown RAID type 0x%02x\n", + meta->type); free(raidp[array], M_AR); raidp[array] = NULL; - goto highpoint_out; + goto hptv2_out; } - raid->flags |= AR_F_HIGHPOINT_RAID; - raid->disks[disk_number].device = adp->device; + raid->format |= AR_F_HPTV2_RAID; + raid->disks[disk_number].dev = parent; raid->disks[disk_number].flags = (AR_DF_PRESENT | AR_DF_ASSIGNED); - AD_SOFTC(raid->disks[disk_number])->flags |= AD_F_RAID_SUBDISK; raid->lun = array; - if (info->magic == HPT_MAGIC_OK) { + strncpy(raid->name, meta->name_1, + min(sizeof(raid->name), sizeof(meta->name_1))); + if (meta->magic == HPTV2_MAGIC_OK) { raid->disks[disk_number].flags |= AR_DF_ONLINE; - raid->flags |= AR_F_READY; - raid->width = info->array_width; + raid->width = meta->array_width; + raid->total_sectors = meta->total_sectors; raid->heads = 255; raid->sectors = 63; - raid->cylinders = info->total_sectors / (63 * 255); - raid->total_sectors = info->total_sectors; - raid->offset = HPT_LBA + 1; - raid->reserved = HPT_LBA + 1; - raid->lock_start = raid->lock_end = info->rebuild_lba; - raid->disks[disk_number].disk_sectors = - info->total_sectors / info->array_width; + raid->cylinders = raid->total_sectors / (63 * 255); + raid->offset_sectors = HPTV2_LBA(parent) + 1; + raid->rebuild_lba = meta->rebuild_lba; + raid->disks[disk_number].sectors = + raid->total_sectors / raid->width; } else - raid->disks[disk_number].flags &= ~ AR_DF_ONLINE; + raid->disks[disk_number].flags &= ~AR_DF_ONLINE; - if ((raid->flags & AR_F_RAID0) && (raid->total_disks < raid->width)) + if ((raid->type & AR_T_RAID0) && (raid->total_disks < raid->width)) raid->total_disks = raid->width; if (disk_number >= raid->total_disks) raid->total_disks = disk_number + 1; + ars->raid = raid; + ars->disk_number = disk_number; retval = 1; break; } -highpoint_out: - free(info, M_AR); +hptv2_out: + free(meta, M_AR); return retval; } static int -ar_highpoint_write_conf(struct ar_softc *rdp) +ata_raid_hptv2_write_meta(struct ar_softc *rdp) { - struct highpoint_raid_conf *config; + struct hptv2_raid_conf *meta; struct timeval timestamp; - int disk; + int disk, error = 0; + + if (!(meta = (struct hptv2_raid_conf *) + malloc(sizeof(struct hptv2_raid_conf), M_AR, M_NOWAIT | M_ZERO))) { + printf("ar%d: failed to allocate metadata storage\n", rdp->lun); + return ENOMEM; + } microtime(×tamp); rdp->magic_0 = timestamp.tv_sec + 2; rdp->magic_1 = timestamp.tv_sec; for (disk = 0; disk < rdp->total_disks; disk++) { - if (!(config = (struct highpoint_raid_conf *) - malloc(sizeof(struct highpoint_raid_conf), - M_AR, M_NOWAIT | M_ZERO))) { - printf("ar%d: Highpoint write conf failed\n", rdp->lun); - return -1; - } if ((rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) == (AR_DF_PRESENT | AR_DF_ONLINE)) - config->magic = HPT_MAGIC_OK; + meta->magic = HPTV2_MAGIC_OK; if (rdp->disks[disk].flags & AR_DF_ASSIGNED) { - config->magic_0 = rdp->magic_0; - strcpy(config->name_1, "FreeBSD"); + meta->magic_0 = rdp->magic_0; + if (strlen(rdp->name)) + strncpy(meta->name_1, rdp->name, sizeof(meta->name_1)); + else + strcpy(meta->name_1, "FreeBSD"); } - config->disk_number = disk; + meta->disk_number = disk; - switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) { - case AR_F_RAID0: - config->type = HPT_T_RAID0; - strcpy(config->name_2, "RAID 0"); + switch (rdp->type) { + case AR_T_RAID0: + meta->type = HPTV2_T_RAID0; + strcpy(meta->name_2, "RAID 0"); if (rdp->disks[disk].flags & AR_DF_ONLINE) - config->order = HPT_O_OK; + meta->order = HPTV2_O_OK; break; - case AR_F_RAID1: - config->type = HPT_T_RAID0; - strcpy(config->name_2, "RAID 1"); - config->disk_number = (disk < rdp->width) ? disk : disk + 5; - config->order = HPT_O_RAID0 | HPT_O_OK; + case AR_T_RAID1: + meta->type = HPTV2_T_RAID0; + strcpy(meta->name_2, "RAID 1"); + meta->disk_number = (disk < rdp->width) ? disk : disk + 5; + meta->order = HPTV2_O_RAID0 | HPTV2_O_OK; break; - case AR_F_RAID0 | AR_F_RAID1: - config->type = HPT_T_RAID01_RAID0; - strcpy(config->name_2, "RAID 0+1"); + case AR_T_RAID01: + meta->type = HPTV2_T_RAID01_RAID0; + strcpy(meta->name_2, "RAID 0+1"); if (rdp->disks[disk].flags & AR_DF_ONLINE) { if (disk < rdp->width) { - config->order = (HPT_O_RAID0 | HPT_O_RAID1); - config->magic_0 = rdp->magic_0 - 1; + meta->order = (HPTV2_O_RAID0 | HPTV2_O_RAID1); + meta->magic_0 = rdp->magic_0 - 1; } else { - config->order = HPT_O_RAID1; - config->disk_number -= rdp->width; + meta->order = HPTV2_O_RAID1; + meta->disk_number -= rdp->width; } } else - config->magic_0 = rdp->magic_0 - 1; - config->magic_1 = rdp->magic_1; + meta->magic_0 = rdp->magic_0 - 1; + meta->magic_1 = rdp->magic_1; break; - case AR_F_SPAN: - config->type = HPT_T_SPAN; - strcpy(config->name_2, "SPAN"); + case AR_T_SPAN: + meta->type = HPTV2_T_SPAN; + strcpy(meta->name_2, "SPAN"); break; } - config->array_width = rdp->width; - config->stripe_shift = (rdp->width > 1) ? (ffs(rdp->interleave)-1) : 0; - config->total_sectors = rdp->total_sectors; - config->rebuild_lba = rdp->lock_start; + meta->array_width = rdp->width; + meta->stripe_shift = (rdp->width > 1) ? (ffs(rdp->interleave)-1) : 0; + meta->total_sectors = rdp->total_sectors; + meta->rebuild_lba = rdp->rebuild_lba; + + if (rdp->disks[disk].dev && + (rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) == + (AR_DF_PRESENT | AR_DF_ONLINE)) { + if (ata_raid_rw(rdp->disks[disk].dev, + HPTV2_LBA(rdp->disks[disk].dev), meta, + sizeof(struct promise_raid_conf), + ATA_R_WRITE | ATA_R_DIRECT)) { + device_printf(rdp->disks[disk].dev, "write metadata failed\n"); + error = EIO; + } + } + } + free(meta, M_AR); + return error; +} + +/* Highpoint V3 RocketRAID Metadata */ +static int +ata_raid_hptv3_read_meta(device_t dev, struct ar_softc **raidp) +{ + struct ata_raid_subdisk *ars = device_get_softc(dev); + device_t parent = device_get_parent(dev); + struct hptv3_raid_conf *meta; + struct ar_softc *raid = NULL; + int array, disk_number, retval = 0; + + if (!(meta = (struct hptv3_raid_conf *) + malloc(sizeof(struct hptv3_raid_conf), M_AR, M_NOWAIT | M_ZERO))) + return ENOMEM; + + if (ata_raid_rw(parent, HPTV3_LBA(parent), + meta, sizeof(struct hptv3_raid_conf), ATA_R_READ)) { + if (testing || bootverbose) + device_printf(parent, "HighPoint (v3) read metadata failed\n"); + goto hptv3_out; + } + + /* check if this is a HighPoint v3 RAID struct */ + if (meta->magic != HPTV3_MAGIC) { + if (testing || bootverbose) + device_printf(parent, "HighPoint (v3) check1 failed\n"); + goto hptv3_out; + } - if (rdp->disks[disk].device && rdp->disks[disk].device->softc && - !(rdp->disks[disk].device->flags & ATA_D_DETACHING)) { - if (ar_rw(AD_SOFTC(rdp->disks[disk]), HPT_LBA, - sizeof(struct highpoint_raid_conf), - (caddr_t)config, AR_WRITE)) { - printf("ar%d: Highpoint write conf failed\n", rdp->lun); - free(config, M_AR); - return -1; + /* check if there are any config_entries */ + if (meta->config_entries < 1) { + if (testing || bootverbose) + device_printf(parent, "HighPoint (v3) check2 failed\n"); + goto hptv3_out; + } + + if (testing || bootverbose) + ata_raid_hptv3_print_meta(meta); + + /* now convert HighPoint (v3) metadata into our generic form */ + for (array = 0; array < MAX_ARRAYS; array++) { + if (!raidp[array]) { + raidp[array] = + (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, + M_NOWAIT | M_ZERO); + if (!raidp[array]) { + device_printf(parent, "failed to allocate metadata storage\n"); + goto hptv3_out; } } - else - free(config, M_AR); + raid = raidp[array]; + if (raid->format && (raid->format != AR_F_HPTV3_RAID)) + continue; + + if ((raid->format & AR_F_HPTV3_RAID) && raid->magic_0 != meta->magic_0) + continue; + + switch (meta->configs[0].type) { + case HPTV3_T_RAID0: + raid->type = AR_T_RAID0; + raid->width = meta->configs[0].total_disks; + disk_number = meta->configs[0].disk_number; + break; + + case HPTV3_T_RAID1: + raid->type = AR_T_RAID1; + raid->width = meta->configs[0].total_disks / 2; + disk_number = meta->configs[0].disk_number; + break; + + case HPTV3_T_RAID5: + raid->type = AR_T_RAID5; + raid->width = meta->configs[0].total_disks; + disk_number = meta->configs[0].disk_number; + break; + + case HPTV3_T_SPAN: + raid->type = AR_T_SPAN; + raid->width = meta->configs[0].total_disks; + disk_number = meta->configs[0].disk_number; + break; + + default: + device_printf(parent, "Highpoint (v3) unknown RAID type 0x%02x\n", + meta->configs[0].type); + free(raidp[array], M_AR); + raidp[array] = NULL; + goto hptv3_out; + } + if (meta->config_entries == 2) { + switch (meta->configs[1].type) { + case HPTV3_T_RAID1: + if (raid->type == AR_T_RAID0) { + raid->type = AR_T_RAID01; + disk_number = meta->configs[1].disk_number + + (meta->configs[0].disk_number << 1); + break; + } + default: + device_printf(parent, "Highpoint (v3) unknown level 2 0x%02x\n", + meta->configs[1].type); + free(raidp[array], M_AR); + raidp[array] = NULL; + goto hptv3_out; + } + } + + raid->magic_0 = meta->magic_0; + raid->format = AR_F_HPTV3_RAID; + raid->generation = meta->timestamp; + raid->interleave = 1 << meta->configs[0].stripe_shift; + raid->total_disks = meta->configs[0].total_disks + + meta->configs[1].total_disks; + raid->total_sectors = meta->configs[0].total_sectors + + ((u_int64_t)meta->configs_high[0].total_sectors << 32); + raid->heads = 255; + raid->sectors = 63; + raid->cylinders = raid->total_sectors / (63 * 255); + raid->offset_sectors = 0; + raid->rebuild_lba = meta->configs[0].rebuild_lba + + ((u_int64_t)meta->configs_high[0].rebuild_lba << 32); + raid->lun = array; + strncpy(raid->name, meta->name, + min(sizeof(raid->name), sizeof(meta->name))); + raid->disks[disk_number].sectors = raid->total_sectors / + (raid->type == AR_T_RAID5 ? raid->width - 1 : raid->width); + raid->disks[disk_number].dev = parent; + raid->disks[disk_number].flags = + (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE); + ars->raid = raid; + ars->disk_number = disk_number; + retval = 1; + break; } - return 0; + +hptv3_out: + free(meta, M_AR); + return retval; } +#if 0 +static int +ata_raid_hptv3_write_meta(struct ar_softc *rdp) +{ + struct hptv3_raid_conf *meta; + int error = 0; + if (!(meta = (struct hptv3_raid_conf *) + malloc(sizeof(struct hptv3_raid_conf), M_AR, M_NOWAIT | M_ZERO))) { + printf("ar%d: failed to allocate metadata storage\n", rdp->lun); + return ENOMEM; + } + return error; +} +#endif + +/* Intel MatrixRAID Metadata */ static int -ar_lsi_read_conf(struct ad_softc *adp, struct ar_softc **raidp) +ata_raid_intel_read_meta(device_t dev, struct ar_softc **raidp) { - struct lsi_raid_conf *info; + struct ata_raid_subdisk *ars = device_get_softc(dev); + device_t parent = device_get_parent(dev); + struct intel_raid_conf *meta; + struct ar_softc *raid = NULL; + u_int32_t checksum, *ptr; + int array, count, disk, retval = 0; + + if (!(meta = (struct intel_raid_conf *) + malloc(1024, M_AR, M_NOWAIT | M_ZERO))) + return ENOMEM; + + if (ata_raid_rw(parent, INTEL_LBA(parent), + meta, 1024, ATA_R_READ)) { + if (testing || bootverbose) + device_printf(parent, "Intel read metadata failed\n"); + goto intel_out; + } + + /* check if this is a Intel RAID struct */ + if (strncmp(meta->intel_id, INTEL_MAGIC, strlen(INTEL_MAGIC))) { + if (testing || bootverbose) + device_printf(parent, "Intel check1 failed\n"); + goto intel_out; + } + for (checksum = 0, ptr = (u_int32_t *)meta, count = 0; + count < (meta->config_size / sizeof(u_int32_t)); count++) { + checksum += *ptr++; + } + +/* XXX SOS needs to be fixed */ +device_printf(parent, "Intel calc=%08x meta=%08x\n", checksum, meta->checksum); + + if (checksum != meta->checksum) { + if (testing || bootverbose) + device_printf(parent, "Intel check2 failed\n"); + //goto intel_out; + } + + if (testing || bootverbose) + ata_raid_intel_print_meta(meta); + + /* now convert Intel metadata into our generic form */ + for (array = 0; array < MAX_ARRAYS; array++) { + if (!raidp[array]) { + raidp[array] = + (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, + M_NOWAIT | M_ZERO); + if (!raidp[array]) { + device_printf(parent, "failed to allocate metadata storage\n"); + goto intel_out; + } + } + raid = raidp[array]; + if (raid->format && (raid->format != AR_F_INTEL_RAID)) + continue; + + if ((raid->format & AR_F_INTEL_RAID) && + (raid->magic_0 != meta->config_id)) + continue; + + /* + * update our knowledge about the array config based on generation + * we only grap the first volume description (yet) since the + * BIOS'n I have access to puts crap into the following XXX SOS + */ + if (!meta->generation || meta->generation > raid->generation) { + struct intel_raid_mapping *map = + (struct intel_raid_mapping *)&meta->disk[meta->total_disks]; + + switch (map->type) { + case INTEL_T_RAID0: + raid->type = AR_T_RAID0; + raid->width = map->total_disks; + break; + + case INTEL_T_RAID1: + raid->type = AR_T_RAID1; + raid->width = map->total_disks / 2; + break; + + default: + device_printf(parent, "Intel unknown RAID type 0x%02x\n", + map->type); + free(raidp[array], M_AR); + raidp[array] = NULL; + goto intel_out; + } + + switch (map->status) { + case INTEL_S_READY: + raid->status = AR_S_READY; + break; + case INTEL_S_DEGRADED: + raid->status |= AR_S_DEGRADED; + break; + case INTEL_S_DISABLED: + case INTEL_S_FAILURE: + raid->status = 0; + } + + raid->magic_0 = meta->config_id; + raid->format = AR_F_INTEL_RAID; + raid->generation = meta->generation; + raid->interleave = map->stripe_sectors; + raid->total_disks = map->total_disks; + raid->total_sectors = map->total_sectors; + raid->heads = 255; + raid->sectors = 63; + raid->cylinders = raid->total_sectors / (63 * 255); + raid->offset_sectors = map->offset; + raid->rebuild_lba = 0; + raid->lun = array; + strncpy(raid->name, map->name, + min(sizeof(raid->name), sizeof(map->name))); + + /* clear out any old info */ + for (disk = 0; disk < raid->total_disks; disk++) { + raid->disks[disk].dev = NULL; + bcopy(meta->disk[map->disk_idx[disk]].serial, + raid->disks[disk].serial, + sizeof(raid->disks[disk].serial)); + raid->disks[disk].sectors = map->disk_sectors; + raid->disks[disk].flags = 0; + if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_ONLINE) + raid->disks[disk].flags |= AR_DF_ONLINE; + if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_ASSIGNED) + raid->disks[disk].flags |= AR_DF_ASSIGNED; + if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_SPARE) { + raid->disks[disk].flags &= ~(AR_DF_ONLINE | AR_DF_ASSIGNED); + raid->disks[disk].flags |= AR_DF_SPARE; + } + if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_DOWN) + raid->disks[disk].flags &= ~AR_DF_ONLINE; + } + } + if (meta->generation >= raid->generation) { + for (disk = 0; disk < raid->total_disks; disk++) { + struct ata_device *atadev = device_get_softc(parent); + + if (!strncmp(raid->disks[disk].serial, atadev->param.serial, + sizeof(raid->disks[disk].serial))) { + raid->disks[disk].dev = parent; + raid->disks[disk].flags |= (AR_DF_PRESENT | AR_DF_ONLINE); + ars->raid = raid; + ars->disk_number = disk; + retval = 1; + } + } + } + if (retval) + break; + } + +intel_out: + free(meta, M_AR); + return retval; +} + +/* Integrated Technology Express Metadata */ +static int +ata_raid_ite_read_meta(device_t dev, struct ar_softc **raidp) +{ + struct ata_raid_subdisk *ars = device_get_softc(dev); + device_t parent = device_get_parent(dev); + struct ite_raid_conf *meta; + struct ar_softc *raid = NULL; + int array, disk_number, count, retval = 0; + u_int16_t *ptr; + + if (!(meta = (struct ite_raid_conf *) + malloc(sizeof(struct ite_raid_conf), M_AR, M_NOWAIT | M_ZERO))) + return ENOMEM; + + if (ata_raid_rw(parent, ITE_LBA(parent), + meta, sizeof(struct ite_raid_conf), ATA_R_READ)) { + if (testing || bootverbose) + device_printf(parent, "ITE read metadata failed\n"); + goto ite_out; + } + + /* check if this is a ITE RAID struct */ + for (ptr = (u_int16_t *)meta->ite_id, count = 0; + count < sizeof(meta->ite_id)/sizeof(uint16_t); count++) + ptr[count] = be16toh(ptr[count]); + + if (strncmp(meta->ite_id, ITE_MAGIC, strlen(ITE_MAGIC))) { + if (testing || bootverbose) + device_printf(parent, "ITE check1 failed\n"); + goto ite_out; + } + + if (testing || bootverbose) + ata_raid_ite_print_meta(meta); + + /* now convert ITE metadata into our generic form */ + for (array = 0; array < MAX_ARRAYS; array++) { + if ((raid = raidp[array])) { + if (raid->format != AR_F_ITE_RAID) + continue; + if (raid->magic_0 != *((u_int64_t *)meta->timestamp_0)) + continue; + } + + /* if we dont have a disks timestamp the RAID is invalidated */ + if (*((u_int64_t *)meta->timestamp_1) == 0) + goto ite_out; + + if (!raid) { + raidp[array] = (struct ar_softc *)malloc(sizeof(struct ar_softc), + M_AR, M_NOWAIT | M_ZERO); + if (!(raid = raidp[array])) { + device_printf(parent, "failed to allocate metadata storage\n"); + goto ite_out; + } + } + + switch (meta->type) { + case ITE_T_RAID0: + raid->type = AR_T_RAID0; + raid->width = meta->array_width; + raid->total_disks = meta->array_width; + disk_number = meta->disk_number; + break; + + case ITE_T_RAID1: + raid->type = AR_T_RAID1; + raid->width = 1; + raid->total_disks = 2; + disk_number = meta->disk_number; + break; + + case ITE_T_RAID01: + raid->type = AR_T_RAID01; + raid->width = meta->array_width; + raid->total_disks = 4; + disk_number = ((meta->disk_number & 0x02) >> 1) | + ((meta->disk_number & 0x01) << 1); + break; + + case ITE_T_SPAN: + raid->type = AR_T_SPAN; + raid->width = 1; + raid->total_disks = meta->array_width; + disk_number = meta->disk_number; + break; + + default: + device_printf(parent, "ITE unknown RAID type 0x%02x\n", meta->type); + free(raidp[array], M_AR); + raidp[array] = NULL; + goto ite_out; + } + + raid->magic_0 = *((u_int64_t *)meta->timestamp_0); + raid->format = AR_F_ITE_RAID; + raid->generation = 0; + raid->interleave = meta->stripe_sectors; + raid->total_sectors = meta->total_sectors; + raid->heads = 255; + raid->sectors = 63; + raid->cylinders = raid->total_sectors / (63 * 255); + raid->offset_sectors = 0; + raid->rebuild_lba = 0; + raid->lun = array; + + raid->disks[disk_number].dev = parent; + raid->disks[disk_number].sectors = raid->total_sectors / raid->width; + raid->disks[disk_number].flags = + (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE); + ars->raid = raid; + ars->disk_number = disk_number; + retval = 1; + break; + } +ite_out: + free(meta, M_AR); + return retval; +} + +/* LSILogic V2 MegaRAID Metadata */ +static int +ata_raid_lsiv2_read_meta(device_t dev, struct ar_softc **raidp) +{ + struct ata_raid_subdisk *ars = device_get_softc(dev); + device_t parent = device_get_parent(dev); + struct lsiv2_raid_conf *meta; struct ar_softc *raid = NULL; int array, retval = 0; - if (!(info = (struct lsi_raid_conf *) - malloc(sizeof(struct lsi_raid_conf), M_AR, M_NOWAIT | M_ZERO))) - return retval; + if (!(meta = (struct lsiv2_raid_conf *) + malloc(sizeof(struct lsiv2_raid_conf), M_AR, M_NOWAIT | M_ZERO))) + return ENOMEM; - if (ar_rw(adp, LSI_LBA(adp), sizeof(struct lsi_raid_conf), - (caddr_t)info, AR_READ | AR_WAIT)) { - if (bootverbose) - printf("ar: LSI read conf failed\n"); - goto lsi_out; + if (ata_raid_rw(parent, LSIV2_LBA(parent), + meta, sizeof(struct lsiv2_raid_conf), ATA_R_READ)) { + if (testing || bootverbose) + device_printf(parent, "LSI (v2) read metadata failed\n"); + goto lsiv2_out; } /* check if this is a LSI RAID struct */ - if (strncmp(info->lsi_id, LSI_MAGIC, strlen(LSI_MAGIC))) { - if (bootverbose) - printf("ar: LSI check1 failed\n"); - goto lsi_out; + if (strncmp(meta->lsi_id, LSIV2_MAGIC, strlen(LSIV2_MAGIC))) { + if (testing || bootverbose) + device_printf(parent, "LSI (v2) check1 failed\n"); + goto lsiv2_out; } - /* now convert LSI config info into our generic form */ + if (testing || bootverbose) + ata_raid_lsiv2_print_meta(meta); + + /* now convert LSI (v2) config meta into our generic form */ for (array = 0; array < MAX_ARRAYS; array++) { int raid_entry, conf_entry; - if (!raidp[array + info->raid_number]) { - raidp[array + info->raid_number] = - (struct ar_softc*)malloc(sizeof(struct ar_softc), M_AR, - M_NOWAIT | M_ZERO); - if (!raidp[array + info->raid_number]) { - printf("ar%d: failed to allocate raid config storage\n", array); - goto lsi_out; + if (!raidp[array + meta->raid_number]) { + raidp[array + meta->raid_number] = + (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, + M_NOWAIT | M_ZERO); + if (!raidp[array + meta->raid_number]) { + device_printf(parent, "failed to allocate metadata storage\n"); + goto lsiv2_out; } } - raid = raidp[array + info->raid_number]; - - if (raid->flags & (AR_F_PROMISE_RAID | AR_F_HIGHPOINT_RAID)) + raid = raidp[array + meta->raid_number]; + if (raid->format && (raid->format != AR_F_LSIV2_RAID)) continue; if (raid->magic_0 && - ((raid->magic_0 != info->timestamp) || - (raid->magic_1 != info->raid_number))) + ((raid->magic_0 != meta->timestamp) || + (raid->magic_1 != meta->raid_number))) continue; - array += info->raid_number; + array += meta->raid_number; - raid_entry = info->raid_number; - conf_entry = (info->configs[raid_entry].raid.config_offset >> 4) + - info->disk_number - 1; + raid_entry = meta->raid_number; + conf_entry = (meta->configs[raid_entry].raid.config_offset >> 4) + + meta->disk_number - 1; - switch (info->configs[raid_entry].raid.type) { - case LSI_R_RAID0: - raid->magic_0 = info->timestamp; - raid->magic_1 = info->raid_number; - raid->flags |= AR_F_RAID0; - raid->interleave = info->configs[raid_entry].raid.stripe_size; - raid->width = info->configs[raid_entry].raid.raid_width; + switch (meta->configs[raid_entry].raid.type) { + case LSIV2_T_RAID0: + raid->magic_0 = meta->timestamp; + raid->magic_1 = meta->raid_number; + raid->type = AR_T_RAID0; + raid->interleave = meta->configs[raid_entry].raid.stripe_sectors; + raid->width = meta->configs[raid_entry].raid.array_width; break; - case LSI_R_RAID1: - raid->magic_0 = info->timestamp; - raid->magic_1 = info->raid_number; - raid->flags |= AR_F_RAID1; - raid->width = info->configs[raid_entry].raid.raid_width; + case LSIV2_T_RAID1: + raid->magic_0 = meta->timestamp; + raid->magic_1 = meta->raid_number; + raid->type = AR_T_RAID1; + raid->width = meta->configs[raid_entry].raid.array_width; break; - case LSI_R_RAID0 | LSI_R_RAID1: - raid->magic_0 = info->timestamp; - raid->magic_1 = info->raid_number; - raid->flags |= (AR_F_RAID0 | AR_F_RAID1); - raid->interleave = info->configs[raid_entry].raid.stripe_size; - raid->width = info->configs[raid_entry].raid.raid_width; + case LSIV2_T_RAID0 | LSIV2_T_RAID1: + raid->magic_0 = meta->timestamp; + raid->magic_1 = meta->raid_number; + raid->type = AR_T_RAID01; + raid->interleave = meta->configs[raid_entry].raid.stripe_sectors; + raid->width = meta->configs[raid_entry].raid.array_width; break; default: - printf("ar%d: LSI unknown RAID type 0x%02x\n", - array, info->configs[raid_entry].raid.type); + device_printf(parent, "LSI v2 unknown RAID type 0x%02x\n", + meta->configs[raid_entry].raid.type); free(raidp[array], M_AR); raidp[array] = NULL; - goto lsi_out; + goto lsiv2_out; } - /* setup RAID specifics */ - raid->flags |= AR_F_LSI_RAID; + raid->format = AR_F_LSIV2_RAID; raid->generation = 0; - raid->total_disks = info->configs[raid_entry].raid.disk_count; + raid->total_disks = meta->configs[raid_entry].raid.disk_count; + raid->total_sectors = meta->configs[raid_entry].raid.total_sectors; raid->heads = 255; raid->sectors = 63; - raid->cylinders = info->configs[raid_entry].raid.total_sectors/(63*255); - raid->total_sectors = info->configs[raid_entry].raid.total_sectors; - raid->offset = 0; - raid->reserved = 1; - raid->lock_start = raid->lock_end = 0; + raid->cylinders = raid->total_sectors / (63 * 255); + raid->offset_sectors = 0; + raid->rebuild_lba = 0; raid->lun = array; - /* setup RAID specifics of this disk */ - if (info->configs[conf_entry].disk.device != LSI_D_NONE) { - raid->disks[info->disk_number].device = adp->device; - raid->disks[info->disk_number].disk_sectors = - info->configs[conf_entry].disk.disk_sectors; - raid->disks[info->disk_number].flags = + if (meta->configs[conf_entry].disk.device != LSIV2_D_NONE) { + raid->disks[meta->disk_number].dev = parent; + raid->disks[meta->disk_number].sectors = + meta->configs[conf_entry].disk.disk_sectors; + raid->disks[meta->disk_number].flags = (AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED); - AD_SOFTC(raid->disks[info->disk_number])->flags |= - AD_F_RAID_SUBDISK; + ars->raid = raid; + ars->disk_number = meta->disk_number; retval = 1; } else - raid->disks[info->disk_number].flags &= ~AR_DF_ONLINE; + raid->disks[meta->disk_number].flags &= ~AR_DF_ONLINE; - return retval; + break; } -lsi_out: - free(info, M_AR); +lsiv2_out: + free(meta, M_AR); return retval; } +/* LSILogic V3 MegaRAID Metadata */ static int -ar_lsi_write_conf(struct ar_softc *rdp) +ata_raid_lsiv3_read_meta(device_t dev, struct ar_softc **raidp) { - struct lsi_raid_conf *config; - struct timeval timestamp; - int disk, disk_entry; + struct ata_raid_subdisk *ars = device_get_softc(dev); + device_t parent = device_get_parent(dev); + struct lsiv3_raid_conf *meta; + struct ar_softc *raid = NULL; + u_int8_t checksum, *ptr; + int array, entry, count, disk_number, retval = 0; - microtime(×tamp); - rdp->magic_0 = timestamp.tv_sec & 0xffffffc0; - rdp->magic_1 = 0; - - for (disk = 0; disk < rdp->total_disks; disk++) { - if (!(config = (struct lsi_raid_conf *) - malloc(sizeof(struct lsi_raid_conf), M_AR, M_NOWAIT | M_ZERO))) { - printf("ar%d: LSI write conf failed\n", rdp->lun); - return -1; - } - - bcopy(LSI_MAGIC, config->lsi_id, strlen(LSI_MAGIC)); - config->dummy_1 = 0x10; - config->flags = 0x19; /* SOS X */ - config->version[0] = '2'; - config->version[1] = '0'; - config->config_entries = 2 + rdp->total_disks; - config->raid_count = 1; - config->total_disks = rdp->total_disks; - config->dummy_e = 0xfc; - config->disk_number = disk; - config->raid_number = 0; - config->timestamp = rdp->magic_0; - - switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) { - case AR_F_RAID0: - config->configs[0].raid.type = LSI_R_RAID0; + if (!(meta = (struct lsiv3_raid_conf *) + malloc(sizeof(struct lsiv3_raid_conf), M_AR, M_NOWAIT | M_ZERO))) + return ENOMEM; + + if (ata_raid_rw(parent, LSIV3_LBA(parent), + meta, sizeof(struct lsiv3_raid_conf), ATA_R_READ)) { + if (testing || bootverbose) + device_printf(parent, "LSI (v3) read metadata failed\n"); + goto lsiv3_out; + } + + /* check if this is a LSI RAID struct */ + if (strncmp(meta->lsi_id, LSIV3_MAGIC, strlen(LSIV3_MAGIC))) { + if (testing || bootverbose) + device_printf(parent, "LSI (v3) check1 failed\n"); + goto lsiv3_out; + } + + /* check if the checksum is OK */ + for (checksum = 0, ptr = meta->lsi_id, count = 0; count < 512; count++) + checksum += *ptr++; + if (checksum) { + if (testing || bootverbose) + device_printf(parent, "LSI (v3) check2 failed\n"); + goto lsiv3_out; + } + + if (testing || bootverbose) + ata_raid_lsiv3_print_meta(meta); + + /* now convert LSI (v3) config meta into our generic form */ + for (array = 0, entry = 0; array < MAX_ARRAYS && entry < 8;) { + if (!raidp[array]) { + raidp[array] = + (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, + M_NOWAIT | M_ZERO); + if (!raidp[array]) { + device_printf(parent, "failed to allocate metadata storage\n"); + goto lsiv3_out; + } + } + raid = raidp[array]; + if (raid->format && (raid->format != AR_F_LSIV3_RAID)) { + array++; + continue; + } + + if ((raid->format == AR_F_LSIV3_RAID) && + (raid->magic_0 != meta->timestamp)) { + array++; + continue; + } + + switch (meta->raid[entry].total_disks) { + case 0: + entry++; + continue; + case 1: + if (meta->raid[entry].device == meta->device) { + disk_number = 0; + break; + } + if (raid->format) + array++; + entry++; + continue; + case 2: + disk_number = (meta->device & (LSIV3_D_DEVICE|LSIV3_D_CHANNEL))?1:0; + break; + default: + device_printf(parent, "lsiv3 > 2 disk support untested!!\n"); + disk_number = (meta->device & LSIV3_D_DEVICE ? 1 : 0) + + (meta->device & LSIV3_D_CHANNEL ? 2 : 0); break; + } - case AR_F_RAID1: - config->configs[0].raid.type = LSI_R_RAID1; + switch (meta->raid[entry].type) { + case LSIV3_T_RAID0: + raid->type = AR_T_RAID0; + raid->width = meta->raid[entry].total_disks; break; - case AR_F_RAID0 | AR_F_RAID1: - config->flags = 0x15; /* SOS X */ - config->configs[0].raid.type = (LSI_R_RAID0 | LSI_R_RAID1); + case LSIV3_T_RAID1: + raid->type = AR_T_RAID1; + raid->width = meta->raid[entry].array_width; break; default: - free(config, M_AR); - return -1; - } - - config->configs[0].raid.dummy_1 = 0x10; - config->configs[0].raid.stripe_size = rdp->interleave; - config->configs[0].raid.raid_width = rdp->width; - config->configs[0].raid.disk_count = rdp->total_disks; - config->configs[0].raid.config_offset = 2 * 0x10; - config->configs[0].raid.total_sectors = rdp->total_sectors; - - for (disk_entry = 0; disk_entry < rdp->total_disks; disk_entry++) { - if (rdp->disks[disk_entry].flags & AR_DF_ONLINE) - config->configs[1 + disk_entry].disk.device = - (rdp->disks[disk_entry].device->channel->unit ? - LSI_D_CHANNEL1 : LSI_D_CHANNEL0) | - (rdp->disks[disk_entry].device->unit ? - LSI_D_SLAVE : LSI_D_MASTER); - else { - config->configs[1 + disk_entry].disk.device = LSI_D_NONE; - config->configs[1 + disk_entry].disk.flags = LSI_D_GONE; - } - config->configs[1 + disk_entry].disk.dummy_1 = 0x10; - config->configs[1 + disk_entry].disk.disk_sectors = - rdp->disks[disk_entry].disk_sectors; - config->configs[1 + disk_entry].disk.disk_number = disk_entry; - config->configs[1 + disk_entry].disk.raid_number = 0; - } - - if ((rdp->disks[disk].device && rdp->disks[disk].device->softc) && - !(rdp->disks[disk].device->flags & ATA_D_DETACHING)) { - - if (ar_rw(AD_SOFTC(rdp->disks[disk]), - LSI_LBA(AD_SOFTC(rdp->disks[disk])), - sizeof(struct lsi_raid_conf), - (caddr_t)config, AR_WRITE)) { - printf("ar%d: LSI write conf failed\n", rdp->lun); - free(config, M_AR); - return -1; - } + device_printf(parent, "LSI v3 unknown RAID type 0x%02x\n", + meta->raid[entry].type); + free(raidp[array], M_AR); + raidp[array] = NULL; + entry++; + continue; } - else - free(config, M_AR); + + raid->magic_0 = meta->timestamp; + raid->format = AR_F_LSIV3_RAID; + raid->generation = 0; + raid->interleave = meta->raid[entry].stripe_pages * 8; + raid->total_disks = meta->raid[entry].total_disks; + raid->total_sectors = raid->width * meta->raid[entry].sectors; + raid->heads = 255; + raid->sectors = 63; + raid->cylinders = raid->total_sectors / (63 * 255); + raid->offset_sectors = meta->raid[entry].offset; + raid->rebuild_lba = 0; + raid->lun = array; + + raid->disks[disk_number].dev = parent; + raid->disks[disk_number].sectors = raid->total_sectors / raid->width; + raid->disks[disk_number].flags = + (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE); + ars->raid = raid; + ars->disk_number = disk_number; + retval = 1; + entry++; + array++; } - return 0; + +lsiv3_out: + free(meta, M_AR); + return retval; } +/* Promise FastTrak Metadata */ static int -ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp, int local) +ata_raid_promise_read_meta(device_t dev, struct ar_softc **raidp, int native) { - struct promise_raid_conf *info; + struct ata_raid_subdisk *ars = device_get_softc(dev); + device_t parent = device_get_parent(dev); + struct promise_raid_conf *meta; struct ar_softc *raid; - u_int32_t magic, cksum, *ckptr; + u_int32_t checksum, *ptr; int array, count, disk, disksum = 0, retval = 0; - if (!(info = (struct promise_raid_conf *) + if (!(meta = (struct promise_raid_conf *) malloc(sizeof(struct promise_raid_conf), M_AR, M_NOWAIT | M_ZERO))) - return retval; + return ENOMEM; - if (ar_rw(adp, PR_LBA(adp), sizeof(struct promise_raid_conf), - (caddr_t)info, AR_READ | AR_WAIT)) { - if (bootverbose) - printf("ar: %s read conf failed\n", local ? "FreeBSD" : "Promise"); + if (ata_raid_rw(parent, PR_LBA(parent), + meta, sizeof(struct promise_raid_conf), ATA_R_READ)) { + if (testing || bootverbose) + device_printf(parent, "%s read metadata failed\n", + native ? "FreeBSD" : "Promise"); goto promise_out; } - /* check if this is a Promise RAID struct (or our local one) */ - if (local) { - if (strncmp(info->promise_id, ATA_MAGIC, strlen(ATA_MAGIC))) { - if (bootverbose) - printf("ar: FreeBSD check1 failed\n"); + /* check the signature */ + if (native) { + if (strncmp(meta->promise_id, ATA_MAGIC, strlen(ATA_MAGIC))) { + if (testing || bootverbose) + device_printf(parent, "FreeBSD check1 failed\n"); goto promise_out; } } else { - if (strncmp(info->promise_id, PR_MAGIC, strlen(PR_MAGIC))) { - if (bootverbose) - printf("ar: Promise check1 failed\n"); + if (strncmp(meta->promise_id, PR_MAGIC, strlen(PR_MAGIC))) { + if (testing || bootverbose) + device_printf(parent, "Promise check1 failed\n"); goto promise_out; } } /* check if the checksum is OK */ - for (cksum = 0, ckptr = (int32_t *)info, count = 0; count < 511; count++) - cksum += *ckptr++; - if (cksum != *ckptr) { - if (bootverbose) - printf("ar: %s check2 failed\n", local ? "FreeBSD" : "Promise"); + for (checksum = 0, ptr = (u_int32_t *)meta, count = 0; count < 511; count++) + checksum += *ptr++; + if (checksum != *ptr) { + if (testing || bootverbose) + device_printf(parent, "%s check2 failed\n", + native ? "FreeBSD" : "Promise"); goto promise_out; } - /* now convert Promise config info into our generic form */ - if (info->raid.integrity != PR_I_VALID) { - if (bootverbose) - printf("ar: %s check3 failed\n", local ? "FreeBSD" : "Promise"); + /* check on disk integrity status */ + if (meta->raid.integrity != PR_I_VALID) { + if (testing || bootverbose) + device_printf(parent, "%s check3 failed\n", + native ? "FreeBSD" : "Promise"); goto promise_out; } + if (testing || bootverbose) + ata_raid_promise_print_meta(meta); + + /* now convert Promise metadata into our generic form */ for (array = 0; array < MAX_ARRAYS; array++) { if (!raidp[array]) { raidp[array] = - (struct ar_softc*)malloc(sizeof(struct ar_softc), M_AR, - M_NOWAIT | M_ZERO); + (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, + M_NOWAIT | M_ZERO); if (!raidp[array]) { - printf("ar%d: failed to allocate raid config storage\n", array); + device_printf(parent, "failed to allocate metadata storage\n"); goto promise_out; } } raid = raidp[array]; - if (raid->flags & (AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID)) + if (raid->format && (raid->format != AR_F_PROMISE_RAID)) continue; - magic = (pci_get_device(device_get_parent( - adp->device->channel->dev)) >> 16) | - (info->raid.array_number << 16); - - if (raid->flags & AR_F_PROMISE_RAID && magic != raid->magic_0) + if ((raid->format == AR_F_PROMISE_RAID) && + !(meta->raid.magic_1 == (raid->magic_1))) continue; /* update our knowledge about the array config based on generation */ - if (!info->raid.generation || info->raid.generation > raid->generation){ - raid->generation = info->raid.generation; - raid->flags = AR_F_PROMISE_RAID; - if (local) - raid->flags |= AR_F_FREEBSD_RAID; - raid->magic_0 = magic; - raid->lun = array; - if ((info->raid.status & - (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY)) == - (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY)) { - raid->flags |= AR_F_READY; - if (info->raid.status & PR_S_DEGRADED) - raid->flags |= AR_F_DEGRADED; - } - else - raid->flags &= ~AR_F_READY; + if (!meta->raid.generation || meta->raid.generation > raid->generation){ + switch (meta->raid.type) { + case PR_T_SPAN: + raid->type = AR_T_SPAN; + break; + + case PR_T_JBOD: + raid->type = AR_T_JBOD; + break; - switch (info->raid.type) { case PR_T_RAID0: - raid->flags |= AR_F_RAID0; + raid->type = AR_T_RAID0; break; case PR_T_RAID1: - raid->flags |= AR_F_RAID1; - if (info->raid.array_width > 1) - raid->flags |= AR_F_RAID0; + raid->type = AR_T_RAID1; + if (meta->raid.array_width > 1) + raid->type = AR_T_RAID01; break; - case PR_T_SPAN: - raid->flags |= AR_F_SPAN; + case PR_T_RAID5: + raid->type = AR_T_RAID5; break; default: - printf("ar%d: %s unknown RAID type 0x%02x\n", - array, local ? "FreeBSD" : "Promise", info->raid.type); + device_printf(parent, "%s unknown RAID type 0x%02x\n", + native ? "FreeBSD" : "Promise", meta->raid.type); free(raidp[array], M_AR); raidp[array] = NULL; goto promise_out; } - raid->interleave = 1 << info->raid.stripe_shift; - raid->width = info->raid.array_width; - raid->total_disks = info->raid.total_disks; - raid->heads = info->raid.heads + 1; - raid->sectors = info->raid.sectors; - raid->cylinders = info->raid.cylinders + 1; - raid->total_sectors = info->raid.total_sectors; - raid->offset = 0; - raid->reserved = 63; - raid->lock_start = raid->lock_end = info->raid.rebuild_lba; + raid->magic_1 = meta->raid.magic_1; + if (native) + raid->format = AR_F_FREEBSD_RAID; + else + raid->format = AR_F_PROMISE_RAID; + raid->generation = meta->raid.generation; + raid->interleave = 1 << meta->raid.stripe_shift; + raid->width = meta->raid.array_width; + raid->total_disks = meta->raid.total_disks; + raid->heads = meta->raid.heads + 1; + raid->sectors = meta->raid.sectors; + raid->cylinders = meta->raid.cylinders + 1; + raid->total_sectors = meta->raid.total_sectors; + raid->offset_sectors = 0; + raid->rebuild_lba = meta->raid.rebuild_lba; + raid->lun = array; + if ((meta->raid.status & + (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY)) == + (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY)) { + raid->status |= AR_S_READY; + if (meta->raid.status & PR_S_DEGRADED) + raid->status |= AR_S_DEGRADED; + } + else + raid->status &= ~AR_S_READY; /* convert disk flags to our internal types */ - for (disk = 0; disk < info->raid.total_disks; disk++) { + for (disk = 0; disk < meta->raid.total_disks; disk++) { + raid->disks[disk].dev = NULL; raid->disks[disk].flags = 0; - disksum += info->raid.disk[disk].flags; - if (info->raid.disk[disk].flags & PR_F_ONLINE) + *((u_int64_t *)(raid->disks[disk].serial)) = + meta->raid.disk[disk].magic_0; + disksum += meta->raid.disk[disk].flags; + if (meta->raid.disk[disk].flags & PR_F_ONLINE) raid->disks[disk].flags |= AR_DF_ONLINE; - if (info->raid.disk[disk].flags & PR_F_ASSIGNED) + if (meta->raid.disk[disk].flags & PR_F_ASSIGNED) raid->disks[disk].flags |= AR_DF_ASSIGNED; - if (info->raid.disk[disk].flags & PR_F_SPARE) { - raid->disks[disk].flags &= ~AR_DF_ONLINE; + if (meta->raid.disk[disk].flags & PR_F_SPARE) { + raid->disks[disk].flags &= ~(AR_DF_ONLINE | AR_DF_ASSIGNED); raid->disks[disk].flags |= AR_DF_SPARE; } - if (info->raid.disk[disk].flags & (PR_F_REDIR | PR_F_DOWN)) + if (meta->raid.disk[disk].flags & (PR_F_REDIR | PR_F_DOWN)) raid->disks[disk].flags &= ~AR_DF_ONLINE; } if (!disksum) { + device_printf(parent, "%s subdisks has no flags\n", + native ? "FreeBSD" : "Promise"); free(raidp[array], M_AR); raidp[array] = NULL; goto promise_out; } } - if (info->raid.generation >= raid->generation) { - if (raid->disks[info->raid.disk_number].flags && adp->device) { - raid->disks[info->raid.disk_number].device = adp->device; - raid->disks[info->raid.disk_number].flags |= AR_DF_PRESENT; - raid->disks[info->raid.disk_number].disk_sectors = - info->raid.disk_sectors; - if ((raid->disks[info->raid.disk_number].flags & + if (meta->raid.generation >= raid->generation) { + int disk_number = meta->raid.disk_number; + + if (raid->disks[disk_number].flags && (meta->magic_0 == + *((u_int64_t *)(raid->disks[disk_number].serial)))) { + raid->disks[disk_number].dev = parent; + raid->disks[disk_number].flags |= AR_DF_PRESENT; + raid->disks[disk_number].sectors = meta->raid.disk_sectors; + if ((raid->disks[disk_number].flags & (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE)) == (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE)) { - AD_SOFTC(raid->disks[info->raid.disk_number])->flags |= - AD_F_RAID_SUBDISK; + ars->raid = raid; + ars->disk_number = disk_number; retval = 1; } } } break; } + promise_out: - free(info, M_AR); + free(meta, M_AR); return retval; } static int -ar_promise_write_conf(struct ar_softc *rdp) +ata_raid_promise_write_meta(struct ar_softc *rdp) { - struct promise_raid_conf *config; + struct promise_raid_conf *meta; struct timeval timestamp; u_int32_t *ckptr; - int count, disk, drive; - int local = rdp->flags & AR_F_FREEBSD_RAID; + int count, disk, drive, error = 0; + + if (!(meta = (struct promise_raid_conf *) + malloc(sizeof(struct promise_raid_conf), M_AR, M_NOWAIT))) { + printf("ar%d: failed to allocate metadata storage\n", rdp->lun); + return ENOMEM; + } rdp->generation++; microtime(×tamp); for (disk = 0; disk < rdp->total_disks; disk++) { - if (!(config = (struct promise_raid_conf *) - malloc(sizeof(struct promise_raid_conf), M_AR, M_NOWAIT))) { - printf("ar%d: %s write conf failed\n", - rdp->lun, local ? "FreeBSD" : "Promise"); - return -1; - } for (count = 0; count < sizeof(struct promise_raid_conf); count++) - *(((u_int8_t *)config) + count) = 255 - (count % 256); - - config->dummy_0 = 0x00020000; - config->magic_0 = PR_MAGIC0(rdp->disks[disk]) | timestamp.tv_sec; - config->magic_1 = timestamp.tv_sec >> 16; - config->magic_2 = timestamp.tv_sec; - config->raid.integrity = PR_I_VALID; - - config->raid.disk_number = disk; - if (rdp->disks[disk].flags & AR_DF_PRESENT && rdp->disks[disk].device) { - config->raid.channel = rdp->disks[disk].device->channel->unit; - config->raid.device = (rdp->disks[disk].device->unit != 0); - if (rdp->disks[disk].device->softc) - config->raid.disk_sectors = PR_LBA(AD_SOFTC(rdp->disks[disk])); - /*config->raid.disk_offset*/ - } - config->raid.magic_0 = config->magic_0; - config->raid.rebuild_lba = rdp->lock_start; - config->raid.generation = rdp->generation; - - if (rdp->flags & AR_F_READY) { - config->raid.flags = (PR_F_VALID | PR_F_ASSIGNED | PR_F_ONLINE); - config->raid.status = + *(((u_int8_t *)meta) + count) = 255 - (count % 256); + meta->dummy_0 = 0x00020000; + meta->raid.disk_number = disk; + + if ((rdp->disks[disk].flags & AR_DF_PRESENT) && rdp->disks[disk].dev) { + struct ata_device *atadev = device_get_softc(rdp->disks[disk].dev); + struct ata_channel *ch = + device_get_softc(device_get_parent(rdp->disks[disk].dev)); + + meta->raid.channel = ch->unit; + meta->raid.device = (atadev->unit != 0); + meta->raid.disk_sectors = rdp->disks[disk].sectors; + meta->raid.disk_offset = rdp->offset_sectors; + } + else { + meta->raid.channel = 0; + meta->raid.device = 0; + meta->raid.disk_sectors = 0; + meta->raid.disk_offset = 0; + } + meta->magic_0 = PR_MAGIC0(meta->raid) | timestamp.tv_sec; + meta->magic_1 = timestamp.tv_sec >> 16; + meta->magic_2 = timestamp.tv_sec; + meta->raid.integrity = PR_I_VALID; + meta->raid.magic_0 = meta->magic_0; + meta->raid.rebuild_lba = rdp->rebuild_lba; + meta->raid.generation = rdp->generation; + + if (rdp->status & AR_S_READY) { + meta->raid.flags = (PR_F_VALID | PR_F_ASSIGNED | PR_F_ONLINE); + meta->raid.status = (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY); - if (rdp->flags & AR_F_DEGRADED) - config->raid.status |= PR_S_DEGRADED; + if (rdp->status & AR_S_DEGRADED) + meta->raid.status |= PR_S_DEGRADED; else - config->raid.status |= PR_S_FUNCTIONAL; + meta->raid.status |= PR_S_FUNCTIONAL; } else { - config->raid.flags = PR_F_DOWN; - config->raid.status = 0; + meta->raid.flags = PR_F_DOWN; + meta->raid.status = 0; } - switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) { - case AR_F_RAID0: - config->raid.type = PR_T_RAID0; + switch (rdp->type) { + case AR_T_RAID0: + meta->raid.type = PR_T_RAID0; break; - case AR_F_RAID1: - config->raid.type = PR_T_RAID1; + case AR_T_RAID1: + meta->raid.type = PR_T_RAID1; break; - case AR_F_RAID0 | AR_F_RAID1: - config->raid.type = PR_T_RAID1; + case AR_T_RAID01: + meta->raid.type = PR_T_RAID1; break; - case AR_F_SPAN: - config->raid.type = PR_T_SPAN; + case AR_T_RAID5: + meta->raid.type = PR_T_RAID5; + break; + case AR_T_SPAN: + meta->raid.type = PR_T_SPAN; + break; + case AR_T_JBOD: + meta->raid.type = PR_T_JBOD; break; } - config->raid.total_disks = rdp->total_disks; - config->raid.stripe_shift = ffs(rdp->interleave) - 1; - config->raid.array_width = rdp->width; - config->raid.array_number = rdp->lun; - config->raid.total_sectors = rdp->total_sectors; - config->raid.cylinders = rdp->cylinders - 1; - config->raid.heads = rdp->heads - 1; - config->raid.sectors = rdp->sectors; - config->raid.magic_1 = (u_int64_t)config->magic_2<<16 | config->magic_1; - - bzero(&config->raid.disk, 8 * 12); + meta->raid.total_disks = rdp->total_disks; + meta->raid.stripe_shift = ffs(rdp->interleave) - 1; + meta->raid.array_width = rdp->width; + meta->raid.array_number = rdp->lun; + meta->raid.total_sectors = rdp->total_sectors; + meta->raid.cylinders = rdp->cylinders - 1; + meta->raid.heads = rdp->heads - 1; + meta->raid.sectors = rdp->sectors; + meta->raid.magic_1 = (u_int64_t)meta->magic_2<<16 | meta->magic_1; + + bzero(&meta->raid.disk, 8 * 12); for (drive = 0; drive < rdp->total_disks; drive++) { - config->raid.disk[drive].flags = 0; + meta->raid.disk[drive].flags = 0; if (rdp->disks[drive].flags & AR_DF_PRESENT) - config->raid.disk[drive].flags |= PR_F_VALID; + meta->raid.disk[drive].flags |= PR_F_VALID; if (rdp->disks[drive].flags & AR_DF_ASSIGNED) - config->raid.disk[drive].flags |= PR_F_ASSIGNED; + meta->raid.disk[drive].flags |= PR_F_ASSIGNED; if (rdp->disks[drive].flags & AR_DF_ONLINE) - config->raid.disk[drive].flags |= PR_F_ONLINE; + meta->raid.disk[drive].flags |= PR_F_ONLINE; else if (rdp->disks[drive].flags & AR_DF_PRESENT) - config->raid.disk[drive].flags = (PR_F_REDIR | PR_F_DOWN); + meta->raid.disk[drive].flags = (PR_F_REDIR | PR_F_DOWN); if (rdp->disks[drive].flags & AR_DF_SPARE) - config->raid.disk[drive].flags |= PR_F_SPARE; - config->raid.disk[drive].dummy_0 = 0x0; - if (rdp->disks[drive].device) { - config->raid.disk[drive].channel = - rdp->disks[drive].device->channel->unit; - config->raid.disk[drive].device = - (rdp->disks[drive].device->unit != 0); + meta->raid.disk[drive].flags |= PR_F_SPARE; + meta->raid.disk[drive].dummy_0 = 0x0; + if (rdp->disks[drive].dev) { + struct ata_channel *ch = + device_get_softc(device_get_parent(rdp->disks[drive].dev)); + struct ata_device *atadev = + device_get_softc(rdp->disks[drive].dev); + + meta->raid.disk[drive].channel = ch->unit; + meta->raid.disk[drive].device = (atadev->unit != 0); } - config->raid.disk[drive].magic_0 = - PR_MAGIC0(rdp->disks[drive]) | timestamp.tv_sec; + meta->raid.disk[drive].magic_0 = + PR_MAGIC0(meta->raid.disk[drive]) | timestamp.tv_sec; } - if (rdp->disks[disk].device && rdp->disks[disk].device->softc && - !(rdp->disks[disk].device->flags & ATA_D_DETACHING)) { + if (rdp->disks[disk].dev) { if ((rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) == (AR_DF_PRESENT | AR_DF_ONLINE)) { - if (local) - bcopy(ATA_MAGIC, config->promise_id, sizeof(ATA_MAGIC)); + if (rdp->format == AR_F_FREEBSD_RAID) + bcopy(ATA_MAGIC, meta->promise_id, sizeof(ATA_MAGIC)); else - bcopy(PR_MAGIC, config->promise_id, sizeof(PR_MAGIC)); + bcopy(PR_MAGIC, meta->promise_id, sizeof(PR_MAGIC)); } else - bzero(config->promise_id, sizeof(config->promise_id)); - config->checksum = 0; - for (ckptr = (int32_t *)config, count = 0; count < 511; count++) - config->checksum += *ckptr++; - if (ar_rw(AD_SOFTC(rdp->disks[disk]), - PR_LBA(AD_SOFTC(rdp->disks[disk])), - sizeof(struct promise_raid_conf), - (caddr_t)config, AR_WRITE)) { - printf("ar%d: %s write conf failed\n", - rdp->lun, local ? "FreeBSD" : "Promise"); - free(config, M_AR); - return -1; + bzero(meta->promise_id, sizeof(meta->promise_id)); + meta->checksum = 0; + for (ckptr = (int32_t *)meta, count = 0; count < 511; count++) + meta->checksum += *ckptr++; + if (ata_raid_rw(rdp->disks[disk].dev, PR_LBA(rdp->disks[disk].dev), + meta, sizeof(struct promise_raid_conf), + ATA_R_WRITE | ATA_R_DIRECT)) { + device_printf(rdp->disks[disk].dev, "write metadata failed\n"); + error = EIO; + } + } + } + free(meta, M_AR); + return error; +} + +/* Silicon Image Medley Metadata */ +static int +ata_raid_sii_read_meta(device_t dev, struct ar_softc **raidp) +{ + struct ata_raid_subdisk *ars = device_get_softc(dev); + device_t parent = device_get_parent(dev); + struct sii_raid_conf *meta; + struct ar_softc *raid = NULL; + u_int16_t checksum, *ptr; + int array, count, disk, retval = 0; + + if (!(meta = (struct sii_raid_conf *) + malloc(sizeof(struct sii_raid_conf), M_AR, M_NOWAIT | M_ZERO))) + return ENOMEM; + + if (ata_raid_rw(parent, SII_LBA(parent), + meta, sizeof(struct sii_raid_conf), ATA_R_READ)) { + if (testing || bootverbose) + device_printf(parent, "Silicon Image read metadata failed\n"); + goto sii_out; + } + + /* check if this is a Silicon Image (Medley) RAID struct */ + for (checksum = 0, ptr = (u_int16_t *)meta, count = 0; count < 160; count++) + checksum += *ptr++; + if (checksum) { + if (testing || bootverbose) + device_printf(parent, "Silicon Image check1 failed\n"); + goto sii_out; + } + + for (checksum = 0, ptr = (u_int16_t *)meta, count = 0; count < 256; count++) + checksum += *ptr++; + if (checksum != meta->checksum_1) { + if (testing || bootverbose) + device_printf(parent, "Silicon Image check2 failed\n"); + goto sii_out; + } + + /* check verison */ + if (meta->version_major != 0x0002 || + (meta->version_minor != 0x0000 && meta->version_minor != 0x0001)) { + if (testing || bootverbose) + device_printf(parent, "Silicon Image check3 failed\n"); + goto sii_out; + } + + if (testing || bootverbose) + ata_raid_sii_print_meta(meta); + + /* now convert Silicon Image meta into our generic form */ + for (array = 0; array < MAX_ARRAYS; array++) { + if (!raidp[array]) { + raidp[array] = + (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, + M_NOWAIT | M_ZERO); + if (!raidp[array]) { + device_printf(parent, "failed to allocate metadata storage\n"); + goto sii_out; } } + raid = raidp[array]; + if (raid->format && (raid->format != AR_F_SII_RAID)) + continue; + + if (raid->format == AR_F_SII_RAID && + (raid->magic_0 != *((u_int64_t *)meta->timestamp))) { + continue; + } + + /* update our knowledge about the array config based on generation */ + if (!meta->generation || meta->generation > raid->generation) { + switch (meta->type) { + case SII_T_RAID0: + raid->type = AR_T_RAID0; + break; + + case SII_T_RAID1: + raid->type = AR_T_RAID1; + break; + + case SII_T_RAID01: + raid->type = AR_T_RAID01; + break; + + case SII_T_SPARE: + device_printf(parent, "Silicon Image SPARE disk\n"); + free(raidp[array], M_AR); + raidp[array] = NULL; + goto sii_out; + + default: + device_printf(parent,"Silicon Image unknown RAID type 0x%02x\n", + meta->type); + free(raidp[array], M_AR); + raidp[array] = NULL; + goto sii_out; + } + raid->magic_0 = *((u_int64_t *)meta->timestamp); + raid->format = AR_F_SII_RAID; + raid->generation = meta->generation; + raid->interleave = meta->stripe_sectors; + raid->width = (meta->raid0_disks != 0xff) ? meta->raid0_disks : 1; + raid->total_disks = + ((meta->raid0_disks != 0xff) ? meta->raid0_disks : 0) + + ((meta->raid1_disks != 0xff) ? meta->raid1_disks : 0); + raid->total_sectors = meta->total_sectors; + raid->heads = 255; + raid->sectors = 63; + raid->cylinders = raid->total_sectors / (63 * 255); + raid->offset_sectors = 0; + raid->rebuild_lba = meta->rebuild_lba; + raid->lun = array; + strncpy(raid->name, meta->name, + min(sizeof(raid->name), sizeof(meta->name))); + + /* clear out any old info */ + if (raid->generation) { + for (disk = 0; disk < raid->total_disks; disk++) { + raid->disks[disk].dev = NULL; + raid->disks[disk].flags = 0; + } + } + } + if (meta->generation >= raid->generation) { + /* XXX SOS add check for the right physical disk by serial# */ + if (meta->status & SII_S_READY) { + int disk_number = (raid->type == AR_T_RAID01) ? + meta->raid1_ident + (meta->raid0_ident << 1) : + meta->disk_number; + + raid->disks[disk_number].dev = parent; + raid->disks[disk_number].sectors = + raid->total_sectors / raid->total_disks; + raid->disks[disk_number].flags = + (AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED); + ars->raid = raid; + ars->disk_number = disk_number; + retval = 1; + } + } + break; + } + +sii_out: + free(meta, M_AR); + return retval; +} + +static struct ata_request * +ata_raid_init_request(struct ar_softc *rdp, struct bio *bio) +{ + struct ata_request *request; + + if (!(request = ata_alloc_request())) { + printf("FAILURE - out of memory in ata_raid_init_request\n"); + return 0; + } + request->timeout = 5; + request->retries = 2; + request->callback = ata_raid_done; + request->driver = rdp; + request->bio = bio; + switch (request->bio->bio_cmd) { + case BIO_READ: + request->flags = ATA_R_READ; + break; + case BIO_WRITE: + request->flags = ATA_R_WRITE; + break; + } + return request; +} + +static int +ata_raid_send_request(struct ata_request *request) +{ + struct ata_device *atadev = device_get_softc(request->dev); + + request->transfersize = min(request->bytecount, atadev->max_iosize); + request->transfersize = DEV_BSIZE; + if (request->flags & ATA_R_READ) { + if (atadev->mode >= ATA_DMA) { + request->flags |= ATA_R_DMA; + request->u.ata.command = ATA_READ_DMA; + } + else if (atadev->max_iosize > DEV_BSIZE) + request->u.ata.command = ATA_READ_MUL; else - free(config, M_AR); + request->u.ata.command = ATA_READ; } + else if (request->flags & ATA_R_WRITE) { + if (atadev->mode >= ATA_DMA) { + request->flags |= ATA_R_DMA; + request->u.ata.command = ATA_WRITE_DMA; + } + else if (atadev->max_iosize > DEV_BSIZE) + request->u.ata.command = ATA_WRITE_MUL; + else + request->u.ata.command = ATA_WRITE; + } + else { + device_printf(request->dev, "FAILURE - unknown IO operation\n"); + ata_free_request(request); + return EIO; + } + request->flags |= (ATA_R_ORDERED | ATA_R_THREAD); + ata_queue_request(request); return 0; } -static void -ar_rw_done(struct bio *bp) +static int +ata_raid_rw(device_t dev, u_int64_t lba, void *data, u_int bcount, int flags) { - free(bp->bio_data, M_AR); - free(bp, M_AR); + struct ata_device *atadev = device_get_softc(dev); + struct ata_request *request; + int error; + + if (bcount % DEV_BSIZE) { + device_printf(dev, "FAILURE - transfers must be modulo sectorsize\n"); + return ENOMEM; + } + + if (!(request = ata_alloc_request())) { + device_printf(dev, "FAILURE - out of memory in ata_raid_rw\n"); + return ENOMEM; + } + + /* setup request */ + request->dev = dev; + request->timeout = 10; + request->retries = 0; + request->data = data; + request->bytecount = bcount; + request->transfersize = DEV_BSIZE; + request->u.ata.lba = lba; + request->u.ata.count = request->bytecount / DEV_BSIZE; + request->flags = flags; + + if (flags & ATA_R_READ) { + if (atadev->mode >= ATA_DMA) { + request->u.ata.command = ATA_READ_DMA; + request->flags |= ATA_R_DMA; + } + else + request->u.ata.command = ATA_READ; + ata_queue_request(request); + } + else if (flags & ATA_R_WRITE) { + if (atadev->mode >= ATA_DMA) { + request->u.ata.command = ATA_WRITE_DMA; + request->flags |= ATA_R_DMA; + } + else + request->u.ata.command = ATA_WRITE; + ata_queue_request(request); + } + else { + device_printf(dev, "FAILURE - unknown IO operation\n"); + request->result = EIO; + } + error = request->result; + ata_free_request(request); + return error; +} + +/* + * module handeling + */ +static int +ata_raid_subdisk_probe(device_t dev) +{ + device_quiet(dev); + return 0; } static int -ar_rw(struct ad_softc *adp, u_int32_t lba, int count, caddr_t data, int flags) +ata_raid_subdisk_attach(device_t dev) { - struct bio *bp; - int retry = 0, error = 0; - - if (!(bp = (struct bio *)malloc(sizeof(struct bio), M_AR, M_NOWAIT|M_ZERO))) - return 1; - bp->bio_disk = adp->disk; - bp->bio_data = data; - bp->bio_pblkno = lba; - bp->bio_bcount = count; - if (flags & AR_READ) - bp->bio_cmd = BIO_READ; - if (flags & AR_WRITE) - bp->bio_cmd = BIO_WRITE; - if (flags & AR_WAIT) - bp->bio_done = (void *)wakeup; - else - bp->bio_done = ar_rw_done; + struct ata_raid_subdisk *ars = device_get_softc(dev); - AR_STRATEGY(bp); + ars->raid = NULL; + ars->disk_number = -1; + return ata_raid_read_metadata(dev); +} - if (flags & AR_WAIT) { - while ((retry++ < (15*hz/10)) && (error = !(bp->bio_flags & BIO_DONE))) - error = tsleep(bp, PRIBIO, "arrw", 10); - if (!error && bp->bio_flags & BIO_ERROR) - error = bp->bio_error; - free(bp, M_AR); +static int +ata_raid_subdisk_detach(device_t dev) +{ + struct ata_raid_subdisk *ars = device_get_softc(dev); + + if (ars->raid) { + ars->raid->disks[ars->disk_number].flags &= + ~(AR_DF_PRESENT | AR_DF_ONLINE); + ars->raid->disks[ars->disk_number].dev = NULL; + ata_raid_config_changed(ars->raid, 1); + ars->raid = NULL; + ars->disk_number = -1; } - return error; + return 0; } -static struct ata_device * -ar_locate_disk(int diskno) +static device_method_t ata_raid_sub_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, ata_raid_subdisk_probe), + DEVMETHOD(device_attach, ata_raid_subdisk_attach), + DEVMETHOD(device_detach, ata_raid_subdisk_detach), + { 0, 0 } +}; + +static driver_t ata_raid_sub_driver = { + "subdisk", + ata_raid_sub_methods, + sizeof(struct ata_raid_subdisk) +}; + +DRIVER_MODULE(subdisk, ad, ata_raid_sub_driver, ata_raid_sub_devclass, NULL, NULL); + +static int +ata_raid_module_event_handler(module_t mod, int what, void *arg) { - struct ata_channel *ch; - int ctlr; + int i; - for (ctlr = 0; ctlr < devclass_get_maxunit(ata_devclass); ctlr++) { - if (!(ch = devclass_get_softc(ata_devclass, ctlr))) - continue; - if (ch->devices & ATA_ATA_MASTER) - if (ch->device[MASTER].softc && - ((struct ad_softc *)(ch->device[MASTER].softc))->lun == diskno) - return &ch->device[MASTER]; - if (ch->devices & ATA_ATA_SLAVE) - if (ch->device[SLAVE].softc && - ((struct ad_softc *)(ch->device[SLAVE].softc))->lun == diskno) - return &ch->device[SLAVE]; - } - return NULL; + switch (what) { + case MOD_LOAD: + printf("ATA PseudoRAID loaded\n"); +#if 0 + /* setup table to hold metadata for all ATA PseudoRAID arrays */ + ata_raid_arrays = malloc(sizeof(struct ar_soft *) * MAX_ARRAYS, + M_AR, M_NOWAIT | M_ZERO); + if (!ata_raid_arrays) { + printf("ataraid: no memory for metadata storage\n"); + return ENOMEM; + } +#endif + /* attach found PseudoRAID arrays */ + for (i = 0; i < MAX_ARRAYS; i++) { + struct ar_softc *rdp = ata_raid_arrays[i]; + + if (!rdp || !rdp->format) + continue; + if (testing || bootverbose) + ata_raid_print_meta(rdp); + ata_raid_attach(rdp, 0); + } + ata_ioctl_func = ata_raid_ioctl; + return 0; + + case MOD_UNLOAD: + /* detach found PseudoRAID arrays */ + for (i = 0; i < MAX_ARRAYS; i++) { + struct ar_softc *rdp = ata_raid_arrays[i]; + + if (!rdp || !rdp->status) + continue; + disk_destroy(rdp->disk); + } + printf("ATA PseudoRAID unloaded\n"); +#if 0 + free(ata_raid_arrays, M_AR); +#endif + ata_ioctl_func = NULL; + return 0; + + default: + return EOPNOTSUPP; + } +} + +static moduledata_t ata_raid_moduledata = + { "ataraid", ata_raid_module_event_handler, NULL }; +DECLARE_MODULE(ata, ata_raid_moduledata, SI_SUB_RAID, SI_ORDER_FIRST); +MODULE_VERSION(ataraid, 1); +MODULE_DEPEND(ataraid, ata, 1, 1, 1); +MODULE_DEPEND(ataraid, ad, 1, 1, 1); + +static char * +ata_raid_format(struct ar_softc *rdp) +{ + switch (rdp->format) { + case AR_F_FREEBSD_RAID: return "FreeBSD PseudoRAID"; + case AR_F_ADAPTEC_RAID: return "Adaptec HostRAID"; + case AR_F_HPTV2_RAID: return "HighPoint v2 RocketRAID"; + case AR_F_HPTV3_RAID: return "HighPoint v3 RocketRAID"; + case AR_F_INTEL_RAID: return "Intel MatrixRAID"; + case AR_F_ITE_RAID: return "Integrated Technology Express"; + case AR_F_LSIV2_RAID: return "LSILogic v2 MegaRAID"; + case AR_F_LSIV3_RAID: return "LSILogic v3 MegaRAID"; + case AR_F_PROMISE_RAID: return "Promise Fasttrak"; + case AR_F_SII_RAID: return "Silicon Image Medley"; + default: return "UNKNOWN"; + } +} + +static char * +ata_raid_type(struct ar_softc *rdp) +{ + switch (rdp->type) { + case AR_T_JBOD: return "JBOD"; + case AR_T_SPAN: return "SPAN"; + case AR_T_RAID0: return "RAID0"; + case AR_T_RAID1: return "RAID1"; + case AR_T_RAID3: return "RAID3"; + case AR_T_RAID4: return "RAID4"; + case AR_T_RAID5: return "RAID5"; + case AR_T_RAID01: return "RAID0+1"; + default: return "UNKNOWN"; + } +} + +static char * +ata_raid_flags(struct ar_softc *rdp) +{ + switch (rdp->status & (AR_S_READY | AR_S_DEGRADED | AR_S_REBUILDING)) { + case AR_S_READY: return "READY"; + case AR_S_READY | AR_S_DEGRADED: return "DEGRADED"; + case AR_S_READY | AR_S_REBUILDING: + case AR_S_READY | AR_S_DEGRADED | AR_S_REBUILDING: return "REBUILDING"; + default: return "BROKEN"; + } +} + +/* debugging gunk */ +static void +ata_raid_print_meta(struct ar_softc *raid) +{ + int i; + + printf("********** ATA PseudoRAID ar%d Metadata **********\n", raid->lun); + printf("=================================================\n"); + printf("format %s\n", ata_raid_format(raid)); + printf("type %s\n", ata_raid_type(raid)); + printf("flags 0x%02x %b\n", raid->status, raid->status, + "\20\3REBUILDING\2DEGRADED\1READY\n"); + printf("magic_0 0x%016llx\n",(unsigned long long)raid->magic_0); + printf("magic_1 0x%016llx\n",(unsigned long long)raid->magic_1); + printf("generation %u\n", raid->generation); + printf("total_sectors %llu\n", + (unsigned long long)raid->total_sectors); + printf("offset_sectors %llu\n", + (unsigned long long)raid->offset_sectors); + printf("heads %u\n", raid->heads); + printf("sectors %u\n", raid->sectors); + printf("cylinders %u\n", raid->cylinders); + printf("width %u\n", raid->width); + printf("interleave %u\n", raid->interleave); + printf("total_disks %u\n", raid->total_disks); + for (i = 0; i < raid->total_disks; i++) { + printf(" disk %d: flags = 0x%02x %b\n", i, raid->disks[i].flags, + raid->disks[i].flags, "\20\4ONLINE\3SPARE\2ASSIGNED\1PRESENT\n"); + if (raid->disks[i].dev) { + printf(" "); + device_printf(raid->disks[i].dev, " sectors %lld\n", + (long long)raid->disks[i].sectors); + } + } + printf("=================================================\n"); +} + +static char * +ata_raid_adaptec_type(int type) +{ + static char buffer[16]; + + switch (type) { + case ADP_T_RAID0: return "RAID0"; + case ADP_T_RAID1: return "RAID1"; + default: sprintf(buffer, "UNKNOWN 0x%02x", type); + return buffer; + } +} + +static void +ata_raid_adaptec_print_meta(struct adaptec_raid_conf *meta) +{ + int i; + + printf("********* ATA Adaptec HostRAID Metadata *********\n"); + printf("magic_0 <0x%08x>\n", be32toh(meta->magic_0)); + printf("generation 0x%08x\n", be32toh(meta->generation)); + printf("dummy_0 0x%04x\n", be16toh(meta->dummy_0)); + printf("total_configs %u\n", be16toh(meta->total_configs)); + printf("dummy_1 0x%04x\n", be16toh(meta->dummy_1)); + printf("checksum 0x%04x\n", be16toh(meta->checksum)); + printf("dummy_2 0x%08x\n", be32toh(meta->dummy_2)); + printf("dummy_3 0x%08x\n", be32toh(meta->dummy_3)); + printf("flags 0x%08x\n", be32toh(meta->flags)); + printf("timestamp 0x%08x\n", be32toh(meta->timestamp)); + printf("dummy_4 0x%08x 0x%08x 0x%08x 0x%08x\n", + be32toh(meta->dummy_4[0]), be32toh(meta->dummy_4[1]), + be32toh(meta->dummy_4[2]), be32toh(meta->dummy_4[3])); + printf("dummy_5 0x%08x 0x%08x 0x%08x 0x%08x\n", + be32toh(meta->dummy_5[0]), be32toh(meta->dummy_5[1]), + be32toh(meta->dummy_5[2]), be32toh(meta->dummy_5[3])); + + for (i = 0; i < be16toh(meta->total_configs); i++) { + printf(" %d total_disks %u\n", i, + be16toh(meta->configs[i].disk_number)); + printf(" %d generation %u\n", i, + be16toh(meta->configs[i].generation)); + printf(" %d magic_0 0x%08x\n", i, + be32toh(meta->configs[i].magic_0)); + printf(" %d dummy_0 0x%02x\n", i, meta->configs[i].dummy_0); + printf(" %d type %s\n", i, + ata_raid_adaptec_type(meta->configs[i].type)); + printf(" %d dummy_1 0x%02x\n", i, meta->configs[i].dummy_1); + printf(" %d flags %d\n", i, + be32toh(meta->configs[i].flags)); + printf(" %d dummy_2 0x%02x\n", i, meta->configs[i].dummy_2); + printf(" %d dummy_3 0x%02x\n", i, meta->configs[i].dummy_3); + printf(" %d dummy_4 0x%02x\n", i, meta->configs[i].dummy_4); + printf(" %d dummy_5 0x%02x\n", i, meta->configs[i].dummy_5); + printf(" %d disk_number %u\n", i, + be32toh(meta->configs[i].disk_number)); + printf(" %d dummy_6 0x%08x\n", i, + be32toh(meta->configs[i].dummy_6)); + printf(" %d sectors %u\n", i, + be32toh(meta->configs[i].sectors)); + printf(" %d stripe_shift %u\n", i, + be16toh(meta->configs[i].stripe_shift)); + printf(" %d dummy_7 0x%08x\n", i, + be32toh(meta->configs[i].dummy_7)); + printf(" %d dummy_8 0x%08x 0x%08x 0x%08x 0x%08x\n", i, + be32toh(meta->configs[i].dummy_8[0]), + be32toh(meta->configs[i].dummy_8[1]), + be32toh(meta->configs[i].dummy_8[2]), + be32toh(meta->configs[i].dummy_8[3])); + printf(" %d name <%s>\n", i, meta->configs[i].name); + } + printf("magic_1 <0x%08x>\n", be32toh(meta->magic_1)); + printf("magic_2 <0x%08x>\n", be32toh(meta->magic_2)); + printf("magic_3 <0x%08x>\n", be32toh(meta->magic_3)); + printf("magic_4 <0x%08x>\n", be32toh(meta->magic_4)); + printf("=================================================\n"); +} + +static char * +ata_raid_hptv2_type(int type) +{ + static char buffer[16]; + + switch (type) { + case HPTV2_T_RAID0: return "RAID0"; + case HPTV2_T_RAID1: return "RAID1"; + case HPTV2_T_RAID01_RAID0: return "RAID01_RAID0"; + case HPTV2_T_SPAN: return "SPAN"; + case HPTV2_T_RAID_3: return "RAID3"; + case HPTV2_T_RAID_5: return "RAID5"; + case HPTV2_T_JBOD: return "JBOD"; + case HPTV2_T_RAID01_RAID1: return "RAID01_RAID1"; + default: sprintf(buffer, "UNKNOWN 0x%02x", type); + return buffer; + } +} + +static void +ata_raid_hptv2_print_meta(struct hptv2_raid_conf *meta) +{ + int i; + + printf("****** ATA Highpoint V2 RocketRAID Metadata *****\n"); + printf("magic 0x%08x\n", meta->magic); + printf("magic_0 0x%08x\n", meta->magic_0); + printf("magic_1 0x%08x\n", meta->magic_1); + printf("order 0x%08x\n", meta->order); + printf("array_width %u\n", meta->array_width); + printf("stripe_shift %u\n", meta->stripe_shift); + printf("type %s\n", ata_raid_hptv2_type(meta->type)); + printf("disk_number %u\n", meta->disk_number); + printf("total_sectors %u\n", meta->total_sectors); + printf("disk_mode 0x%08x\n", meta->disk_mode); + printf("boot_mode 0x%08x\n", meta->boot_mode); + printf("boot_disk 0x%02x\n", meta->boot_disk); + printf("boot_protect 0x%02x\n", meta->boot_protect); + printf("log_entries 0x%02x\n", meta->error_log_entries); + printf("log_index 0x%02x\n", meta->error_log_index); + if (meta->error_log_entries) { + printf(" timestamp reason disk status sectors lba\n"); + for (i = meta->error_log_index; + i < meta->error_log_index + meta->error_log_entries; i++) + printf(" 0x%08x 0x%02x 0x%02x 0x%02x 0x%02x 0x%08x\n", + meta->errorlog[i%32].timestamp, + meta->errorlog[i%32].reason, + meta->errorlog[i%32].disk, meta->errorlog[i%32].status, + meta->errorlog[i%32].sectors, meta->errorlog[i%32].lba); + } + printf("rebuild_lba 0x%08x\n", meta->rebuild_lba); + printf("dummy_1 0x%02x\n", meta->dummy_1); + printf("name_1 <%.15s>\n", meta->name_1); + printf("dummy_2 0x%02x\n", meta->dummy_2); + printf("name_2 <%.15s>\n", meta->name_2); + printf("=================================================\n"); +} + +static char * +ata_raid_hptv3_type(int type) +{ + static char buffer[16]; + + switch (type) { + case HPTV3_T_SPARE: return "SPARE"; + case HPTV3_T_JBOD: return "JBOD"; + case HPTV3_T_SPAN: return "SPAN"; + case HPTV3_T_RAID0: return "RAID0"; + case HPTV3_T_RAID1: return "RAID1"; + case HPTV3_T_RAID3: return "RAID3"; + case HPTV3_T_RAID5: return "RAID5"; + default: sprintf(buffer, "UNKNOWN 0x%02x", type); + return buffer; + } } static void -ar_print_conf(struct ar_softc *config) +ata_raid_hptv3_print_meta(struct hptv3_raid_conf *meta) { int i; - printf("lun %d\n", config->lun); - printf("magic_0 0x%08x\n", config->magic_0); - printf("magic_1 0x%08x\n", config->magic_1); - printf("flags 0x%02x %b\n", config->flags, config->flags, - "\20\16HIGHPOINT\15PROMISE\13REBUILDING\12DEGRADED\11READY\3SPAN\2RAID1\1RAID0\n"); - printf("total_disks %d\n", config->total_disks); - printf("generation %d\n", config->generation); - printf("width %d\n", config->width); - printf("heads %d\n", config->heads); - printf("sectors %d\n", config->sectors); - printf("cylinders %d\n", config->cylinders); - printf("total_sectors %lld\n", (long long)config->total_sectors); - printf("interleave %d\n", config->interleave); - printf("reserved %d\n", config->reserved); - printf("offset %d\n", config->offset); - for (i = 0; i < config->total_disks; i++) { - printf("disk %d: flags = 0x%02x %b\n", i, config->disks[i].flags, config->disks[i].flags, "\20\4ONLINE\3SPARE\2ASSIGNED\1PRESENT\n"); - if (config->disks[i].device) - printf(" %s\n", config->disks[i].device->name); - printf(" sectors %lld\n", (long long)config->disks[i].disk_sectors); + printf("****** ATA Highpoint V3 RocketRAID Metadata *****\n"); + printf("magic 0x%08x\n", meta->magic); + printf("magic_0 0x%08x\n", meta->magic_0); + printf("checksum_0 0x%02x\n", meta->checksum_0); + printf("mode 0x%02x\n", meta->mode); + printf("user_mode 0x%02x\n", meta->user_mode); + printf("config_entries 0x%02x\n", meta->config_entries); + for (i = 0; i < meta->config_entries; i++) { + printf("config %d:\n", i); + printf(" total_sectors %llu\n", + (unsigned long long)(meta->configs[0].total_sectors + + ((u_int64_t)meta->configs_high[0].total_sectors << 32))); + printf(" type %s\n", + ata_raid_hptv3_type(meta->configs[i].type)); + printf(" total_disks %u\n", meta->configs[i].total_disks); + printf(" disk_number %u\n", meta->configs[i].disk_number); + printf(" stripe_shift %u\n", meta->configs[i].stripe_shift); + printf(" status %b\n", meta->configs[i].status, + "\20\2RAID5\1NEED_REBUILD\n"); + printf(" critical_disks %u\n", meta->configs[i].critical_disks); + printf(" rebuild_lba %llu\n", + (unsigned long long)(meta->configs_high[0].rebuild_lba + + ((u_int64_t)meta->configs_high[0].rebuild_lba << 32))); } + printf("name <%.16s>\n", meta->name); + printf("timestamp 0x%08x\n", meta->timestamp); + printf("description <%.16s>\n", meta->description); + printf("creator <%.16s>\n", meta->creator); + printf("checksum_1 0x%02x\n", meta->checksum_1); + printf("dummy_0 0x%02x\n", meta->dummy_0); + printf("dummy_1 0x%02x\n", meta->dummy_1); + printf("flags %b\n", meta->flags, + "\20\4RCACHE\3WCACHE\2NCQ\1TCQ\n"); + printf("=================================================\n"); +} + +static char * +ata_raid_intel_type(int type) +{ + static char buffer[16]; + + switch (type) { + case INTEL_T_RAID0: return "RAID0"; + case INTEL_T_RAID1: return "RAID1"; + default: sprintf(buffer, "UNKNOWN 0x%02x", type); + return buffer; + } +} + +static void +ata_raid_intel_print_meta(struct intel_raid_conf *meta) +{ + struct intel_raid_mapping *map; + int i, j; + + printf("********* ATA Intel MatrixRAID Metadata *********\n"); + printf("intel_id <%.24s>\n", meta->intel_id); + printf("version <%.6s>\n", meta->version); + printf("checksum 0x%08x\n", meta->checksum); + printf("config_size 0x%08x\n", meta->config_size); + printf("config_id 0x%08x\n", meta->config_id); + printf("generation 0x%08x\n", meta->generation); + printf("total_disks %u\n", meta->total_disks); + printf("total_volumes %u\n", meta->total_volumes); + printf("DISK# serial disk_sectors disk_id flags\n"); + for (i = 0; i < meta->total_disks; i++ ) { + printf(" %d <%.16s> %u 0x%08x 0x%08x\n", i, + meta->disk[i].serial, meta->disk[i].sectors, + meta->disk[i].id, meta->disk[i].flags); + } + map = (struct intel_raid_mapping *)&meta->disk[meta->total_disks]; + for (j = 0; j < meta->total_volumes; j++) { + printf("name %.16s\n", map->name); + printf("total_sectors %llu\n", + (unsigned long long)map->total_sectors); + printf("state %u\n", map->state); + printf("reserved %u\n", map->reserved); + printf("offset %u\n", map->offset); + printf("disk_sectors %u\n", map->disk_sectors); + printf("stripe_count %u\n", map->stripe_count); + printf("stripe_sectors %u\n", map->stripe_sectors); + printf("status %u\n", map->status); + printf("type %s\n", ata_raid_intel_type(map->type)); + printf("total_disks %u\n", map->total_disks); + for (i = 0; i < map->total_disks; i++ ) { + printf(" disk %d at disk_idx 0x%08x\n", i, map->disk_idx[i]); + } + map = (struct intel_raid_mapping *)&map->disk_idx[i]; + } + printf("=================================================\n"); +} + +static char * +ata_raid_ite_type(int type) +{ + static char buffer[16]; + + switch (type) { + case ITE_T_RAID0: return "RAID0"; + case ITE_T_RAID1: return "RAID1"; + case ITE_T_RAID01: return "RAID0+1"; + case ITE_T_SPAN: return "SPAN"; + default: sprintf(buffer, "UNKNOWN 0x%02x", type); + return buffer; + } +} + +static void +ata_raid_ite_print_meta(struct ite_raid_conf *meta) +{ + printf("*** ATA Integrated Technology Express Metadata **\n"); + printf("ite_id <%.40s>\n", meta->ite_id); + printf("timestamp_0 %04x/%02x/%02x %02x:%02x:%02x.%02x\n", + *((u_int16_t *)meta->timestamp_0), meta->timestamp_0[2], + meta->timestamp_0[3], meta->timestamp_0[5], meta->timestamp_0[4], + meta->timestamp_0[7], meta->timestamp_0[6]); + printf("total_sectors %lld\n", + (unsigned long long)meta->total_sectors); + printf("type %s\n", ata_raid_ite_type(meta->type)); + printf("stripe_1kblocks %u\n", meta->stripe_1kblocks); + printf("timestamp_1 %04x/%02x/%02x %02x:%02x:%02x.%02x\n", + *((u_int16_t *)meta->timestamp_1), meta->timestamp_1[2], + meta->timestamp_1[3], meta->timestamp_1[5], meta->timestamp_1[4], + meta->timestamp_1[7], meta->timestamp_1[6]); + printf("stripe_sectors %u\n", meta->stripe_sectors); + printf("array_width %u\n", meta->array_width); + printf("disk_number %u\n", meta->disk_number); + printf("disk_sectors %u\n", meta->disk_sectors); + printf("=================================================\n"); +} + +static char * +ata_raid_lsiv2_type(int type) +{ + static char buffer[16]; + + switch (type) { + case LSIV2_T_RAID0: return "RAID0"; + case LSIV2_T_RAID1: return "RAID1"; + case LSIV2_T_SPARE: return "SPARE"; + default: sprintf(buffer, "UNKNOWN 0x%02x", type); + return buffer; + } +} + +static void +ata_raid_lsiv2_print_meta(struct lsiv2_raid_conf *meta) +{ + int i; + + printf("******* ATA LSILogic V2 MegaRAID Metadata *******\n"); + printf("lsi_id <%s>\n", meta->lsi_id); + printf("dummy_0 0x%02x\n", meta->dummy_0); + printf("flags 0x%02x\n", meta->flags); + printf("version 0x%04x\n", meta->version); + printf("config_entries 0x%02x\n", meta->config_entries); + printf("raid_count 0x%02x\n", meta->raid_count); + printf("total_disks 0x%02x\n", meta->total_disks); + printf("dummy_1 0x%02x\n", meta->dummy_1); + printf("dummy_2 0x%04x\n", meta->dummy_2); + for (i = 0; i < meta->config_entries; i++) { + printf(" type %s\n", + ata_raid_lsiv2_type(meta->configs[i].raid.type)); + printf(" dummy_0 %02x\n", meta->configs[i].raid.dummy_0); + printf(" stripe_sectors %u\n", + meta->configs[i].raid.stripe_sectors); + printf(" array_width %u\n", + meta->configs[i].raid.array_width); + printf(" disk_count %u\n", meta->configs[i].raid.disk_count); + printf(" config_offset %u\n", + meta->configs[i].raid.config_offset); + printf(" dummy_1 %u\n", meta->configs[i].raid.dummy_1); + printf(" flags %02x\n", meta->configs[i].raid.flags); + printf(" total_sectors %u\n", + meta->configs[i].raid.total_sectors); + } + printf("disk_number 0x%02x\n", meta->disk_number); + printf("raid_number 0x%02x\n", meta->raid_number); + printf("timestamp 0x%08x\n", meta->timestamp); + printf("=================================================\n"); +} + +static char * +ata_raid_lsiv3_type(int type) +{ + static char buffer[16]; + + switch (type) { + case LSIV3_T_RAID0: return "RAID0"; + case LSIV3_T_RAID1: return "RAID1"; + default: sprintf(buffer, "UNKNOWN 0x%02x", type); + return buffer; + } +} + +static void +ata_raid_lsiv3_print_meta(struct lsiv3_raid_conf *meta) +{ + int i; + + printf("******* ATA LSILogic V3 MegaRAID Metadata *******\n"); + printf("lsi_id <%.6s>\n", meta->lsi_id); + printf("dummy_0 0x%04x\n", meta->dummy_0); + printf("version 0x%04x\n", meta->version); + printf("dummy_0 0x%04x\n", meta->dummy_1); + printf("RAID configs:\n"); + for (i = 0; i < 8; i++) { + if (meta->raid[i].total_disks) { + printf("%02d stripe_pages %u\n", i, + meta->raid[i].stripe_pages); + printf("%02d type %s\n", i, + ata_raid_lsiv3_type(meta->raid[i].type)); + printf("%02d total_disks %u\n", i, + meta->raid[i].total_disks); + printf("%02d array_width %u\n", i, + meta->raid[i].array_width); + printf("%02d sectors %u\n", i, meta->raid[i].sectors); + printf("%02d offset %u\n", i, meta->raid[i].offset); + printf("%02d device 0x%02x\n", i, + meta->raid[i].device); + } + } + printf("DISK configs:\n"); + for (i = 0; i < 6; i++) { + if (meta->disk[i].disk_sectors) { + printf("%02d disk_sectors %u\n", i, + meta->disk[i].disk_sectors); + printf("%02d flags 0x%02x\n", i, meta->disk[i].flags); + } + } + printf("device 0x%02x\n", meta->device); + printf("timestamp 0x%08x\n", meta->timestamp); + printf("checksum_1 0x%02x\n", meta->checksum_1); + printf("=================================================\n"); +} + +static char * +ata_raid_promise_type(int type) +{ + static char buffer[16]; + + switch (type) { + case PR_T_RAID0: return "RAID0"; + case PR_T_RAID1: return "RAID1"; + case PR_T_RAID3: return "RAID3"; + case PR_T_RAID5: return "RAID5"; + case PR_T_SPAN: return "SPAN"; + default: sprintf(buffer, "UNKNOWN 0x%02x", type); + return buffer; + } +} + +static void +ata_raid_promise_print_meta(struct promise_raid_conf *meta) +{ + int i; + + printf("********* ATA Promise FastTrak Metadata *********\n"); + printf("promise_id <%s>\n", meta->promise_id); + printf("dummy_0 0x%08x\n", meta->dummy_0); + printf("magic_0 0x%016llx\n",(unsigned long long)meta->magic_0); + printf("magic_1 0x%04x\n", meta->magic_1); + printf("magic_2 0x%08x\n", meta->magic_2); + printf("integrity 0x%08x %b\n", meta->raid.integrity, + meta->raid.integrity, "\20\10VALID\n" ); + printf("flags 0x%02x %b\n", + meta->raid.flags, meta->raid.flags, + "\20\10READY\7DOWN\6REDIR\5DUPLICATE\4SPARE" + "\3ASSIGNED\2ONLINE\1VALID\n"); + printf("disk_number %d\n", meta->raid.disk_number); + printf("channel 0x%02x\n", meta->raid.channel); + printf("device 0x%02x\n", meta->raid.device); + printf("magic_0 0x%016llx\n", + (unsigned long long)meta->raid.magic_0); + printf("disk_offset %u\n", meta->raid.disk_offset); + printf("disk_sectors %u\n", meta->raid.disk_sectors); + printf("rebuild_lba 0x%08x\n", meta->raid.rebuild_lba); + printf("generation 0x%04x\n", meta->raid.generation); + printf("status 0x%02x %b\n", + meta->raid.status, meta->raid.status, + "\20\6MARKED\5DEGRADED\4READY\3INITED\2ONLINE\1VALID\n"); + printf("type %s\n", ata_raid_promise_type(meta->raid.type)); + printf("total_disks %u\n", meta->raid.total_disks); + printf("stripe_shift %u\n", meta->raid.stripe_shift); + printf("array_width %u\n", meta->raid.array_width); + printf("array_number %u\n", meta->raid.array_number); + printf("total_sectors %u\n", meta->raid.total_sectors); + printf("cylinders %u\n", meta->raid.cylinders); + printf("heads %u\n", meta->raid.heads); + printf("sectors %u\n", meta->raid.sectors); + printf("magic_1 0x%016llx\n", + (unsigned long long)meta->raid.magic_1); + printf("DISK# flags dummy_0 channel device magic_0\n"); + for (i = 0; i < 8; i++) { + printf(" %d %b 0x%02x 0x%02x 0x%02x ", + i, meta->raid.disk[i].flags, + "\20\10READY\7DOWN\6REDIR\5DUPLICATE\4SPARE" + "\3ASSIGNED\2ONLINE\1VALID\n", meta->raid.disk[i].dummy_0, + meta->raid.disk[i].channel, meta->raid.disk[i].device); + printf("0x%016llx\n", + (unsigned long long)meta->raid.disk[i].magic_0); + } + printf("checksum 0x%08x\n", meta->checksum); + printf("=================================================\n"); +} + +static char * +ata_raid_sii_type(int type) +{ + static char buffer[16]; + + switch (type) { + case SII_T_RAID0: return "RAID0"; + case SII_T_RAID1: return "RAID1"; + case SII_T_RAID01: return "RAID0+1"; + case SII_T_SPARE: return "SPARE"; + default: sprintf(buffer, "UNKNOWN 0x%02x", type); + return buffer; + } +} + +static void +ata_raid_sii_print_meta(struct sii_raid_conf *meta) +{ + printf("******* ATA Silicon Image Medley Metadata *******\n"); + printf("total_sectors %llu\n", + (unsigned long long)meta->total_sectors); + printf("dummy_0 0x%04x\n", meta->dummy_0); + printf("dummy_1 0x%04x\n", meta->dummy_1); + printf("controller_pci_id 0x%08x\n", meta->controller_pci_id); + printf("version_minor 0x%04x\n", meta->version_minor); + printf("version_major 0x%04x\n", meta->version_major); + printf("timestamp 20%02x/%02x/%02x %02x:%02x:%02x\n", + meta->timestamp[5], meta->timestamp[4], meta->timestamp[3], + meta->timestamp[2], meta->timestamp[1], meta->timestamp[0]); + printf("stripe_sectors %u\n", meta->stripe_sectors); + printf("dummy_2 0x%04x\n", meta->dummy_2); + printf("disk_number %u\n", meta->disk_number); + printf("type %s\n", ata_raid_sii_type(meta->type)); + printf("raid0_disks %u\n", meta->raid0_disks); + printf("raid0_ident %u\n", meta->raid0_ident); + printf("raid1_disks %u\n", meta->raid1_disks); + printf("raid1_ident %u\n", meta->raid1_ident); + printf("rebuild_lba %llu\n", (unsigned long long)meta->rebuild_lba); + printf("generation 0x%08x\n", meta->generation); + printf("status 0x%02x %b\n", + meta->status, meta->status, + "\20\1READY\n"); + printf("base_raid1_position %02x\n", meta->base_raid1_position); + printf("base_raid0_position %02x\n", meta->base_raid0_position); + printf("position %02x\n", meta->position); + printf("dummy_3 %04x\n", meta->dummy_3); + printf("name <%.16s>\n", meta->name); + printf("checksum_0 0x%04x\n", meta->checksum_0); + printf("checksum_1 0x%04x\n", meta->checksum_1); + printf("=================================================\n"); } diff --git a/sys/dev/ata/ata-raid.h b/sys/dev/ata/ata-raid.h index 7a3e7a9..31c785d 100644 --- a/sys/dev/ata/ata-raid.h +++ b/sys/dev/ata/ata-raid.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000 - 2003 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 2000 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,273 +29,614 @@ */ /* misc defines */ -#define MAX_ARRAYS 16 -#define MAX_DISKS 16 -#define AR_PROXIMITY 2048 -#define AR_READ 0x01 -#define AR_WRITE 0x02 -#define AR_WAIT 0x04 -#define AR_STRATEGY(x) (x)->bio_disk->d_strategy((x)) -#define AD_SOFTC(x) ((struct ad_softc *)(x.device->softc)) -#define ATA_MAGIC "FreeBSD ATA driver RAID " - -struct ar_disk { - struct ata_device *device; - u_int64_t disk_sectors; /* sectors on this disk */ - off_t last_lba; /* last lba used */ - int flags; -#define AR_DF_PRESENT 0x00000001 -#define AR_DF_ASSIGNED 0x00000002 -#define AR_DF_SPARE 0x00000004 -#define AR_DF_ONLINE 0x00000008 +#define MAX_ARRAYS 16 +#define MAX_DISKS 16 +#define AR_PROXIMITY 2048 /* how many sectors is "close" */ + +#define ATA_MAGIC "FreeBSD ATA driver RAID " + +struct ata_raid_subdisk { + struct ar_softc *raid; + int disk_number; }; +/* ATA PseudoRAID Metadata */ struct ar_softc { - int lun; - int32_t magic_0; /* ident for this array */ - int32_t magic_1; /* ident for this array */ - int flags; -#define AR_F_SPAN 0x00000001 -#define AR_F_RAID0 0x00000002 -#define AR_F_RAID1 0x00000004 -#define AR_F_RAID3 0x00000008 -#define AR_F_RAID5 0x00000010 - -#define AR_F_READY 0x00000100 -#define AR_F_DEGRADED 0x00000200 -#define AR_F_REBUILDING 0x00000400 -#define AR_F_TOGGLE 0x00000800 - -#define AR_F_FREEBSD_RAID 0x00010000 -#define AR_F_PROMISE_RAID 0x00020000 -#define AR_F_HIGHPOINT_RAID 0x00040000 -#define AR_F_ADAPTEC_RAID 0x00080000 -#define AR_F_LSI_RAID 0x00100000 -#define AR_F_INTEL_RAID 0x00200000 -#define AR_F_QTEC_RAID 0x00400000 - - int total_disks; /* number of disks in this array */ - int generation; /* generation of this array */ - struct ar_disk disks[MAX_DISKS+1]; /* ptr to each disk in array */ - int width; /* array width in disks */ - u_int16_t heads; - u_int16_t sectors; - u_int32_t cylinders; - u_int64_t total_sectors; - int interleave; /* interleave in blocks */ - int reserved; /* sectors that are NOT to be used */ - int offset; /* offset from start of disk */ - u_int64_t lock_start; /* start of locked area for rebuild */ - u_int64_t lock_end; /* end of locked area for rebuild */ - struct disk *disk; /* disklabel/slice stuff */ - struct proc *pid; /* rebuilder process id */ -}; + int lun; /* logical unit number of this RAID */ + u_int8_t name[32]; /* name of array if any */ + u_int64_t magic_0; /* magic for this array */ + u_int64_t magic_1; /* magic for this array */ + int type; +#define AR_T_JBOD 0x0001 +#define AR_T_SPAN 0x0002 +#define AR_T_RAID0 0x0004 +#define AR_T_RAID1 0x0008 +#define AR_T_RAID01 0x0010 +#define AR_T_RAID3 0x0020 +#define AR_T_RAID4 0x0040 +#define AR_T_RAID5 0x0080 + + int status; +#define AR_S_READY 0x0001 +#define AR_S_DEGRADED 0x0002 +#define AR_S_REBUILDING 0x0004 + + int format; +#define AR_F_FREEBSD_RAID 0x0001 +#define AR_F_ADAPTEC_RAID 0x0002 +#define AR_F_HPTV2_RAID 0x0004 +#define AR_F_HPTV3_RAID 0x0008 +#define AR_F_INTEL_RAID 0x0010 +#define AR_F_ITE_RAID 0x0020 +#define AR_F_LSIV2_RAID 0x0040 +#define AR_F_LSIV3_RAID 0x0080 +#define AR_F_PROMISE_RAID 0x0100 +#define AR_F_SII_RAID 0x0200 +#define AR_F_FORMAT_MASK 0x03ff -struct ar_buf { - struct bio bp; /* must be first element! */ - struct bio *org; - struct ar_buf *mirror; - int drive; - int flags; -#define AB_F_DONE 0x01 + u_int generation; /* generation of this array */ + u_int64_t total_sectors; + u_int64_t offset_sectors; /* offset from start of disk */ + u_int16_t heads; + u_int16_t sectors; + u_int32_t cylinders; + u_int width; /* array width in disks */ + u_int interleave; /* interleave in blocks */ + u_int total_disks; /* number of disks in this array */ + struct ar_disk { + device_t dev; + u_int8_t serial[16]; /* serial # of physical disk */ + u_int64_t sectors; /* useable sectors on this disk */ + off_t last_lba; /* last lba used (for performance) */ + u_int flags; +#define AR_DF_PRESENT 0x0001 /* this HW pos has a disk present */ +#define AR_DF_ASSIGNED 0x0002 /* this HW pos assigned to an array */ +#define AR_DF_SPARE 0x0004 /* this HW pos is a spare */ +#define AR_DF_ONLINE 0x0008 /* this HW pos is online and in use */ + + } disks[MAX_DISKS]; + int toggle; /* performance hack for RAID1's */ + u_int64_t rebuild_lba; /* rebuild progress indicator */ + struct mtx lock; /* metadata lock */ + struct disk *disk; /* disklabel/slice stuff */ + struct proc *pid; /* rebuilder process id */ }; +/* Adaptec HostRAID Metadata */ +#define ADP_LBA(dev) \ + (((struct ad_softc *)device_get_ivars(dev))->total_secs - 17) + +/* note all entries are big endian */ +struct adaptec_raid_conf { + u_int32_t magic_0; /* 0x0000 */ +#define ADP_MAGIC_0 0xc4650790 + + u_int32_t generation; + u_int16_t dummy_0; + u_int16_t total_configs; + u_int16_t dummy_1; + u_int16_t checksum; + u_int32_t dummy_2; /* 0x0010 */ + u_int32_t dummy_3; + u_int32_t flags; + u_int32_t timestamp; + u_int32_t dummy_4[4]; /* 0x0020 */ + u_int32_t dummy_5[4]; /* 0x0030 */ + struct { /* 0x0040 */ + u_int16_t total_disks; + u_int16_t generation; + u_int32_t magic_0; + u_int8_t dummy_0; + u_int8_t type; +#define ADP_T_RAID0 0x00 +#define ADP_T_RAID1 0x01 + u_int8_t dummy_1; + u_int8_t flags; + + u_int8_t dummy_2; + u_int8_t dummy_3; + u_int8_t dummy_4; + u_int8_t dummy_5; -#define HPT_LBA 9 - -struct highpoint_raid_conf { - int8_t filler1[32]; - u_int32_t magic; -#define HPT_MAGIC_OK 0x5a7816f0 -#define HPT_MAGIC_BAD 0x5a7816fd - - u_int32_t magic_0; - u_int32_t magic_1; - u_int32_t order; -#define HPT_O_RAID0 0x01 -#define HPT_O_RAID1 0x02 -#define HPT_O_OK 0x04 - - u_int8_t array_width; - u_int8_t stripe_shift; - u_int8_t type; -#define HPT_T_RAID0 0x00 -#define HPT_T_RAID1 0x01 -#define HPT_T_RAID01_RAID0 0x02 -#define HPT_T_SPAN 0x03 -#define HPT_T_RAID_3 0x04 -#define HPT_T_RAID_5 0x05 -#define HPT_T_SINGLEDISK 0x06 -#define HPT_T_RAID01_RAID1 0x07 - - u_int8_t disk_number; - u_int32_t total_sectors; - u_int32_t disk_mode; - u_int32_t boot_mode; - u_int8_t boot_disk; - u_int8_t boot_protect; - u_int8_t error_log_entries; - u_int8_t error_log_index; + u_int32_t disk_number; + u_int32_t dummy_6; + u_int32_t sectors; + u_int16_t stripe_shift; + u_int16_t dummy_7; + + u_int32_t dummy_8[4]; + u_int8_t name[16]; + } configs[127]; /* x 0x40 bytes */ + + u_int32_t dummy_6[13]; /* 0x2000 */ + u_int32_t magic_1; +#define ADP_MAGIC_1 0x9ff85009 + u_int32_t dummy_7[3]; + u_int32_t magic_2; + u_int32_t dummy_8[46]; + u_int32_t magic_3; +#define ADP_MAGIC_3 0x4d545044 + u_int32_t magic_4; +#define ADP_MAGIC_4 0x9ff85009 + u_int32_t dummy_9[62]; +} __packed; + + +/* Highpoint V2 RocketRAID Metadata */ +#define HPTV2_LBA(dev) 9 + +struct hptv2_raid_conf { + int8_t filler1[32]; + u_int32_t magic; +#define HPTV2_MAGIC_OK 0x5a7816f0 +#define HPTV2_MAGIC_BAD 0x5a7816fd + + u_int32_t magic_0; + u_int32_t magic_1; + u_int32_t order; +#define HPTV2_O_RAID0 0x01 +#define HPTV2_O_RAID1 0x02 +#define HPTV2_O_OK 0x04 + + u_int8_t array_width; + u_int8_t stripe_shift; + u_int8_t type; +#define HPTV2_T_RAID0 0x00 +#define HPTV2_T_RAID1 0x01 +#define HPTV2_T_RAID01_RAID0 0x02 +#define HPTV2_T_SPAN 0x03 +#define HPTV2_T_RAID_3 0x04 +#define HPTV2_T_RAID_5 0x05 +#define HPTV2_T_JBOD 0x06 +#define HPTV2_T_RAID01_RAID1 0x07 + + u_int8_t disk_number; + u_int32_t total_sectors; + u_int32_t disk_mode; + u_int32_t boot_mode; + u_int8_t boot_disk; + u_int8_t boot_protect; + u_int8_t error_log_entries; + u_int8_t error_log_index; struct { - u_int32_t timestamp; - u_int8_t reason; -#define HPT_R_REMOVED 0xfe -#define HPT_R_BROKEN 0xff + u_int32_t timestamp; + u_int8_t reason; +#define HPTV2_R_REMOVED 0xfe +#define HPTV2_R_BROKEN 0xff - u_int8_t disk; - u_int8_t status; - u_int8_t sectors; - u_int32_t lba; + u_int8_t disk; + u_int8_t status; + u_int8_t sectors; + u_int32_t lba; } errorlog[32]; - int8_t filler2[16]; - u_int32_t rebuild_lba; - u_int8_t dummy_1; - u_int8_t name_1[15]; - u_int8_t dummy_2; - u_int8_t name_2[15]; - int8_t filler3[8]; + int8_t filler2[16]; + u_int32_t rebuild_lba; + u_int8_t dummy_1; + u_int8_t name_1[15]; + u_int8_t dummy_2; + u_int8_t name_2[15]; + int8_t filler3[8]; } __packed; -#define LSI_LBA(adp) (adp->total_secs - 1) +/* Highpoint V3 RocketRAID Metadata */ +#define HPTV3_LBA(dev) \ + (((struct ad_softc *)device_get_ivars(dev))->total_secs - 11) + +struct hptv3_raid_conf { + u_int32_t magic; +#define HPTV3_MAGIC 0x5a7816f3 -struct lsi_raid_conf { - u_int8_t lsi_id[6]; -#define LSI_MAGIC "$XIDE$" + u_int32_t magic_0; + u_int8_t checksum_0; + u_int8_t mode; +#define HPTV3_BOOT_MARK 0x01 +#define HPTV3_USER_MODE 0x02 + + u_int8_t user_mode; + u_int8_t config_entries; + struct { + u_int32_t total_sectors; + u_int8_t type; +#define HPTV3_T_SPARE 0x00 +#define HPTV3_T_JBOD 0x03 +#define HPTV3_T_SPAN 0x04 +#define HPTV3_T_RAID0 0x05 +#define HPTV3_T_RAID1 0x06 +#define HPTV3_T_RAID3 0x07 +#define HPTV3_T_RAID5 0x08 + + u_int8_t total_disks; + u_int8_t disk_number; + u_int8_t stripe_shift; + u_int16_t status; +#define HPTV3_T_NEED_REBUILD 0x01 +#define HPTV3_T_RAID5_FLAG 0x02 + + u_int16_t critical_disks; + u_int32_t rebuild_lba; + } __packed configs[2]; + u_int8_t name[16]; + u_int32_t timestamp; + u_int8_t description[64]; + u_int8_t creator[16]; + u_int8_t checksum_1; + u_int8_t dummy_0; + u_int8_t dummy_1; + u_int8_t flags; +#define HPTV3_T_ENABLE_TCQ 0x01 +#define HPTV3_T_ENABLE_NCQ 0x02 +#define HPTV3_T_ENABLE_WCACHE 0x04 +#define HPTV3_T_ENABLE_RCACHE 0x08 + + struct { + u_int32_t total_sectors; + u_int32_t rebuild_lba; + } __packed configs_high[2]; + u_int32_t filler[87]; +} __packed; + + +/* Intel MatrixRAID Metadata */ +#define INTEL_LBA(dev) \ + (((struct ad_softc *)device_get_ivars(dev))->total_secs - 2) + +struct intel_raid_conf { + u_int8_t intel_id[24]; +#define INTEL_MAGIC "Intel Raid ISM Cfg Sig. " + + u_int8_t version[6]; + u_int8_t dummy_0[2]; + u_int32_t checksum; + u_int32_t config_size; + u_int32_t config_id; + u_int32_t generation; + u_int32_t dummy_1[2]; + u_int8_t total_disks; + u_int8_t total_volumes; + u_int8_t dummy_2[2]; + u_int32_t filler_0[39]; + struct { + u_int8_t serial[16]; + u_int32_t sectors; + u_int32_t id; + u_int32_t flags; +#define INTEL_F_SPARE 0x01 +#define INTEL_F_ASSIGNED 0x02 +#define INTEL_F_DOWN 0x04 +#define INTEL_F_ONLINE 0x08 + + u_int32_t filler[5]; + } __packed disk[1]; + u_int32_t filler_1[62]; +} __packed; + +struct intel_raid_mapping { + u_int8_t name[16]; + u_int64_t total_sectors __packed; + u_int32_t state; + u_int32_t reserved; + u_int32_t filler_1[20]; + u_int32_t offset; + u_int32_t disk_sectors; + u_int32_t stripe_count; + u_int16_t stripe_sectors; + u_int8_t status; +#define INTEL_S_READY 0x00 +#define INTEL_S_DISABLED 0x01 +#define INTEL_S_DEGRADED 0x02 +#define INTEL_S_FAILURE 0x03 + + u_int8_t type; +#define INTEL_T_RAID0 0x00 +#define INTEL_T_RAID1 0x01 + + u_int8_t total_disks; + u_int8_t dummy_2[3]; + u_int32_t filler_2[7]; + u_int32_t disk_idx[1]; +} __packed; - u_int8_t dummy_1; - u_int8_t flags; - u_int8_t version[2]; - u_int8_t config_entries; - u_int8_t raid_count; - u_int8_t total_disks; - u_int8_t dummy_d; - u_int8_t dummy_e; - u_int8_t dummy_f; + +/* Integrated Technology Express Metadata */ +#define ITE_LBA(dev) \ + (((struct ad_softc *)device_get_ivars(dev))->total_secs - 2) + +struct ite_raid_conf { + u_int32_t filler_1[5]; + u_int8_t timestamp_0[8]; /* BCD coded y:Y:M:D:m:h:f:s */ + u_int32_t dummy_1; + u_int32_t filler_2[5]; + u_int16_t filler_3; + u_int8_t ite_id[40]; /* byte swapped */ +#define ITE_MAGIC "Integrated Technology Express Inc " + + u_int16_t filler_4; + u_int32_t filler_5[6]; + u_int32_t dummy_2; + u_int32_t dummy_3; + u_int32_t filler_6[12]; + u_int32_t dummy_4; + u_int32_t filler_7[5]; + u_int64_t total_sectors __packed; + u_int32_t filler_8[12]; + + u_int16_t filler_9; /* 0x100 */ + u_int8_t type; +#define ITE_T_RAID0 0x00 +#define ITE_T_RAID1 0x01 +#define ITE_T_RAID01 0x02 +#define ITE_T_SPAN 0x03 + + u_int8_t filler_10; + u_int32_t dummy_5[8]; + u_int8_t stripe_1kblocks; + u_int8_t filler_11[3]; + u_int32_t filler_12[54]; + + u_int32_t dummy_6[4]; /* 0x200 */ + u_int8_t timestamp_1[8]; /* same as timestamp_0 */ + u_int32_t filler_13[9]; + u_int8_t stripe_sectors; + u_int8_t filler_14[3]; + u_int8_t array_width; + u_int8_t filler_15[3]; + u_int32_t filler_16; + u_int8_t filler_17; + u_int8_t disk_number; + u_int32_t disk_sectors; + u_int16_t filler_18; + u_int32_t dummy_7[4]; + u_int32_t filler_20[104]; +} __packed; + + +/* LSILogic V2 MegaRAID Metadata */ +#define LSIV2_LBA(dev) \ + (((struct ad_softc *)device_get_ivars(dev))->total_secs - 1) + +struct lsiv2_raid_conf { + u_int8_t lsi_id[6]; +#define LSIV2_MAGIC "$XIDE$" + + u_int8_t dummy_0; + u_int8_t flags; + u_int16_t version; + u_int8_t config_entries; + u_int8_t raid_count; + u_int8_t total_disks; + u_int8_t dummy_1; + u_int16_t dummy_2; union { struct { - u_int8_t type; -#define LSI_R_RAID0 0x01 -#define LSI_R_RAID1 0x02 -#define LSI_R_SPARE 0x08 - - u_int8_t dummy_1; - u_int16_t stripe_size; - u_int8_t raid_width; - u_int8_t disk_count; - u_int8_t config_offset; - u_int8_t dummy_7; - u_int8_t flags; -#define LSI_R_DEGRADED 0x02 - - u_int32_t total_sectors; - u_int8_t filler[3]; + u_int8_t type; +#define LSIV2_T_RAID0 0x01 +#define LSIV2_T_RAID1 0x02 +#define LSIV2_T_SPARE 0x08 + + u_int8_t dummy_0; + u_int16_t stripe_sectors; + u_int8_t array_width; + u_int8_t disk_count; + u_int8_t config_offset; + u_int8_t dummy_1; + u_int8_t flags; +#define LSIV2_R_DEGRADED 0x02 + + u_int32_t total_sectors; + u_int8_t filler[3]; } __packed raid; struct { - u_int8_t device; -#define LSI_D_MASTER 0x00 -#define LSI_D_SLAVE 0x01 -#define LSI_D_CHANNEL0 0x00 -#define LSI_D_CHANNEL1 0x10 -#define LSI_D_NONE 0xff - - u_int8_t dummy_1; - u_int32_t disk_sectors; - u_int8_t disk_number; - u_int8_t raid_number; - u_int8_t flags; -#define LSI_D_GONE 0x02 - - u_int8_t filler[7]; + u_int8_t device; +#define LSIV2_D_MASTER 0x00 +#define LSIV2_D_SLAVE 0x01 +#define LSIV2_D_CHANNEL0 0x00 +#define LSIV2_D_CHANNEL1 0x10 +#define LSIV2_D_NONE 0xff + + u_int8_t dummy_0; + u_int32_t disk_sectors; + u_int8_t disk_number; + u_int8_t raid_number; + u_int8_t flags; +#define LSIV2_D_GONE 0x02 + + u_int8_t filler[7]; } __packed disk; } configs[30]; - u_int8_t disk_number; - u_int8_t raid_number; - u_int32_t timestamp; - u_int8_t filler[10]; + u_int8_t disk_number; + u_int8_t raid_number; + u_int32_t timestamp; + u_int8_t filler[10]; +} __packed; + + +/* LSILogic V3 MegaRAID Metadata */ +#define LSIV3_LBA(dev) \ + (((struct ad_softc *)device_get_ivars(dev))->total_secs - 4) + +struct lsiv3_raid_conf { + u_int32_t magic_0; /* 0xa0203200 */ + u_int32_t filler_0[3]; + u_int8_t magic_1[4]; /* "SATA" */ + u_int32_t filler_1[40]; + u_int32_t dummy_0; /* 0x0d000003 */ + u_int32_t filler_2[7]; + u_int32_t dummy_1; /* 0x0d000003 */ + u_int32_t filler_3[70]; + u_int8_t magic_2[8]; /* "$_ENQ$31" */ + u_int8_t filler_4[7]; + u_int8_t checksum_0; + u_int8_t filler_5[512*2]; + u_int8_t lsi_id[6]; +#define LSIV3_MAGIC "$_IDE$" + + u_int16_t dummy_2; /* 0x33de for OK disk */ + u_int16_t version; /* 0x0131 for this version */ + u_int16_t dummy_3; /* 0x0440 always */ + u_int32_t filler_6; + + struct { + u_int16_t stripe_pages; + u_int8_t type; +#define LSIV3_T_RAID0 0x00 +#define LSIV3_T_RAID1 0x01 + + u_int8_t dummy_0; + u_int8_t total_disks; + u_int8_t array_width; + u_int8_t filler_0[10]; + + u_int32_t sectors; + u_int16_t dummy_1; + u_int32_t offset; + u_int16_t dummy_2; + u_int8_t device; +#define LSIV3_D_DEVICE 0x01 +#define LSIV3_D_CHANNEL 0x10 + + u_int8_t dummy_3; + u_int8_t dummy_4; + u_int8_t dummy_5; + u_int8_t filler_1[16]; + } __packed raid[8]; + struct { + u_int32_t disk_sectors; + u_int32_t dummy_0; + u_int32_t dummy_1; + u_int8_t dummy_2; + u_int8_t dummy_3; + u_int8_t flags; +#define LSIV3_D_MIRROR 0x00 +#define LSIV3_D_STRIPE 0xff + u_int8_t dummy_4; + } __packed disk[6]; + u_int8_t filler_7[7]; + u_int8_t device; + u_int32_t timestamp; + u_int8_t filler_8[3]; + u_int8_t checksum_1; } __packed; -#define PR_LBA(adp) \ - (((adp->total_secs / (adp->heads * adp->sectors)) * \ - adp->heads * adp->sectors) - adp->sectors) +/* Promise FastTrak Metadata */ +#define PR_LBA(dev) \ + (((struct ad_softc *)device_get_ivars(dev))->total_secs - 63) +#if 0 + (((((struct ad_softc *)device_get_ivars(dev))->total_secs / (((struct ad_softc *)device_get_ivars(dev))->heads * ((struct ad_softc *)device_get_ivars(dev))->sectors)) * ((struct ad_softc *)device_get_ivars(dev))->heads * ((struct ad_softc *)device_get_ivars(dev))->sectors) - ((struct ad_softc *)device_get_ivars(dev))->sectors) +#endif struct promise_raid_conf { - char promise_id[24]; -#define PR_MAGIC "Promise Technology, Inc." - - u_int32_t dummy_0; - u_int64_t magic_0; -#define PR_MAGIC0(x) (x.device ? ((u_int64_t)x.device->channel->unit<<48) | \ - ((u_int64_t)(x.device->unit != 0) << 56) : 0) - u_int16_t magic_1; - u_int32_t magic_2; - u_int8_t filler1[470]; + char promise_id[24]; +#define PR_MAGIC "Promise Technology, Inc." + + u_int32_t dummy_0; + u_int64_t magic_0; +#define PR_MAGIC0(x) (((u_int64_t)(x.channel) << 48) | \ + ((u_int64_t)(x.device != 0) << 56)) + u_int16_t magic_1; + u_int32_t magic_2; + u_int8_t filler1[470]; struct { - u_int32_t integrity; -#define PR_I_VALID 0x00000080 - - u_int8_t flags; -#define PR_F_VALID 0x00000001 -#define PR_F_ONLINE 0x00000002 -#define PR_F_ASSIGNED 0x00000004 -#define PR_F_SPARE 0x00000008 -#define PR_F_DUPLICATE 0x00000010 -#define PR_F_REDIR 0x00000020 -#define PR_F_DOWN 0x00000040 -#define PR_F_READY 0x00000080 - - u_int8_t disk_number; - u_int8_t channel; - u_int8_t device; - u_int64_t magic_0 __packed; - u_int32_t disk_offset; - u_int32_t disk_sectors; - u_int32_t rebuild_lba; - u_int16_t generation; - u_int8_t status; -#define PR_S_VALID 0x01 -#define PR_S_ONLINE 0x02 -#define PR_S_INITED 0x04 -#define PR_S_READY 0x08 -#define PR_S_DEGRADED 0x10 -#define PR_S_MARKED 0x20 -#define PR_S_FUNCTIONAL 0x80 - - u_int8_t type; -#define PR_T_RAID0 0x00 -#define PR_T_RAID1 0x01 -#define PR_T_RAID3 0x02 -#define PR_T_RAID5 0x04 -#define PR_T_SPAN 0x08 - - u_int8_t total_disks; - u_int8_t stripe_shift; - u_int8_t array_width; - u_int8_t array_number; - u_int32_t total_sectors; - u_int16_t cylinders; - u_int8_t heads; - u_int8_t sectors; - int64_t magic_1 __packed; + u_int32_t integrity; +#define PR_I_VALID 0x00000080 + + u_int8_t flags; +#define PR_F_VALID 0x00000001 +#define PR_F_ONLINE 0x00000002 +#define PR_F_ASSIGNED 0x00000004 +#define PR_F_SPARE 0x00000008 +#define PR_F_DUPLICATE 0x00000010 +#define PR_F_REDIR 0x00000020 +#define PR_F_DOWN 0x00000040 +#define PR_F_READY 0x00000080 + + u_int8_t disk_number; + u_int8_t channel; + u_int8_t device; + u_int64_t magic_0 __packed; + u_int32_t disk_offset; + u_int32_t disk_sectors; + u_int32_t rebuild_lba; + u_int16_t generation; + u_int8_t status; +#define PR_S_VALID 0x01 +#define PR_S_ONLINE 0x02 +#define PR_S_INITED 0x04 +#define PR_S_READY 0x08 +#define PR_S_DEGRADED 0x10 +#define PR_S_MARKED 0x20 +#define PR_S_FUNCTIONAL 0x80 + + u_int8_t type; +#define PR_T_RAID0 0x00 +#define PR_T_RAID1 0x01 +#define PR_T_RAID3 0x02 +#define PR_T_RAID5 0x04 +#define PR_T_SPAN 0x08 +#define PR_T_JBOD 0x10 + + u_int8_t total_disks; + u_int8_t stripe_shift; + u_int8_t array_width; + u_int8_t array_number; + u_int32_t total_sectors; + u_int16_t cylinders; + u_int8_t heads; + u_int8_t sectors; + u_int64_t magic_1 __packed; struct { - u_int8_t flags; - u_int8_t dummy_0; - u_int8_t channel; - u_int8_t device; - u_int64_t magic_0 __packed; + u_int8_t flags; + u_int8_t dummy_0; + u_int8_t channel; + u_int8_t device; + u_int64_t magic_0 __packed; } disk[8]; } raid; - int32_t filler2[346]; - u_int32_t checksum; + int32_t filler2[346]; + u_int32_t checksum; } __packed; -int ata_raiddisk_attach(struct ad_softc *); -int ata_raiddisk_detach(struct ad_softc *); -void ata_raid_attach(void); -int ata_raid_create(struct raid_setup *); -int ata_raid_delete(int); -int ata_raid_status(int, struct raid_status *); -int ata_raid_addspare(int, int); -int ata_raid_rebuild(int); + +/* Silicon Image Medley Metadata */ +#define SII_LBA(dev) \ + ( ((struct ad_softc *)device_get_ivars(dev))->total_secs - 1) + +struct sii_raid_conf { + u_int16_t ata_params_00_53[54]; + u_int64_t total_sectors; + u_int16_t ata_params_58_79[70]; + u_int16_t dummy_0; + u_int16_t dummy_1; + u_int32_t controller_pci_id; + u_int16_t version_minor; + u_int16_t version_major; + u_int8_t timestamp[6]; /* BCD coded s:m:h:D:M:Y */ + u_int16_t stripe_sectors; + u_int16_t dummy_2; + u_int8_t disk_number; + u_int8_t type; +#define SII_T_RAID0 0x00 +#define SII_T_RAID1 0x01 +#define SII_T_RAID01 0x02 +#define SII_T_SPARE 0x03 + + u_int8_t raid0_disks; + u_int8_t raid0_ident; + u_int8_t raid1_disks; + u_int8_t raid1_ident; + u_int64_t rebuild_lba; + u_int32_t generation; + u_int8_t status; +#define SII_S_READY 0x01 + + u_int8_t base_raid1_position; + u_int8_t base_raid0_position; + u_int8_t position; + u_int16_t dummy_3; + u_int8_t name[16]; + u_int16_t checksum_0; + int8_t filler1[190]; + u_int16_t checksum_1; /* sum of all 128 shorts == 0 */ +} __packed; diff --git a/sys/dev/ata/atapi-cd.c b/sys/dev/ata/atapi-cd.c index 4a7df80..7f7efa7 100644 --- a/sys/dev/ata/atapi-cd.c +++ b/sys/dev/ata/atapi-cd.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/ata.h> #include <sys/kernel.h> +#include <sys/module.h> #include <sys/malloc.h> #include <sys/proc.h> #include <sys/bio.h> @@ -52,49 +53,47 @@ __FBSDID("$FreeBSD$"); #include <geom/geom.h> #include <dev/ata/ata-all.h> #include <dev/ata/atapi-cd.h> +#include <ata_if.h> /* prototypes */ -static void acd_detach(struct ata_device *); -static void acd_start(struct ata_device *); -static struct acd_softc *acd_init_lun(struct ata_device *); -static void acd_geom_create(void *, int); -static void acd_set_ioparm(struct acd_softc *); -static void acd_describe(struct acd_softc *); +static void acd_geom_attach(void *, int); +static void acd_geom_detach(void *, int); +static void acd_set_ioparm(device_t); +static void acd_describe(device_t); static void lba2msf(u_int32_t, u_int8_t *, u_int8_t *, u_int8_t *); static u_int32_t msf2lba(u_int8_t, u_int8_t, u_int8_t); static int acd_geom_access(struct g_provider *, int, int, int); static g_ioctl_t acd_geom_ioctl; static void acd_geom_start(struct bio *); +static void acd_strategy(struct bio *); static void acd_done(struct ata_request *); -static void acd_read_toc(struct acd_softc *); -static int acd_play(struct acd_softc *, int, int); -static int acd_setchan(struct acd_softc *, u_int8_t, u_int8_t, u_int8_t, u_int8_t); -static void acd_select_slot(struct acd_softc *); -static int acd_init_writer(struct acd_softc *, int); -static int acd_fixate(struct acd_softc *, int); -static int acd_init_track(struct acd_softc *, struct cdr_track *); -static int acd_flush(struct acd_softc *); -static int acd_read_track_info(struct acd_softc *, int32_t, struct acd_track_info *); -static int acd_get_progress(struct acd_softc *, int *); -static int acd_send_cue(struct acd_softc *, struct cdr_cuesheet *); -static int acd_report_key(struct acd_softc *, struct dvd_authinfo *); -static int acd_send_key(struct acd_softc *, struct dvd_authinfo *); -static int acd_read_structure(struct acd_softc *, struct dvd_struct *); -static int acd_tray(struct acd_softc *, int); -static int acd_blank(struct acd_softc *, int); -static int acd_prevent_allow(struct acd_softc *, int); -static int acd_start_stop(struct acd_softc *, int); -static int acd_pause_resume(struct acd_softc *, int); -static int acd_mode_sense(struct acd_softc *, int, caddr_t, int); -static int acd_mode_select(struct acd_softc *, caddr_t, int); -static int acd_set_speed(struct acd_softc *, int, int); -static void acd_get_cap(struct acd_softc *); -static int acd_read_format_caps(struct acd_softc *, struct cdr_format_capacities *); -static int acd_format(struct acd_softc *, struct cdr_format_params *); -static int acd_test_ready(struct ata_device *); +static void acd_read_toc(device_t); +static int acd_play(device_t, int, int); +static int acd_setchan(device_t, u_int8_t, u_int8_t, u_int8_t, u_int8_t); +static int acd_init_writer(device_t, int); +static int acd_fixate(device_t, int); +static int acd_init_track(device_t, struct cdr_track *); +static int acd_flush(device_t); +static int acd_read_track_info(device_t, int32_t, struct acd_track_info *); +static int acd_get_progress(device_t, int *); +static int acd_send_cue(device_t, struct cdr_cuesheet *); +static int acd_report_key(device_t, struct dvd_authinfo *); +static int acd_send_key(device_t, struct dvd_authinfo *); +static int acd_read_structure(device_t, struct dvd_struct *); +static int acd_tray(device_t, int); +static int acd_blank(device_t, int); +static int acd_prevent_allow(device_t, int); +static int acd_start_stop(device_t, int); +static int acd_pause_resume(device_t, int); +static int acd_mode_sense(device_t, int, caddr_t, int); +static int acd_mode_select(device_t, caddr_t, int); +static int acd_set_speed(device_t, int, int); +static void acd_get_cap(device_t); +static int acd_read_format_caps(device_t, struct cdr_format_capacities *); +static int acd_format(device_t, struct cdr_format_params *); +static int acd_test_ready(device_t); /* internal vars */ -static u_int32_t acd_lun_map = 0; static MALLOC_DEFINE(M_ACD, "ACD driver", "ATAPI CD driver buffers"); static struct g_class acd_class = { .name = "ACD", @@ -103,503 +102,166 @@ static struct g_class acd_class = { .ioctl = acd_geom_ioctl, .start = acd_geom_start, }; -DECLARE_GEOM_CLASS(acd_class, acd); +//DECLARE_GEOM_CLASS(acd_class, acd); -void -acd_attach(struct ata_device *atadev) +static void +acd_identify(driver_t *driver, device_t parent) { - struct acd_softc *cdp; - struct changer *chp; - - if ((cdp = acd_init_lun(atadev)) == NULL) { - ata_prtdev(atadev, "out of memory\n"); - return; - } + ata_identify(driver, parent, ATA_ATAPI_TYPE_CDROM, "acd"); +} - ata_set_name(atadev, "acd", cdp->lun); - acd_get_cap(cdp); +static int +acd_probe(device_t dev) +{ + return 0; +} - /* if this is a changer device, allocate the neeeded lun's */ - if ((cdp->cap.mechanism & MST_MECH_MASK) == MST_MECH_CHANGER) { - int8_t ccb[16] = { ATAPI_MECH_STATUS, 0, 0, 0, 0, 0, 0, 0, - sizeof(struct changer)>>8, sizeof(struct changer), - 0, 0, 0, 0, 0, 0 }; +static int +acd_attach(device_t dev) +{ + struct ata_device *atadev = device_get_softc(dev); + struct acd_softc *cdp; - if (!(chp = malloc(sizeof(struct changer), M_ACD, M_NOWAIT | M_ZERO))) { - ata_prtdev(atadev, "out of memory\n"); - free(cdp, M_ACD); - return; - } - if (!ata_atapicmd(cdp->device, ccb, (caddr_t)chp, - sizeof(struct changer), ATA_R_READ, 60)) { - struct acd_softc *tmpcdp = cdp; - struct acd_softc **cdparr; - char *name; - int count; - - chp->table_length = htons(chp->table_length); - if (!(cdparr = malloc(sizeof(struct acd_softc) * chp->slots, - M_ACD, M_NOWAIT))) { - ata_prtdev(atadev, "out of memory\n"); - free(chp, M_ACD); - free(cdp, M_ACD); - return; - } - for (count = 0; count < chp->slots; count++) { - if (count > 0) { - tmpcdp = acd_init_lun(atadev); - if (!tmpcdp) { - ata_prtdev(atadev, "out of memory\n"); - break; - } - } - cdparr[count] = tmpcdp; - tmpcdp->driver = cdparr; - tmpcdp->slot = count; - tmpcdp->changer_info = chp; - g_post_event(acd_geom_create, tmpcdp, M_WAITOK, NULL); - } - if (!(name = malloc(strlen(atadev->name) + 2, M_ACD, M_NOWAIT))) { - ata_prtdev(atadev, "out of memory\n"); - free(cdp, M_ACD); - return; - } - strcpy(name, atadev->name); - strcat(name, "-"); - ata_free_name(atadev); - ata_set_name(atadev, name, cdp->lun + cdp->changer_info->slots - 1); - free(name, M_ACD); - } + if (!(cdp = malloc(sizeof(struct acd_softc), M_ACD, M_NOWAIT | M_ZERO))) { + device_printf(dev, "out of memory\n"); + device_set_softc(dev, NULL); + free(atadev, M_ATA); + return ENOMEM; } - else - g_post_event(acd_geom_create, cdp, M_WAITOK, NULL); - - /* setup the function ptrs */ - atadev->detach = acd_detach; - atadev->start = acd_start; - atadev->softc = cdp; + cdp->block_size = 2048; + device_set_ivars(dev, cdp); + ATA_SETMODE(GRANDPARENT(dev), dev); + acd_get_cap(dev); + g_post_event(acd_geom_attach, dev, M_WAITOK, NULL); /* announce we are here */ - acd_describe(cdp); + acd_describe(dev); + return 0; } -static void -acd_geom_detach(void *arg, int flag) +static int +acd_detach(device_t dev) { - struct ata_device *atadev = arg; - struct acd_softc *cdp = atadev->softc; - int subdev; - - g_wither_geom(cdp->gp, ENXIO); - if (cdp->changer_info) { - for (subdev = 0; subdev < cdp->changer_info->slots; subdev++) { - if (cdp->driver[subdev] == cdp) - continue; - mtx_lock(&cdp->driver[subdev]->queue_mtx); - bioq_flush(&cdp->driver[subdev]->queue, NULL, ENXIO); - mtx_unlock(&cdp->driver[subdev]->queue_mtx); - ata_free_lun(&acd_lun_map, cdp->driver[subdev]->lun); - free(cdp->driver[subdev], M_ACD); - } - free(cdp->driver, M_ACD); - free(cdp->changer_info, M_ACD); - } - mtx_lock(&cdp->queue_mtx); - bioq_flush(&cdp->queue, NULL, ENXIO); - mtx_unlock(&cdp->queue_mtx); - mtx_destroy(&cdp->queue_mtx); - ata_prtdev(atadev, "WARNING - removed from configuration\n"); - ata_free_name(atadev); - ata_free_lun(&acd_lun_map, cdp->lun); - atadev->attach = NULL; - atadev->detach = NULL; - atadev->start = NULL; - atadev->softc = NULL; - atadev->flags = 0; - free(cdp, M_ACD); + g_waitfor_event(acd_geom_detach, dev, M_WAITOK, NULL); + return 0; } static void -acd_detach(struct ata_device *atadev) -{ - g_waitfor_event(acd_geom_detach, atadev, M_WAITOK, NULL); +acd_shutdown(device_t dev) +{ + struct ata_device *atadev = device_get_softc(dev); + + if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE) + ata_controlcmd(atadev, ATA_FLUSHCACHE, 0, 0, 0); } -static struct acd_softc * -acd_init_lun(struct ata_device *atadev) +static int +acd_reinit(device_t dev) { - struct acd_softc *cdp; - - if (!(cdp = malloc(sizeof(struct acd_softc), M_ACD, M_NOWAIT | M_ZERO))) - return NULL; - bioq_init(&cdp->queue); - mtx_init(&cdp->queue_mtx, "ATAPI CD bioqueue lock", NULL, MTX_DEF); - cdp->device = atadev; - cdp->lun = ata_get_lun(&acd_lun_map); - cdp->block_size = 2048; - cdp->slot = -1; - cdp->changer_info = NULL; - return cdp; + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_device *atadev = device_get_softc(dev); + struct acd_softc *cdp = device_get_ivars(dev); + + if (((atadev->unit == ATA_MASTER) && !(ch->devices & ATA_ATAPI_MASTER)) || + ((atadev->unit == ATA_SLAVE) && !(ch->devices & ATA_ATAPI_SLAVE))) { + device_set_ivars(dev, NULL); + free(cdp, M_ACD); + return 1; + } + ATA_SETMODE(GRANDPARENT(dev), dev); + return 0; } static void -acd_geom_create(void *arg, int flag) +acd_geom_attach(void *arg, int flag) { - struct acd_softc *cdp; + struct ata_device *atadev = device_get_softc(arg); + struct acd_softc *cdp = device_get_ivars(arg); struct g_geom *gp; struct g_provider *pp; - cdp = arg; g_topology_assert(); - gp = g_new_geomf(&acd_class, "acd%d", cdp->lun); - gp->softc = cdp; + gp = g_new_geomf(&acd_class, "acd%d", device_get_unit(arg)); + gp->softc = arg; cdp->gp = gp; - pp = g_new_providerf(gp, "acd%d", cdp->lun); + pp = g_new_providerf(gp, "acd%d", device_get_unit(arg)); pp->index = 0; cdp->pp[0] = pp; g_error_provider(pp, 0); - cdp->device->flags |= ATA_D_MEDIA_CHANGED; - acd_set_ioparm(cdp); + atadev->flags |= ATA_D_MEDIA_CHANGED; + acd_set_ioparm(arg); } static void -acd_set_ioparm(struct acd_softc *cdp) -{ - - if (cdp->device->channel->dma) - cdp->iomax = min(cdp->device->channel->dma->max_iosize, 65534); - else - cdp->iomax = min(DFLTPHYS, 65534); -} - -static void -acd_describe(struct acd_softc *cdp) -{ - int comma = 0; - char *mechanism; - - if (bootverbose) { - ata_prtdev(cdp->device, "<%.40s/%.8s> %s drive at ata%d as %s\n", - cdp->device->param->model, cdp->device->param->revision, - (cdp->cap.media & MST_WRITE_DVDR) ? "DVDR" : - (cdp->cap.media & MST_WRITE_DVDRAM) ? "DVDRAM" : - (cdp->cap.media & MST_WRITE_CDRW) ? "CDRW" : - (cdp->cap.media & MST_WRITE_CDR) ? "CDR" : - (cdp->cap.media & MST_READ_DVDROM) ? "DVDROM" : "CDROM", - device_get_unit(cdp->device->channel->dev), - (cdp->device->unit == ATA_MASTER) ? "master" : "slave"); - - ata_prtdev(cdp->device, "%s", ""); - if (cdp->cap.cur_read_speed) { - printf("read %dKB/s", cdp->cap.cur_read_speed * 1000 / 1024); - if (cdp->cap.max_read_speed) - printf(" (%dKB/s)", cdp->cap.max_read_speed * 1000 / 1024); - if ((cdp->cap.cur_write_speed) && - (cdp->cap.media & (MST_WRITE_CDR | MST_WRITE_CDRW | - MST_WRITE_DVDR | MST_WRITE_DVDRAM))) { - printf(" write %dKB/s", cdp->cap.cur_write_speed * 1000 / 1024); - if (cdp->cap.max_write_speed) - printf(" (%dKB/s)", cdp->cap.max_write_speed * 1000 / 1024); - } - comma = 1; - } - if (cdp->cap.buf_size) { - printf("%s %dKB buffer", comma ? "," : "", cdp->cap.buf_size); - comma = 1; - } - printf("%s %s\n", comma ? "," : "", ata_mode2str(cdp->device->mode)); - - ata_prtdev(cdp->device, "Reads:"); - comma = 0; - if (cdp->cap.media & MST_READ_CDR) { - printf(" CDR"); comma = 1; - } - if (cdp->cap.media & MST_READ_CDRW) { - printf("%s CDRW", comma ? "," : ""); comma = 1; - } - if (cdp->cap.capabilities & MST_READ_CDDA) { - if (cdp->cap.capabilities & MST_CDDA_STREAM) - printf("%s CDDA stream", comma ? "," : ""); - else - printf("%s CDDA", comma ? "," : ""); - comma = 1; - } - if (cdp->cap.media & MST_READ_DVDROM) { - printf("%s DVDROM", comma ? "," : ""); comma = 1; - } - if (cdp->cap.media & MST_READ_DVDR) { - printf("%s DVDR", comma ? "," : ""); comma = 1; - } - if (cdp->cap.media & MST_READ_DVDRAM) { - printf("%s DVDRAM", comma ? "," : ""); comma = 1; - } - if (cdp->cap.media & MST_READ_PACKET) - printf("%s packet", comma ? "," : ""); - - printf("\n"); - ata_prtdev(cdp->device, "Writes:"); - if (cdp->cap.media & (MST_WRITE_CDR | MST_WRITE_CDRW | - MST_WRITE_DVDR | MST_WRITE_DVDRAM)) { - comma = 0; - if (cdp->cap.media & MST_WRITE_CDR) { - printf(" CDR" ); comma = 1; - } - if (cdp->cap.media & MST_WRITE_CDRW) { - printf("%s CDRW", comma ? "," : ""); comma = 1; - } - if (cdp->cap.media & MST_WRITE_DVDR) { - printf("%s DVDR", comma ? "," : ""); comma = 1; - } - if (cdp->cap.media & MST_WRITE_DVDRAM) { - printf("%s DVDRAM", comma ? "," : ""); comma = 1; - } - if (cdp->cap.media & MST_WRITE_TEST) { - printf("%s test write", comma ? "," : ""); comma = 1; - } - if (cdp->cap.capabilities & MST_BURNPROOF) - printf("%s burnproof", comma ? "," : ""); - } - printf("\n"); - if (cdp->cap.capabilities & MST_AUDIO_PLAY) { - ata_prtdev(cdp->device, "Audio: "); - if (cdp->cap.capabilities & MST_AUDIO_PLAY) - printf("play"); - if (cdp->cap.max_vol_levels) - printf(", %d volume levels", cdp->cap.max_vol_levels); - printf("\n"); - } - ata_prtdev(cdp->device, "Mechanism: "); - switch (cdp->cap.mechanism & MST_MECH_MASK) { - case MST_MECH_CADDY: - mechanism = "caddy"; break; - case MST_MECH_TRAY: - mechanism = "tray"; break; - case MST_MECH_POPUP: - mechanism = "popup"; break; - case MST_MECH_CHANGER: - mechanism = "changer"; break; - case MST_MECH_CARTRIDGE: - mechanism = "cartridge"; break; - default: - mechanism = 0; break; - } - if (mechanism) - printf("%s%s", (cdp->cap.mechanism & MST_EJECT) ? - "ejectable " : "", mechanism); - else if (cdp->cap.mechanism & MST_EJECT) - printf("ejectable"); - - if (cdp->cap.mechanism & MST_LOCKABLE) - printf((cdp->cap.mechanism & MST_LOCKED) ? ", locked":", unlocked"); - if (cdp->cap.mechanism & MST_PREVENT) - printf(", lock protected"); - printf("\n"); - - if ((cdp->cap.mechanism & MST_MECH_MASK) != MST_MECH_CHANGER) { - ata_prtdev(cdp->device, "Medium: "); - switch (cdp->cap.medium_type & MST_TYPE_MASK_HIGH) { - case MST_CDROM: - printf("CD-ROM "); break; - case MST_CDR: - printf("CD-R "); break; - case MST_CDRW: - printf("CD-RW "); break; - case MST_DOOR_OPEN: - printf("door open"); break; - case MST_NO_DISC: - printf("no/blank disc"); break; - case MST_FMT_ERROR: - printf("medium format error"); break; - } - if ((cdp->cap.medium_type & MST_TYPE_MASK_HIGH)<MST_TYPE_MASK_HIGH){ - switch (cdp->cap.medium_type & MST_TYPE_MASK_LOW) { - case MST_DATA_120: - printf("120mm data disc"); break; - case MST_AUDIO_120: - printf("120mm audio disc"); break; - case MST_COMB_120: - printf("120mm data/audio disc"); break; - case MST_PHOTO_120: - printf("120mm photo disc"); break; - case MST_DATA_80: - printf("80mm data disc"); break; - case MST_AUDIO_80: - printf("80mm audio disc"); break; - case MST_COMB_80: - printf("80mm data/audio disc"); break; - case MST_PHOTO_80: - printf("80mm photo disc"); break; - case MST_FMT_NONE: - switch (cdp->cap.medium_type & MST_TYPE_MASK_HIGH) { - case MST_CDROM: - printf("unknown"); break; - case MST_CDR: - case MST_CDRW: - printf("blank"); break; - } - break; - default: - printf("unknown (0x%x)", cdp->cap.medium_type); break; - } - } - printf("\n"); - } - } - else { - ata_prtdev(cdp->device, "%s ", - (cdp->cap.media & MST_WRITE_DVDR) ? "DVDR" : - (cdp->cap.media & MST_WRITE_DVDRAM) ? "DVDRAM" : - (cdp->cap.media & MST_WRITE_CDRW) ? "CDRW" : - (cdp->cap.media & MST_WRITE_CDR) ? "CDR" : - (cdp->cap.media & MST_READ_DVDROM) ? "DVDROM" : "CDROM"); - if (cdp->changer_info) - printf("with %d CD changer ", cdp->changer_info->slots); - printf("<%.40s/%.8s> at ata%d-%s %s\n", - cdp->device->param->model, cdp->device->param->revision, - device_get_unit(cdp->device->channel->dev), - (cdp->device->unit == ATA_MASTER) ? "master" : "slave", - ata_mode2str(cdp->device->mode) ); - } -} - -static __inline void -lba2msf(u_int32_t lba, u_int8_t *m, u_int8_t *s, u_int8_t *f) -{ - lba += 150; - lba &= 0xffffff; - *m = lba / (60 * 75); - lba %= (60 * 75); - *s = lba / 75; - *f = lba % 75; -} - -static __inline u_int32_t -msf2lba(u_int8_t m, u_int8_t s, u_int8_t f) -{ - return (m * 60 + s) * 75 + f - 150; -} - -static int -acd_geom_access(struct g_provider *pp, int dr, int dw, int de) -{ - struct acd_softc *cdp; - struct ata_request *request; - int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - int timeout = 60, track; - - - cdp = pp->geom->softc; - if (cdp->device->flags & ATA_D_DETACHING) - return ENXIO; - - if (!(request = ata_alloc_request())) - return ENOMEM; - - /* wait if drive is not finished loading the medium */ - while (timeout--) { - bzero(request, sizeof(struct ata_request)); - request->device = cdp->device; - request->driver = cdp; - bcopy(ccb, request->u.atapi.ccb, 16); - request->flags = ATA_R_ATAPI; - request->timeout = 5; - ata_queue_request(request); - if (!request->error && - (request->u.atapi.sense_data.sense_key == 2 || - request->u.atapi.sense_data.sense_key == 7) && - request->u.atapi.sense_data.asc == 4 && - request->u.atapi.sense_data.ascq == 1) - tsleep(&timeout, PRIBIO, "acdld", hz / 2); - else - break; - } - ata_free_request(request); - - if (pp->acr == 0) { - if (cdp->changer_info && cdp->slot != cdp->changer_info->current_slot) { - acd_select_slot(cdp); - tsleep(&cdp->changer_info, PRIBIO, "acdopn", 0); - } - acd_prevent_allow(cdp, 1); - cdp->flags |= F_LOCKED; - acd_read_toc(cdp); - } +acd_geom_detach(void *arg, int flag) +{ + struct ata_channel *ch = device_get_softc(device_get_parent(arg)); + struct ata_device *atadev = device_get_softc(arg); + struct acd_softc *cdp = device_get_ivars(arg); - if (dr + pp->acr == 0) { - if (cdp->changer_info && cdp->slot != cdp->changer_info->current_slot) { - acd_select_slot(cdp); - tsleep(&cdp->changer_info, PRIBIO, "acdclo", 0); - } - acd_prevent_allow(cdp, 0); - cdp->flags &= ~F_LOCKED; - } + /* signal geom so we dont get any further requests */ + g_wither_geom(cdp->gp, ENXIO); - if ((track = pp->index)) { - pp->sectorsize = (cdp->toc.tab[track - 1].control & 4) ? 2048 : 2352; - pp->mediasize = ntohl(cdp->toc.tab[track].addr.lba) - - ntohl(cdp->toc.tab[track - 1].addr.lba); - } - else { - pp->sectorsize = cdp->block_size; - pp->mediasize = cdp->disk_size; - } - pp->mediasize *= pp->sectorsize; + /* fail requests on the queue and any thats "in flight" for this device */ + ata_fail_requests(ch, arg); - return 0; + /* dont leave anything behind */ + device_set_ivars(arg, NULL); + free(cdp, M_ACD); + device_set_softc(arg, NULL); + free(atadev, M_ATA); } static int acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct thread *td) { - struct acd_softc *cdp = pp->geom->softc; - int error = 0, nocopyout; + device_t dev = pp->geom->softc; + struct ata_device *atadev = device_get_softc(dev); + struct acd_softc *cdp = device_get_ivars(dev); + int error = 0, nocopyout = 0; if (!cdp) return ENXIO; - if (cdp->changer_info && cdp->slot != cdp->changer_info->current_slot) { - acd_select_slot(cdp); - tsleep(&cdp->changer_info, PRIBIO, "acdctl", 0); - } - if (cdp->device->flags & ATA_D_MEDIA_CHANGED) + if (atadev->flags & ATA_D_MEDIA_CHANGED) { switch (cmd) { case CDIOCRESET: - acd_test_ready(cdp->device); + acd_test_ready(dev); break; default: - acd_read_toc(cdp); - acd_prevent_allow(cdp, 1); + acd_read_toc(dev); + acd_prevent_allow(dev, 1); cdp->flags |= F_LOCKED; break; } - nocopyout = 0; + } + switch (cmd) { case CDIOCRESUME: - error = acd_pause_resume(cdp, 1); + error = acd_pause_resume(dev, 1); break; case CDIOCPAUSE: - error = acd_pause_resume(cdp, 0); + error = acd_pause_resume(dev, 0); break; case CDIOCSTART: - error = acd_start_stop(cdp, 1); + error = acd_start_stop(dev, 1); break; case CDIOCSTOP: - error = acd_start_stop(cdp, 0); + error = acd_start_stop(dev, 0); break; case CDIOCALLOW: - error = acd_prevent_allow(cdp, 0); + error = acd_prevent_allow(dev, 0); cdp->flags &= ~F_LOCKED; break; case CDIOCPREVENT: - error = acd_prevent_allow(cdp, 1); + error = acd_prevent_allow(dev, 1); cdp->flags |= F_LOCKED; break; @@ -607,7 +269,7 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct error = suser(td); if (error) break; - error = acd_test_ready(cdp->device); + error = acd_test_ready(dev); break; case CDIOCEJECT: @@ -615,13 +277,13 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct error = EBUSY; break; } - error = acd_tray(cdp, 0); + error = acd_tray(dev, 0); break; case CDIOCCLOSE: if (pp->acr != 1) break; - error = acd_tray(cdp, 1); + error = acd_tray(dev, 1); break; case CDIOREADTOCHEADER: @@ -739,9 +401,12 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct } break; +#if __FreeBSD_version > 600008 case CDIOCREADSUBCHANNEL_SYSSPACE: - nocopyout = 1; - /* Fallthrough */ + nocopyout = 1; + /* FALLTHROUGH */ + +#endif case CDIOCREADSUBCHANNEL: { struct ioc_read_subchannel *args = @@ -766,7 +431,7 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct ccb[1] = args->address_format & CD_MSF_FORMAT; - if ((error = ata_atapicmd(cdp->device, ccb, (caddr_t)&cdp->subchan, + if ((error = ata_atapicmd(atadev, ccb, (caddr_t)&cdp->subchan, sizeof(cdp->subchan), ATA_R_READ, 10))) break; @@ -780,17 +445,16 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct if (format == CD_TRACK_INFO) ccb[6] = args->track; - if ((error = ata_atapicmd(cdp->device, ccb, - (caddr_t)&cdp->subchan, + if ((error = ata_atapicmd(atadev, ccb, (caddr_t)&cdp->subchan, sizeof(cdp->subchan),ATA_R_READ,10))){ break; } } if (nocopyout == 0) { - error = copyout(&cdp->subchan, args->data, args->data_len); + error = copyout(&cdp->subchan, args->data, args->data_len); } else { - error = 0; - bcopy(&cdp->subchan, args->data, args->data_len); + error = 0; + bcopy(&cdp->subchan, args->data, args->data_len); } } break; @@ -800,7 +464,7 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct struct ioc_play_msf *args = (struct ioc_play_msf *)addr; error = - acd_play(cdp, + acd_play(dev, msf2lba(args->start_m, args->start_s, args->start_f), msf2lba(args->end_m, args->end_s, args->end_f)); } @@ -810,7 +474,7 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct { struct ioc_play_blocks *args = (struct ioc_play_blocks *)addr; - error = acd_play(cdp, args->blk, args->blk + args->len); + error = acd_play(dev, args->blk, args->blk + args->len); } break; @@ -834,7 +498,7 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct error = EINVAL; break; } - error = acd_play(cdp, ntohl(cdp->toc.tab[t1].addr.lba), + error = acd_play(dev, ntohl(cdp->toc.tab[t1].addr.lba), ntohl(cdp->toc.tab[t2].addr.lba)); } break; @@ -843,7 +507,7 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct { struct ioc_vol *arg = (struct ioc_vol *)addr; - if ((error = acd_mode_sense(cdp, ATAPI_CDROM_AUDIO_PAGE, + if ((error = acd_mode_sense(dev, ATAPI_CDROM_AUDIO_PAGE, (caddr_t)&cdp->au, sizeof(cdp->au)))) break; @@ -862,14 +526,14 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct { struct ioc_vol *arg = (struct ioc_vol *)addr; - if ((error = acd_mode_sense(cdp, ATAPI_CDROM_AUDIO_PAGE, + if ((error = acd_mode_sense(dev, ATAPI_CDROM_AUDIO_PAGE, (caddr_t)&cdp->au, sizeof(cdp->au)))) break; if (cdp->au.page_code != ATAPI_CDROM_AUDIO_PAGE) { error = EIO; break; } - if ((error = acd_mode_sense(cdp, ATAPI_CDROM_AUDIO_PAGE_MASK, + if ((error = acd_mode_sense(dev, ATAPI_CDROM_AUDIO_PAGE_MASK, (caddr_t)&cdp->aumask, sizeof(cdp->aumask)))) break; @@ -880,7 +544,7 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct cdp->au.port[1].volume = arg->vol[1] & cdp->aumask.port[1].volume; cdp->au.port[2].volume = arg->vol[2] & cdp->aumask.port[2].volume; cdp->au.port[3].volume = arg->vol[3] & cdp->aumask.port[3].volume; - error = acd_mode_select(cdp, (caddr_t)&cdp->au, sizeof(cdp->au)); + error = acd_mode_select(dev, (caddr_t)&cdp->au, sizeof(cdp->au)); } break; @@ -888,40 +552,40 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct { struct ioc_patch *arg = (struct ioc_patch *)addr; - error = acd_setchan(cdp, arg->patch[0], arg->patch[1], + error = acd_setchan(dev, arg->patch[0], arg->patch[1], arg->patch[2], arg->patch[3]); } break; case CDIOCSETMONO: - error = acd_setchan(cdp, CHANNEL_0|CHANNEL_1, CHANNEL_0|CHANNEL_1, 0,0); + error = acd_setchan(dev, CHANNEL_0|CHANNEL_1, CHANNEL_0|CHANNEL_1, 0,0); break; case CDIOCSETSTEREO: - error = acd_setchan(cdp, CHANNEL_0, CHANNEL_1, 0, 0); + error = acd_setchan(dev, CHANNEL_0, CHANNEL_1, 0, 0); break; case CDIOCSETMUTE: - error = acd_setchan(cdp, 0, 0, 0, 0); + error = acd_setchan(dev, 0, 0, 0, 0); break; case CDIOCSETLEFT: - error = acd_setchan(cdp, CHANNEL_0, CHANNEL_0, 0, 0); + error = acd_setchan(dev, CHANNEL_0, CHANNEL_0, 0, 0); break; case CDIOCSETRIGHT: - error = acd_setchan(cdp, CHANNEL_1, CHANNEL_1, 0, 0); + error = acd_setchan(dev, CHANNEL_1, CHANNEL_1, 0, 0); break; case CDRIOCBLANK: - error = acd_blank(cdp, (*(int *)addr)); + error = acd_blank(dev, (*(int *)addr)); break; case CDRIOCNEXTWRITEABLEADDR: { struct acd_track_info track_info; - if ((error = acd_read_track_info(cdp, 0xff, &track_info))) + if ((error = acd_read_track_info(dev, 0xff, &track_info))) break; if (!track_info.nwa_valid) { @@ -933,19 +597,19 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct break; case CDRIOCINITWRITER: - error = acd_init_writer(cdp, (*(int *)addr)); + error = acd_init_writer(dev, (*(int *)addr)); break; case CDRIOCINITTRACK: - error = acd_init_track(cdp, (struct cdr_track *)addr); + error = acd_init_track(dev, (struct cdr_track *)addr); break; case CDRIOCFLUSH: - error = acd_flush(cdp); + error = acd_flush(dev); break; case CDRIOCFIXATE: - error = acd_fixate(cdp, (*(int *)addr)); + error = acd_fixate(dev, (*(int *)addr)); break; case CDRIOCREADSPEED: @@ -955,7 +619,7 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct /* Preserve old behavior: units in multiples of CDROM speed */ if (speed < 177) speed *= 177; - error = acd_set_speed(cdp, speed, CDR_MAX_SPEED); + error = acd_set_speed(dev, speed, CDR_MAX_SPEED); } break; @@ -965,7 +629,7 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct if (speed < 177) speed *= 177; - error = acd_set_speed(cdp, CDR_MAX_SPEED, speed); + error = acd_set_speed(dev, CDR_MAX_SPEED, speed); } break; @@ -975,43 +639,43 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct case CDRIOCSETBLOCKSIZE: cdp->block_size = *(int *)addr; - pp->sectorsize = cdp->block_size; /* hack for GEOM SOS */ - acd_set_ioparm(cdp); + pp->sectorsize = cdp->block_size; /* hack for GEOM SOS */ + acd_set_ioparm(dev); break; case CDRIOCGETPROGRESS: - error = acd_get_progress(cdp, (int *)addr); + error = acd_get_progress(dev, (int *)addr); break; case CDRIOCSENDCUE: - error = acd_send_cue(cdp, (struct cdr_cuesheet *)addr); + error = acd_send_cue(dev, (struct cdr_cuesheet *)addr); break; case CDRIOCREADFORMATCAPS: - error = acd_read_format_caps(cdp, (struct cdr_format_capacities *)addr); + error = acd_read_format_caps(dev, (struct cdr_format_capacities *)addr); break; case CDRIOCFORMAT: - error = acd_format(cdp, (struct cdr_format_params *)addr); + error = acd_format(dev, (struct cdr_format_params *)addr); break; case DVDIOCREPORTKEY: if (cdp->cap.media & MST_READ_DVDROM) - error = acd_report_key(cdp, (struct dvd_authinfo *)addr); + error = acd_report_key(dev, (struct dvd_authinfo *)addr); else error = EINVAL; break; case DVDIOCSENDKEY: if (cdp->cap.media & MST_READ_DVDROM) - error = acd_send_key(cdp, (struct dvd_authinfo *)addr); + error = acd_send_key(dev, (struct dvd_authinfo *)addr); else error = EINVAL; break; case DVDIOCREADSTRUCTURE: if (cdp->cap.media & MST_READ_DVDROM) - error = acd_read_structure(cdp, (struct dvd_struct *)addr); + error = acd_read_structure(dev, (struct dvd_struct *)addr); else error = EINVAL; break; @@ -1022,16 +686,69 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct return error; } -static void -acd_geom_start(struct bio *bp) +static int +acd_geom_access(struct g_provider *pp, int dr, int dw, int de) { - struct acd_softc *cdp = bp->bio_to->geom->softc; + device_t dev = pp->geom->softc; + struct acd_softc *cdp = device_get_ivars(dev); + struct ata_request *request; + int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + int timeout = 60, track; - if (cdp->device->flags & ATA_D_DETACHING) { - g_io_deliver(bp, ENXIO); - return; + if (!(request = ata_alloc_request())) + return ENOMEM; + + /* wait if drive is not finished loading the medium */ + while (timeout--) { + bzero(request, sizeof(struct ata_request)); + request->dev = dev; + bcopy(ccb, request->u.atapi.ccb, 16); + request->flags = ATA_R_ATAPI; + request->timeout = 5; + ata_queue_request(request); + if (!request->error && + (request->u.atapi.sense_data.sense_key == 2 || + request->u.atapi.sense_data.sense_key == 7) && + request->u.atapi.sense_data.asc == 4 && + request->u.atapi.sense_data.ascq == 1) + tsleep(&timeout, PRIBIO, "acdld", hz / 2); + else + break; + } + ata_free_request(request); + + if (pp->acr == 0) { + acd_prevent_allow(dev, 1); + cdp->flags |= F_LOCKED; + acd_read_toc(dev); + } + + if (dr + pp->acr == 0) { + acd_prevent_allow(dev, 0); + cdp->flags &= ~F_LOCKED; } + if ((track = pp->index)) { + pp->sectorsize = (cdp->toc.tab[track - 1].control & 4) ? 2048 : 2352; + pp->mediasize = ntohl(cdp->toc.tab[track].addr.lba) - + ntohl(cdp->toc.tab[track - 1].addr.lba); + } + else { + pp->sectorsize = cdp->block_size; + pp->mediasize = cdp->disk_size; + } + pp->mediasize *= pp->sectorsize; + + return 0; +} + +static void +acd_geom_start(struct bio *bp) +{ + device_t dev = bp->bio_to->geom->softc; + struct acd_softc *cdp = device_get_ivars(dev); + if (bp->bio_cmd != BIO_READ && bp->bio_cmd != BIO_WRITE) { g_io_deliver(bp, EOPNOTSUPP); return; @@ -1044,10 +761,8 @@ acd_geom_start(struct bio *bp) /* GEOM classes must do their own request limiting */ if (bp->bio_length <= cdp->iomax) { - mtx_lock(&cdp->queue_mtx); bp->bio_pblkno = bp->bio_offset / bp->bio_to->sectorsize; - bioq_disksort(&cdp->queue, bp); - mtx_unlock(&cdp->queue_mtx); + acd_strategy(bp); } else { u_int pos, size = cdp->iomax - cdp->iomax % bp->bio_to->sectorsize; @@ -1063,59 +778,25 @@ acd_geom_start(struct bio *bp) bp2->bio_offset += pos; bp2->bio_data += pos; bp2->bio_length = MIN(size, bp->bio_length - pos); - mtx_lock(&cdp->queue_mtx); bp2->bio_pblkno = bp2->bio_offset / bp2->bio_to->sectorsize; - bioq_disksort(&cdp->queue, bp2); - mtx_unlock(&cdp->queue_mtx); + acd_strategy(bp2); } } - ata_start(cdp->device->channel); } static void -acd_start(struct ata_device *atadev) +acd_strategy(struct bio *bp) { - struct acd_softc *cdp = atadev->softc; - struct bio *bp; + device_t dev = bp->bio_to->geom->softc; + struct ata_device *atadev = device_get_softc(dev); + struct acd_softc *cdp = device_get_ivars(dev); struct ata_request *request; u_int32_t lba, lastlba, count; int8_t ccb[16]; int track, blocksize; - if (cdp->changer_info) { - int i; - - cdp = cdp->driver[cdp->changer_info->current_slot]; - mtx_lock(&cdp->queue_mtx); - bp = bioq_first(&cdp->queue); - mtx_unlock(&cdp->queue_mtx); - - /* check for work pending on any other slot */ - for (i = 0; i < cdp->changer_info->slots; i++) { - if (i == cdp->changer_info->current_slot) - continue; - mtx_lock(&cdp->queue_mtx); - if (bioq_first(&(cdp->driver[i]->queue))) { - if (!bp || time_second > (cdp->timestamp + 10)) { - mtx_unlock(&cdp->queue_mtx); - acd_select_slot(cdp->driver[i]); - return; - } - } - mtx_unlock(&cdp->queue_mtx); - - } - } - mtx_lock(&cdp->queue_mtx); - bp = bioq_first(&cdp->queue); - if (bp) - bioq_remove(&cdp->queue, bp); - mtx_unlock(&cdp->queue_mtx); - if (!bp) - return; - /* reject all queued entries if media changed */ - if (cdp->device->flags & ATA_D_MEDIA_CHANGED) { + if (atadev->flags & ATA_D_MEDIA_CHANGED) { g_io_deliver(bp, EIO); return; } @@ -1179,10 +860,10 @@ acd_start(struct ata_device *atadev) g_io_deliver(bp, ENOMEM); return; } - request->device = atadev; + request->dev = dev; request->driver = bp; bcopy(ccb, request->u.atapi.ccb, - (request->device->param->config & ATA_PROTO_MASK) == + (atadev->param.config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12 ? 16 : 12); request->data = bp->bio_data; request->bytecount = count * blocksize; @@ -1191,7 +872,7 @@ acd_start(struct ata_device *atadev) request->retries = 2; request->callback = acd_done; request->flags = ATA_R_ATAPI; - if (request->device->mode >= ATA_DMA) + if (atadev->mode >= ATA_DMA) request->flags |= ATA_R_DMA; switch (bp->bio_cmd) { case BIO_READ: @@ -1201,7 +882,7 @@ acd_start(struct ata_device *atadev) request->flags |= ATA_R_WRITE; break; default: - ata_prtdev(atadev, "unknown BIO operation\n"); + device_printf(dev, "unknown BIO operation\n"); ata_free_request(request); g_io_deliver(bp, EIO); return; @@ -1220,30 +901,61 @@ acd_done(struct ata_request *request) ata_free_request(request); } +static void +acd_set_ioparm(device_t dev) +{ + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct acd_softc *cdp = device_get_ivars(dev); + + if (ch->dma) + cdp->iomax = min(ch->dma->max_iosize, 65534); + else + cdp->iomax = min(DFLTPHYS, 65534); +} + static void -acd_read_toc(struct acd_softc *cdp) +lba2msf(u_int32_t lba, u_int8_t *m, u_int8_t *s, u_int8_t *f) { - int track, ntracks, len; + lba += 150; + lba &= 0xffffff; + *m = lba / (60 * 75); + lba %= (60 * 75); + *s = lba / 75; + *f = lba % 75; +} + +static u_int32_t +msf2lba(u_int8_t m, u_int8_t s, u_int8_t f) +{ + return (m * 60 + s) * 75 + f - 150; +} + +static void +acd_read_toc(device_t dev) +{ + struct ata_device *atadev = device_get_softc(dev); + struct acd_softc *cdp = device_get_ivars(dev); + struct g_provider *pp; u_int32_t sizes[2]; int8_t ccb[16]; - struct g_provider *pp; + int track, ntracks, len; - if (acd_test_ready(cdp->device)) + if (acd_test_ready(dev)) return; - if (!(cdp->device->flags & ATA_D_MEDIA_CHANGED)) + if (!(atadev->flags & ATA_D_MEDIA_CHANGED)) return; - cdp->device->flags &= ~ATA_D_MEDIA_CHANGED; + atadev->flags &= ~ATA_D_MEDIA_CHANGED; bzero(&cdp->toc, sizeof(cdp->toc)); bzero(ccb, sizeof(ccb)); - cdp->disk_size = -1; /* hack for GEOM SOS */ + cdp->disk_size = -1; /* hack for GEOM SOS */ len = sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry); ccb[0] = ATAPI_READ_TOC; ccb[7] = len>>8; ccb[8] = len; - if (ata_atapicmd(cdp->device, ccb, (caddr_t)&cdp->toc, len, + if (ata_atapicmd(atadev, ccb, (caddr_t)&cdp->toc, len, ATA_R_READ | ATA_R_QUIET, 30)) { bzero(&cdp->toc, sizeof(cdp->toc)); return; @@ -1259,7 +971,7 @@ acd_read_toc(struct acd_softc *cdp) ccb[0] = ATAPI_READ_TOC; ccb[7] = len>>8; ccb[8] = len; - if (ata_atapicmd(cdp->device, ccb, (caddr_t)&cdp->toc, len, + if (ata_atapicmd(atadev, ccb, (caddr_t)&cdp->toc, len, ATA_R_READ | ATA_R_QUIET, 30)) { bzero(&cdp->toc, sizeof(cdp->toc)); return; @@ -1267,10 +979,10 @@ acd_read_toc(struct acd_softc *cdp) cdp->toc.hdr.len = ntohs(cdp->toc.hdr.len); cdp->block_size = (cdp->toc.tab[0].control & 4) ? 2048 : 2352; - acd_set_ioparm(cdp); + acd_set_ioparm(dev); bzero(ccb, sizeof(ccb)); ccb[0] = ATAPI_READ_CAPACITY; - if (ata_atapicmd(cdp->device, ccb, (caddr_t)sizes, sizeof(sizes), + if (ata_atapicmd(atadev, ccb, (caddr_t)sizes, sizeof(sizes), ATA_R_READ | ATA_R_QUIET, 30)) { bzero(&cdp->toc, sizeof(cdp->toc)); return; @@ -1280,7 +992,7 @@ acd_read_toc(struct acd_softc *cdp) for (track = 1; track <= ntracks; track ++) { if (cdp->pp[track] != NULL) continue; - pp = g_new_providerf(cdp->gp, "acd%dt%02d", cdp->lun, track); + pp = g_new_providerf(cdp->gp, "acd%dt%02d", device_get_unit(dev),track); pp->index = track; cdp->pp[track] = pp; g_error_provider(pp, 0); @@ -1295,9 +1007,9 @@ acd_read_toc(struct acd_softc *cdp) #ifdef ACD_DEBUG if (cdp->disk_size && cdp->toc.hdr.ending_track) { - ata_prtdev(cdp->device, "(%d sectors (%d bytes)), %d tracks ", - cdp->disk_size, cdp->block_size, - cdp->toc.hdr.ending_track - cdp->toc.hdr.starting_track + 1); + device_printd(dev, "(%d sectors (%d bytes)), %d tracks ", + cdp->disk_size, cdp->block_size, + cdp->toc.hdr.ending_track-cdp->toc.hdr.starting_track+1); if (cdp->toc.tab[0].control & 4) printf("%dMB\n", cdp->disk_size / 512); else @@ -1308,24 +1020,25 @@ acd_read_toc(struct acd_softc *cdp) } static int -acd_play(struct acd_softc *cdp, int start, int end) +acd_play(device_t dev, int start, int end) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16]; bzero(ccb, sizeof(ccb)); ccb[0] = ATAPI_PLAY_MSF; lba2msf(start, &ccb[3], &ccb[4], &ccb[5]); lba2msf(end, &ccb[6], &ccb[7], &ccb[8]); - return ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 10); + return ata_atapicmd(atadev, ccb, NULL, 0, 0, 10); } static int -acd_setchan(struct acd_softc *cdp, - u_int8_t c0, u_int8_t c1, u_int8_t c2, u_int8_t c3) +acd_setchan(device_t dev, u_int8_t c0, u_int8_t c1, u_int8_t c2, u_int8_t c3) { + struct acd_softc *cdp = device_get_ivars(dev); int error; - if ((error = acd_mode_sense(cdp, ATAPI_CDROM_AUDIO_PAGE, (caddr_t)&cdp->au, + if ((error = acd_mode_sense(dev, ATAPI_CDROM_AUDIO_PAGE, (caddr_t)&cdp->au, sizeof(cdp->au)))) return error; if (cdp->au.page_code != ATAPI_CDROM_AUDIO_PAGE) @@ -1335,81 +1048,36 @@ acd_setchan(struct acd_softc *cdp, cdp->au.port[1].channels = c1; cdp->au.port[2].channels = c2; cdp->au.port[3].channels = c3; - return acd_mode_select(cdp, (caddr_t)&cdp->au, sizeof(cdp->au)); -} - -static void -acd_load_done(struct ata_request *request) -{ - struct acd_softc *cdp = request->driver; - - /* finish the slot select and wakeup caller */ - cdp->changer_info->current_slot = cdp->slot; - cdp->driver[cdp->changer_info->current_slot]->timestamp = time_second; - wakeup(&cdp->changer_info); -} - -static void -acd_unload_done(struct ata_request *request) -{ - struct acd_softc *cdp = request->driver; - int8_t ccb[16] = { ATAPI_LOAD_UNLOAD, 0, 0, 0, 3, 0, 0, 0, - cdp->slot, 0, 0, 0, 0, 0, 0, 0 }; - - /* load the wanted slot */ - bcopy(ccb, request->u.atapi.ccb, - (request->device->param->config & ATA_PROTO_MASK) == - ATA_PROTO_ATAPI_12 ? 16 : 12); - request->callback = acd_load_done; - ata_queue_request(request); -} - -static void -acd_select_slot(struct acd_softc *cdp) -{ - struct ata_request *request; - int8_t ccb[16] = { ATAPI_LOAD_UNLOAD, 0, 0, 0, 2, 0, 0, 0, - cdp->changer_info->current_slot, 0, 0, 0, 0, 0, 0, 0 }; - - /* unload the current media from player */ - if (!(request = ata_alloc_request())) - return; - - request->device = cdp->device; - request->driver = cdp; - bcopy(ccb, request->u.atapi.ccb, - (request->device->param->config & ATA_PROTO_MASK) == - ATA_PROTO_ATAPI_12 ? 16 : 12); - request->timeout = 30; - request->callback = acd_unload_done; - request->flags |= (ATA_R_ATAPI | ATA_R_IMMEDIATE); - ata_queue_request(request); + return acd_mode_select(dev, (caddr_t)&cdp->au, sizeof(cdp->au)); } static int -acd_init_writer(struct acd_softc *cdp, int test_write) +acd_init_writer(device_t dev, int test_write) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16]; bzero(ccb, sizeof(ccb)); ccb[0] = ATAPI_REZERO; - ata_atapicmd(cdp->device, ccb, NULL, 0, ATA_R_QUIET, 60); + ata_atapicmd(atadev, ccb, NULL, 0, ATA_R_QUIET, 60); ccb[0] = ATAPI_SEND_OPC_INFO; ccb[1] = 0x01; - ata_atapicmd(cdp->device, ccb, NULL, 0, ATA_R_QUIET, 30); + ata_atapicmd(atadev, ccb, NULL, 0, ATA_R_QUIET, 30); return 0; } static int -acd_fixate(struct acd_softc *cdp, int multisession) +acd_fixate(device_t dev, int multisession) { + struct ata_device *atadev = device_get_softc(dev); + struct acd_softc *cdp = device_get_ivars(dev); int8_t ccb[16] = { ATAPI_CLOSE_TRACK, 0x01, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int timeout = 5*60*2; int error, dummy; struct write_param param; - if ((error = acd_mode_sense(cdp, ATAPI_CDROM_WRITE_PARAMETERS_PAGE, + if ((error = acd_mode_sense(dev, ATAPI_CDROM_WRITE_PARAMETERS_PAGE, (caddr_t)¶m, sizeof(param)))) return error; @@ -1419,24 +1087,24 @@ acd_fixate(struct acd_softc *cdp, int multisession) else param.session_type = CDR_SESS_NONE; - if ((error = acd_mode_select(cdp, (caddr_t)¶m, param.page_length + 10))) + if ((error = acd_mode_select(dev, (caddr_t)¶m, param.page_length + 10))) return error; - error = ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 30); + error = ata_atapicmd(atadev, ccb, NULL, 0, 0, 30); if (error) return error; /* some drives just return ready, wait for the expected fixate time */ - if ((error = acd_test_ready(cdp->device)) != EBUSY) { + if ((error = acd_test_ready(dev)) != EBUSY) { timeout = timeout / (cdp->cap.cur_write_speed / 177); tsleep(&error, PRIBIO, "acdfix", timeout * hz / 2); - return acd_test_ready(cdp->device); + return acd_test_ready(dev); } while (timeout-- > 0) { - if ((error = acd_get_progress(cdp, &dummy))) + if ((error = acd_get_progress(dev, &dummy))) return error; - if ((error = acd_test_ready(cdp->device)) != EBUSY) + if ((error = acd_test_ready(dev)) != EBUSY) return error; tsleep(&error, PRIBIO, "acdcld", hz / 2); } @@ -1444,12 +1112,13 @@ acd_fixate(struct acd_softc *cdp, int multisession) } static int -acd_init_track(struct acd_softc *cdp, struct cdr_track *track) +acd_init_track(device_t dev, struct cdr_track *track) { + struct acd_softc *cdp = device_get_ivars(dev); struct write_param param; int error; - if ((error = acd_mode_sense(cdp, ATAPI_CDROM_WRITE_PARAMETERS_PAGE, + if ((error = acd_mode_sense(dev, ATAPI_CDROM_WRITE_PARAMETERS_PAGE, (caddr_t)¶m, sizeof(param)))) return error; @@ -1519,30 +1188,31 @@ acd_init_track(struct acd_softc *cdp, struct cdr_track *track) param.session_format = CDR_SESS_CDROM_XA; break; } - acd_set_ioparm(cdp); - return acd_mode_select(cdp, (caddr_t)¶m, param.page_length + 10); + acd_set_ioparm(dev); + return acd_mode_select(dev, (caddr_t)¶m, param.page_length + 10); } static int -acd_flush(struct acd_softc *cdp) +acd_flush(device_t dev) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_SYNCHRONIZE_CACHE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - return ata_atapicmd(cdp->device, ccb, NULL, 0, ATA_R_QUIET, 60); + return ata_atapicmd(atadev, ccb, NULL, 0, ATA_R_QUIET, 60); } static int -acd_read_track_info(struct acd_softc *cdp, - int32_t lba, struct acd_track_info *info) +acd_read_track_info(device_t dev, int32_t lba, struct acd_track_info *info) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_READ_TRACK_INFO, 1, lba>>24, lba>>16, lba>>8, lba, 0, sizeof(*info)>>8, sizeof(*info), 0, 0, 0, 0, 0, 0, 0 }; int error; - if ((error = ata_atapicmd(cdp->device, ccb, (caddr_t)info, sizeof(*info), + if ((error = ata_atapicmd(atadev, ccb, (caddr_t)info, sizeof(*info), ATA_R_READ, 30))) return error; info->track_start_addr = ntohl(info->track_start_addr); @@ -1554,7 +1224,7 @@ acd_read_track_info(struct acd_softc *cdp, } static int -acd_get_progress(struct acd_softc *cdp, int *finished) +acd_get_progress(device_t dev, int *finished) { int8_t ccb[16] = { ATAPI_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -1564,8 +1234,7 @@ acd_get_progress(struct acd_softc *cdp, int *finished) if (!(request = ata_alloc_request())) return ENOMEM; - request->device = cdp->device; - request->driver = cdp; + request->dev = dev; bcopy(ccb, request->u.atapi.ccb, 16); request->data = dummy; request->bytecount = sizeof(dummy); @@ -1583,8 +1252,10 @@ acd_get_progress(struct acd_softc *cdp, int *finished) } static int -acd_send_cue(struct acd_softc *cdp, struct cdr_cuesheet *cuesheet) +acd_send_cue(device_t dev, struct cdr_cuesheet *cuesheet) { + struct ata_device *atadev = device_get_softc(dev); + struct acd_softc *cdp = device_get_ivars(dev); struct write_param param; int8_t ccb[16] = { ATAPI_SEND_CUE_SHEET, 0, 0, 0, 0, 0, cuesheet->len>>16, cuesheet->len>>8, cuesheet->len, @@ -1595,7 +1266,7 @@ acd_send_cue(struct acd_softc *cdp, struct cdr_cuesheet *cuesheet) int i; #endif - if ((error = acd_mode_sense(cdp, ATAPI_CDROM_WRITE_PARAMETERS_PAGE, + if ((error = acd_mode_sense(dev, ATAPI_CDROM_WRITE_PARAMETERS_PAGE, (caddr_t)¶m, sizeof(param)))) return error; @@ -1613,7 +1284,7 @@ acd_send_cue(struct acd_softc *cdp, struct cdr_cuesheet *cuesheet) if (cdp->cap.capabilities & MST_BURNPROOF) param.burnproof = 1; - if ((error = acd_mode_select(cdp, (caddr_t)¶m, param.page_length + 10))) + if ((error = acd_mode_select(dev, (caddr_t)¶m, param.page_length + 10))) return error; if (!(buffer = malloc(cuesheet->len, M_ACD, M_NOWAIT))) @@ -1629,15 +1300,16 @@ acd_send_cue(struct acd_softc *cdp, struct cdr_cuesheet *cuesheet) printf("\n%02x", buffer[i]); printf("\n"); #endif - error = ata_atapicmd(cdp->device, ccb, buffer, cuesheet->len, 0, 30); + error = ata_atapicmd(atadev, ccb, buffer, cuesheet->len, 0, 30); } free(buffer, M_ACD); return error; } static int -acd_report_key(struct acd_softc *cdp, struct dvd_authinfo *ai) +acd_report_key(device_t dev, struct dvd_authinfo *ai) { + struct ata_device *atadev = device_get_softc(dev); struct dvd_miscauth *d = NULL; u_int32_t lba = 0; int16_t length; @@ -1683,7 +1355,7 @@ acd_report_key(struct acd_softc *cdp, struct dvd_authinfo *ai) d->length = htons(length - 2); } - error = ata_atapicmd(cdp->device, ccb, (caddr_t)d, length, + error = ata_atapicmd(atadev, ccb, (caddr_t)d, length, ai->format == DVD_INVALIDATE_AGID ? 0 : ATA_R_READ,10); if (error) { free(d, M_ACD); @@ -1733,8 +1405,9 @@ acd_report_key(struct acd_softc *cdp, struct dvd_authinfo *ai) } static int -acd_send_key(struct acd_softc *cdp, struct dvd_authinfo *ai) +acd_send_key(device_t dev, struct dvd_authinfo *ai) { + struct ata_device *atadev = device_get_softc(dev); struct dvd_miscauth *d; int16_t length; int8_t ccb[16]; @@ -1772,14 +1445,15 @@ acd_send_key(struct acd_softc *cdp, struct dvd_authinfo *ai) ccb[9] = length & 0xff; ccb[10] = (ai->agid << 6) | ai->format; d->length = htons(length - 2); - error = ata_atapicmd(cdp->device, ccb, (caddr_t)d, length, 0, 10); + error = ata_atapicmd(atadev, ccb, (caddr_t)d, length, 0, 10); free(d, M_ACD); return error; } static int -acd_read_structure(struct acd_softc *cdp, struct dvd_struct *s) +acd_read_structure(device_t dev, struct dvd_struct *s) { + struct ata_device *atadev = device_get_softc(dev); struct dvd_miscauth *d; u_int16_t length; int8_t ccb[16]; @@ -1831,7 +1505,7 @@ acd_read_structure(struct acd_softc *cdp, struct dvd_struct *s) ccb[8] = (length >> 8) & 0xff; ccb[9] = length & 0xff; ccb[10] = s->agid << 6; - error = ata_atapicmd(cdp->device, ccb, (caddr_t)d, length, ATA_R_READ, 30); + error = ata_atapicmd(atadev, ccb, (caddr_t)d, length, ATA_R_READ, 30); if (error) { free(d, M_ACD); return error; @@ -1884,74 +1558,81 @@ acd_read_structure(struct acd_softc *cdp, struct dvd_struct *s) } static int -acd_tray(struct acd_softc *cdp, int close) +acd_tray(device_t dev, int close) { + struct ata_device *atadev = device_get_softc(dev); + struct acd_softc *cdp = device_get_ivars(dev); int error = ENODEV; if (cdp->cap.mechanism & MST_EJECT) { if (close) { - if (!(error = acd_start_stop(cdp, 3))) { - acd_read_toc(cdp); - acd_prevent_allow(cdp, 1); + if (!(error = acd_start_stop(dev, 3))) { + acd_read_toc(dev); + acd_prevent_allow(dev, 1); cdp->flags |= F_LOCKED; } } else { - acd_start_stop(cdp, 0); - acd_prevent_allow(cdp, 0); + acd_start_stop(dev, 0); + acd_prevent_allow(dev, 0); cdp->flags &= ~F_LOCKED; - cdp->device->flags |= ATA_D_MEDIA_CHANGED; - error = acd_start_stop(cdp, 2); + atadev->flags |= ATA_D_MEDIA_CHANGED; + error = acd_start_stop(dev, 2); } } return error; } static int -acd_blank(struct acd_softc *cdp, int blanktype) +acd_blank(device_t dev, int blanktype) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_BLANK, 0x10 | (blanktype & 0x7), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - cdp->device->flags |= ATA_D_MEDIA_CHANGED; - return ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 30); + atadev->flags |= ATA_D_MEDIA_CHANGED; + return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30); } static int -acd_prevent_allow(struct acd_softc *cdp, int lock) +acd_prevent_allow(device_t dev, int lock) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - return ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 30); + return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30); } static int -acd_start_stop(struct acd_softc *cdp, int start) +acd_start_stop(device_t dev, int start) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_START_STOP, 0, 0, 0, start, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - return ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 30); + return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30); } static int -acd_pause_resume(struct acd_softc *cdp, int pause) +acd_pause_resume(device_t dev, int pause) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_PAUSE, 0, 0, 0, 0, 0, 0, 0, pause, 0, 0, 0, 0, 0, 0, 0 }; - return ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 30); + return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30); } static int -acd_mode_sense(struct acd_softc *cdp, int page, caddr_t pagebuf, int pagesize) +acd_mode_sense(device_t dev, int page, caddr_t pagebuf, int pagesize) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_MODE_SENSE_BIG, 0, page, 0, 0, 0, 0, pagesize>>8, pagesize, 0, 0, 0, 0, 0, 0, 0 }; int error; - error = ata_atapicmd(cdp->device, ccb, pagebuf, pagesize, ATA_R_READ, 10); + error = ata_atapicmd(atadev, ccb, pagebuf, pagesize, ATA_R_READ, 10); #ifdef ACD_DEBUG atapi_dump("acd: mode sense ", pagebuf, pagesize); #endif @@ -1959,40 +1640,42 @@ acd_mode_sense(struct acd_softc *cdp, int page, caddr_t pagebuf, int pagesize) } static int -acd_mode_select(struct acd_softc *cdp, caddr_t pagebuf, int pagesize) +acd_mode_select(device_t dev, caddr_t pagebuf, int pagesize) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_MODE_SELECT_BIG, 0x10, 0, 0, 0, 0, 0, pagesize>>8, pagesize, 0, 0, 0, 0, 0, 0, 0 }; #ifdef ACD_DEBUG - ata_prtdev(cdp->device, - "modeselect pagesize=%d\n", pagesize); + device_printf(dev, "modeselect pagesize=%d\n", pagesize); atapi_dump("mode select ", pagebuf, pagesize); #endif - return ata_atapicmd(cdp->device, ccb, pagebuf, pagesize, 0, 30); + return ata_atapicmd(atadev, ccb, pagebuf, pagesize, 0, 30); } static int -acd_set_speed(struct acd_softc *cdp, int rdspeed, int wrspeed) +acd_set_speed(device_t dev, int rdspeed, int wrspeed) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_SET_SPEED, 0, rdspeed >> 8, rdspeed, wrspeed >> 8, wrspeed, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int error; - error = ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 30); + error = ata_atapicmd(atadev, ccb, NULL, 0, 0, 30); if (!error) - acd_get_cap(cdp); + acd_get_cap(dev); return error; } static void -acd_get_cap(struct acd_softc *cdp) +acd_get_cap(device_t dev) { + struct acd_softc *cdp = device_get_ivars(dev); int count; /* get drive capabilities, some bugridden drives needs this repeated */ for (count = 0 ; count < 5 ; count++) { - if (!acd_mode_sense(cdp, ATAPI_CDROM_CAP_PAGE, + if (!acd_mode_sense(dev, ATAPI_CDROM_CAP_PAGE, (caddr_t)&cdp->cap, sizeof(cdp->cap)) && cdp->cap.page_code == ATAPI_CDROM_CAP_PAGE) { cdp->cap.max_read_speed = ntohs(cdp->cap.max_read_speed); @@ -2006,34 +1689,277 @@ acd_get_cap(struct acd_softc *cdp) } static int -acd_read_format_caps(struct acd_softc *cdp, struct cdr_format_capacities *caps) +acd_read_format_caps(device_t dev, struct cdr_format_capacities *caps) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_READ_FORMAT_CAPACITIES, 0, 0, 0, 0, 0, 0, (sizeof(struct cdr_format_capacities) >> 8) & 0xff, sizeof(struct cdr_format_capacities) & 0xff, 0, 0, 0, 0, 0, 0, 0 }; - return ata_atapicmd(cdp->device, ccb, (caddr_t)caps, + return ata_atapicmd(atadev, ccb, (caddr_t)caps, sizeof(struct cdr_format_capacities), ATA_R_READ, 30); } static int -acd_format(struct acd_softc *cdp, struct cdr_format_params* params) +acd_format(device_t dev, struct cdr_format_params* params) { - int error; + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_FORMAT, 0x11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + int error; - error = ata_atapicmd(cdp->device, ccb, (u_int8_t *)params, + error = ata_atapicmd(atadev, ccb, (u_int8_t *)params, sizeof(struct cdr_format_params), 0, 30); return error; } static int -acd_test_ready(struct ata_device *atadev) +acd_test_ready(device_t dev) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30); } + +static void +acd_describe(device_t dev) +{ + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_device *atadev = device_get_softc(dev); + struct acd_softc *cdp = device_get_ivars(dev); + int comma = 0; + char *mechanism; + + if (bootverbose) { + device_printf(dev, "<%.40s/%.8s> %s drive at ata%d as %s\n", + atadev->param.model, atadev->param.revision, + (cdp->cap.media & MST_WRITE_DVDR) ? "DVDR" : + (cdp->cap.media & MST_WRITE_DVDRAM) ? "DVDRAM" : + (cdp->cap.media & MST_WRITE_CDRW) ? "CDRW" : + (cdp->cap.media & MST_WRITE_CDR) ? "CDR" : + (cdp->cap.media & MST_READ_DVDROM) ? "DVDROM":"CDROM", + device_get_unit(ch->dev), + (atadev->unit == ATA_MASTER) ? "master" : "slave"); + + device_printf(dev, "%s", ""); + if (cdp->cap.cur_read_speed) { + printf("read %dKB/s", cdp->cap.cur_read_speed * 1000 / 1024); + if (cdp->cap.max_read_speed) + printf(" (%dKB/s)", cdp->cap.max_read_speed * 1000 / 1024); + if ((cdp->cap.cur_write_speed) && + (cdp->cap.media & (MST_WRITE_CDR | MST_WRITE_CDRW | + MST_WRITE_DVDR | MST_WRITE_DVDRAM))) { + printf(" write %dKB/s", cdp->cap.cur_write_speed * 1000 / 1024); + if (cdp->cap.max_write_speed) + printf(" (%dKB/s)", cdp->cap.max_write_speed * 1000 / 1024); + } + comma = 1; + } + if (cdp->cap.buf_size) { + printf("%s %dKB buffer", comma ? "," : "", cdp->cap.buf_size); + comma = 1; + } + printf("%s %s\n", comma ? "," : "", ata_mode2str(atadev->mode)); + + device_printf(dev, "Reads:"); + comma = 0; + if (cdp->cap.media & MST_READ_CDR) { + printf(" CDR"); comma = 1; + } + if (cdp->cap.media & MST_READ_CDRW) { + printf("%s CDRW", comma ? "," : ""); comma = 1; + } + if (cdp->cap.capabilities & MST_READ_CDDA) { + if (cdp->cap.capabilities & MST_CDDA_STREAM) + printf("%s CDDA stream", comma ? "," : ""); + else + printf("%s CDDA", comma ? "," : ""); + comma = 1; + } + if (cdp->cap.media & MST_READ_DVDROM) { + printf("%s DVDROM", comma ? "," : ""); comma = 1; + } + if (cdp->cap.media & MST_READ_DVDR) { + printf("%s DVDR", comma ? "," : ""); comma = 1; + } + if (cdp->cap.media & MST_READ_DVDRAM) { + printf("%s DVDRAM", comma ? "," : ""); comma = 1; + } + if (cdp->cap.media & MST_READ_PACKET) + printf("%s packet", comma ? "," : ""); + + printf("\n"); + device_printf(dev, "Writes:"); + if (cdp->cap.media & (MST_WRITE_CDR | MST_WRITE_CDRW | + MST_WRITE_DVDR | MST_WRITE_DVDRAM)) { + comma = 0; + if (cdp->cap.media & MST_WRITE_CDR) { + printf(" CDR" ); comma = 1; + } + if (cdp->cap.media & MST_WRITE_CDRW) { + printf("%s CDRW", comma ? "," : ""); comma = 1; + } + if (cdp->cap.media & MST_WRITE_DVDR) { + printf("%s DVDR", comma ? "," : ""); comma = 1; + } + if (cdp->cap.media & MST_WRITE_DVDRAM) { + printf("%s DVDRAM", comma ? "," : ""); comma = 1; + } + if (cdp->cap.media & MST_WRITE_TEST) { + printf("%s test write", comma ? "," : ""); comma = 1; + } + if (cdp->cap.capabilities & MST_BURNPROOF) + printf("%s burnproof", comma ? "," : ""); + } + printf("\n"); + if (cdp->cap.capabilities & MST_AUDIO_PLAY) { + device_printf(dev, "Audio: "); + if (cdp->cap.capabilities & MST_AUDIO_PLAY) + printf("play"); + if (cdp->cap.max_vol_levels) + printf(", %d volume levels", cdp->cap.max_vol_levels); + printf("\n"); + } + device_printf(dev, "Mechanism: "); + switch (cdp->cap.mechanism & MST_MECH_MASK) { + case MST_MECH_CADDY: + mechanism = "caddy"; break; + case MST_MECH_TRAY: + mechanism = "tray"; break; + case MST_MECH_POPUP: + mechanism = "popup"; break; + case MST_MECH_CHANGER: + mechanism = "changer"; break; + case MST_MECH_CARTRIDGE: + mechanism = "cartridge"; break; + default: + mechanism = 0; break; + } + if (mechanism) + printf("%s%s", (cdp->cap.mechanism & MST_EJECT) ? + "ejectable " : "", mechanism); + else if (cdp->cap.mechanism & MST_EJECT) + printf("ejectable"); + + if (cdp->cap.mechanism & MST_LOCKABLE) + printf((cdp->cap.mechanism & MST_LOCKED) ? ", locked":", unlocked"); + if (cdp->cap.mechanism & MST_PREVENT) + printf(", lock protected"); + printf("\n"); + + if ((cdp->cap.mechanism & MST_MECH_MASK) != MST_MECH_CHANGER) { + device_printf(dev, "Medium: "); + switch (cdp->cap.medium_type & MST_TYPE_MASK_HIGH) { + case MST_CDROM: + printf("CD-ROM "); break; + case MST_CDR: + printf("CD-R "); break; + case MST_CDRW: + printf("CD-RW "); break; + case MST_DOOR_OPEN: + printf("door open"); break; + case MST_NO_DISC: + printf("no/blank disc"); break; + case MST_FMT_ERROR: + printf("medium format error"); break; + } + if ((cdp->cap.medium_type & MST_TYPE_MASK_HIGH)<MST_TYPE_MASK_HIGH){ + switch (cdp->cap.medium_type & MST_TYPE_MASK_LOW) { + case MST_DATA_120: + printf("120mm data disc"); break; + case MST_AUDIO_120: + printf("120mm audio disc"); break; + case MST_COMB_120: + printf("120mm data/audio disc"); break; + case MST_PHOTO_120: + printf("120mm photo disc"); break; + case MST_DATA_80: + printf("80mm data disc"); break; + case MST_AUDIO_80: + printf("80mm audio disc"); break; + case MST_COMB_80: + printf("80mm data/audio disc"); break; + case MST_PHOTO_80: + printf("80mm photo disc"); break; + case MST_FMT_NONE: + switch (cdp->cap.medium_type & MST_TYPE_MASK_HIGH) { + case MST_CDROM: + printf("unknown"); break; + case MST_CDR: + case MST_CDRW: + printf("blank"); break; + } + break; + default: + printf("unknown (0x%x)", cdp->cap.medium_type); break; + } + } + printf("\n"); + } + } + else { + device_printf(dev, "%s ", + (cdp->cap.media & MST_WRITE_DVDR) ? "DVDR" : + (cdp->cap.media & MST_WRITE_DVDRAM) ? "DVDRAM" : + (cdp->cap.media & MST_WRITE_CDRW) ? "CDRW" : + (cdp->cap.media & MST_WRITE_CDR) ? "CDR" : + (cdp->cap.media & MST_READ_DVDROM) ? "DVDROM" : + "CDROM"); + if (cdp->changer_info) + printf("with %d CD changer ", cdp->changer_info->slots); + printf("<%.40s/%.8s> at ata%d-%s %s\n", + atadev->param.model, atadev->param.revision, + device_get_unit(ch->dev), + (atadev->unit == ATA_MASTER) ? "master" : "slave", + ata_mode2str(atadev->mode) ); + } +} + +static device_method_t acd_methods[] = { + /* device interface */ + DEVMETHOD(device_identify, acd_identify), + DEVMETHOD(device_probe, acd_probe), + DEVMETHOD(device_attach, acd_attach), + DEVMETHOD(device_detach, acd_detach), + DEVMETHOD(device_shutdown, acd_shutdown), + + /* ATA methods */ + DEVMETHOD(ata_reinit, acd_reinit), + + { 0, 0 } +}; + +static driver_t acd_driver = { + "acd", + acd_methods, + sizeof(struct acd_softc) +}; + +static devclass_t acd_devclass; + +static int +acd_modevent(module_t mod, int what, void *arg) +{ + device_t *devs; + int ndevs, i; + + if (what == MOD_LOAD) { + g_modevent(0, what, &acd_class); + } + if (what == MOD_UNLOAD) { + if (!devclass_get_devices(acd_devclass, &devs, &ndevs) && devs) { + for (i = 0; i < ndevs; i++) + device_delete_child(device_get_parent(devs[i]), devs[i]); + free(devs, M_TEMP); + } + g_modevent(0, what, &acd_class); + } + return 0; +} + +DRIVER_MODULE(acd, ata, acd_driver, acd_devclass, acd_modevent, NULL); +MODULE_VERSION(acd, 1); +MODULE_DEPEND(acd, ata, 1, 1, 1); diff --git a/sys/dev/ata/atapi-cd.h b/sys/dev/ata/atapi-cd.h index 1618df5..ba16837 100644 --- a/sys/dev/ata/atapi-cd.h +++ b/sys/dev/ata/atapi-cd.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,48 +31,48 @@ /* CDROM Table Of Contents */ #define MAXTRK 99 struct toc { - struct ioc_toc_header hdr; - struct cd_toc_entry tab[MAXTRK + 1]; + struct ioc_toc_header hdr; + struct cd_toc_entry tab[MAXTRK + 1]; }; /* DVD CSS authentication */ struct dvd_miscauth { - u_int16_t length; - u_int16_t reserved; - u_int8_t data[2048]; + u_int16_t length; + u_int16_t reserved; + u_int8_t data[2048]; }; /* CDROM Audio Control Parameters Page */ struct audiopage { /* mode page data header */ - u_int16_t data_length; - u_int8_t medium_type; - u_int8_t dev_spec; - u_int8_t unused[2]; - u_int16_t blk_desc_len; + u_int16_t data_length; + u_int8_t medium_type; + u_int8_t dev_spec; + u_int8_t unused[2]; + u_int16_t blk_desc_len; /* audio control page */ - u_int8_t page_code; -#define ATAPI_CDROM_AUDIO_PAGE 0x0e + u_int8_t page_code; +#define ATAPI_CDROM_AUDIO_PAGE 0x0e #define ATAPI_CDROM_AUDIO_PAGE_MASK 0x4e - u_int8_t param_len; - u_int8_t flags; -#define CD_PA_SOTC 0x02 -#define CD_PA_IMMED 0x04 + u_int8_t param_len; + u_int8_t flags; +#define CD_PA_SOTC 0x02 +#define CD_PA_IMMED 0x04 - u_int8_t reserved3; - u_int8_t reserved4; - u_int8_t reserved5; - u_int16_t lb_per_sec; + u_int8_t reserved3; + u_int8_t reserved4; + u_int8_t reserved5; + u_int16_t lb_per_sec; struct port_control { - u_int8_t channels:4; -#define CHANNEL_0 1 -#define CHANNEL_1 2 -#define CHANNEL_2 4 -#define CHANNEL_3 8 + u_int8_t channels:4; +#define CHANNEL_0 1 +#define CHANNEL_1 2 +#define CHANNEL_2 4 +#define CHANNEL_3 8 - u_int8_t volume; + u_int8_t volume; } port[4]; }; @@ -80,241 +80,237 @@ struct audiopage { /* CDROM Capabilities and Mechanical Status Page */ struct cappage { /* mode page data header */ - u_int16_t data_length; - u_int8_t medium_type; -#define MST_TYPE_MASK_LOW 0x0f -#define MST_FMT_NONE 0x00 -#define MST_DATA_120 0x01 -#define MST_AUDIO_120 0x02 -#define MST_COMB_120 0x03 -#define MST_PHOTO_120 0x04 -#define MST_DATA_80 0x05 -#define MST_AUDIO_80 0x06 -#define MST_COMB_80 0x07 -#define MST_PHOTO_80 0x08 - -#define MST_TYPE_MASK_HIGH 0x70 -#define MST_CDROM 0x00 -#define MST_CDR 0x10 -#define MST_CDRW 0x20 - -#define MST_NO_DISC 0x70 -#define MST_DOOR_OPEN 0x71 -#define MST_FMT_ERROR 0x72 - - u_int8_t dev_spec; - u_int16_t unused; - u_int16_t blk_desc_len; + u_int16_t data_length; + u_int8_t medium_type; +#define MST_TYPE_MASK_LOW 0x0f +#define MST_FMT_NONE 0x00 +#define MST_DATA_120 0x01 +#define MST_AUDIO_120 0x02 +#define MST_COMB_120 0x03 +#define MST_PHOTO_120 0x04 +#define MST_DATA_80 0x05 +#define MST_AUDIO_80 0x06 +#define MST_COMB_80 0x07 +#define MST_PHOTO_80 0x08 + +#define MST_TYPE_MASK_HIGH 0x70 +#define MST_CDROM 0x00 +#define MST_CDR 0x10 +#define MST_CDRW 0x20 + +#define MST_NO_DISC 0x70 +#define MST_DOOR_OPEN 0x71 +#define MST_FMT_ERROR 0x72 + + u_int8_t dev_spec; + u_int16_t unused; + u_int16_t blk_desc_len; /* capabilities page */ - u_int8_t page_code; -#define ATAPI_CDROM_CAP_PAGE 0x2a - - u_int8_t param_len; - - u_int16_t media; -#define MST_READ_CDR 0x0001 -#define MST_READ_CDRW 0x0002 -#define MST_READ_PACKET 0x0004 -#define MST_READ_DVDROM 0x0008 -#define MST_READ_DVDR 0x0010 -#define MST_READ_DVDRAM 0x0020 -#define MST_WRITE_CDR 0x0100 -#define MST_WRITE_CDRW 0x0200 -#define MST_WRITE_TEST 0x0400 -#define MST_WRITE_DVDR 0x1000 -#define MST_WRITE_DVDRAM 0x2000 - - u_int16_t capabilities; -#define MST_AUDIO_PLAY 0x0001 -#define MST_COMPOSITE 0x0002 -#define MST_AUDIO_P1 0x0004 -#define MST_AUDIO_P2 0x0008 -#define MST_MODE2_f1 0x0010 -#define MST_MODE2_f2 0x0020 -#define MST_MULTISESSION 0x0040 -#define MST_BURNPROOF 0x0080 -#define MST_READ_CDDA 0x0100 -#define MST_CDDA_STREAM 0x0200 -#define MST_COMBINED_RW 0x0400 -#define MST_CORRECTED_RW 0x0800 -#define MST_SUPPORT_C2 0x1000 -#define MST_ISRC 0x2000 -#define MST_UPC 0x4000 - - u_int8_t mechanism; -#define MST_LOCKABLE 0x01 -#define MST_LOCKED 0x02 -#define MST_PREVENT 0x04 -#define MST_EJECT 0x08 -#define MST_MECH_MASK 0xe0 -#define MST_MECH_CADDY 0x00 -#define MST_MECH_TRAY 0x20 -#define MST_MECH_POPUP 0x40 -#define MST_MECH_CHANGER 0x80 -#define MST_MECH_CARTRIDGE 0xa0 - - uint8_t audio; -#define MST_SEP_VOL 0x01 -#define MST_SEP_MUTE 0x02 - - u_int16_t max_read_speed; /* max raw data rate in bytes/1000 */ - u_int16_t max_vol_levels; /* number of discrete volume levels */ - u_int16_t buf_size; /* internal buffer size in bytes/1024 */ - u_int16_t cur_read_speed; /* current data rate in bytes/1000 */ - - u_int8_t reserved3; - u_int8_t misc; - - u_int16_t max_write_speed; /* max raw data rate in bytes/1000 */ - u_int16_t cur_write_speed; /* current data rate in bytes/1000 */ - u_int16_t copy_protect_rev; - u_int16_t reserved4; + u_int8_t page_code; +#define ATAPI_CDROM_CAP_PAGE 0x2a + + u_int8_t param_len; + + u_int16_t media; +#define MST_READ_CDR 0x0001 +#define MST_READ_CDRW 0x0002 +#define MST_READ_PACKET 0x0004 +#define MST_READ_DVDROM 0x0008 +#define MST_READ_DVDR 0x0010 +#define MST_READ_DVDRAM 0x0020 +#define MST_WRITE_CDR 0x0100 +#define MST_WRITE_CDRW 0x0200 +#define MST_WRITE_TEST 0x0400 +#define MST_WRITE_DVDR 0x1000 +#define MST_WRITE_DVDRAM 0x2000 + + u_int16_t capabilities; +#define MST_AUDIO_PLAY 0x0001 +#define MST_COMPOSITE 0x0002 +#define MST_AUDIO_P1 0x0004 +#define MST_AUDIO_P2 0x0008 +#define MST_MODE2_f1 0x0010 +#define MST_MODE2_f2 0x0020 +#define MST_MULTISESSION 0x0040 +#define MST_BURNPROOF 0x0080 +#define MST_READ_CDDA 0x0100 +#define MST_CDDA_STREAM 0x0200 +#define MST_COMBINED_RW 0x0400 +#define MST_CORRECTED_RW 0x0800 +#define MST_SUPPORT_C2 0x1000 +#define MST_ISRC 0x2000 +#define MST_UPC 0x4000 + + u_int8_t mechanism; +#define MST_LOCKABLE 0x01 +#define MST_LOCKED 0x02 +#define MST_PREVENT 0x04 +#define MST_EJECT 0x08 +#define MST_MECH_MASK 0xe0 +#define MST_MECH_CADDY 0x00 +#define MST_MECH_TRAY 0x20 +#define MST_MECH_POPUP 0x40 +#define MST_MECH_CHANGER 0x80 +#define MST_MECH_CARTRIDGE 0xa0 + + uint8_t audio; +#define MST_SEP_VOL 0x01 +#define MST_SEP_MUTE 0x02 + + u_int16_t max_read_speed; /* max raw data rate in bytes/1000 */ + u_int16_t max_vol_levels; /* number of discrete volume levels */ + u_int16_t buf_size; /* internal buffer size in bytes/1024 */ + u_int16_t cur_read_speed; /* current data rate in bytes/1000 */ + + u_int8_t reserved3; + u_int8_t misc; + + u_int16_t max_write_speed; /* max raw data rate in bytes/1000 */ + u_int16_t cur_write_speed; /* current data rate in bytes/1000 */ + u_int16_t copy_protect_rev; + u_int16_t reserved4; }; -#define CH_READY 0 -#define CH_LOADING 1 -#define CH_UNLOADING 2 -#define CH_INITIALIZING 3 +#define CH_READY 0 +#define CH_LOADING 1 +#define CH_UNLOADING 2 +#define CH_INITIALIZING 3 -#define CD_IDLE 0 -#define CD_AUDIO_ACTIVE 1 -#define CD_AUDIO_SCAN 2 -#define CD_HOST_ACTIVE 3 -#define CD_NO_STATE 7 +#define CD_IDLE 0 +#define CD_AUDIO_ACTIVE 1 +#define CD_AUDIO_SCAN 2 +#define CD_HOST_ACTIVE 3 +#define CD_NO_STATE 7 /* CDROM Changer mechanism status structure */ struct changer { - u_int8_t current_slot :5; /* active changer slot */ - u_int8_t mech_state :2; /* current changer state */ + u_int8_t current_slot :5; /* active changer slot */ + u_int8_t mech_state :2; /* current changer state */ - u_int8_t fault :1; /* fault in last operation */ - u_int8_t reserved0 :5; - u_int8_t cd_state :3; /* current mechanism state */ + u_int8_t fault :1; /* fault in last operation */ + u_int8_t reserved0 :5; + u_int8_t cd_state :3; /* current mechanism state */ - u_int8_t current_lba[3]; /* current LBA */ - u_int8_t slots; /* number of available slots */ - u_int16_t table_length; /* slot table length */ + u_int8_t current_lba[3]; /* current LBA */ + u_int8_t slots; /* number of available slots */ + u_int16_t table_length; /* slot table length */ struct { - u_int8_t changed :1; /* media has changed in this slot */ - u_int8_t unused :6; - u_int8_t present :1; /* slot has a CD present */ - u_int8_t reserved0; - u_int8_t reserved1; - u_int8_t reserved2; + u_int8_t changed :1; /* media has changed in this slot */ + u_int8_t unused :6; + u_int8_t present :1; /* slot has a CD present */ + u_int8_t reserved0; + u_int8_t reserved1; + u_int8_t reserved2; } slot[32]; }; /* CDROM Write Parameters Mode Page (Burners ONLY) */ struct write_param { /* mode page data header */ - u_int16_t data_length; - u_int8_t medium_type; - u_int8_t dev_spec; - u_int8_t unused[2]; - u_int16_t blk_desc_len; + u_int16_t data_length; + u_int8_t medium_type; + u_int8_t dev_spec; + u_int8_t unused[2]; + u_int16_t blk_desc_len; /* write parameters page */ - u_int8_t page_code; + u_int8_t page_code; #define ATAPI_CDROM_WRITE_PARAMETERS_PAGE 0x05 - u_int8_t page_length; /* 0x32 */ - u_int8_t write_type :4; /* write stream type */ -#define CDR_WTYPE_PACKET 0x00 -#define CDR_WTYPE_TRACK 0x01 -#define CDR_WTYPE_SESSION 0x02 -#define CDR_WTYPE_RAW 0x03 - - u_int8_t test_write :1; /* test write enable */ - u_int8_t link_size_valid :1; - u_int8_t burnproof :1; /* BurnProof enable */ - u_int8_t reserved2_7 :1; - u_int8_t track_mode :4; /* track mode */ -#define CDR_TMODE_AUDIO 0x00 -#define CDR_TMODE_AUDIO_PREEMP 0x01 -#define CDR_TMODE_ALLOW_COPY 0x02 -#define CDR_TMODE_DATA 0x04 -#define CDR_TMODE_QUAD_AUDIO 0x08 - - u_int8_t copy :1; /* generation stamp */ - u_int8_t fp :1; /* fixed packet type */ - u_int8_t session_type :2; /* session type */ -#define CDR_SESS_NONE 0x00 -#define CDR_SESS_FINAL 0x01 -#define CDR_SESS_RESERVED 0x02 -#define CDR_SESS_MULTI 0x03 - - u_int8_t datablock_type :4; /* data type code (see cdrio.h) */ - u_int8_t reserved4_4567 :4; - u_int8_t link_size; - u_int8_t reserved6; - u_int8_t host_app_code :6; /* host application code */ - u_int8_t reserved7_67 :2; - u_int8_t session_format; /* session format */ -#define CDR_SESS_CDROM 0x00 -#define CDR_SESS_CDI 0x10 -#define CDR_SESS_CDROM_XA 0x20 - - u_int8_t reserved9; - u_int32_t packet_size; /* packet size in bytes */ - u_int16_t audio_pause_length; /* audio pause length in secs */ - u_int8_t media_catalog_number[16]; - u_int8_t isr_code[16]; - u_int8_t sub_hdr_byte0; - u_int8_t sub_hdr_byte1; - u_int8_t sub_hdr_byte2; - u_int8_t sub_hdr_byte3; - u_int8_t vendor_specific_byte0; - u_int8_t vendor_specific_byte1; - u_int8_t vendor_specific_byte2; - u_int8_t vendor_specific_byte3; + u_int8_t page_length; /* 0x32 */ + u_int8_t write_type :4; /* write stream type */ +#define CDR_WTYPE_PACKET 0x00 +#define CDR_WTYPE_TRACK 0x01 +#define CDR_WTYPE_SESSION 0x02 +#define CDR_WTYPE_RAW 0x03 + + u_int8_t test_write :1; /* test write enable */ + u_int8_t link_size_valid :1; + u_int8_t burnproof :1; /* BurnProof enable */ + u_int8_t reserved2_7 :1; + u_int8_t track_mode :4; /* track mode */ +#define CDR_TMODE_AUDIO 0x00 +#define CDR_TMODE_AUDIO_PREEMP 0x01 +#define CDR_TMODE_ALLOW_COPY 0x02 +#define CDR_TMODE_DATA 0x04 +#define CDR_TMODE_QUAD_AUDIO 0x08 + + u_int8_t copy :1; /* generation stamp */ + u_int8_t fp :1; /* fixed packet type */ + u_int8_t session_type :2; /* session type */ +#define CDR_SESS_NONE 0x00 +#define CDR_SESS_FINAL 0x01 +#define CDR_SESS_RESERVED 0x02 +#define CDR_SESS_MULTI 0x03 + + u_int8_t datablock_type :4; /* data type code (see cdrio.h) */ + u_int8_t reserved4_4567 :4; + u_int8_t link_size; + u_int8_t reserved6; + u_int8_t host_app_code :6; /* host application code */ + u_int8_t reserved7_67 :2; + u_int8_t session_format; /* session format */ +#define CDR_SESS_CDROM 0x00 +#define CDR_SESS_CDI 0x10 +#define CDR_SESS_CDROM_XA 0x20 + + u_int8_t reserved9; + u_int32_t packet_size; /* packet size in bytes */ + u_int16_t audio_pause_length; /* audio pause length in secs */ + u_int8_t media_catalog_number[16]; + u_int8_t isr_code[16]; + u_int8_t sub_hdr_byte0; + u_int8_t sub_hdr_byte1; + u_int8_t sub_hdr_byte2; + u_int8_t sub_hdr_byte3; + u_int8_t vendor_specific_byte0; + u_int8_t vendor_specific_byte1; + u_int8_t vendor_specific_byte2; + u_int8_t vendor_specific_byte3; } __packed; /* CDROM Read Track Information structure */ struct acd_track_info { - u_int16_t data_length; - u_int8_t track_number; /* current track number */ - u_int8_t session_number; /* current session number */ - u_int8_t reserved4; - u_int8_t track_mode :4; /* mode of this track */ - u_int8_t copy :1; /* generation stamp */ - u_int8_t damage :1; /* damaged track */ - u_int8_t reserved5_67 :2; - u_int8_t data_mode :4; /* data mode of this disc */ - u_int8_t fp :1; /* fixed packet */ - u_int8_t packet :1; /* packet track */ - u_int8_t blank :1; /* blank (empty) track */ - u_int8_t rt :1; /* reserved track */ - u_int8_t nwa_valid :1; /* next_writeable_addr field valid */ - u_int8_t reserved7_17 :7; - u_int track_start_addr; /* start of this track */ - u_int next_writeable_addr; /* next writeable addr on this disc */ - u_int free_blocks; /* free block on this disc */ - u_int fixed_packet_size; /* size of packets on this track */ - u_int track_length; /* length of this track */ + u_int16_t data_length; + u_int8_t track_number; /* current track number */ + u_int8_t session_number; /* current session number */ + u_int8_t reserved4; + u_int8_t track_mode :4; /* mode of this track */ + u_int8_t copy :1; /* generation stamp */ + u_int8_t damage :1; /* damaged track */ + u_int8_t reserved5_67 :2; + u_int8_t data_mode :4; /* data mode of this disc */ + u_int8_t fp :1; /* fixed packet */ + u_int8_t packet :1; /* packet track */ + u_int8_t blank :1; /* blank (empty) track */ + u_int8_t rt :1; /* reserved track */ + u_int8_t nwa_valid :1; /* next_writeable_addr field valid */ + u_int8_t reserved7_17 :7; + u_int track_start_addr; /* start of this track */ + u_int next_writeable_addr; /* next writeable addr on this disc */ + u_int free_blocks; /* free block on this disc */ + u_int fixed_packet_size; /* size of packets on this track */ + u_int track_length; /* length of this track */ }; /* Structure describing an ATAPI CDROM device */ struct acd_softc { - struct ata_device *device; /* device softc */ - int lun; /* logical device unit */ - int flags; /* device state flags */ -#define F_LOCKED 0x0001 /* this unit is locked */ - - struct mtx queue_mtx; /* bio queue lock */ - struct bio_queue_head queue; /* queue of i/o requests */ - struct toc toc; /* table of disc contents */ - struct audiopage au; /* audio page info */ - struct audiopage aumask; /* audio page mask */ - struct cappage cap; /* capabilities page info */ - struct cd_sub_channel_info subchan; /* subchannel info */ - struct changer *changer_info; /* changer info */ - struct acd_softc **driver; /* softc's of changer slots */ - int slot; /* this instance slot number */ - time_t timestamp; /* this instance timestamp */ - u_int32_t disk_size; /* size of current media */ - u_int32_t block_size; /* blocksize currently used */ - u_int32_t iomax; /* Max I/O request (bytes) */ - struct g_geom *gp; /* geom instance */ - struct g_provider *pp[MAXTRK+1]; /* providers */ + int flags; /* device state flags */ +#define F_LOCKED 0x0001 /* this unit is locked */ + + struct toc toc; /* table of disc contents */ + struct audiopage au; /* audio page info */ + struct audiopage aumask; /* audio page mask */ + struct cappage cap; /* capabilities page info */ + struct cd_sub_channel_info subchan; /* subchannel info */ + struct changer *changer_info; /* changer info */ + struct acd_softc **driver; /* softc's of changer slots */ + int slot; /* this instance slot number */ + time_t timestamp; /* this instance timestamp */ + u_int32_t disk_size; /* size of current media */ + u_int32_t block_size; /* blocksize currently used */ + u_int32_t iomax; /* Max I/O request (bytes) */ + struct g_geom *gp; /* geom instance */ + struct g_provider *pp[MAXTRK+1]; /* providers */ }; diff --git a/sys/dev/ata/atapi-fd.c b/sys/dev/ata/atapi-fd.c index 9fda140..0c701c4 100644 --- a/sys/dev/ata/atapi-fd.c +++ b/sys/dev/ata/atapi-fd.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/ata.h> #include <sys/kernel.h> +#include <sys/module.h> #include <sys/malloc.h> #include <sys/bio.h> #include <sys/bus.h> @@ -45,196 +46,143 @@ __FBSDID("$FreeBSD$"); #include <geom/geom_disk.h> #include <dev/ata/ata-all.h> #include <dev/ata/atapi-fd.h> +#include <ata_if.h> + /* prototypes */ -static disk_open_t afd_open; -static disk_close_t afd_close; -#ifdef notyet -static disk_ioctl_t afd_ioctl; -#endif -static disk_strategy_t afdstrategy; -static void afd_detach(struct ata_device *); -static void afd_start(struct ata_device *); -static int afd_sense(struct afd_softc *); -static void afd_describe(struct afd_softc *); +static disk_open_t afd_open; +static disk_close_t afd_close; +static disk_strategy_t afd_strategy; +static int afd_sense(device_t); +static void afd_describe(device_t); static void afd_done(struct ata_request *); -static int afd_eject(struct afd_softc *, int); -static int afd_start_stop(struct afd_softc *, int); -static int afd_prevent_allow(struct afd_softc *, int); -static int afd_test_ready(struct ata_device *); +static int afd_prevent_allow(device_t, int); +static int afd_test_ready(device_t); /* internal vars */ -static u_int32_t afd_lun_map = 0; static MALLOC_DEFINE(M_AFD, "AFD driver", "ATAPI floppy driver buffers"); -void -afd_attach(struct ata_device *atadev) +static void +afd_identify(driver_t *driver, device_t parent) +{ + ata_identify(driver, parent, ATA_ATAPI_TYPE_DIRECT, "afd"); +} + +static int +afd_probe(device_t dev) +{ + return 0; +} + +static int +afd_attach(device_t dev) { + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_device *atadev = device_get_softc(dev); struct afd_softc *fdp; - fdp = malloc(sizeof(struct afd_softc), M_AFD, M_NOWAIT | M_ZERO); - if (!fdp) { - ata_prtdev(atadev, "out of memory\n"); - return; + if (!(fdp = malloc(sizeof(struct afd_softc), M_AFD, M_NOWAIT | M_ZERO))) { + device_printf(dev, "out of memory\n"); + device_set_softc(dev, NULL); + free(atadev, M_ATA); + return ENOMEM; } + device_set_ivars(dev, fdp); + ATA_SETMODE(GRANDPARENT(dev), dev); - fdp->device = atadev; - fdp->lun = ata_get_lun(&afd_lun_map); - ata_set_name(atadev, "afd", fdp->lun); - bioq_init(&fdp->queue); - mtx_init(&fdp->queue_mtx, "ATAPI FD bioqueue lock", NULL, MTX_DEF); - - if (afd_sense(fdp)) { + if (afd_sense(dev)) { + device_set_ivars(dev, NULL); free(fdp, M_AFD); - return; + device_set_softc(dev, NULL); + free(atadev, M_ATA); + return ENXIO; } - - /* setup the function ptrs */ - atadev->detach = afd_detach; - atadev->start = afd_start; - atadev->softc = fdp; atadev->flags |= ATA_D_MEDIA_CHANGED; - /* lets create the disk device */ + /* announce we are here */ + afd_describe(dev); + + /* create the disk device */ fdp->disk = disk_alloc(); fdp->disk->d_open = afd_open; fdp->disk->d_close = afd_close; -#ifdef notyet - fdp->disk->d_ioctl = afd_ioctl; -#endif - fdp->disk->d_strategy = afdstrategy; + fdp->disk->d_strategy = afd_strategy; fdp->disk->d_name = "afd"; - fdp->disk->d_drv1 = fdp; - if (atadev->channel->dma) - fdp->disk->d_maxsize = atadev->channel->dma->max_iosize; + fdp->disk->d_drv1 = dev; + if (ch->dma) + fdp->disk->d_maxsize = ch->dma->max_iosize; else fdp->disk->d_maxsize = DFLTPHYS; - fdp->disk->d_unit = fdp->lun; + fdp->disk->d_unit = device_get_unit(dev); disk_create(fdp->disk, DISK_VERSION); - - /* announce we are here */ - afd_describe(fdp); + return 0; } -static void -afd_detach(struct ata_device *atadev) +static int +afd_detach(device_t dev) { - struct afd_softc *fdp = atadev->softc; + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_device *atadev = device_get_softc(dev); + struct afd_softc *fdp = device_get_ivars(dev); - mtx_lock(&fdp->queue_mtx); - bioq_flush(&fdp->queue, NULL, ENXIO); - mtx_unlock(&fdp->queue_mtx); - mtx_destroy(&fdp->queue_mtx); + /* detroy disk from the system so we dont get any further requests */ disk_destroy(fdp->disk); - ata_prtdev(atadev, "WARNING - removed from configuration\n"); - ata_free_name(atadev); - ata_free_lun(&afd_lun_map, fdp->lun); - atadev->attach = NULL; - atadev->detach = NULL; - atadev->start = NULL; - atadev->softc = NULL; - atadev->flags = 0; - free(fdp, M_AFD); -} -static int -afd_sense(struct afd_softc *fdp) -{ - int8_t ccb[16] = { ATAPI_MODE_SENSE_BIG, 0, ATAPI_REWRITEABLE_CAP_PAGE, - 0, 0, 0, 0, sizeof(struct afd_cappage) >> 8, - sizeof(struct afd_cappage) & 0xff, 0, 0, 0, 0, 0, 0, 0 }; - int count; + /* fail requests on the queue and any thats "in flight" for this device */ + ata_fail_requests(ch, dev); - /* The IOMEGA Clik! doesn't support reading the cap page, fake it */ - if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12)) { - fdp->cap.transfer_rate = 500; - fdp->cap.heads = 1; - fdp->cap.sectors = 2; - fdp->cap.cylinders = 39441; - fdp->cap.sector_size = 512; - afd_test_ready(fdp->device); - return 0; - } - - /* get drive capabilities, some bugridden drives needs this repeated */ - for (count = 0 ; count < 5 ; count++) { - if (!ata_atapicmd(fdp->device, ccb, (caddr_t)&fdp->cap, - sizeof(struct afd_cappage), ATA_R_READ, 30) && - fdp->cap.page_code == ATAPI_REWRITEABLE_CAP_PAGE) { - fdp->cap.cylinders = ntohs(fdp->cap.cylinders); - fdp->cap.sector_size = ntohs(fdp->cap.sector_size); - fdp->cap.transfer_rate = ntohs(fdp->cap.transfer_rate); - return 0; - } - } - return 1; + /* dont leave anything behind */ + device_set_ivars(dev, NULL); + free(fdp, M_AFD); + device_set_softc(dev, NULL); + free(atadev, M_ATA); + return 0; } -static void -afd_describe(struct afd_softc *fdp) +static void +afd_shutdown(device_t dev) { - if (bootverbose) { - ata_prtdev(fdp->device, - "<%.40s/%.8s> removable drive at ata%d as %s\n", - fdp->device->param->model, fdp->device->param->revision, - device_get_unit(fdp->device->channel->dev), - (fdp->device->unit == ATA_MASTER) ? "master" : "slave"); - ata_prtdev(fdp->device, - "%luMB (%u sectors), %u cyls, %u heads, %u S/T, %u B/S\n", - (fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) / - ((1024L * 1024L) / fdp->cap.sector_size), - fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors, - fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors, - fdp->cap.sector_size); - ata_prtdev(fdp->device, "%dKB/s,", fdp->cap.transfer_rate / 8); - printf(" %s\n", ata_mode2str(fdp->device->mode)); - if (fdp->cap.medium_type) { - ata_prtdev(fdp->device, "Medium: "); - switch (fdp->cap.medium_type) { - case MFD_2DD: - printf("720KB DD disk"); break; + struct ata_device *atadev = device_get_softc(dev); - case MFD_HD_12: - printf("1.2MB HD disk"); break; - - case MFD_HD_144: - printf("1.44MB HD disk"); break; - - case MFD_UHD: - printf("120MB UHD disk"); break; + if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE) + ata_controlcmd(atadev, ATA_FLUSHCACHE, 0, 0, 0); +} - default: - printf("Unknown (0x%x)", fdp->cap.medium_type); - } - if (fdp->cap.wp) printf(", writeprotected"); - printf("\n"); - } - } - else { - ata_prtdev(fdp->device, "REMOVABLE <%.40s/%.8s> at ata%d-%s %s\n", - fdp->device->param->model, fdp->device->param->revision, - device_get_unit(fdp->device->channel->dev), - (fdp->device->unit == ATA_MASTER) ? "master" : "slave", - ata_mode2str(fdp->device->mode)); +static int +afd_reinit(device_t dev) +{ + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_device *atadev = device_get_softc(dev); + struct afd_softc *fdp = device_get_ivars(dev); + + if (((atadev->unit == ATA_MASTER) && !(ch->devices & ATA_ATAPI_MASTER)) || + ((atadev->unit == ATA_SLAVE) && !(ch->devices & ATA_ATAPI_SLAVE))) { + device_set_ivars(dev, NULL); + free(fdp, M_AFD); + return 1; } + ATA_SETMODE(GRANDPARENT(dev), dev); + return 0; } static int afd_open(struct disk *dp) { - struct afd_softc *fdp = dp->d_drv1; + device_t dev = dp->d_drv1; + struct ata_device *atadev = device_get_softc(dev); + struct afd_softc *fdp = device_get_ivars(dev); - if (fdp->device->flags & ATA_D_DETACHING) + if (!fdp) return ENXIO; + if (!device_is_attached(dev)) + return EBUSY; - afd_test_ready(fdp->device); - - afd_prevent_allow(fdp, 1); - - if (afd_sense(fdp)) - ata_prtdev(fdp->device, "sense media type failed\n"); + afd_test_ready(dev); + afd_prevent_allow(dev, 1); - fdp->device->flags &= ~ATA_D_MEDIA_CHANGED; + if (afd_sense(dev)) + device_printf(dev, "sense media type failed\n"); + atadev->flags &= ~ATA_D_MEDIA_CHANGED; fdp->disk->d_sectorsize = fdp->cap.sector_size; fdp->disk->d_mediasize = (off_t)fdp->cap.sector_size * fdp->cap.sectors * @@ -248,47 +196,21 @@ afd_open(struct disk *dp) static int afd_close(struct disk *dp) { - struct afd_softc *fdp = dp->d_drv1; - - afd_prevent_allow(fdp, 0); - if (0) - afd_eject(fdp, 0); /* to keep gcc quiet */ + device_t dev = dp->d_drv1; + afd_prevent_allow(dev, 0); return 0; } -#ifdef notyet -static int -afd_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) -{ - struct afd_softc *fdp = dp->d_drv1; - - switch (cmd) { - case CDIOCEJECT: - if (count_dev(dev) > 1) - return EBUSY; - return afd_eject(fdp, 0); - - case CDIOCCLOSE: - if (count_dev(dev) > 1) - return 0; - return afd_eject(fdp, 1); - - default: - return ENOIOCTL; - } -} -#endif - static void -afdstrategy(struct bio *bp) +afd_strategy(struct bio *bp) { - struct afd_softc *fdp = bp->bio_disk->d_drv1; - - if (fdp->device->flags & ATA_D_DETACHING) { - biofinish(bp, NULL, ENXIO); - return; - } + device_t dev = bp->bio_disk->d_drv1; + struct ata_device *atadev = device_get_softc(dev); + struct afd_softc *fdp = device_get_ivars(dev); + struct ata_request *request; + u_int16_t count; + int8_t ccb[16]; /* if it's a null transfer, return immediatly. */ if (bp->bio_bcount == 0) { @@ -297,39 +219,12 @@ afdstrategy(struct bio *bp) return; } - mtx_lock(&fdp->queue_mtx); - bioq_disksort(&fdp->queue, bp); - mtx_unlock(&fdp->queue_mtx); - ata_start(fdp->device->channel); -} - -static void -afd_start(struct ata_device *atadev) -{ - struct afd_softc *fdp = atadev->softc; - struct bio *bp; - struct ata_request *request; - u_int32_t lba; - u_int16_t count; - int8_t ccb[16]; - - - mtx_lock(&fdp->queue_mtx); - bp = bioq_first(&fdp->queue); - if (!bp) { - mtx_unlock(&fdp->queue_mtx); - return; - } - bioq_remove(&fdp->queue, bp); - mtx_unlock(&fdp->queue_mtx); - /* should reject all queued entries if media have changed. */ - if (fdp->device->flags & ATA_D_MEDIA_CHANGED) { + if (atadev->flags & ATA_D_MEDIA_CHANGED) { biofinish(bp, NULL, EIO); return; } - lba = bp->bio_pblkno; count = bp->bio_bcount / fdp->cap.sector_size; bp->bio_resid = bp->bio_bcount; @@ -340,10 +235,10 @@ afd_start(struct ata_device *atadev) else ccb[0] = ATAPI_WRITE_BIG; - ccb[2] = lba>>24; - ccb[3] = lba>>16; - ccb[4] = lba>>8; - ccb[5] = lba; + ccb[2] = bp->bio_pblkno >> 24; + ccb[3] = bp->bio_pblkno >> 16; + ccb[4] = bp->bio_pblkno >> 8; + ccb[5] = bp->bio_pblkno; ccb[7] = count>>8; ccb[8] = count; @@ -351,10 +246,10 @@ afd_start(struct ata_device *atadev) biofinish(bp, NULL, ENOMEM); return; } - request->device = atadev; - request->driver = bp; + request->dev = dev; + request->bio = bp; bcopy(ccb, request->u.atapi.ccb, - (request->device->param->config & ATA_PROTO_MASK) == + (atadev->param.config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12 ? 16 : 12); request->data = bp->bio_data; request->bytecount = count * fdp->cap.sector_size; @@ -364,25 +259,27 @@ afd_start(struct ata_device *atadev) request->callback = afd_done; switch (bp->bio_cmd) { case BIO_READ: - request->flags |= (ATA_R_ATAPI | ATA_R_READ); + request->flags = (ATA_R_ATAPI | ATA_R_READ); break; case BIO_WRITE: - request->flags |= (ATA_R_ATAPI | ATA_R_WRITE); + request->flags = (ATA_R_ATAPI | ATA_R_WRITE); break; default: - ata_prtdev(atadev, "unknown BIO operation\n"); + device_printf(dev, "unknown BIO operation\n"); ata_free_request(request); biofinish(bp, NULL, EIO); return; } + if (atadev->mode >= ATA_DMA) + request->flags |= ATA_R_DMA; + request->flags |= ATA_R_ORDERED; ata_queue_request(request); - } static void afd_done(struct ata_request *request) { - struct bio *bp = request->driver; + struct bio *bp = request->bio; /* finish up transfer */ if ((bp->bio_error = request->result)) @@ -393,52 +290,153 @@ afd_done(struct ata_request *request) } static int -afd_eject(struct afd_softc *fdp, int close) +afd_sense(device_t dev) { - int error; - - if ((error = afd_start_stop(fdp, 0)) == EBUSY) { - if (!close) - return 0; - if ((error = afd_start_stop(fdp, 3))) - return error; - return afd_prevent_allow(fdp, 1); - } - if (error) - return error; - if (close) - return 0; - if ((error = afd_prevent_allow(fdp, 0))) - return error; - fdp->device->flags |= ATA_D_MEDIA_CHANGED; - return afd_start_stop(fdp, 2); -} + struct ata_device *atadev = device_get_softc(dev); + struct afd_softc *fdp = device_get_ivars(dev); + int8_t ccb[16] = { ATAPI_MODE_SENSE_BIG, 0, ATAPI_REWRITEABLE_CAP_PAGE, + 0, 0, 0, 0, sizeof(struct afd_cappage) >> 8, + sizeof(struct afd_cappage) & 0xff, 0, 0, 0, 0, 0, 0, 0 }; + int count; -static int -afd_start_stop(struct afd_softc *fdp, int start) -{ - int8_t ccb[16] = { ATAPI_START_STOP, 0, 0, 0, start, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + /* The IOMEGA Clik! doesn't support reading the cap page, fake it */ + if (!strncmp(atadev->param.model, "IOMEGA Clik!", 12)) { + fdp->cap.transfer_rate = 500; + fdp->cap.heads = 1; + fdp->cap.sectors = 2; + fdp->cap.cylinders = 39441; + fdp->cap.sector_size = 512; + afd_test_ready(dev); + return 0; + } - return ata_atapicmd(fdp->device, ccb, NULL, 0, 0, 30); + /* get drive capabilities, some bugridden drives needs this repeated */ + for (count = 0 ; count < 5 ; count++) { + if (!ata_atapicmd(atadev, ccb, (caddr_t)&fdp->cap, + sizeof(struct afd_cappage), ATA_R_READ, 30) && + fdp->cap.page_code == ATAPI_REWRITEABLE_CAP_PAGE) { + fdp->cap.cylinders = ntohs(fdp->cap.cylinders); + fdp->cap.sector_size = ntohs(fdp->cap.sector_size); + fdp->cap.transfer_rate = ntohs(fdp->cap.transfer_rate); + return 0; + } + } + return 1; } static int -afd_prevent_allow(struct afd_softc *fdp, int lock) +afd_prevent_allow(device_t dev, int lock) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12)) + if (!strncmp(atadev->param.model, "IOMEGA Clik!", 12)) return 0; - return ata_atapicmd(fdp->device, ccb, NULL, 0, 0, 30); + return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30); } static int -afd_test_ready(struct ata_device *atadev) +afd_test_ready(device_t dev) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30); } + +static void +afd_describe(device_t dev) +{ + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_device *atadev = device_get_softc(dev); + struct afd_softc *fdp = device_get_ivars(dev); + + if (bootverbose) { + device_printf(dev, "<%.40s/%.8s> removable drive at ata%d as %s\n", + atadev->param.model, atadev->param.revision, + device_get_unit(ch->dev), + (atadev->unit == ATA_MASTER) ? "master" : "slave"); + device_printf(dev, + "%luMB (%u sectors), %u cyls, %u heads, %u S/T, %u B/S\n", + (fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) / + ((1024L * 1024L) / fdp->cap.sector_size), + fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors, + fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors, + fdp->cap.sector_size); + device_printf(dev, "%dKB/s,", fdp->cap.transfer_rate / 8); + printf(" %s\n", ata_mode2str(atadev->mode)); + if (fdp->cap.medium_type) { + device_printf(dev, "Medium: "); + switch (fdp->cap.medium_type) { + case MFD_2DD: + printf("720KB DD disk"); break; + + case MFD_HD_12: + printf("1.2MB HD disk"); break; + + case MFD_HD_144: + printf("1.44MB HD disk"); break; + + case MFD_UHD: + printf("120MB UHD disk"); break; + + default: + printf("Unknown (0x%x)", fdp->cap.medium_type); + } + if (fdp->cap.wp) printf(", writeprotected"); + printf("\n"); + } + } + else { + device_printf(dev, "REMOVABLE <%.40s/%.8s> at ata%d-%s %s\n", + atadev->param.model, atadev->param.revision, + device_get_unit(ch->dev), + (atadev->unit == ATA_MASTER) ? "master" : "slave", + ata_mode2str(atadev->mode)); + } +} + +static device_method_t afd_methods[] = { + /* device interface */ + DEVMETHOD(device_identify, afd_identify), + DEVMETHOD(device_probe, afd_probe), + DEVMETHOD(device_attach, afd_attach), + DEVMETHOD(device_detach, afd_detach), + DEVMETHOD(device_shutdown, afd_shutdown), + + /* ATA methods */ + DEVMETHOD(ata_reinit, afd_reinit), + + { 0, 0 } +}; + +static driver_t afd_driver = { + "afd", + afd_methods, + sizeof(struct afd_softc) +}; + +static devclass_t afd_devclass; + +static int +afd_modevent(module_t mod, int what, void *arg) +{ + device_t *devs; + int ndevs, i; + + if (what == MOD_UNLOAD) { + if (!devclass_get_devices(afd_devclass, &devs, &ndevs) && devs) { + for (i = 0; i < ndevs; i++) + device_delete_child(device_get_parent(devs[i]), devs[i]); + free(devs, M_TEMP); + } + } + return 0; +} + +DRIVER_MODULE(afd, ata, afd_driver, afd_devclass, afd_modevent, NULL); +MODULE_VERSION(afd, 1); +MODULE_DEPEND(afd, ata, 1, 1, 1); + diff --git a/sys/dev/ata/atapi-fd.h b/sys/dev/ata/atapi-fd.h index 4f37b0d..2a2f699 100644 --- a/sys/dev/ata/atapi-fd.h +++ b/sys/dev/ata/atapi-fd.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,50 +30,46 @@ /* ATAPI Rewriteable drive Capabilities and Mechanical Status Page */ struct afd_cappage { - u_int16_t data_length; - u_int8_t medium_type; -#define MFD_2DD_UN 0x10 -#define MFD_2DD 0x11 -#define MFD_HD_UN 0x20 -#define MFD_HD_12_98 0x22 -#define MFD_HD_12 0x23 -#define MFD_HD_144 0x24 -#define MFD_UHD 0x31 + u_int16_t data_length; + u_int8_t medium_type; +#define MFD_2DD_UN 0x10 +#define MFD_2DD 0x11 +#define MFD_HD_UN 0x20 +#define MFD_HD_12_98 0x22 +#define MFD_HD_12 0x23 +#define MFD_HD_144 0x24 +#define MFD_UHD 0x31 -#define MFD_UNKNOWN 0x00 -#define MFD_NO_DISC 0x70 -#define MFD_DOOR_OPEN 0x71 -#define MFD_FMT_ERROR 0x72 +#define MFD_UNKNOWN 0x00 +#define MFD_NO_DISC 0x70 +#define MFD_DOOR_OPEN 0x71 +#define MFD_FMT_ERROR 0x72 - u_int8_t reserved0 :7; - u_int8_t wp :1; /* write protect */ - u_int8_t unused[4]; + u_int8_t reserved0 :7; + u_int8_t wp :1; /* write protect */ + u_int8_t unused[4]; /* capabilities page */ - u_int8_t page_code :6; -#define ATAPI_REWRITEABLE_CAP_PAGE 0x05 + u_int8_t page_code :6; +#define ATAPI_REWRITEABLE_CAP_PAGE 0x05 - u_int8_t reserved1_6 :1; - u_int8_t ps :1; /* page save supported */ - u_int8_t page_length; /* page length */ - u_int16_t transfer_rate; /* in kilobits per second */ - u_int8_t heads; /* number of heads */ - u_int8_t sectors; /* number of sectors pr track */ - u_int16_t sector_size; /* number of bytes per sector */ - u_int16_t cylinders; /* number of cylinders */ - u_int8_t reserved10[10]; - u_int8_t motor_delay; /* motor off delay */ - u_int8_t reserved21[7]; - u_int16_t rpm; /* rotations per minute */ - u_int8_t reserved30[2]; + u_int8_t reserved1_6 :1; + u_int8_t ps :1; /* page save supported */ + u_int8_t page_length; /* page length */ + u_int16_t transfer_rate; /* in kilobits per second */ + u_int8_t heads; /* number of heads */ + u_int8_t sectors; /* number of sectors pr track */ + u_int16_t sector_size; /* number of bytes per sector */ + u_int16_t cylinders; /* number of cylinders */ + u_int8_t reserved10[10]; + u_int8_t motor_delay; /* motor off delay */ + u_int8_t reserved21[7]; + u_int16_t rpm; /* rotations per minute */ + u_int8_t reserved30[2]; }; struct afd_softc { - struct ata_device *device; /* device softc */ - int lun; /* logical device unit */ - struct mtx queue_mtx; /* bio queue lock */ - struct bio_queue_head queue; /* queue of i/o requests */ - struct afd_cappage cap; /* capabilities page info */ - struct disk *disk; /* virtual drives */ + struct afd_cappage cap; /* capabilities page info */ + struct disk *disk; /* virtual drives */ }; diff --git a/sys/dev/ata/atapi-tape.c b/sys/dev/ata/atapi-tape.c index 827edec..b1e90f0 100644 --- a/sys/dev/ata/atapi-tape.c +++ b/sys/dev/ata/atapi-tape.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,8 +34,9 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/ata.h> #include <sys/kernel.h> -#include <sys/conf.h> +#include <sys/module.h> #include <sys/malloc.h> +#include <sys/conf.h> #include <sys/bio.h> #include <sys/bus.h> #include <sys/mtio.h> @@ -46,281 +47,234 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <dev/ata/ata-all.h> #include <dev/ata/atapi-tape.h> +#include <ata_if.h> -/* device structures */ -static d_open_t ast_open; -static d_close_t ast_close; -static d_ioctl_t ast_ioctl; -static d_strategy_t ast_strategy; +/* device structure */ +static d_open_t ast_open; +static d_close_t ast_close; +static d_ioctl_t ast_ioctl; +static d_strategy_t ast_strategy; static struct cdevsw ast_cdevsw = { - .d_version = D_VERSION, - .d_open = ast_open, - .d_close = ast_close, - .d_read = physread, - .d_write = physwrite, - .d_ioctl = ast_ioctl, - .d_strategy = ast_strategy, - .d_name = "ast", - .d_flags = D_TAPE | D_TRACKCLOSE, + .d_version = D_VERSION, + .d_open = ast_open, + .d_close = ast_close, + .d_read = physread, + .d_write = physwrite, + .d_ioctl = ast_ioctl, + .d_strategy = ast_strategy, + .d_name = "ast", + .d_flags = D_TAPE | D_TRACKCLOSE, }; /* prototypes */ -static void ast_detach(struct ata_device *); -static void ast_start(struct ata_device *); -static int ast_sense(struct ast_softc *); -static void ast_describe(struct ast_softc *); +static int ast_sense(device_t); +static void ast_describe(device_t); static void ast_done(struct ata_request *); -static int ast_mode_sense(struct ast_softc *, int, void *, int); -static int ast_mode_select(struct ast_softc *, void *, int); -static int ast_write_filemark(struct ast_softc *, u_int8_t); -static int ast_read_position(struct ast_softc *, int, struct ast_readposition *); -static int ast_space(struct ast_softc *, u_int8_t, int32_t); -static int ast_locate(struct ast_softc *, int, u_int32_t); -static int ast_prevent_allow(struct ast_softc *stp, int); -static int ast_load_unload(struct ast_softc *, u_int8_t); -static int ast_rewind(struct ast_softc *); -static int ast_erase(struct ast_softc *); -static int ast_test_ready(struct ata_device *); -static int ast_wait_dsc(struct ata_device *, int); +static int ast_mode_sense(device_t, int, void *, int); +static int ast_mode_select(device_t, void *, int); +static int ast_write_filemark(device_t, u_int8_t); +static int ast_read_position(device_t, int, struct ast_readposition *); +static int ast_space(device_t, u_int8_t, int32_t); +static int ast_locate(device_t, int, u_int32_t); +static int ast_prevent_allow(device_t, int); +static int ast_load_unload(device_t, u_int8_t); +static int ast_rewind(device_t); +static int ast_erase(device_t); +static int ast_test_ready(device_t); +static int ast_wait_dsc(device_t, int); /* internal vars */ -static u_int32_t ast_lun_map = 0; static u_int64_t ast_total = 0; static MALLOC_DEFINE(M_AST, "AST driver", "ATAPI tape driver buffers"); -void -ast_attach(struct ata_device *atadev) +static void +ast_identify(driver_t *driver, device_t parent) +{ + ata_identify(driver, parent, ATA_ATAPI_TYPE_TAPE, "ast"); +} + +static int +ast_probe(device_t dev) +{ + return 0; +} + +static int +ast_attach(device_t dev) { + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_device *atadev = device_get_softc(dev); struct ast_softc *stp; struct ast_readposition position; - struct cdev *dev; + struct cdev *device; - stp = malloc(sizeof(struct ast_softc), M_AST, M_NOWAIT | M_ZERO); - if (!stp) { - ata_prtdev(atadev, "out of memory\n"); - return; + if (!(stp = malloc(sizeof(struct ast_softc), M_AST, M_NOWAIT | M_ZERO))) { + device_printf(dev, "out of memory\n"); + device_set_softc(dev, NULL); + free(atadev, M_ATA); + return ENOMEM; } + device_set_ivars(dev, stp); + ATA_SETMODE(GRANDPARENT(dev), dev); - stp->device = atadev; - stp->lun = ata_get_lun(&ast_lun_map); - ata_set_name(atadev, "ast", stp->lun); - bioq_init(&stp->queue); - mtx_init(&stp->queue_mtx, "ATAPI TAPE bioqueue lock", NULL, MTX_DEF); - - if (ast_sense(stp)) { + if (ast_sense(dev)) { + device_set_ivars(dev, NULL); free(stp, M_AST); - return; + device_set_softc(dev, NULL); + free(atadev, M_ATA); + return ENXIO; } - - if (!strcmp(atadev->param->model, "OnStream DI-30")) { + if (!strcmp(atadev->param.model, "OnStream DI-30")) { struct ast_transferpage transfer; struct ast_identifypage identify; stp->flags |= F_ONSTREAM; bzero(&transfer, sizeof(struct ast_transferpage)); - ast_mode_sense(stp, ATAPI_TAPE_TRANSFER_PAGE, + ast_mode_sense(dev, ATAPI_TAPE_TRANSFER_PAGE, &transfer, sizeof(transfer)); bzero(&identify, sizeof(struct ast_identifypage)); - ast_mode_sense(stp, ATAPI_TAPE_IDENTIFY_PAGE, + ast_mode_sense(dev, ATAPI_TAPE_IDENTIFY_PAGE, &identify, sizeof(identify)); strncpy(identify.ident, "FBSD", 4); - ast_mode_select(stp, &identify, sizeof(identify)); - ast_read_position(stp, 0, &position); + ast_mode_select(dev, &identify, sizeof(identify)); + ast_read_position(dev, 0, &position); } - stp->stats = devstat_new_entry("ast", stp->lun, DEV_BSIZE, + stp->stats = devstat_new_entry("ast", device_get_unit(dev), DEV_BSIZE, DEVSTAT_NO_ORDERED_TAGS, DEVSTAT_TYPE_SEQUENTIAL | DEVSTAT_TYPE_IF_IDE, DEVSTAT_PRIORITY_TAPE); - dev = make_dev(&ast_cdevsw, 2 * stp->lun, - UID_ROOT, GID_OPERATOR, 0640, "ast%d", stp->lun); - dev->si_drv1 = stp; - if (atadev->channel->dma) - dev->si_iosize_max = atadev->channel->dma->max_iosize; + device = make_dev(&ast_cdevsw, 2 * device_get_unit(dev), + UID_ROOT, GID_OPERATOR, 0640, "ast%d", + device_get_unit(dev)); + device->si_drv1 = dev; + if (ch->dma) + device->si_iosize_max = ch->dma->max_iosize; else - dev->si_iosize_max = DFLTPHYS; - stp->dev1 = dev; - dev = make_dev(&ast_cdevsw, 2 * stp->lun + 1, - UID_ROOT, GID_OPERATOR, 0640, "nast%d", stp->lun); - - dev->si_drv1 = stp; - if (atadev->channel->dma) - dev->si_iosize_max = atadev->channel->dma->max_iosize; + device->si_iosize_max = DFLTPHYS; + stp->dev1 = device; + device = make_dev(&ast_cdevsw, 2 * device_get_unit(dev) + 1, + UID_ROOT, GID_OPERATOR, 0640, "nast%d", + device_get_unit(dev)); + device->si_drv1 = dev; + if (ch->dma) + device->si_iosize_max = ch->dma->max_iosize; else - dev->si_iosize_max = DFLTPHYS; - stp->dev2 = dev; - - /* setup the function ptrs */ - atadev->detach = ast_detach; - atadev->start = ast_start; - atadev->softc = stp; - atadev->flags |= ATA_D_MEDIA_CHANGED; + device->si_iosize_max = DFLTPHYS; + stp->dev2 = device; - /* announce we are here */ - ast_describe(stp); + /* announce we are here and ready */ + ast_describe(dev); + return 0; } -static void -ast_detach(struct ata_device *atadev) +static int +ast_detach(device_t dev) { - struct ast_softc *stp = atadev->softc; + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_device *atadev = device_get_softc(dev); + struct ast_softc *stp = device_get_ivars(dev); - mtx_lock(&stp->queue_mtx); - bioq_flush(&stp->queue, NULL, ENXIO); - mtx_unlock(&stp->queue_mtx); - mtx_destroy(&stp->queue_mtx); + /* detroy devices from the system so we dont get any further requests */ destroy_dev(stp->dev1); destroy_dev(stp->dev2); + + /* fail requests on the queue and any thats "in flight" for this device */ + ata_fail_requests(ch, dev); + + /* dont leave anything behind */ devstat_remove_entry(stp->stats); - ata_prtdev(atadev, "WARNING - removed from configuration\n"); - ata_free_name(atadev); - ata_free_lun(&ast_lun_map, stp->lun); - atadev->attach = NULL; - atadev->detach = NULL; - atadev->start = NULL; - atadev->softc = NULL; - atadev->flags = 0; + device_set_ivars(dev, NULL); free(stp, M_AST); + device_set_softc(dev, NULL); + free(atadev, M_ATA); + return 0; } -static int -ast_sense(struct ast_softc *stp) +static void +ast_shutdown(device_t dev) { - int count; + struct ata_device *atadev = device_get_softc(dev); - /* get drive capabilities, some bugridden drives needs this repeated */ - for (count = 0 ; count < 5 ; count++) { - if (!ast_mode_sense(stp, ATAPI_TAPE_CAP_PAGE, - &stp->cap, sizeof(stp->cap)) && - stp->cap.page_code == ATAPI_TAPE_CAP_PAGE) { - if (stp->cap.blk32k) - stp->blksize = 32768; - if (stp->cap.blk1024) - stp->blksize = 1024; - if (stp->cap.blk512) - stp->blksize = 512; - if (!stp->blksize) - continue; - stp->cap.max_speed = ntohs(stp->cap.max_speed); - stp->cap.max_defects = ntohs(stp->cap.max_defects); - stp->cap.ctl = ntohs(stp->cap.ctl); - stp->cap.speed = ntohs(stp->cap.speed); - stp->cap.buffer_size = ntohs(stp->cap.buffer_size); - return 0; - } - } - return 1; + if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE) + ata_controlcmd(atadev, ATA_FLUSHCACHE, 0, 0, 0); } -static void -ast_describe(struct ast_softc *stp) +static int +ast_reinit(device_t dev) { - if (bootverbose) { - ata_prtdev(stp->device, "<%.40s/%.8s> tape drive at ata%d as %s\n", - stp->device->param->model, stp->device->param->revision, - device_get_unit(stp->device->channel->dev), - (stp->device->unit == ATA_MASTER) ? "master" : "slave"); - ata_prtdev(stp->device, "%dKB/s, ", stp->cap.max_speed); - printf("transfer limit %d blk%s, ", - stp->cap.ctl, (stp->cap.ctl > 1) ? "s" : ""); - printf("%dKB buffer, ", (stp->cap.buffer_size * DEV_BSIZE) / 1024); - printf("%s\n", ata_mode2str(stp->device->mode)); - ata_prtdev(stp->device, "Medium: "); - switch (stp->cap.medium_type) { - case 0x00: - printf("none"); break; - case 0x17: - printf("Travan 1 (400 Mbyte)"); break; - case 0xb6: - printf("Travan 4 (4 Gbyte)"); break; - case 0xda: - printf("OnStream ADR (15Gyte)"); break; - default: - printf("unknown (0x%x)", stp->cap.medium_type); - } - if (stp->cap.readonly) printf(", readonly"); - if (stp->cap.reverse) printf(", reverse"); - if (stp->cap.eformat) printf(", eformat"); - if (stp->cap.qfa) printf(", qfa"); - if (stp->cap.lock) printf(", lock"); - if (stp->cap.locked) printf(", locked"); - if (stp->cap.prevent) printf(", prevent"); - if (stp->cap.eject) printf(", eject"); - if (stp->cap.disconnect) printf(", disconnect"); - if (stp->cap.ecc) printf(", ecc"); - if (stp->cap.compress) printf(", compress"); - if (stp->cap.blk512) printf(", 512b"); - if (stp->cap.blk1024) printf(", 1024b"); - if (stp->cap.blk32k) printf(", 32kb"); - printf("\n"); - } - else { - ata_prtdev(stp->device, "TAPE <%.40s/%.8s> at ata%d-%s %s\n", - stp->device->param->model, stp->device->param->revision, - device_get_unit(stp->device->channel->dev), - (stp->device->unit == ATA_MASTER) ? "master" : "slave", - ata_mode2str(stp->device->mode)); + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_device *atadev = device_get_softc(dev); + struct ast_softc *stp = device_get_ivars(dev); + + if (((atadev->unit == ATA_MASTER) && !(ch->devices & ATA_ATAPI_MASTER)) || + ((atadev->unit == ATA_SLAVE) && !(ch->devices & ATA_ATAPI_SLAVE))) { + device_set_ivars(dev, NULL); + free(stp, M_AST); + return 1; } + ATA_SETMODE(GRANDPARENT(dev), dev); + return 0; } static int -ast_open(struct cdev *dev, int flags, int fmt, struct thread *td) +ast_open(struct cdev *cdev, int flags, int fmt, struct thread *td) { - struct ast_softc *stp = dev->si_drv1; + device_t dev = cdev->si_drv1; + struct ata_device *atadev = device_get_softc(dev); + struct ast_softc *stp = device_get_ivars(dev); - if (!stp || stp->device->flags & ATA_D_DETACHING) + if (!stp) return ENXIO; - - if (count_dev(dev) > 1) + if (!device_is_attached(dev)) return EBUSY; - ast_test_ready(stp->device); - + ast_test_ready(dev); if (stp->cap.lock) - ast_prevent_allow(stp, 1); - - if (ast_sense(stp)) - ata_prtdev(stp->device, "sense media type failed\n"); + ast_prevent_allow(dev, 1); + if (ast_sense(dev)) + device_printf(dev, "sense media type failed\n"); - stp->device->flags &= ~ATA_D_MEDIA_CHANGED; + atadev->flags &= ~ATA_D_MEDIA_CHANGED; stp->flags &= ~(F_DATA_WRITTEN | F_FM_WRITTEN); ast_total = 0; return 0; } static int -ast_close(struct cdev *dev, int flags, int fmt, struct thread *td) +ast_close(struct cdev *cdev, int flags, int fmt, struct thread *td) { - struct ast_softc *stp = dev->si_drv1; + device_t dev = cdev->si_drv1; + struct ast_softc *stp = device_get_ivars(dev); /* flush buffers, some drives fail here, they should report ctl = 0 */ if (stp->cap.ctl && (stp->flags & F_DATA_WRITTEN)) - ast_write_filemark(stp, 0); + ast_write_filemark(dev, 0); /* write filemark if data written to tape */ if (!(stp->flags & F_ONSTREAM) && (stp->flags & (F_DATA_WRITTEN | F_FM_WRITTEN)) == F_DATA_WRITTEN) - ast_write_filemark(stp, ATAPI_WF_WRITE); + ast_write_filemark(dev, ATAPI_WF_WRITE); /* if minor is even rewind on close */ - if (!(minor(dev) & 0x01)) - ast_rewind(stp); + if (!(minor(cdev) & 0x01)) + ast_rewind(dev); - if (stp->cap.lock && count_dev(dev) == 1) - ast_prevent_allow(stp, 0); + if (stp->cap.lock && count_dev(cdev) == 1) + ast_prevent_allow(dev, 0); stp->flags &= ~F_CTL_WARN; #ifdef AST_DEBUG - ata_prtdev(stp->device, "%ju total bytes transferred\n", - (uintmax_t)ast_total); + device_printf(dev, "%ju total bytes transferred\n", (uintmax_t)ast_total); #endif return 0; } static int -ast_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) +ast_ioctl(struct cdev *cdev, u_long cmd, caddr_t addr, int flag, struct thread *td) { - struct ast_softc *stp = dev->si_drv1; + device_t dev = cdev->si_drv1; + struct ast_softc *stp = device_get_ivars(dev); int error = 0; switch (cmd) { @@ -340,10 +294,10 @@ ast_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *t g->mt_comp0 = 0; g->mt_comp1 = 0; g->mt_comp2 = 0; g->mt_comp3 = 0; } - break; + break; case MTIOCTOP: - { + { int i; struct mtop *mt = (struct mtop *)addr; @@ -351,44 +305,44 @@ ast_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *t case MTWEOF: for (i=0; i < mt->mt_count && !error; i++) - error = ast_write_filemark(stp, ATAPI_WF_WRITE); + error = ast_write_filemark(dev, ATAPI_WF_WRITE); break; case MTFSF: if (mt->mt_count) - error = ast_space(stp, ATAPI_SP_FM, mt->mt_count); + error = ast_space(dev, ATAPI_SP_FM, mt->mt_count); break; case MTBSF: if (mt->mt_count) - error = ast_space(stp, ATAPI_SP_FM, -(mt->mt_count)); + error = ast_space(dev, ATAPI_SP_FM, -(mt->mt_count)); break; case MTREW: - error = ast_rewind(stp); + error = ast_rewind(dev); break; case MTOFFL: - error = ast_load_unload(stp, ATAPI_SS_EJECT); + error = ast_load_unload(dev, ATAPI_SS_EJECT); break; case MTNOP: - error = ast_write_filemark(stp, 0); + error = ast_write_filemark(dev, 0); break; case MTERASE: - error = ast_erase(stp); + error = ast_erase(dev); break; case MTEOD: - error = ast_space(stp, ATAPI_SP_EOD, 0); + error = ast_space(dev, ATAPI_SP_EOD, 0); break; case MTRETENS: - error = ast_load_unload(stp, ATAPI_SS_RETENSION|ATAPI_SS_LOAD); + error = ast_load_unload(dev, ATAPI_SS_RETENSION|ATAPI_SS_LOAD); break; - case MTFSR: + case MTFSR: case MTBSR: case MTCACHE: case MTNOCACHE: @@ -405,7 +359,7 @@ ast_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *t { struct ast_readposition position; - if ((error = ast_read_position(stp, 0, &position))) + if ((error = ast_read_position(dev, 0, &position))) break; *(u_int32_t *)addr = position.tape; } @@ -415,18 +369,18 @@ ast_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *t { struct ast_readposition position; - if ((error = ast_read_position(stp, 1, &position))) + if ((error = ast_read_position(dev, 1, &position))) break; *(u_int32_t *)addr = position.tape; } break; case MTIOCSLOCATE: - error = ast_locate(stp, 0, *(u_int32_t *)addr); + error = ast_locate(dev, 0, *(u_int32_t *)addr); break; case MTIOCHLOCATE: - error = ast_locate(stp, 1, *(u_int32_t *)addr); + error = ast_locate(dev, 1, *(u_int32_t *)addr); break; default: @@ -438,12 +392,12 @@ ast_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *t static void ast_strategy(struct bio *bp) { - struct ast_softc *stp = bp->bio_dev->si_drv1; - - if (stp->device->flags & ATA_D_DETACHING) { - biofinish(bp, NULL, ENXIO); - return; - } + device_t dev = bp->bio_dev->si_drv1; + struct ata_device *atadev = device_get_softc(dev); + struct ast_softc *stp = device_get_ivars(dev); + struct ata_request *request; + u_int32_t blkcount; + int8_t ccb[16]; /* if it's a null transfer, return immediatly. */ if (bp->bio_bcount == 0) { @@ -458,45 +412,20 @@ ast_strategy(struct bio *bp) /* check for != blocksize requests */ if (bp->bio_bcount % stp->blksize) { - ata_prtdev(stp->device, "transfers must be multiple of %d\n", - stp->blksize); + device_printf(dev, "transfers must be multiple of %d\n", stp->blksize); biofinish(bp, NULL, EIO); return; } /* warn about transfers bigger than the device suggests */ - if (bp->bio_bcount > stp->blksize * stp->cap.ctl) { + if (bp->bio_bcount > stp->blksize * stp->cap.ctl) { if ((stp->flags & F_CTL_WARN) == 0) { - ata_prtdev(stp->device, "WARNING: CTL exceeded %ld>%d\n", - bp->bio_bcount, stp->blksize * stp->cap.ctl); + device_printf(dev, "WARNING: CTL exceeded %ld>%d\n", + bp->bio_bcount, stp->blksize * stp->cap.ctl); stp->flags |= F_CTL_WARN; } } - mtx_lock(&stp->queue_mtx); - bioq_insert_tail(&stp->queue, bp); - mtx_unlock(&stp->queue_mtx); - ata_start(stp->device->channel); -} - -static void -ast_start(struct ata_device *atadev) -{ - struct ast_softc *stp = atadev->softc; - struct bio *bp; - struct ata_request *request; - u_int32_t blkcount; - int8_t ccb[16]; - - mtx_lock(&stp->queue_mtx); - bp = bioq_first(&stp->queue); - if (!bp) { - mtx_unlock(&stp->queue_mtx); - return; - } - bioq_remove(&stp->queue, bp); - mtx_unlock(&stp->queue_mtx); - bzero(ccb, sizeof(ccb)); if (bp->bio_cmd == BIO_READ) @@ -507,18 +436,18 @@ ast_start(struct ata_device *atadev) blkcount = bp->bio_bcount / stp->blksize; ccb[1] = 1; - ccb[2] = blkcount>>16; - ccb[3] = blkcount>>8; + ccb[2] = blkcount >> 16; + ccb[3] = blkcount >> 8; ccb[4] = blkcount; if (!(request = ata_alloc_request())) { biofinish(bp, NULL, ENOMEM); return; } - request->device = atadev; + request->dev = dev; request->driver = bp; bcopy(ccb, request->u.atapi.ccb, - (request->device->param->config & ATA_PROTO_MASK) == + (atadev->param.config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12 ? 16 : 12); request->data = bp->bio_data; request->bytecount = blkcount * stp->blksize; @@ -534,7 +463,7 @@ ast_start(struct ata_device *atadev) request->flags |= (ATA_R_ATAPI | ATA_R_WRITE); break; default: - ata_prtdev(atadev, "unknown BIO operation\n"); + device_printf(dev, "unknown BIO operation\n"); ata_free_request(request); biofinish(bp, NULL, EIO); return; @@ -546,8 +475,8 @@ ast_start(struct ata_device *atadev) static void ast_done(struct ata_request *request) { + struct ast_softc *stp = device_get_ivars(request->dev); struct bio *bp = request->driver; - struct ast_softc *stp = request->device->softc; /* finish up transfer */ if ((bp->bio_error = request->result)) @@ -561,41 +490,68 @@ ast_done(struct ata_request *request) } static int -ast_mode_sense(struct ast_softc *stp, int page, void *pagebuf, int pagesize) +ast_sense(device_t dev) { + struct ast_softc *stp = device_get_ivars(dev); + int count; + + /* get drive capabilities, some bugridden drives needs this repeated */ + for (count = 0 ; count < 5 ; count++) { + if (!ast_mode_sense(dev, ATAPI_TAPE_CAP_PAGE, + &stp->cap, sizeof(stp->cap)) && + stp->cap.page_code == ATAPI_TAPE_CAP_PAGE) { + if (stp->cap.blk32k) + stp->blksize = 32768; + if (stp->cap.blk1024) + stp->blksize = 1024; + if (stp->cap.blk512) + stp->blksize = 512; + if (!stp->blksize) + continue; + stp->cap.max_speed = ntohs(stp->cap.max_speed); + stp->cap.max_defects = ntohs(stp->cap.max_defects); + stp->cap.ctl = ntohs(stp->cap.ctl); + stp->cap.speed = ntohs(stp->cap.speed); + stp->cap.buffer_size = ntohs(stp->cap.buffer_size); + return 0; + } + } + return 1; +} + +static int +ast_mode_sense(device_t dev, int page, void *pagebuf, int pagesize) +{ + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_MODE_SENSE, 0x08, page, pagesize>>8, pagesize, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int error; - error = ata_atapicmd(stp->device, ccb, pagebuf, pagesize, ATA_R_READ, 10); -#ifdef AST_DEBUG - atapi_dump("ast: mode sense ", pagebuf, pagesize); -#endif + error = ata_atapicmd(atadev, ccb, pagebuf, pagesize, ATA_R_READ, 10); return error; } -static int -ast_mode_select(struct ast_softc *stp, void *pagebuf, int pagesize) +static int +ast_mode_select(device_t dev, void *pagebuf, int pagesize) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_MODE_SELECT, 0x10, 0, pagesize>>8, pagesize, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -#ifdef AST_DEBUG - ata_prtdev(stp->device, "modeselect pagesize=%d\n", pagesize); - atapi_dump("mode select ", pagebuf, pagesize); -#endif - return ata_atapicmd(stp->device, ccb, pagebuf, pagesize, 0, 10); + return ata_atapicmd(atadev, ccb, pagebuf, pagesize, 0, 10); } static int -ast_write_filemark(struct ast_softc *stp, u_int8_t function) +ast_write_filemark(device_t dev, u_int8_t function) { + struct ata_device *atadev = device_get_softc(dev); + struct ast_softc *stp = device_get_ivars(dev); int8_t ccb[16] = { ATAPI_WEOF, 0x01, 0, 0, function, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int error; if (stp->flags & F_ONSTREAM) - ccb[4] = 0x00; /* only flush buffers supported */ + ccb[4] = 0x00; /* only flush buffers supported */ else { if (function) { if (stp->flags & F_FM_WRITTEN) @@ -604,21 +560,21 @@ ast_write_filemark(struct ast_softc *stp, u_int8_t function) stp->flags |= F_FM_WRITTEN; } } - error = ata_atapicmd(stp->device, ccb, NULL, 0, 0, 10); + error = ata_atapicmd(atadev, ccb, NULL, 0, 0, 10); if (error) return error; - return ast_wait_dsc(stp->device, 10*60); + return ast_wait_dsc(dev, 10*60); } static int -ast_read_position(struct ast_softc *stp, int hard, - struct ast_readposition *position) +ast_read_position(device_t dev, int hard, struct ast_readposition *position) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_READ_POSITION, (hard ? 0x01 : 0), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int error; - error = ata_atapicmd(stp->device, ccb, (caddr_t)position, + error = ata_atapicmd(atadev, ccb, (caddr_t)position, sizeof(struct ast_readposition), ATA_R_READ, 10); position->tape = ntohl(position->tape); position->host = ntohl(position->host); @@ -626,84 +582,93 @@ ast_read_position(struct ast_softc *stp, int hard, } static int -ast_space(struct ast_softc *stp, u_int8_t function, int32_t count) +ast_space(device_t dev, u_int8_t function, int32_t count) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_SPACE, function, count>>16, count>>8, count, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - return ata_atapicmd(stp->device, ccb, NULL, 0, 0, 60*60); + return ata_atapicmd(atadev, ccb, NULL, 0, 0, 60*60); } static int -ast_locate(struct ast_softc *stp, int hard, u_int32_t pos) +ast_locate(device_t dev, int hard, u_int32_t pos) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_LOCATE, 0x01 | (hard ? 0x4 : 0), 0, pos>>24, pos>>16, pos>>8, pos, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int error; - error = ata_atapicmd(stp->device, ccb, NULL, 0, 0, 10); + error = ata_atapicmd(atadev, ccb, NULL, 0, 0, 10); if (error) return error; - return ast_wait_dsc(stp->device, 60*60); + return ast_wait_dsc(dev, 60*60); } static int -ast_prevent_allow(struct ast_softc *stp, int lock) +ast_prevent_allow(device_t dev, int lock) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - return ata_atapicmd(stp->device, ccb, NULL, 0, 0, 30); + return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30); } static int -ast_load_unload(struct ast_softc *stp, u_int8_t function) +ast_load_unload(device_t dev, u_int8_t function) { + struct ata_device *atadev = device_get_softc(dev); + struct ast_softc *stp = device_get_ivars(dev); int8_t ccb[16] = { ATAPI_START_STOP, 0x01, 0, 0, function, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int error; if ((function & ATAPI_SS_EJECT) && !stp->cap.eject) return 0; - error = ata_atapicmd(stp->device, ccb, NULL, 0, 0, 10); + error = ata_atapicmd(atadev, ccb, NULL, 0, 0, 10); if (error) return error; tsleep((caddr_t)&error, PRIBIO, "astlu", 1 * hz); if (function == ATAPI_SS_EJECT) return 0; - return ast_wait_dsc(stp->device, 60*60); + return ast_wait_dsc(dev, 60*60); } static int -ast_rewind(struct ast_softc *stp) +ast_rewind(device_t dev) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_REZERO, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int error; - error = ata_atapicmd(stp->device, ccb, NULL, 0, 0, 10); + error = ata_atapicmd(atadev, ccb, NULL, 0, 0, 10); if (error) return error; - return ast_wait_dsc(stp->device, 60*60); + return ast_wait_dsc(dev, 60*60); } static int -ast_erase(struct ast_softc *stp) +ast_erase(device_t dev) { + struct ata_device *atadev = device_get_softc(dev); int8_t ccb[16] = { ATAPI_ERASE, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int error; - if ((error = ast_rewind(stp))) + if ((error = ast_rewind(dev))) return error; - return ata_atapicmd(stp->device, ccb, NULL, 0, 0, 60*60); + return ata_atapicmd(atadev, ccb, NULL, 0, 0, 60*60); } static int -ast_test_ready(struct ata_device *atadev) +ast_test_ready(device_t dev) { + struct ata_device *atadev = device_get_softc(dev); + int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -711,8 +676,10 @@ ast_test_ready(struct ata_device *atadev) } static int -ast_wait_dsc(struct ata_device *atadev, int timeout) +ast_wait_dsc(device_t dev, int timeout) { + struct ata_device *atadev = device_get_softc(dev); + int error = 0; int8_t ccb[16] = { ATAPI_POLL_DSC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -727,3 +694,100 @@ ast_wait_dsc(struct ata_device *atadev, int timeout) } return error; } + +static void +ast_describe(device_t dev) +{ + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_device *atadev = device_get_softc(dev); + struct ast_softc *stp = device_get_ivars(dev); + + if (bootverbose) { + device_printf(dev, "<%.40s/%.8s> tape drive at ata%d as %s\n", + atadev->param.model, atadev->param.revision, + device_get_unit(ch->dev), + (atadev->unit == ATA_MASTER) ? "master" : "slave"); + device_printf(dev, "%dKB/s, ", stp->cap.max_speed); + printf("transfer limit %d blk%s, ", + stp->cap.ctl, (stp->cap.ctl > 1) ? "s" : ""); + printf("%dKB buffer, ", (stp->cap.buffer_size * DEV_BSIZE) / 1024); + printf("%s\n", ata_mode2str(atadev->mode)); + device_printf(dev, "Medium: "); + switch (stp->cap.medium_type) { + case 0x00: + printf("none"); break; + case 0x17: + printf("Travan 1 (400 Mbyte)"); break; + case 0xb6: + printf("Travan 4 (4 Gbyte)"); break; + case 0xda: + printf("OnStream ADR (15Gyte)"); break; + default: + printf("unknown (0x%x)", stp->cap.medium_type); + } + if (stp->cap.readonly) printf(", readonly"); + if (stp->cap.reverse) printf(", reverse"); + if (stp->cap.eformat) printf(", eformat"); + if (stp->cap.qfa) printf(", qfa"); + if (stp->cap.lock) printf(", lock"); + if (stp->cap.locked) printf(", locked"); + if (stp->cap.prevent) printf(", prevent"); + if (stp->cap.eject) printf(", eject"); + if (stp->cap.disconnect) printf(", disconnect"); + if (stp->cap.ecc) printf(", ecc"); + if (stp->cap.compress) printf(", compress"); + if (stp->cap.blk512) printf(", 512b"); + if (stp->cap.blk1024) printf(", 1024b"); + if (stp->cap.blk32k) printf(", 32kb"); + printf("\n"); + } + else { + device_printf(dev, "TAPE <%.40s/%.8s> at ata%d-%s %s\n", + atadev->param.model, atadev->param.revision, + device_get_unit(ch->dev), + (atadev->unit == ATA_MASTER) ? "master" : "slave", + ata_mode2str(atadev->mode)); + } +} + +static device_method_t ast_methods[] = { + /* device interface */ + DEVMETHOD(device_identify, ast_identify), + DEVMETHOD(device_probe, ast_probe), + DEVMETHOD(device_attach, ast_attach), + DEVMETHOD(device_detach, ast_detach), + DEVMETHOD(device_shutdown, ast_shutdown), + + /* ATA methods */ + DEVMETHOD(ata_reinit, ast_reinit), + + { 0, 0 } +}; + +static driver_t ast_driver = { + "ast", + ast_methods, + sizeof(struct ast_softc) +}; + +static devclass_t ast_devclass; + +static int +ast_modevent(module_t mod, int what, void *arg) +{ + device_t *devs; + int ndevs, i; + + if (what == MOD_UNLOAD) { + if (!devclass_get_devices(ast_devclass, &devs, &ndevs) && devs) { + for (i = 0; i < ndevs; i++) + device_delete_child(device_get_parent(devs[i]), devs[i]); + free(devs, M_TEMP); + } + } + return 0; +} + +DRIVER_MODULE(ast, ata, ast_driver, ast_devclass, ast_modevent, NULL); +MODULE_VERSION(ast, 1); +MODULE_DEPEND(ast, ata, 1, 1, 1); diff --git a/sys/dev/ata/atapi-tape.h b/sys/dev/ata/atapi-tape.h index f34328d..e51cff2 100644 --- a/sys/dev/ata/atapi-tape.h +++ b/sys/dev/ata/atapi-tape.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,133 +31,129 @@ /* ATAPI tape drive Capabilities and Mechanical Status Page */ struct ast_cappage { /* mode page data header */ - u_int8_t data_length; /* total length of data */ - u_int8_t medium_type; /* medium type (if any) */ - u_int8_t reserved :4; - u_int8_t mode :3; /* buffering mode */ - u_int8_t write_protect :1; /* media is writeprotected */ - u_int8_t blk_desc_len; /* block Descriptor Length */ + u_int8_t data_length; /* total length of data */ + u_int8_t medium_type; /* medium type (if any) */ + u_int8_t reserved :4; + u_int8_t mode :3; /* buffering mode */ + u_int8_t write_protect :1; /* media is writeprotected */ + u_int8_t blk_desc_len; /* block Descriptor Length */ /* capabilities page */ - u_int8_t page_code :6; -#define ATAPI_TAPE_CAP_PAGE 0x2a + u_int8_t page_code :6; +#define ATAPI_TAPE_CAP_PAGE 0x2a - u_int8_t reserved0_6 :1; - u_int8_t ps :1; /* parameters saveable */ - u_int8_t page_length; /* page Length == 0x12 */ - u_int8_t reserved2; - u_int8_t reserved3; - u_int8_t readonly :1; /* read Only Mode */ - u_int8_t reserved4_1234 :4; - u_int8_t reverse :1; /* supports reverse direction */ - u_int8_t reserved4_67 :2; - u_int8_t reserved5_012 :3; - u_int8_t eformat :1; /* supports ERASE formatting */ - u_int8_t reserved5_4 :1; - u_int8_t qfa :1; /* supports QFA formats */ - u_int8_t reserved5_67 :2; - u_int8_t lock :1; /* supports locking media */ - u_int8_t locked :1; /* the media is locked */ - u_int8_t prevent :1; /* defaults to prevent state */ - u_int8_t eject :1; /* supports eject */ - u_int8_t disconnect :1; /* can break request > ctl */ - u_int8_t reserved6_5 :1; - u_int8_t ecc :1; /* supports error correction */ - u_int8_t compress :1; /* supports data compression */ - u_int8_t reserved7_0 :1; - u_int8_t blk512 :1; /* supports 512b block size */ - u_int8_t blk1024 :1; /* supports 1024b block size */ - u_int8_t reserved7_3456 :4; - u_int8_t blk32k :1; /* supports 32kb block size */ - u_int16_t max_speed; /* supported speed in KBps */ - u_int16_t max_defects; /* max stored defect entries */ - u_int16_t ctl; /* continuous transfer limit */ - u_int16_t speed; /* current Speed, in KBps */ - u_int16_t buffer_size; /* buffer Size, in 512 bytes */ - u_int8_t reserved18; - u_int8_t reserved19; + u_int8_t reserved0_6 :1; + u_int8_t ps :1; /* parameters saveable */ + u_int8_t page_length; /* page Length == 0x12 */ + u_int8_t reserved2; + u_int8_t reserved3; + u_int8_t readonly :1; /* read Only Mode */ + u_int8_t reserved4_1234 :4; + u_int8_t reverse :1; /* supports reverse direction */ + u_int8_t reserved4_67 :2; + u_int8_t reserved5_012 :3; + u_int8_t eformat :1; /* supports ERASE formatting */ + u_int8_t reserved5_4 :1; + u_int8_t qfa :1; /* supports QFA formats */ + u_int8_t reserved5_67 :2; + u_int8_t lock :1; /* supports locking media */ + u_int8_t locked :1; /* the media is locked */ + u_int8_t prevent :1; /* defaults to prevent state */ + u_int8_t eject :1; /* supports eject */ + u_int8_t disconnect :1; /* can break request > ctl */ + u_int8_t reserved6_5 :1; + u_int8_t ecc :1; /* supports error correction */ + u_int8_t compress :1; /* supports data compression */ + u_int8_t reserved7_0 :1; + u_int8_t blk512 :1; /* supports 512b block size */ + u_int8_t blk1024 :1; /* supports 1024b block size */ + u_int8_t reserved7_3456 :4; + u_int8_t blk32k :1; /* supports 32kb block size */ + u_int16_t max_speed; /* supported speed in KBps */ + u_int16_t max_defects; /* max stored defect entries */ + u_int16_t ctl; /* continuous transfer limit */ + u_int16_t speed; /* current Speed, in KBps */ + u_int16_t buffer_size; /* buffer Size, in 512 bytes */ + u_int8_t reserved18; + u_int8_t reserved19; }; /* ATAPI OnStream ADR data transfer mode page (ADR unique) */ struct ast_transferpage { /* mode page data header */ - u_int8_t data_length; /* total length of data */ - u_int8_t medium_type; /* medium type (if any) */ - u_int8_t dsp; /* device specific parameter */ - u_int8_t blk_desc_len; /* block Descriptor Length */ + u_int8_t data_length; /* total length of data */ + u_int8_t medium_type; /* medium type (if any) */ + u_int8_t dsp; /* device specific parameter */ + u_int8_t blk_desc_len; /* block Descriptor Length */ /* data transfer page */ - u_int8_t page_code :6; + u_int8_t page_code :6; #define ATAPI_TAPE_TRANSFER_PAGE 0x30 - u_int8_t reserved0_6 :1; - u_int8_t ps :1; /* parameters saveable */ - u_int8_t page_length; /* page Length == 0x02 */ - u_int8_t reserved2; - u_int8_t read32k :1; /* 32k blk size (data only) */ - u_int8_t read32k5 :1; /* 32.5k blk size (data&AUX) */ - u_int8_t reserved3_23 :2; - u_int8_t write32k :1; /* 32k blk size (data only) */ - u_int8_t write32k5 :1; /* 32.5k blk size (data&AUX) */ - u_int8_t reserved3_6 :1; - u_int8_t streaming :1; /* streaming mode enable */ + u_int8_t reserved0_6 :1; + u_int8_t ps :1; /* parameters saveable */ + u_int8_t page_length; /* page Length == 0x02 */ + u_int8_t reserved2; + u_int8_t read32k :1; /* 32k blk size (data only) */ + u_int8_t read32k5 :1; /* 32.5k blk size (data&AUX) */ + u_int8_t reserved3_23 :2; + u_int8_t write32k :1; /* 32k blk size (data only) */ + u_int8_t write32k5 :1; /* 32.5k blk size (data&AUX) */ + u_int8_t reserved3_6 :1; + u_int8_t streaming :1; /* streaming mode enable */ }; /* ATAPI OnStream ADR vendor identification mode page (ADR unique) */ struct ast_identifypage { /* mode page data header */ - u_int8_t data_length; /* total length of data */ - u_int8_t medium_type; /* medium type (if any) */ - u_int8_t dsp; /* device specific parameter */ - u_int8_t blk_desc_len; /* block Descriptor Length */ + u_int8_t data_length; /* total length of data */ + u_int8_t medium_type; /* medium type (if any) */ + u_int8_t dsp; /* device specific parameter */ + u_int8_t blk_desc_len; /* block Descriptor Length */ /* data transfer page */ - u_int8_t page_code :6; + u_int8_t page_code :6; #define ATAPI_TAPE_IDENTIFY_PAGE 0x36 - u_int8_t reserved0_6 :1; - u_int8_t ps :1; /* parameters saveable */ - u_int8_t page_length; /* page Length == 0x06 */ - u_int8_t ident[4]; /* host id string */ - u_int8_t reserved6; - u_int8_t reserved7; + u_int8_t reserved0_6 :1; + u_int8_t ps :1; /* parameters saveable */ + u_int8_t page_length; /* page Length == 0x06 */ + u_int8_t ident[4]; /* host id string */ + u_int8_t reserved6; + u_int8_t reserved7; }; /* ATAPI read position structure */ struct ast_readposition { - u_int8_t reserved0_05 :6; - u_int8_t eop :1; /* end of partition */ - u_int8_t bop :1; /* beginning of partition */ - u_int8_t reserved1; - u_int8_t reserved2; - u_int8_t reserved3; - u_int32_t host; /* frame address in buffer */ - u_int32_t tape; /* frame address on tape */ - u_int8_t reserved12; - u_int8_t reserved13; - u_int8_t reserved14; - u_int8_t blks_in_buf; /* blocks in buffer */ - u_int8_t reserved16; - u_int8_t reserved17; - u_int8_t reserved18; - u_int8_t reserved19; + u_int8_t reserved0_05 :6; + u_int8_t eop :1; /* end of partition */ + u_int8_t bop :1; /* beginning of partition */ + u_int8_t reserved1; + u_int8_t reserved2; + u_int8_t reserved3; + u_int32_t host; /* frame address in buffer */ + u_int32_t tape; /* frame address on tape */ + u_int8_t reserved12; + u_int8_t reserved13; + u_int8_t reserved14; + u_int8_t blks_in_buf; /* blocks in buffer */ + u_int8_t reserved16; + u_int8_t reserved17; + u_int8_t reserved18; + u_int8_t reserved19; }; struct ast_softc { - struct ata_device *device; /* device softc */ - int lun; /* logical device unit */ - int flags; /* device state flags */ -#define F_CTL_WARN 0x0001 /* warned about CTL wrong? */ -#define F_WRITEPROTECT 0x0002 /* media is writeprotected */ -#define F_DATA_WRITTEN 0x0004 /* data has been written */ -#define F_FM_WRITTEN 0x0008 /* filemark has been written */ -#define F_ONSTREAM 0x0100 /* OnStream ADR device */ + int flags; /* device state flags */ +#define F_CTL_WARN 0x0001 /* warned about CTL wrong? */ +#define F_WRITEPROTECT 0x0002 /* media is writeprotected */ +#define F_DATA_WRITTEN 0x0004 /* data has been written */ +#define F_FM_WRITTEN 0x0008 /* filemark has been written */ +#define F_ONSTREAM 0x0100 /* OnStream ADR device */ - int blksize; /* block size (512 | 1024) */ - struct mtx queue_mtx; /* bio queue lock */ - struct bio_queue_head queue; /* queue of i/o requests */ - struct atapi_params *param; /* drive parameters table */ - struct ast_cappage cap; /* capabilities page info */ - struct devstat *stats; /* devstat entry */ - struct cdev *dev1, *dev2; /* device place holders */ + int blksize; /* block size (512 | 1024) */ + struct atapi_params *param; /* drive parameters table */ + struct ast_cappage cap; /* capabilities page info */ + struct devstat *stats; /* devstat entry */ + struct cdev *dev1, *dev2; /* device place holders */ }; diff --git a/sys/modules/Makefile b/sys/modules/Makefile index a196b78..deb74b4 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -23,6 +23,7 @@ SUBDIR= ${_3dfx} \ ${_arcnet} \ ${_arl} \ ${_asr} \ + ata \ ath \ ${_ath_hal} \ ath_rate_amrr \ diff --git a/sys/modules/ata/Makefile b/sys/modules/ata/Makefile new file mode 100644 index 0000000..b01d00f --- /dev/null +++ b/sys/modules/ata/Makefile @@ -0,0 +1,13 @@ +# $FreeBSD$ + +SUBDIR = ata +SUBDIR += atacard +.if ${MACHINE} == "pc98" +SUBDIR += atacbus +.else +SUBDIR += ataisa +.endif +SUBDIR += atapci +SUBDIR += atadisk atapicd atapifd atapist ataraid #atacam + +.include <bsd.subdir.mk> diff --git a/sys/modules/ata/Makefile.inc b/sys/modules/ata/Makefile.inc new file mode 100644 index 0000000..265f86d --- /dev/null +++ b/sys/modules/ata/Makefile.inc @@ -0,0 +1,3 @@ +# $FreeBSD$ + +.include "../Makefile.inc" diff --git a/sys/modules/ata/ata/Makefile b/sys/modules/ata/ata/Makefile new file mode 100644 index 0000000..262984e --- /dev/null +++ b/sys/modules/ata/ata/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../dev/ata + +KMOD= ata +SRCS= ata-all.c ata-queue.c ata-lowlevel.c ata_if.c +# ata-pci.c ata-dma.c ata-chipset.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h + +.include <bsd.kmod.mk> diff --git a/sys/modules/ata/atacam/Makefile b/sys/modules/ata/atacam/Makefile new file mode 100644 index 0000000..dcaf847a --- /dev/null +++ b/sys/modules/ata/atacam/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../dev/ata + +KMOD= atacam +SRCS= ata-cam.c +SRCS+= opt_ata.h opt_cam.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> diff --git a/sys/modules/ata/atacard/Makefile b/sys/modules/ata/atacard/Makefile new file mode 100644 index 0000000..1bb8b5b --- /dev/null +++ b/sys/modules/ata/atacard/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../dev/ata + +KMOD= atacard +SRCS= ata-card.c +SRCS+= opt_ata.h pccarddevs.h ata_if.h device_if.h bus_if.h isa_if.h card_if.h + +.include <bsd.kmod.mk> diff --git a/sys/modules/ata/atacbus/Makefile b/sys/modules/ata/atacbus/Makefile new file mode 100644 index 0000000..2b11a89 --- /dev/null +++ b/sys/modules/ata/atacbus/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../dev/ata + +KMOD= atacbus +SRCS= ata-cbus.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h isa_if.h + +.include <bsd.kmod.mk> diff --git a/sys/modules/ata/atadisk/Makefile b/sys/modules/ata/atadisk/Makefile new file mode 100644 index 0000000..c64cd3f --- /dev/null +++ b/sys/modules/ata/atadisk/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../dev/ata + +KMOD= atadisk +SRCS= ata-disk.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> diff --git a/sys/modules/ata/ataisa/Makefile b/sys/modules/ata/ataisa/Makefile new file mode 100644 index 0000000..b43fd2e --- /dev/null +++ b/sys/modules/ata/ataisa/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../dev/ata + +KMOD= ataisa +SRCS= ata-isa.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h isa_if.h + +.include <bsd.kmod.mk> diff --git a/sys/modules/ata/atapci/Makefile b/sys/modules/ata/atapci/Makefile new file mode 100644 index 0000000..00d188b --- /dev/null +++ b/sys/modules/ata/atapci/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../dev/ata + +KMOD= atapci +SRCS= ata-pci.c ata-dma.c ata-chipset.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> diff --git a/sys/modules/ata/atapicd/Makefile b/sys/modules/ata/atapicd/Makefile new file mode 100644 index 0000000..bcc2319 --- /dev/null +++ b/sys/modules/ata/atapicd/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../dev/ata + +KMOD= atapicd +SRCS= atapi-cd.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> diff --git a/sys/modules/ata/atapifd/Makefile b/sys/modules/ata/atapifd/Makefile new file mode 100644 index 0000000..f563748 --- /dev/null +++ b/sys/modules/ata/atapifd/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../dev/ata + +KMOD= atapifd +SRCS= atapi-fd.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> diff --git a/sys/modules/ata/atapist/Makefile b/sys/modules/ata/atapist/Makefile new file mode 100644 index 0000000..86c19b5 --- /dev/null +++ b/sys/modules/ata/atapist/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../dev/ata + +KMOD= atapist +SRCS= atapi-tape.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> diff --git a/sys/modules/ata/ataraid/Makefile b/sys/modules/ata/ataraid/Makefile new file mode 100644 index 0000000..8f41bd7 --- /dev/null +++ b/sys/modules/ata/ataraid/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../dev/ata + +KMOD= ataraid +SRCS= ata-raid.c +SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h + +.include <bsd.kmod.mk> diff --git a/sys/sys/ata.h b/sys/sys/ata.h index be12cf3..fa214c9 100644 --- a/sys/sys/ata.h +++ b/sys/sys/ata.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000 - 2004 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 2000 - 2005 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,7 +37,7 @@ struct ata_params { /*000*/ u_int16_t config; /* configuration info */ #define ATA_PROTO_MASK 0x8003 -#define ATA_PROTO_ATA 0x0002 +#define ATA_PROTO_ATA 0x0000 #define ATA_PROTO_ATAPI_12 0x8000 #define ATA_PROTO_ATAPI_16 0x8001 #define ATA_ATAPI_TYPE_MASK 0x1f00 @@ -82,7 +82,11 @@ struct ata_params { #define ATA_FLAG_64_70 0x0002 /* words 64-70 valid */ #define ATA_FLAG_88 0x0004 /* word 88 valid */ -/*054*/ u_int16_t obsolete54[5]; +/*054*/ u_int16_t current_cylinders; +/*055*/ u_int16_t current_heads; +/*056*/ u_int16_t current_sectors; +/*057*/ u_int16_t current_size_1; +/*058*/ u_int16_t current_size_2; /*059*/ u_int16_t multi; #define ATA_MULTI_VALID 0x0100 @@ -155,7 +159,7 @@ struct ata_params { #define ATA_SUPPORT_FLUSHCACHE48 0x2000 /*084/087*/ u_int16_t extension; - } support, enabled; + } __packed support, enabled; /*088*/ u_int16_t udmamodes; /* UltraDMA modes */ /*089*/ u_int16_t erase_time; @@ -182,11 +186,11 @@ struct ata_params { /*128*/ u_int16_t security_status; u_int16_t reserved129[31]; /*160*/ u_int16_t cfa_powermode1; - u_int16_t reserved161[14]; + u_int16_t reserved161[15]; /*176*/ u_int16_t media_serial[30]; u_int16_t reserved206[49]; /*255*/ u_int16_t integrity; -}; +} __packed; /* ATA transfer modes */ #define ATA_MODE_MASK 0x0f @@ -368,9 +372,14 @@ struct ata_cmd { struct raid_setup { int type; -#define AR_RAID0 1 -#define AR_RAID1 2 -#define AR_SPAN 4 +#define AR_JBOD 0x01 +#define AR_SPAN 0x02 +#define AR_RAID0 0x04 +#define AR_RAID1 0x08 +#define AR_RAID01 0x10 +#define AR_RAID3 0x20 +#define AR_RAID4 0x40 +#define AR_RAID5 0x80 int total_disks; int disks[16]; |