| Commit | Line | Data |
|---|---|---|
| c1b3d7c5 TS |
1 | /*- |
| 2 | * Copyright (c) 1998 - 2006 Søren Schmidt <sos@FreeBSD.org> | |
| 3 | * All rights reserved. | |
| 4 | * | |
| 5 | * Redistribution and use in source and binary forms, with or without | |
| 6 | * modification, are permitted provided that the following conditions | |
| 7 | * are met: | |
| 8 | * 1. Redistributions of source code must retain the above copyright | |
| 9 | * notice, this list of conditions and the following disclaimer, | |
| 10 | * without modification, immediately at the beginning of the file. | |
| 11 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 12 | * notice, this list of conditions and the following disclaimer in the | |
| 13 | * documentation and/or other materials provided with the distribution. | |
| 14 | * | |
| 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
| 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
| 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
| 18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
| 20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
| 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 25 | * | |
| 02d7aa4a | 26 | * $FreeBSD: src/sys/dev/ata/ata-all.c,v 1.279 2007/02/23 16:25:08 jhb Exp $ |
| 3ec9ecbc | 27 | * $DragonFly: src/sys/dev/disk/nata/ata-all.c,v 1.14 2008/03/24 06:41:56 dillon Exp $ |
| c1b3d7c5 TS |
28 | */ |
| 29 | ||
| 30 | #include "opt_ata.h" | |
| 31 | ||
| 32 | #include <sys/param.h> | |
| 33 | #include <sys/bus.h> | |
| 34 | #include <sys/callout.h> | |
| 35 | #include <sys/conf.h> | |
| 36 | #include <sys/ctype.h> | |
| 37 | #include <sys/device.h> | |
| 38 | #include <sys/endian.h> | |
| 39 | #include <sys/kernel.h> | |
| 40 | #include <sys/libkern.h> | |
| 41 | #include <sys/lock.h> /* for {get,rel}_mplock() */ | |
| 42 | #include <sys/malloc.h> | |
| 43 | #include <sys/module.h> | |
| 44 | #include <sys/nata.h> | |
| 45 | #include <sys/objcache.h> | |
| 46 | #include <sys/queue.h> | |
| 47 | #include <sys/spinlock2.h> | |
| 48 | #include <sys/sysctl.h> | |
| 49 | #include <sys/systm.h> | |
| 50 | ||
| 51 | #include "ata-all.h" | |
| 52 | #include "ata_if.h" | |
| 53 | ||
| 54 | /* device structure */ | |
| 55 | static d_ioctl_t ata_ioctl; | |
| 56 | static struct dev_ops ata_ops = { | |
| 57 | { "ata", 159, 0 }, | |
| 58 | .d_open = nullopen, | |
| 59 | .d_close = nullclose, | |
| 60 | .d_ioctl = ata_ioctl, | |
| 61 | }; | |
| 62 | ||
| 63 | /* prototypes */ | |
| 64 | static void ata_boot_attach(void); | |
| 65 | static device_t ata_add_child(device_t, struct ata_device *, int); | |
| 66 | static int ata_getparam(struct ata_device *, int); | |
| 67 | static void bswap(int8_t *, int); | |
| 68 | static void btrim(int8_t *, int); | |
| 69 | static void bpack(int8_t *, int8_t *, int); | |
| 70 | ||
| 71 | /* global vars */ | |
| 72 | MALLOC_DEFINE(M_ATA, "ata_generic", "ATA driver generic layer"); | |
| 73 | int (*ata_raid_ioctl_func)(u_long cmd, caddr_t data) = NULL; | |
| c1b3d7c5 TS |
74 | devclass_t ata_devclass; |
| 75 | struct objcache *ata_request_cache; | |
| 76 | struct objcache *ata_composite_cache; | |
| 1d4619bd TS |
77 | struct objcache_malloc_args ata_request_malloc_args = { |
| 78 | sizeof(struct ata_request), M_ATA }; | |
| 79 | struct objcache_malloc_args ata_composite_malloc_args = { | |
| 80 | sizeof(struct ata_composite), M_ATA }; | |
| c1b3d7c5 TS |
81 | int ata_wc = 1; |
| 82 | ||
| 83 | /* local vars */ | |
| 84 | static int ata_dma = 1; | |
| 85 | static int atapi_dma = 1; | |
| 86 | ||
| 87 | /* sysctl vars */ | |
| 88 | SYSCTL_NODE(_hw, OID_AUTO, ata, CTLFLAG_RD, 0, "ATA driver parameters"); | |
| 89 | TUNABLE_INT("hw.ata.ata_dma", &ata_dma); | |
| 90 | SYSCTL_INT(_hw_ata, OID_AUTO, ata_dma, CTLFLAG_RW, &ata_dma, 0, | |
| 91 | "ATA disk DMA mode control"); | |
| 92 | TUNABLE_INT("hw.ata.atapi_dma", &atapi_dma); | |
| 93 | SYSCTL_INT(_hw_ata, OID_AUTO, atapi_dma, CTLFLAG_RW, &atapi_dma, 0, | |
| 94 | "ATAPI device DMA mode control"); | |
| 95 | TUNABLE_INT("hw.ata.wc", &ata_wc); | |
| 96 | SYSCTL_INT(_hw_ata, OID_AUTO, ata_wc, CTLFLAG_RW, &ata_wc, 0, | |
| 97 | "ATA disk write caching"); | |
| 98 | ||
| 99 | /* | |
| 100 | * newbus device interface related functions | |
| 101 | */ | |
| 102 | int | |
| 103 | ata_probe(device_t dev) | |
| 104 | { | |
| 105 | return 0; | |
| 106 | } | |
| 107 | ||
| 108 | int | |
| 109 | ata_attach(device_t dev) | |
| 110 | { | |
| 111 | struct ata_channel *ch = device_get_softc(dev); | |
| 112 | int error, rid; | |
| 113 | ||
| 114 | /* check that we have a virgin channel to attach */ | |
| 115 | if (ch->r_irq) | |
| 116 | return EEXIST; | |
| 117 | ||
| 118 | /* initialize the softc basics */ | |
| 119 | ch->dev = dev; | |
| 120 | ch->state = ATA_IDLE; | |
| 121 | spin_init(&ch->state_mtx); | |
| 122 | spin_init(&ch->queue_mtx); | |
| 123 | TAILQ_INIT(&ch->ata_queue); | |
| 124 | ||
| 125 | /* reset the controller HW, the channel and device(s) */ | |
| 126 | while (ATA_LOCKING(dev, ATA_LF_LOCK) != ch->unit) | |
| 127 | tsleep(&error, 0, "ataatch", 1); | |
| 128 | ATA_RESET(dev); | |
| 129 | ATA_LOCKING(dev, ATA_LF_UNLOCK); | |
| 130 | ||
| 131 | /* setup interrupt delivery */ | |
| 132 | rid = ATA_IRQ_RID; | |
| 133 | ch->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, | |
| 134 | RF_SHAREABLE | RF_ACTIVE); | |
| 135 | if (!ch->r_irq) { | |
| 136 | device_printf(dev, "unable to allocate interrupt\n"); | |
| 137 | return ENXIO; | |
| 138 | } | |
| 139 | if ((error = bus_setup_intr(dev, ch->r_irq, ATA_INTR_FLAGS, | |
| 140 | (driver_intr_t *)ata_interrupt, ch, &ch->ih, | |
| 141 | NULL))) { | |
| 142 | device_printf(dev, "unable to setup interrupt\n"); | |
| 143 | return error; | |
| 144 | } | |
| 145 | ||
| 146 | /* probe and attach devices on this channel unless we are in early boot */ | |
| dbcd0c9b | 147 | ata_identify(dev); |
| c1b3d7c5 TS |
148 | return 0; |
| 149 | } | |
| 150 | ||
| 151 | int | |
| 152 | ata_detach(device_t dev) | |
| 153 | { | |
| 154 | struct ata_channel *ch = device_get_softc(dev); | |
| 155 | device_t *children; | |
| 156 | int nchildren, i; | |
| 157 | ||
| 158 | /* check that we have a valid channel to detach */ | |
| 159 | if (!ch->r_irq) | |
| 160 | return ENXIO; | |
| 161 | ||
| 162 | /* grap the channel lock so no new requests gets launched */ | |
| 163 | spin_lock_wr(&ch->state_mtx); | |
| 164 | ch->state |= ATA_STALL_QUEUE; | |
| 165 | spin_unlock_wr(&ch->state_mtx); | |
| 166 | ||
| 167 | /* detach & delete all children */ | |
| 168 | if (!device_get_children(dev, &children, &nchildren)) { | |
| 169 | for (i = 0; i < nchildren; i++) | |
| 170 | if (children[i]) | |
| 171 | device_delete_child(dev, children[i]); | |
| 172 | kfree(children, M_TEMP); | |
| 173 | } | |
| 174 | ||
| 175 | /* release resources */ | |
| 176 | bus_teardown_intr(dev, ch->r_irq, ch->ih); | |
| 177 | bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ch->r_irq); | |
| 178 | ch->r_irq = NULL; | |
| 179 | spin_uninit(&ch->state_mtx); | |
| 180 | spin_uninit(&ch->queue_mtx); | |
| 181 | return 0; | |
| 182 | } | |
| 183 | ||
| 184 | int | |
| 185 | ata_reinit(device_t dev) | |
| 186 | { | |
| 187 | struct ata_channel *ch = device_get_softc(dev); | |
| 188 | struct ata_request *request; | |
| 189 | device_t *children; | |
| 190 | int nchildren, i; | |
| 191 | ||
| 192 | /* check that we have a valid channel to reinit */ | |
| 193 | if (!ch || !ch->r_irq) | |
| 194 | return ENXIO; | |
| 195 | ||
| 196 | if (bootverbose) | |
| 197 | device_printf(dev, "reiniting channel ..\n"); | |
| 198 | ||
| 199 | /* poll for locking the channel */ | |
| 200 | while (ATA_LOCKING(dev, ATA_LF_LOCK) != ch->unit) | |
| 201 | tsleep(&dev, 0, "atarini", 1); | |
| 202 | ||
| 203 | /* catch eventual request in ch->running */ | |
| 204 | spin_lock_wr(&ch->state_mtx); | |
| 205 | if ((request = ch->running)) | |
| 206 | callout_stop(&request->callout); | |
| 207 | ch->running = NULL; | |
| 208 | ||
| 209 | /* unconditionally grap the channel lock */ | |
| 210 | ch->state |= ATA_STALL_QUEUE; | |
| 211 | spin_unlock_wr(&ch->state_mtx); | |
| 212 | ||
| 213 | /* reset the controller HW, the channel and device(s) */ | |
| 214 | ATA_RESET(dev); | |
| 215 | ||
| 216 | /* reinit the children and delete any that fails */ | |
| 217 | if (!device_get_children(dev, &children, &nchildren)) { | |
| 218 | get_mplock(); | |
| 219 | for (i = 0; i < nchildren; i++) { | |
| 220 | /* did any children go missing ? */ | |
| 221 | if (children[i] && device_is_attached(children[i]) && | |
| 222 | ATA_REINIT(children[i])) { | |
| 223 | /* | |
| 224 | * if we had a running request and its device matches | |
| 225 | * this child we need to inform the request that the | |
| 226 | * device is gone. | |
| 227 | */ | |
| 228 | if (request && request->dev == children[i]) { | |
| 229 | request->result = ENXIO; | |
| 230 | device_printf(request->dev, "FAILURE - device detached\n"); | |
| 231 | ||
| 232 | /* if not timeout finish request here */ | |
| 233 | if (!(request->flags & ATA_R_TIMEOUT)) | |
| 234 | ata_finish(request); | |
| 235 | request = NULL; | |
| 236 | } | |
| 237 | device_delete_child(dev, children[i]); | |
| 238 | } | |
| 239 | } | |
| 240 | kfree(children, M_TEMP); | |
| 241 | rel_mplock(); | |
| 242 | } | |
| 243 | ||
| 244 | /* if we still have a good request put it on the queue again */ | |
| 245 | if (request && !(request->flags & ATA_R_TIMEOUT)) { | |
| 246 | device_printf(request->dev, | |
| 247 | "WARNING - %s requeued due to channel reset", | |
| 248 | ata_cmd2str(request)); | |
| 249 | if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) | |
| e3869ec7 SW |
250 | kprintf(" LBA=%ju", request->u.ata.lba); |
| 251 | kprintf("\n"); | |
| c1b3d7c5 TS |
252 | request->flags |= ATA_R_REQUEUE; |
| 253 | ata_queue_request(request); | |
| 254 | } | |
| 255 | ||
| 256 | /* we're done release the channel for new work */ | |
| 257 | spin_lock_wr(&ch->state_mtx); | |
| 258 | ch->state = ATA_IDLE; | |
| 259 | spin_unlock_wr(&ch->state_mtx); | |
| 260 | ATA_LOCKING(dev, ATA_LF_UNLOCK); | |
| 261 | ||
| 262 | if (bootverbose) | |
| 263 | device_printf(dev, "reinit done ..\n"); | |
| 264 | ||
| 265 | /* kick off requests on the queue */ | |
| 266 | ata_start(dev); | |
| 267 | return 0; | |
| 268 | } | |
| 269 | ||
| 270 | int | |
| 271 | ata_suspend(device_t dev) | |
| 272 | { | |
| 273 | struct ata_channel *ch; | |
| 274 | ||
| 275 | /* check for valid device */ | |
| 276 | if (!dev || !(ch = device_get_softc(dev))) | |
| 277 | return ENXIO; | |
| 278 | ||
| 279 | /* wait for the channel to be IDLE or detached before suspending */ | |
| 280 | while (ch->r_irq) { | |
| 281 | spin_lock_wr(&ch->state_mtx); | |
| 282 | if (ch->state == ATA_IDLE) { | |
| 283 | ch->state = ATA_ACTIVE; | |
| 284 | spin_unlock_wr(&ch->state_mtx); | |
| 285 | break; | |
| 286 | } | |
| 287 | spin_unlock_wr(&ch->state_mtx); | |
| 288 | tsleep(ch, 0, "atasusp", hz/10); | |
| 289 | } | |
| 290 | ATA_LOCKING(dev, ATA_LF_UNLOCK); | |
| 291 | return 0; | |
| 292 | } | |
| 293 | ||
| 294 | int | |
| 295 | ata_resume(device_t dev) | |
| 296 | { | |
| 297 | struct ata_channel *ch; | |
| 298 | int error; | |
| 299 | ||
| 300 | /* check for valid device */ | |
| 301 | if (!dev || !(ch = device_get_softc(dev))) | |
| 302 | return ENXIO; | |
| 303 | ||
| 304 | /* reinit the devices, we dont know what mode/state they are in */ | |
| 305 | error = ata_reinit(dev); | |
| 306 | ||
| 307 | /* kick off requests on the queue */ | |
| 308 | ata_start(dev); | |
| 309 | return error; | |
| 310 | } | |
| 311 | ||
| 312 | int | |
| 313 | ata_interrupt(void *data) | |
| 314 | { | |
| 315 | struct ata_channel *ch = (struct ata_channel *)data; | |
| 316 | struct ata_request *request; | |
| 317 | ||
| 318 | spin_lock_wr(&ch->state_mtx); | |
| 319 | do { | |
| 658104b9 MD |
320 | /* |
| 321 | * Ignore interrupt if its not for us. This may also have the | |
| 322 | * side effect of processing events unrelated to I/O requests. | |
| 323 | */ | |
| c1b3d7c5 TS |
324 | if (ch->hw.status && !ch->hw.status(ch->dev)) |
| 325 | break; | |
| 326 | ||
| 658104b9 MD |
327 | /* |
| 328 | * Check if we have a running request, and make sure it has been | |
| 329 | * completely queued. Otherwise the channel status may indicate | |
| 330 | * not-busy when, in fact, the command had not yet been issued. | |
| 331 | */ | |
| 332 | if ((request = ch->running) == NULL) | |
| c1b3d7c5 | 333 | break; |
| 658104b9 MD |
334 | if ((request->flags & ATA_R_HWCMDQUEUED) == 0) { |
| 335 | kprintf("ata_interrupt: early interrupt\n"); | |
| 336 | break; | |
| 337 | } | |
| c1b3d7c5 TS |
338 | |
| 339 | ATA_DEBUG_RQ(request, "interrupt"); | |
| 340 | ||
| 341 | /* safetycheck for the right state */ | |
| 342 | if (ch->state == ATA_IDLE) { | |
| 343 | device_printf(request->dev, "interrupt on idle channel ignored\n"); | |
| 344 | break; | |
| 345 | } | |
| 346 | ||
| 347 | /* | |
| 348 | * we have the HW locks, so end the transaction for this request | |
| 349 | * if it finishes immediately otherwise wait for next interrupt | |
| 350 | */ | |
| 351 | if (ch->hw.end_transaction(request) == ATA_OP_FINISHED) { | |
| 352 | ch->running = NULL; | |
| 353 | if (ch->state == ATA_ACTIVE) | |
| 354 | ch->state = ATA_IDLE; | |
| 355 | spin_unlock_wr(&ch->state_mtx); | |
| 356 | ATA_LOCKING(ch->dev, ATA_LF_UNLOCK); | |
| 357 | ata_finish(request); | |
| 358 | return 1; | |
| 359 | } | |
| 360 | } while (0); | |
| 361 | spin_unlock_wr(&ch->state_mtx); | |
| 362 | return 0; | |
| 363 | } | |
| 364 | ||
| 365 | /* | |
| 366 | * device related interfaces | |
| 367 | */ | |
| 368 | static int | |
| 369 | ata_ioctl(struct dev_ioctl_args *ap) | |
| 370 | { | |
| 371 | device_t device, *children; | |
| 372 | struct ata_ioc_devices *devices = (struct ata_ioc_devices *)ap->a_data; | |
| 373 | int *value = (int *)ap->a_data; | |
| 374 | int i, nchildren, error = ENOTTY; | |
| 375 | ||
| 376 | switch (ap->a_cmd) { | |
| 377 | case IOCATAGMAXCHANNEL: | |
| 378 | *value = devclass_get_maxunit(ata_devclass); | |
| 379 | error = 0; | |
| 380 | break; | |
| 381 | ||
| 382 | case IOCATAREINIT: | |
| 383 | if (*value > devclass_get_maxunit(ata_devclass) || | |
| 384 | !(device = devclass_get_device(ata_devclass, *value))) | |
| 385 | return ENXIO; | |
| 386 | error = ata_reinit(device); | |
| 387 | ata_start(device); | |
| 388 | break; | |
| 389 | ||
| 390 | case IOCATAATTACH: | |
| 391 | if (*value > devclass_get_maxunit(ata_devclass) || | |
| 392 | !(device = devclass_get_device(ata_devclass, *value))) | |
| 393 | return ENXIO; | |
| 394 | /* XXX SOS should enable channel HW on controller */ | |
| 395 | error = ata_attach(device); | |
| 396 | break; | |
| 397 | ||
| 398 | case IOCATADETACH: | |
| 399 | if (*value > devclass_get_maxunit(ata_devclass) || | |
| 400 | !(device = devclass_get_device(ata_devclass, *value))) | |
| 401 | return ENXIO; | |
| 402 | error = ata_detach(device); | |
| 403 | /* XXX SOS should disable channel HW on controller */ | |
| 404 | break; | |
| 405 | ||
| 406 | case IOCATADEVICES: | |
| 407 | if (devices->channel > devclass_get_maxunit(ata_devclass) || | |
| 408 | !(device = devclass_get_device(ata_devclass, devices->channel))) | |
| 409 | return ENXIO; | |
| 410 | bzero(devices->name[0], 32); | |
| 411 | bzero(&devices->params[0], sizeof(struct ata_params)); | |
| 412 | bzero(devices->name[1], 32); | |
| 413 | bzero(&devices->params[1], sizeof(struct ata_params)); | |
| 414 | if (!device_get_children(device, &children, &nchildren)) { | |
| 415 | for (i = 0; i < nchildren; i++) { | |
| 416 | if (children[i] && device_is_attached(children[i])) { | |
| 417 | struct ata_device *atadev = device_get_softc(children[i]); | |
| 418 | ||
| 419 | if (atadev->unit == ATA_MASTER) { | |
| 420 | strncpy(devices->name[0], | |
| 421 | device_get_nameunit(children[i]), 32); | |
| 422 | bcopy(&atadev->param, &devices->params[0], | |
| 423 | sizeof(struct ata_params)); | |
| 424 | } | |
| 425 | if (atadev->unit == ATA_SLAVE) { | |
| 426 | strncpy(devices->name[1], | |
| 427 | device_get_nameunit(children[i]), 32); | |
| 428 | bcopy(&atadev->param, &devices->params[1], | |
| 429 | sizeof(struct ata_params)); | |
| 430 | } | |
| 431 | } | |
| 432 | } | |
| 433 | kfree(children, M_TEMP); | |
| 434 | error = 0; | |
| 435 | } | |
| 436 | else | |
| 437 | error = ENODEV; | |
| 438 | break; | |
| 439 | ||
| 440 | default: | |
| 441 | if (ata_raid_ioctl_func) | |
| 442 | error = ata_raid_ioctl_func(ap->a_cmd, ap->a_data); | |
| 443 | } | |
| 444 | return error; | |
| 445 | } | |
| 446 | ||
| 447 | int | |
| 448 | ata_device_ioctl(device_t dev, u_long cmd, caddr_t data) | |
| 449 | { | |
| 450 | struct ata_device *atadev = device_get_softc(dev); | |
| 451 | struct ata_ioc_request *ioc_request = (struct ata_ioc_request *)data; | |
| 452 | struct ata_params *params = (struct ata_params *)data; | |
| 453 | int *mode = (int *)data; | |
| 454 | struct ata_request *request; | |
| 455 | caddr_t buf; | |
| 456 | int error; | |
| 457 | ||
| 458 | switch (cmd) { | |
| 459 | case IOCATAREQUEST: | |
| a774914b | 460 | if (!(buf = kmalloc(ioc_request->count, M_ATA, M_WAITOK | M_NULLOK))) { |
| c1b3d7c5 TS |
461 | return ENOMEM; |
| 462 | } | |
| 463 | if (!(request = ata_alloc_request())) { | |
| 464 | kfree(buf, M_ATA); | |
| 465 | return ENOMEM; | |
| 466 | } | |
| 467 | if (ioc_request->flags & ATA_CMD_WRITE) { | |
| 468 | error = copyin(ioc_request->data, buf, ioc_request->count); | |
| 469 | if (error) { | |
| 470 | kfree(buf, M_ATA); | |
| 471 | ata_free_request(request); | |
| 472 | return error; | |
| 473 | } | |
| 474 | } | |
| 475 | request->dev = dev; | |
| 476 | if (ioc_request->flags & ATA_CMD_ATAPI) { | |
| 477 | request->flags = ATA_R_ATAPI; | |
| 478 | bcopy(ioc_request->u.atapi.ccb, request->u.atapi.ccb, 16); | |
| 479 | } | |
| 480 | else { | |
| 481 | request->u.ata.command = ioc_request->u.ata.command; | |
| 482 | request->u.ata.feature = ioc_request->u.ata.feature; | |
| 483 | request->u.ata.lba = ioc_request->u.ata.lba; | |
| 484 | request->u.ata.count = ioc_request->u.ata.count; | |
| 485 | } | |
| 486 | request->timeout = ioc_request->timeout; | |
| 487 | request->data = buf; | |
| 488 | request->bytecount = ioc_request->count; | |
| 489 | request->transfersize = request->bytecount; | |
| 490 | if (ioc_request->flags & ATA_CMD_CONTROL) | |
| 491 | request->flags |= ATA_R_CONTROL; | |
| 492 | if (ioc_request->flags & ATA_CMD_READ) | |
| 493 | request->flags |= ATA_R_READ; | |
| 494 | if (ioc_request->flags & ATA_CMD_WRITE) | |
| 495 | request->flags |= ATA_R_WRITE; | |
| 496 | ata_queue_request(request); | |
| 497 | if (request->flags & ATA_R_ATAPI) { | |
| 498 | bcopy(&request->u.atapi.sense, &ioc_request->u.atapi.sense, | |
| 499 | sizeof(struct atapi_sense)); | |
| 500 | } | |
| 501 | else { | |
| 502 | ioc_request->u.ata.command = request->u.ata.command; | |
| 503 | ioc_request->u.ata.feature = request->u.ata.feature; | |
| 504 | ioc_request->u.ata.lba = request->u.ata.lba; | |
| 505 | ioc_request->u.ata.count = request->u.ata.count; | |
| 506 | } | |
| 507 | ioc_request->error = request->result; | |
| 508 | if (ioc_request->flags & ATA_CMD_READ) | |
| 509 | error = copyout(buf, ioc_request->data, ioc_request->count); | |
| 510 | else | |
| 511 | error = 0; | |
| 512 | kfree(buf, M_ATA); | |
| 513 | ata_free_request(request); | |
| 514 | return error; | |
| 515 | ||
| 516 | case IOCATAGPARM: | |
| 517 | ata_getparam(atadev, 0); | |
| 518 | bcopy(&atadev->param, params, sizeof(struct ata_params)); | |
| 519 | return 0; | |
| 520 | ||
| 521 | case IOCATASMODE: | |
| 522 | atadev->mode = *mode; | |
| 523 | ATA_SETMODE(device_get_parent(dev), dev); | |
| 524 | return 0; | |
| 525 | ||
| 526 | case IOCATAGMODE: | |
| 527 | *mode = atadev->mode; | |
| 528 | return 0; | |
| 529 | default: | |
| 530 | return ENOTTY; | |
| 531 | } | |
| 532 | } | |
| 533 | ||
| 534 | static void | |
| 535 | ata_boot_attach(void) | |
| 536 | { | |
| 537 | struct ata_channel *ch; | |
| 538 | int ctlr; | |
| 539 | ||
| 540 | get_mplock(); | |
| 541 | ||
| 542 | /* kick of probe and attach on all channels */ | |
| 543 | for (ctlr = 0; ctlr < devclass_get_maxunit(ata_devclass); ctlr++) { | |
| 544 | if ((ch = devclass_get_softc(ata_devclass, ctlr))) { | |
| 545 | ata_identify(ch->dev); | |
| 546 | } | |
| 547 | } | |
| 548 | ||
| c1b3d7c5 TS |
549 | rel_mplock(); |
| 550 | } | |
| 551 | ||
| 552 | ||
| 553 | /* | |
| 554 | * misc support functions | |
| 555 | */ | |
| 556 | static device_t | |
| 557 | ata_add_child(device_t parent, struct ata_device *atadev, int unit) | |
| 558 | { | |
| 559 | device_t child; | |
| 560 | ||
| 561 | if ((child = device_add_child(parent, NULL, unit))) { | |
| 562 | device_set_softc(child, atadev); | |
| 563 | device_quiet(child); | |
| 564 | atadev->dev = child; | |
| 565 | atadev->max_iosize = DEV_BSIZE; | |
| 566 | atadev->mode = ATA_PIO_MAX; | |
| 567 | } | |
| 568 | return child; | |
| 569 | } | |
| 570 | ||
| 571 | static int | |
| 572 | ata_getparam(struct ata_device *atadev, int init) | |
| 573 | { | |
| 574 | struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); | |
| 575 | struct ata_request *request; | |
| 576 | u_int8_t command = 0; | |
| 577 | int error = ENOMEM, retries = 2; | |
| 578 | ||
| 579 | if (ch->devices & | |
| 580 | (atadev->unit == ATA_MASTER ? ATA_ATA_MASTER : ATA_ATA_SLAVE)) | |
| 581 | command = ATA_ATA_IDENTIFY; | |
| 582 | if (ch->devices & | |
| 583 | (atadev->unit == ATA_MASTER ? ATA_ATAPI_MASTER : ATA_ATAPI_SLAVE)) | |
| 584 | command = ATA_ATAPI_IDENTIFY; | |
| 585 | if (!command) | |
| 586 | return ENXIO; | |
| 587 | ||
| 588 | while (retries-- > 0 && error) { | |
| 589 | if (!(request = ata_alloc_request())) | |
| 590 | break; | |
| 591 | request->dev = atadev->dev; | |
| 592 | request->timeout = 1; | |
| 593 | request->retries = 0; | |
| 594 | request->u.ata.command = command; | |
| 595 | request->flags = (ATA_R_READ|ATA_R_AT_HEAD|ATA_R_DIRECT|ATA_R_QUIET); | |
| 596 | request->data = (void *)&atadev->param; | |
| 597 | request->bytecount = sizeof(struct ata_params); | |
| 598 | request->donecount = 0; | |
| 599 | request->transfersize = DEV_BSIZE; | |
| 600 | ata_queue_request(request); | |
| 601 | error = request->result; | |
| 602 | ata_free_request(request); | |
| 603 | } | |
| 604 | ||
| 605 | if (!error && (isprint(atadev->param.model[0]) || | |
| 606 | isprint(atadev->param.model[1]))) { | |
| 607 | struct ata_params *atacap = &atadev->param; | |
| 608 | char buffer[64]; | |
| c1b3d7c5 TS |
609 | int16_t *ptr; |
| 610 | ||
| 611 | for (ptr = (int16_t *)atacap; | |
| 612 | ptr < (int16_t *)atacap + sizeof(struct ata_params)/2; ptr++) { | |
| 87870bc8 | 613 | *ptr = le16toh(*ptr); |
| c1b3d7c5 | 614 | } |
| c1b3d7c5 TS |
615 | if (!(!strncmp(atacap->model, "FX", 2) || |
| 616 | !strncmp(atacap->model, "NEC", 3) || | |
| 617 | !strncmp(atacap->model, "Pioneer", 7) || | |
| 618 | !strncmp(atacap->model, "SHARP", 5))) { | |
| 619 | bswap(atacap->model, sizeof(atacap->model)); | |
| 620 | bswap(atacap->revision, sizeof(atacap->revision)); | |
| 621 | bswap(atacap->serial, sizeof(atacap->serial)); | |
| 622 | } | |
| 623 | btrim(atacap->model, sizeof(atacap->model)); | |
| 624 | bpack(atacap->model, atacap->model, sizeof(atacap->model)); | |
| 625 | btrim(atacap->revision, sizeof(atacap->revision)); | |
| 626 | bpack(atacap->revision, atacap->revision, sizeof(atacap->revision)); | |
| 627 | btrim(atacap->serial, sizeof(atacap->serial)); | |
| 628 | bpack(atacap->serial, atacap->serial, sizeof(atacap->serial)); | |
| 629 | ||
| 630 | if (bootverbose) | |
| e3869ec7 | 631 | kprintf("ata%d-%s: pio=%s wdma=%s udma=%s cable=%s wire\n", |
| c1b3d7c5 TS |
632 | device_get_unit(ch->dev), |
| 633 | atadev->unit == ATA_MASTER ? "master" : "slave", | |
| 634 | ata_mode2str(ata_pmode(atacap)), | |
| 635 | ata_mode2str(ata_wmode(atacap)), | |
| 636 | ata_mode2str(ata_umode(atacap)), | |
| 637 | (atacap->hwres & ATA_CABLE_ID) ? "80":"40"); | |
| 638 | ||
| 639 | if (init) { | |
| f8c7a42d | 640 | ksprintf(buffer, "%.40s/%.8s", atacap->model, atacap->revision); |
| c1b3d7c5 | 641 | device_set_desc_copy(atadev->dev, buffer); |
| 87870bc8 MD |
642 | if ((atadev->param.config & ATA_PROTO_ATAPI) && |
| 643 | (atadev->param.config != ATA_CFA_MAGIC1) && | |
| 644 | (atadev->param.config != ATA_CFA_MAGIC2)) { | |
| c1b3d7c5 TS |
645 | if (atapi_dma && ch->dma && |
| 646 | (atadev->param.config & ATA_DRQ_MASK) != ATA_DRQ_INTR && | |
| 647 | ata_umode(&atadev->param) >= ATA_UDMA2) | |
| 648 | atadev->mode = ATA_DMA_MAX; | |
| 649 | } | |
| 650 | else { | |
| 651 | if (ata_dma && ch->dma && | |
| 652 | (ata_umode(&atadev->param) > 0 || | |
| 653 | ata_wmode(&atadev->param) > 0)) | |
| 654 | atadev->mode = ATA_DMA_MAX; | |
| 655 | } | |
| 656 | } | |
| 657 | } | |
| 658 | else { | |
| 659 | if (!error) | |
| 660 | error = ENXIO; | |
| 661 | } | |
| 662 | return error; | |
| 663 | } | |
| 664 | ||
| 665 | int | |
| 666 | ata_identify(device_t dev) | |
| 667 | { | |
| 668 | struct ata_channel *ch = device_get_softc(dev); | |
| 669 | struct ata_device *master = NULL, *slave = NULL; | |
| 670 | device_t master_child = NULL, slave_child = NULL; | |
| 671 | int master_unit = -1, slave_unit = -1; | |
| 672 | ||
| 673 | if (ch->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER)) { | |
| 674 | if (!(master = kmalloc(sizeof(struct ata_device), | |
| a774914b | 675 | M_ATA, M_INTWAIT | M_ZERO))) { |
| c1b3d7c5 TS |
676 | device_printf(dev, "out of memory\n"); |
| 677 | return ENOMEM; | |
| 678 | } | |
| 679 | master->unit = ATA_MASTER; | |
| 680 | } | |
| 681 | if (ch->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE)) { | |
| 682 | if (!(slave = kmalloc(sizeof(struct ata_device), | |
| a774914b | 683 | M_ATA, M_INTWAIT | M_ZERO))) { |
| c1b3d7c5 TS |
684 | kfree(master, M_ATA); |
| 685 | device_printf(dev, "out of memory\n"); | |
| 686 | return ENOMEM; | |
| 687 | } | |
| 688 | slave->unit = ATA_SLAVE; | |
| 689 | } | |
| 690 | ||
| 691 | #ifdef ATA_STATIC_ID | |
| 692 | if (ch->devices & ATA_ATA_MASTER) | |
| 693 | master_unit = (device_get_unit(dev) << 1); | |
| 694 | #endif | |
| 695 | if (master && !(master_child = ata_add_child(dev, master, master_unit))) { | |
| 696 | kfree(master, M_ATA); | |
| 697 | master = NULL; | |
| 698 | } | |
| 699 | #ifdef ATA_STATIC_ID | |
| 700 | if (ch->devices & ATA_ATA_SLAVE) | |
| 701 | slave_unit = (device_get_unit(dev) << 1) + 1; | |
| 702 | #endif | |
| 703 | if (slave && !(slave_child = ata_add_child(dev, slave, slave_unit))) { | |
| 704 | kfree(slave, M_ATA); | |
| 705 | slave = NULL; | |
| 706 | } | |
| 707 | ||
| 708 | if (slave && ata_getparam(slave, 1)) { | |
| 709 | device_delete_child(dev, slave_child); | |
| 710 | kfree(slave, M_ATA); | |
| 711 | } | |
| 712 | if (master && ata_getparam(master, 1)) { | |
| 713 | device_delete_child(dev, master_child); | |
| 714 | kfree(master, M_ATA); | |
| 715 | } | |
| 716 | ||
| 717 | bus_generic_probe(dev); | |
| 718 | bus_generic_attach(dev); | |
| 719 | return 0; | |
| 720 | } | |
| 721 | ||
| 722 | void | |
| 723 | ata_default_registers(device_t dev) | |
| 724 | { | |
| 725 | struct ata_channel *ch = device_get_softc(dev); | |
| 726 | ||
| 727 | /* fill in the defaults from whats setup already */ | |
| 728 | ch->r_io[ATA_ERROR].res = ch->r_io[ATA_FEATURE].res; | |
| 729 | ch->r_io[ATA_ERROR].offset = ch->r_io[ATA_FEATURE].offset; | |
| 730 | ch->r_io[ATA_IREASON].res = ch->r_io[ATA_COUNT].res; | |
| 731 | ch->r_io[ATA_IREASON].offset = ch->r_io[ATA_COUNT].offset; | |
| 732 | ch->r_io[ATA_STATUS].res = ch->r_io[ATA_COMMAND].res; | |
| 733 | ch->r_io[ATA_STATUS].offset = ch->r_io[ATA_COMMAND].offset; | |
| 734 | ch->r_io[ATA_ALTSTAT].res = ch->r_io[ATA_CONTROL].res; | |
| 735 | ch->r_io[ATA_ALTSTAT].offset = ch->r_io[ATA_CONTROL].offset; | |
| 736 | } | |
| 737 | ||
| 738 | void | |
| 739 | ata_modify_if_48bit(struct ata_request *request) | |
| 740 | { | |
| 741 | struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); | |
| 742 | struct ata_device *atadev = device_get_softc(request->dev); | |
| 743 | ||
| 744 | atadev->flags &= ~ATA_D_48BIT_ACTIVE; | |
| 745 | ||
| 3ec9ecbc | 746 | if ((request->u.ata.lba + request->u.ata.count >= ATA_MAX_28BIT_LBA || |
| c1b3d7c5 TS |
747 | request->u.ata.count > 256) && |
| 748 | atadev->param.support.command2 & ATA_SUPPORT_ADDRESS48) { | |
| 749 | ||
| 750 | /* translate command into 48bit version */ | |
| 751 | switch (request->u.ata.command) { | |
| 752 | case ATA_READ: | |
| 753 | request->u.ata.command = ATA_READ48; | |
| 754 | break; | |
| 755 | case ATA_READ_MUL: | |
| 756 | request->u.ata.command = ATA_READ_MUL48; | |
| 757 | break; | |
| 758 | case ATA_READ_DMA: | |
| 759 | if (ch->flags & ATA_NO_48BIT_DMA) { | |
| 760 | if (request->transfersize > DEV_BSIZE) | |
| 761 | request->u.ata.command = ATA_READ_MUL48; | |
| 762 | else | |
| 763 | request->u.ata.command = ATA_READ48; | |
| 764 | request->flags &= ~ATA_R_DMA; | |
| 765 | } | |
| 766 | else | |
| 767 | request->u.ata.command = ATA_READ_DMA48; | |
| 768 | break; | |
| 769 | case ATA_READ_DMA_QUEUED: | |
| 770 | if (ch->flags & ATA_NO_48BIT_DMA) { | |
| 771 | if (request->transfersize > DEV_BSIZE) | |
| 772 | request->u.ata.command = ATA_READ_MUL48; | |
| 773 | else | |
| 774 | request->u.ata.command = ATA_READ48; | |
| 775 | request->flags &= ~ATA_R_DMA; | |
| 776 | } | |
| 777 | else | |
| 778 | request->u.ata.command = ATA_READ_DMA_QUEUED48; | |
| 779 | break; | |
| 780 | case ATA_WRITE: | |
| 781 | request->u.ata.command = ATA_WRITE48; | |
| 782 | break; | |
| 783 | case ATA_WRITE_MUL: | |
| 784 | request->u.ata.command = ATA_WRITE_MUL48; | |
| 785 | break; | |
| 786 | case ATA_WRITE_DMA: | |
| 787 | if (ch->flags & ATA_NO_48BIT_DMA) { | |
| 788 | if (request->transfersize > DEV_BSIZE) | |
| 789 | request->u.ata.command = ATA_WRITE_MUL48; | |
| 790 | else | |
| 791 | request->u.ata.command = ATA_WRITE48; | |
| 792 | request->flags &= ~ATA_R_DMA; | |
| 793 | } | |
| 794 | else | |
| 795 | request->u.ata.command = ATA_WRITE_DMA48; | |
| 796 | break; | |
| 797 | case ATA_WRITE_DMA_QUEUED: | |
| 798 | if (ch->flags & ATA_NO_48BIT_DMA) { | |
| 799 | if (request->transfersize > DEV_BSIZE) | |
| 800 | request->u.ata.command = ATA_WRITE_MUL48; | |
| 801 | else | |
| 802 | request->u.ata.command = ATA_WRITE48; | |
| 803 | request->u.ata.command = ATA_WRITE48; | |
| 804 | request->flags &= ~ATA_R_DMA; | |
| 805 | } | |
| 806 | else | |
| 807 | request->u.ata.command = ATA_WRITE_DMA_QUEUED48; | |
| 808 | break; | |
| 809 | case ATA_FLUSHCACHE: | |
| 810 | request->u.ata.command = ATA_FLUSHCACHE48; | |
| 811 | break; | |
| 812 | case ATA_READ_NATIVE_MAX_ADDDRESS: | |
| 813 | request->u.ata.command = ATA_READ_NATIVE_MAX_ADDDRESS48; | |
| 814 | break; | |
| 815 | case ATA_SET_MAX_ADDRESS: | |
| 816 | request->u.ata.command = ATA_SET_MAX_ADDRESS48; | |
| 817 | break; | |
| 818 | default: | |
| 819 | return; | |
| 820 | } | |
| 821 | atadev->flags |= ATA_D_48BIT_ACTIVE; | |
| 822 | } | |
| 823 | } | |
| 824 | ||
| 825 | void | |
| 826 | ata_udelay(int interval) | |
| 827 | { | |
| 6e40a325 | 828 | /* |
| b43e83df SS |
829 | * We can't use tsleep here, because we might be called from callout |
| 830 | * context. | |
| 6e40a325 | 831 | */ |
| b43e83df | 832 | if (1 || interval < (1000000/hz)) |
| c1b3d7c5 TS |
833 | DELAY(interval); |
| 834 | else | |
| b43e83df | 835 | tsleep(&interval, 0, "ataslp", 1 + interval / (1000000 / hz)); |
| c1b3d7c5 TS |
836 | } |
| 837 | ||
| 838 | char * | |
| 839 | ata_mode2str(int mode) | |
| 840 | { | |
| 841 | switch (mode) { | |
| 842 | case -1: return "UNSUPPORTED"; | |
| 843 | case ATA_PIO0: return "PIO0"; | |
| 844 | case ATA_PIO1: return "PIO1"; | |
| 845 | case ATA_PIO2: return "PIO2"; | |
| 846 | case ATA_PIO3: return "PIO3"; | |
| 847 | case ATA_PIO4: return "PIO4"; | |
| 848 | case ATA_WDMA0: return "WDMA0"; | |
| 849 | case ATA_WDMA1: return "WDMA1"; | |
| 850 | case ATA_WDMA2: return "WDMA2"; | |
| 851 | case ATA_UDMA0: return "UDMA16"; | |
| 852 | case ATA_UDMA1: return "UDMA25"; | |
| 853 | case ATA_UDMA2: return "UDMA33"; | |
| 854 | case ATA_UDMA3: return "UDMA40"; | |
| 855 | case ATA_UDMA4: return "UDMA66"; | |
| 856 | case ATA_UDMA5: return "UDMA100"; | |
| 857 | case ATA_UDMA6: return "UDMA133"; | |
| 858 | case ATA_SA150: return "SATA150"; | |
| 859 | case ATA_SA300: return "SATA300"; | |
| 860 | case ATA_USB: return "USB"; | |
| 861 | case ATA_USB1: return "USB1"; | |
| 862 | case ATA_USB2: return "USB2"; | |
| 863 | default: | |
| 864 | if (mode & ATA_DMA_MASK) | |
| 865 | return "BIOSDMA"; | |
| 866 | else | |
| 867 | return "BIOSPIO"; | |
| 868 | } | |
| 869 | } | |
| 870 | ||
| 871 | int | |
| 872 | ata_pmode(struct ata_params *ap) | |
| 873 | { | |
| 874 | if (ap->atavalid & ATA_FLAG_64_70) { | |
| 875 | if (ap->apiomodes & 0x02) | |
| 876 | return ATA_PIO4; | |
| 877 | if (ap->apiomodes & 0x01) | |
| 878 | return ATA_PIO3; | |
| 879 | } | |
| 880 | if (ap->mwdmamodes & 0x04) | |
| 881 | return ATA_PIO4; | |
| 882 | if (ap->mwdmamodes & 0x02) | |
| 883 | return ATA_PIO3; | |
| 884 | if (ap->mwdmamodes & 0x01) | |
| 885 | return ATA_PIO2; | |
| 886 | if ((ap->retired_piomode & ATA_RETIRED_PIO_MASK) == 0x200) | |
| 887 | return ATA_PIO2; | |
| 888 | if ((ap->retired_piomode & ATA_RETIRED_PIO_MASK) == 0x100) | |
| 889 | return ATA_PIO1; | |
| 890 | if ((ap->retired_piomode & ATA_RETIRED_PIO_MASK) == 0x000) | |
| 891 | return ATA_PIO0; | |
| 892 | return ATA_PIO0; | |
| 893 | } | |
| 894 | ||
| 895 | int | |
| 896 | ata_wmode(struct ata_params *ap) | |
| 897 | { | |
| 898 | if (ap->mwdmamodes & 0x04) | |
| 899 | return ATA_WDMA2; | |
| 900 | if (ap->mwdmamodes & 0x02) | |
| 901 | return ATA_WDMA1; | |
| 902 | if (ap->mwdmamodes & 0x01) | |
| 903 | return ATA_WDMA0; | |
| 904 | return -1; | |
| 905 | } | |
| 906 | ||
| 907 | int | |
| 908 | ata_umode(struct ata_params *ap) | |
| 909 | { | |
| 910 | if (ap->atavalid & ATA_FLAG_88) { | |
| 911 | if (ap->udmamodes & 0x40) | |
| 912 | return ATA_UDMA6; | |
| 913 | if (ap->udmamodes & 0x20) | |
| 914 | return ATA_UDMA5; | |
| 915 | if (ap->udmamodes & 0x10) | |
| 916 | return ATA_UDMA4; | |
| 917 | if (ap->udmamodes & 0x08) | |
| 918 | return ATA_UDMA3; | |
| 919 | if (ap->udmamodes & 0x04) | |
| 920 | return ATA_UDMA2; | |
| 921 | if (ap->udmamodes & 0x02) | |
| 922 | return ATA_UDMA1; | |
| 923 | if (ap->udmamodes & 0x01) | |
| 924 | return ATA_UDMA0; | |
| 925 | } | |
| 926 | return -1; | |
| 927 | } | |
| 928 | ||
| 929 | int | |
| 930 | ata_limit_mode(device_t dev, int mode, int maxmode) | |
| 931 | { | |
| 932 | struct ata_device *atadev = device_get_softc(dev); | |
| 933 | ||
| 934 | if (maxmode && mode > maxmode) | |
| 935 | mode = maxmode; | |
| 936 | ||
| 937 | if (mode >= ATA_UDMA0 && ata_umode(&atadev->param) > 0) | |
| 938 | return min(mode, ata_umode(&atadev->param)); | |
| 939 | ||
| 940 | if (mode >= ATA_WDMA0 && ata_wmode(&atadev->param) > 0) | |
| 941 | return min(mode, ata_wmode(&atadev->param)); | |
| 942 | ||
| 943 | if (mode > ata_pmode(&atadev->param)) | |
| 944 | return min(mode, ata_pmode(&atadev->param)); | |
| 945 | ||
| 946 | return mode; | |
| 947 | } | |
| 948 | ||
| 949 | static void | |
| 950 | bswap(int8_t *buf, int len) | |
| 951 | { | |
| 952 | u_int16_t *ptr = (u_int16_t*)(buf + len); | |
| 953 | ||
| 954 | while (--ptr >= (u_int16_t*)buf) | |
| 955 | *ptr = ntohs(*ptr); | |
| 956 | } | |
| 957 | ||
| 958 | static void | |
| 959 | btrim(int8_t *buf, int len) | |
| 960 | { | |
| 961 | int8_t *ptr; | |
| 962 | ||
| 963 | for (ptr = buf; ptr < buf+len; ++ptr) | |
| 964 | if (!*ptr || *ptr == '_') | |
| 965 | *ptr = ' '; | |
| 966 | for (ptr = buf + len - 1; ptr >= buf && *ptr == ' '; --ptr) | |
| 967 | *ptr = 0; | |
| 968 | } | |
| 969 | ||
| 970 | static void | |
| 971 | bpack(int8_t *src, int8_t *dst, int len) | |
| 972 | { | |
| 973 | int i, j, blank; | |
| 974 | ||
| 975 | for (i = j = blank = 0 ; i < len; i++) { | |
| 976 | if (blank && src[i] == ' ') continue; | |
| 977 | if (blank && src[i] != ' ') { | |
| 978 | dst[j++] = src[i]; | |
| 979 | blank = 0; | |
| 980 | continue; | |
| 981 | } | |
| 982 | if (src[i] == ' ') { | |
| 983 | blank = 1; | |
| 984 | if (i == 0) | |
| 985 | continue; | |
| 986 | } | |
| 987 | dst[j++] = src[i]; | |
| 988 | } | |
| 989 | if (j < len) | |
| 990 | dst[j] = 0x00; | |
| 991 | } | |
| 992 | ||
| 993 | ||
| 994 | /* | |
| 995 | * module handeling | |
| 996 | */ | |
| 997 | static int | |
| 998 | ata_module_event_handler(module_t mod, int what, void *arg) | |
| 999 | { | |
| 1000 | /* static because we need the reference at destruction time */ | |
| 1001 | static cdev_t atacdev; | |
| 1002 | ||
| 1003 | switch (what) { | |
| 1004 | case MOD_LOAD: | |
| 1005 | /* register controlling device */ | |
| c1b3d7c5 TS |
1006 | atacdev = make_dev(&ata_ops, 0, UID_ROOT, GID_OPERATOR, 0600, "ata"); |
| 1007 | reference_dev(atacdev); | |
| c1b3d7c5 TS |
1008 | return 0; |
| 1009 | ||
| 1010 | case MOD_UNLOAD: | |
| 1011 | /* deregister controlling device */ | |
| 1012 | destroy_dev(atacdev); | |
| cd29885a | 1013 | dev_ops_remove_all(&ata_ops); |
| c1b3d7c5 TS |
1014 | return 0; |
| 1015 | ||
| 1016 | default: | |
| 1017 | return EOPNOTSUPP; | |
| 1018 | } | |
| 1019 | } | |
| 1020 | ||
| 1021 | static moduledata_t ata_moduledata = { "ata", ata_module_event_handler, NULL }; | |
| 1022 | DECLARE_MODULE(ata, ata_moduledata, SI_SUB_CONFIGURE, SI_ORDER_SECOND); | |
| 1023 | MODULE_VERSION(ata, 1); | |
| 1024 | ||
| 1d4619bd TS |
1025 | /* |
| 1026 | * Construct a completely zero'ed ata_request. On objcache_put(), an | |
| 1027 | * ata_request object is also zero'ed, so objcache_get() is guaranteed to give | |
| 1028 | * completely zero'ed objects without spending too much time. | |
| 1029 | */ | |
| 1030 | static boolean_t | |
| 1031 | ata_request_cache_ctor(void *obj, void *private, int ocflags) | |
| 1032 | { | |
| 1033 | struct ata_request *arp = obj; | |
| 1034 | ||
| 1035 | bzero(arp, sizeof(struct ata_request)); | |
| 1036 | return(TRUE); | |
| 1037 | } | |
| 1038 | ||
| 1039 | /* | |
| 1040 | * Construct a completely zero'ed ata_composite. On objcache_put(), an | |
| 1041 | * ata_composite object is also zero'ed, so objcache_get() is guaranteed to give | |
| 1042 | * completely zero'ed objects without spending too much time. | |
| 1043 | */ | |
| 1044 | static boolean_t | |
| 1045 | ata_composite_cache_ctor(void *obj, void *private, int ocflags) | |
| 1046 | { | |
| 1047 | struct ata_composite *acp = obj; | |
| 1048 | ||
| 1049 | bzero(acp, sizeof(struct ata_composite)); | |
| 1050 | return(TRUE); | |
| 1051 | } | |
| 1052 | ||
| c1b3d7c5 TS |
1053 | static void |
| 1054 | ata_init(void) | |
| 1055 | { | |
| 1d4619bd | 1056 | ata_request_cache = objcache_create("ata_request", 0, 0, |
| 5b7da64a | 1057 | ata_request_cache_ctor, NULL, NULL, |
| 1d4619bd TS |
1058 | objcache_malloc_alloc, |
| 1059 | objcache_malloc_free, | |
| 1060 | &ata_request_malloc_args); | |
| 1061 | ata_composite_cache = objcache_create("ata_composite", 0, 0, | |
| 5b7da64a | 1062 | ata_composite_cache_ctor, NULL, NULL, |
| 1d4619bd TS |
1063 | objcache_malloc_alloc, |
| 1064 | objcache_malloc_free, | |
| 1065 | &ata_composite_malloc_args); | |
| c1b3d7c5 TS |
1066 | } |
| 1067 | SYSINIT(ata_register, SI_SUB_DRIVERS, SI_ORDER_SECOND, ata_init, NULL); | |
| 1068 | ||
| 1069 | static void | |
| 1070 | ata_uninit(void) | |
| 1071 | { | |
| 1072 | objcache_destroy(ata_composite_cache); | |
| 1073 | objcache_destroy(ata_request_cache); | |
| 1074 | } | |
| 1075 | SYSUNINIT(ata_unregister, SI_SUB_DRIVERS, SI_ORDER_SECOND, ata_uninit, NULL); |