diff options
41 files changed, 8313 insertions, 5892 deletions
diff --git a/sbin/atacontrol/atacontrol.c b/sbin/atacontrol/atacontrol.c index 4332299f324c..4f1973a75abb 100644 --- a/sbin/atacontrol/atacontrol.c +++ b/sbin/atacontrol/atacontrol.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 @@ -373,17 +373,21 @@ main(int argc, char **argv) iocmd.cmd = ATARAIDCREATE; if (argc > 2) { - if (!strcmp(argv[2], "RAID0") || - !strcmp(argv[2], "stripe")) - iocmd.u.raid_setup.type = 1; - if (!strcmp(argv[2], "RAID1") || - !strcmp(argv[2],"mirror")) - iocmd.u.raid_setup.type = 2; - if (!strcmp(argv[2], "RAID0+1")) - iocmd.u.raid_setup.type = 3; - if (!strcmp(argv[2], "SPAN") || - !strcmp(argv[2], "JBOD")) - iocmd.u.raid_setup.type = 4; + if (!strcasecmp(argv[2], "RAID0") || + !strcasecmp(argv[2], "stripe")) + iocmd.u.raid_setup.type = AR_RAID0; + if (!strcasecmp(argv[2], "RAID1") || + !strcasecmp(argv[2],"mirror")) + iocmd.u.raid_setup.type = AR_RAID1; + if (!strcasecmp(argv[2], "RAID0+1") || + !strcasecmp(argv[2],"RAID10")) + iocmd.u.raid_setup.type = AR_RAID01; + if (!strcasecmp(argv[2], "RAID5")) + iocmd.u.raid_setup.type = AR_RAID5; + if (!strcasecmp(argv[2], "SPAN")) + iocmd.u.raid_setup.type = AR_SPAN; + if (!strcasecmp(argv[2], "JBOD")) + iocmd.u.raid_setup.type = AR_JBOD; } if (!iocmd.u.raid_setup.type) { fprintf(stderr, "atacontrol: Invalid RAID type\n"); @@ -393,7 +397,9 @@ main(int argc, char **argv) exit(EX_USAGE); } - if (iocmd.u.raid_setup.type & 1) { + if (iocmd.u.raid_setup.type == AR_RAID0 || + iocmd.u.raid_setup.type == AR_RAID01 || + iocmd.u.raid_setup.type == AR_RAID5) { if (argc < 4 || !sscanf(argv[3], "%d", &iocmd.u.raid_setup.interleave) == 1) { @@ -451,6 +457,14 @@ main(int argc, char **argv) iocmd.cmd = ATARAIDREBUILD; if (ioctl(fd, IOCATA, &iocmd) < 0) warn("ioctl(ATARAIDREBUILD)"); + else { + char buffer[128]; + sprintf(buffer, "/usr/bin/nice -n 20 /bin/dd " + "if=/dev/ar%d of=/dev/null bs=1m &", + iocmd.channel); + if (system(buffer)) + warn("background dd"); + } } else if (!strcmp(argv[1], "status") && argc == 3) { int i; @@ -467,10 +481,16 @@ main(int argc, char **argv) case AR_RAID1: printf("RAID1"); break; - case AR_RAID0 | AR_RAID1: + case AR_RAID01: printf("RAID0+1 stripesize=%d", iocmd.u.raid_status.interleave); break; + case AR_RAID5: + printf("RAID5 stripesize=%d", + iocmd.u.raid_status.interleave); + break; + case AR_JBOD: + printf("JBOD"); case AR_SPAN: printf("SPAN"); break; diff --git a/sys/conf/files b/sys/conf/files index c734acc8f4b8..73fd93a147cb 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 c75325492f5a..07d0c3872ca0 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 25608bcf5f92..eb0174f67f5d 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 ca38b5b1e1e7..45786e374790 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 6a9d09904dc0..72608e3ff84e 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 0a6c8c64f969..a8aa985686e3 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 5c3926165802..46b009cad9c6 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 1e1735f63bd2..b87c1b38a09d 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 ea27d683325f..4a6320ba00bb 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 2a338c6de877..91836452124a 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 c24c4ae4fca8..cbfc4a65b9c4 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 974fb7d2ea7c..98e35a16ad2f 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 4fadd2dc5349..c15a2d37de74 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 aec3b051d130..bb9d9e03ad1c 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 747ba419ca35..523ee8e46d29 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 5189e700a9ba..be15b38801fc 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 8800230a20ab..603e85d6818c 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 4edaa7960af7..ab9d902d52f3 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 7a3e7a998d58..31c785d9d9e8 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 4a7df8083459..7f7efa779db9 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 1618df513fbc..ba16837e3517 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 9fda1406aa56..0c701c4a38f8 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 4f37b0dea5d1..2a2f699e7106 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 827edec19c11..b1e90f06fb30 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 f34328d255fa..e51cff22ede4 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 a196b7869e68..deb74b4002e9 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 000000000000..b01d00f4cbcd --- /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 000000000000..265f86d1ed55 --- /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 000000000000..262984e35e27 --- /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 000000000000..dcaf847a3561 --- /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 000000000000..1bb8b5bcddb2 --- /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 000000000000..2b11a89137ee --- /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 000000000000..c64cd3f79a07 --- /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 000000000000..b43fd2e34888 --- /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 000000000000..00d188bb9a8d --- /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 000000000000..bcc23199d653 --- /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 000000000000..f5637480a26d --- /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 000000000000..86c19b5f7b89 --- /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 000000000000..8f41bd7425b1 --- /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 be12cf361606..fa214c9be7ae 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]; |