Annotation of sys/dev/ic/wdc.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: wdc.c,v 1.96 2007/05/08 16:07:03 deraadt Exp $ */
! 2: /* $NetBSD: wdc.c,v 1.68 1999/06/23 19:00:17 bouyer Exp $ */
! 3:
! 4:
! 5: /*
! 6: * Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. All advertising materials mentioning features or use of this software
! 17: * must display the following acknowledgement:
! 18: * This product includes software developed by Manuel Bouyer.
! 19: * 4. The name of the author may not be used to endorse or promote products
! 20: * derived from this software without specific prior written permission.
! 21: *
! 22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 31: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 32: */
! 33:
! 34: /*-
! 35: * Copyright (c) 1998 The NetBSD Foundation, Inc.
! 36: * All rights reserved.
! 37: *
! 38: * This code is derived from software contributed to The NetBSD Foundation
! 39: * by Charles M. Hannum, by Onno van der Linden and by Manuel Bouyer.
! 40: *
! 41: * Redistribution and use in source and binary forms, with or without
! 42: * modification, are permitted provided that the following conditions
! 43: * are met:
! 44: * 1. Redistributions of source code must retain the above copyright
! 45: * notice, this list of conditions and the following disclaimer.
! 46: * 2. Redistributions in binary form must reproduce the above copyright
! 47: * notice, this list of conditions and the following disclaimer in the
! 48: * documentation and/or other materials provided with the distribution.
! 49: * 3. All advertising materials mentioning features or use of this software
! 50: * must display the following acknowledgement:
! 51: * This product includes software developed by the NetBSD
! 52: * Foundation, Inc. and its contributors.
! 53: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 54: * contributors may be used to endorse or promote products derived
! 55: * from this software without specific prior written permission.
! 56: *
! 57: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 58: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 59: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 60: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 61: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 62: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 63: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 64: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 65: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 66: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 67: * POSSIBILITY OF SUCH DAMAGE.
! 68: */
! 69:
! 70: #include <sys/param.h>
! 71: #include <sys/systm.h>
! 72: #include <sys/kernel.h>
! 73: #include <sys/conf.h>
! 74: #include <sys/buf.h>
! 75: #include <sys/device.h>
! 76: #include <sys/malloc.h>
! 77: #include <sys/syslog.h>
! 78: #include <sys/proc.h>
! 79: #include <sys/pool.h>
! 80: #include <uvm/uvm_extern.h>
! 81:
! 82: #include <machine/intr.h>
! 83: #include <machine/bus.h>
! 84:
! 85: #include <dev/ata/atavar.h>
! 86: #include <dev/ata/atareg.h>
! 87: #include <dev/ic/wdcreg.h>
! 88: #include <dev/ic/wdcvar.h>
! 89: #include <dev/ic/wdcevent.h>
! 90:
! 91: #include "atapiscsi.h"
! 92:
! 93: #define WDCDELAY 100 /* 100 microseconds */
! 94: #define WDCNDELAY_RST (WDC_RESET_WAIT * 1000 / WDCDELAY)
! 95: #if 0
! 96: /* If you enable this, it will report any delays more than WDCDELAY * N long. */
! 97: #define WDCNDELAY_DEBUG 50
! 98: #endif /* 0 */
! 99:
! 100: struct pool wdc_xfer_pool;
! 101:
! 102: void __wdcerror(struct channel_softc *, char *);
! 103: int __wdcwait_reset(struct channel_softc *, int);
! 104: void __wdccommand_done(struct channel_softc *, struct wdc_xfer *);
! 105: void __wdccommand_start(struct channel_softc *, struct wdc_xfer *);
! 106: int __wdccommand_intr(struct channel_softc *, struct wdc_xfer *, int);
! 107: int wdprint(void *, const char *);
! 108: void wdc_kill_pending(struct channel_softc *);
! 109:
! 110: #define DEBUG_INTR 0x01
! 111: #define DEBUG_XFERS 0x02
! 112: #define DEBUG_STATUS 0x04
! 113: #define DEBUG_FUNCS 0x08
! 114: #define DEBUG_PROBE 0x10
! 115: #define DEBUG_STATUSX 0x20
! 116: #define DEBUG_SDRIVE 0x40
! 117: #define DEBUG_DETACH 0x80
! 118:
! 119: #ifdef WDCDEBUG
! 120: #ifndef WDCDEBUG_MASK
! 121: #define WDCDEBUG_MASK 0x00
! 122: #endif
! 123: int wdcdebug_mask = WDCDEBUG_MASK;
! 124: int wdc_nxfer = 0;
! 125: #define WDCDEBUG_PRINT(args, level) do { \
! 126: if ((wdcdebug_mask & (level)) != 0) \
! 127: printf args; \
! 128: } while (0)
! 129: #else
! 130: #define WDCDEBUG_PRINT(args, level)
! 131: #endif /* WDCDEBUG */
! 132:
! 133: int at_poll = AT_POLL;
! 134:
! 135: int wdc_floating_bus(struct channel_softc *, int);
! 136: int wdc_preata_drive(struct channel_softc *, int);
! 137: int wdc_ata_present(struct channel_softc *, int);
! 138:
! 139: struct channel_softc_vtbl wdc_default_vtbl = {
! 140: wdc_default_read_reg,
! 141: wdc_default_write_reg,
! 142: wdc_default_lba48_write_reg,
! 143: wdc_default_read_raw_multi_2,
! 144: wdc_default_write_raw_multi_2,
! 145: wdc_default_read_raw_multi_4,
! 146: wdc_default_write_raw_multi_4
! 147: };
! 148:
! 149: static char *wdc_log_buf = NULL;
! 150: static unsigned int wdc_tail = 0;
! 151: static unsigned int wdc_head = 0;
! 152: static unsigned int wdc_log_cap = 16 * 1024;
! 153: static int chp_idx = 1;
! 154:
! 155: void
! 156: wdc_log(struct channel_softc *chp, enum wdcevent_type type,
! 157: unsigned int size, char val[])
! 158: {
! 159: unsigned int request_size;
! 160: char *ptr;
! 161: int log_size;
! 162: unsigned int head = wdc_head;
! 163: unsigned int tail = wdc_tail;
! 164:
! 165: #ifdef DIAGNOSTIC
! 166: if (head < 0 || head > wdc_log_cap ||
! 167: tail < 0 || tail > wdc_log_cap) {
! 168: printf ("wdc_log: head %x wdc_tail %x\n", head,
! 169: tail);
! 170: return;
! 171: }
! 172:
! 173: if (size > wdc_log_cap / 2) {
! 174: printf ("wdc_log: type %d size %x\n", type, size);
! 175: return;
! 176: }
! 177: #endif
! 178:
! 179: if (wdc_log_buf == NULL) {
! 180: wdc_log_buf = malloc(wdc_log_cap, M_DEVBUF, M_NOWAIT);
! 181: if (wdc_log_buf == NULL)
! 182: return;
! 183: }
! 184: if (chp->ch_log_idx == 0)
! 185: chp->ch_log_idx = chp_idx++;
! 186:
! 187: request_size = size + 2;
! 188:
! 189: /* Check how many bytes are left */
! 190: log_size = head - tail;
! 191: if (log_size < 0) log_size += wdc_log_cap;
! 192:
! 193: if (log_size + request_size >= wdc_log_cap) {
! 194: int nb = 0;
! 195: int rec_size;
! 196:
! 197: while (nb <= (request_size * 2)) {
! 198: if (wdc_log_buf[tail] == 0)
! 199: rec_size = 1;
! 200: else
! 201: rec_size = (wdc_log_buf[tail + 1] & 0x1f) + 2;
! 202: tail = (tail + rec_size) % wdc_log_cap;
! 203: nb += rec_size;
! 204: }
! 205: }
! 206:
! 207: /* Avoid wrapping in the middle of a request */
! 208: if (head + request_size >= wdc_log_cap) {
! 209: memset(&wdc_log_buf[head], 0, wdc_log_cap - head);
! 210: head = 0;
! 211: }
! 212:
! 213: ptr = &wdc_log_buf[head];
! 214: *ptr++ = type & 0xff;
! 215: *ptr++ = ((chp->ch_log_idx & 0x7) << 5) | (size & 0x1f);
! 216: memcpy(ptr, val, size);
! 217:
! 218: wdc_head = (head + request_size) % wdc_log_cap;
! 219: wdc_tail = tail;
! 220: }
! 221:
! 222: char *wdc_get_log(unsigned int *, unsigned int *);
! 223:
! 224: char *
! 225: wdc_get_log(unsigned int * size, unsigned int *left)
! 226: {
! 227: int log_size;
! 228: char *retbuf = NULL;
! 229: int nb, tocopy;
! 230: int s;
! 231: unsigned int head = wdc_head;
! 232: unsigned int tail = wdc_tail;
! 233:
! 234: s = splbio();
! 235:
! 236: log_size = (head - tail);
! 237: if (left != NULL)
! 238: *left = 0;
! 239:
! 240: if (log_size < 0)
! 241: log_size += wdc_log_cap;
! 242:
! 243: tocopy = log_size;
! 244: if ((u_int)tocopy > *size)
! 245: tocopy = *size;
! 246:
! 247: if (wdc_log_buf == NULL) {
! 248: *size = 0;
! 249: *left = 0;
! 250: goto out;
! 251: }
! 252:
! 253: #ifdef DIAGNOSTIC
! 254: if (head < 0 || head > wdc_log_cap ||
! 255: tail < 0 || tail > wdc_log_cap) {
! 256: printf ("wdc_log: head %x tail %x\n", head,
! 257: tail);
! 258: *size = 0;
! 259: *left = 0;
! 260: goto out;
! 261: }
! 262: #endif
! 263:
! 264: retbuf = malloc(tocopy, M_TEMP, M_NOWAIT);
! 265: if (retbuf == NULL) {
! 266: *size = 0;
! 267: *left = log_size;
! 268: goto out;
! 269: }
! 270:
! 271: nb = 0;
! 272: for (;;) {
! 273: int rec_size;
! 274:
! 275: if (wdc_log_buf[tail] == 0)
! 276: rec_size = 1;
! 277: else
! 278: rec_size = (wdc_log_buf[tail + 1] & 0x1f) + 2;
! 279:
! 280: if ((nb + rec_size) >= tocopy)
! 281: break;
! 282:
! 283: memcpy(&retbuf[nb], &wdc_log_buf[tail], rec_size);
! 284: tail = (tail + rec_size) % wdc_log_cap;
! 285: nb += rec_size;
! 286: }
! 287:
! 288: wdc_tail = tail;
! 289: *size = nb;
! 290: *left = log_size - nb;
! 291:
! 292: out:
! 293: splx(s);
! 294: return (retbuf);
! 295: }
! 296:
! 297:
! 298: u_int8_t
! 299: wdc_default_read_reg(chp, reg)
! 300: struct channel_softc *chp;
! 301: enum wdc_regs reg;
! 302: {
! 303: #ifdef DIAGNOSTIC
! 304: if (reg & _WDC_WRONLY) {
! 305: printf ("wdc_default_read_reg: reading from a write-only register %d\n", reg);
! 306: }
! 307: #endif /* DIAGNOSTIC */
! 308:
! 309: if (reg & _WDC_AUX)
! 310: return (bus_space_read_1(chp->ctl_iot, chp->ctl_ioh,
! 311: reg & _WDC_REGMASK));
! 312: else
! 313: return (bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
! 314: reg & _WDC_REGMASK));
! 315: }
! 316:
! 317: void
! 318: wdc_default_write_reg(chp, reg, val)
! 319: struct channel_softc *chp;
! 320: enum wdc_regs reg;
! 321: u_int8_t val;
! 322: {
! 323: #ifdef DIAGNOSTIC
! 324: if (reg & _WDC_RDONLY) {
! 325: printf ("wdc_default_write_reg: writing to a read-only register %d\n", reg);
! 326: }
! 327: #endif /* DIAGNOSTIC */
! 328:
! 329: if (reg & _WDC_AUX)
! 330: bus_space_write_1(chp->ctl_iot, chp->ctl_ioh,
! 331: reg & _WDC_REGMASK, val);
! 332: else
! 333: bus_space_write_1(chp->cmd_iot, chp->cmd_ioh,
! 334: reg & _WDC_REGMASK, val);
! 335: }
! 336:
! 337: void
! 338: wdc_default_lba48_write_reg(chp, reg, val)
! 339: struct channel_softc *chp;
! 340: enum wdc_regs reg;
! 341: u_int16_t val;
! 342: {
! 343: /* All registers are two byte deep FIFOs. */
! 344: CHP_WRITE_REG(chp, reg, val >> 8);
! 345: CHP_WRITE_REG(chp, reg, val);
! 346: }
! 347:
! 348: void
! 349: wdc_default_read_raw_multi_2(chp, data, nbytes)
! 350: struct channel_softc *chp;
! 351: void *data;
! 352: unsigned int nbytes;
! 353: {
! 354: if (data == NULL) {
! 355: unsigned int i;
! 356:
! 357: for (i = 0; i < nbytes; i += 2) {
! 358: bus_space_read_2(chp->cmd_iot, chp->cmd_ioh, 0);
! 359: }
! 360:
! 361: return;
! 362: }
! 363:
! 364: bus_space_read_raw_multi_2(chp->cmd_iot, chp->cmd_ioh, 0,
! 365: data, nbytes);
! 366: }
! 367:
! 368:
! 369: void
! 370: wdc_default_write_raw_multi_2(chp, data, nbytes)
! 371: struct channel_softc *chp;
! 372: void *data;
! 373: unsigned int nbytes;
! 374: {
! 375: if (data == NULL) {
! 376: unsigned int i;
! 377:
! 378: for (i = 0; i < nbytes; i += 2) {
! 379: bus_space_write_2(chp->cmd_iot, chp->cmd_ioh, 0, 0);
! 380: }
! 381:
! 382: return;
! 383: }
! 384:
! 385: bus_space_write_raw_multi_2(chp->cmd_iot, chp->cmd_ioh, 0,
! 386: data, nbytes);
! 387: }
! 388:
! 389:
! 390: void
! 391: wdc_default_write_raw_multi_4(chp, data, nbytes)
! 392: struct channel_softc *chp;
! 393: void *data;
! 394: unsigned int nbytes;
! 395: {
! 396: if (data == NULL) {
! 397: unsigned int i;
! 398:
! 399: for (i = 0; i < nbytes; i += 4) {
! 400: bus_space_write_4(chp->cmd_iot, chp->cmd_ioh, 0, 0);
! 401: }
! 402:
! 403: return;
! 404: }
! 405:
! 406: bus_space_write_raw_multi_4(chp->cmd_iot, chp->cmd_ioh, 0,
! 407: data, nbytes);
! 408: }
! 409:
! 410:
! 411: void
! 412: wdc_default_read_raw_multi_4(chp, data, nbytes)
! 413: struct channel_softc *chp;
! 414: void *data;
! 415: unsigned int nbytes;
! 416: {
! 417: if (data == NULL) {
! 418: unsigned int i;
! 419:
! 420: for (i = 0; i < nbytes; i += 4) {
! 421: bus_space_read_4(chp->cmd_iot, chp->cmd_ioh, 0);
! 422: }
! 423:
! 424: return;
! 425: }
! 426:
! 427: bus_space_read_raw_multi_4(chp->cmd_iot, chp->cmd_ioh, 0,
! 428: data, nbytes);
! 429: }
! 430:
! 431:
! 432: int
! 433: wdprint(aux, pnp)
! 434: void *aux;
! 435: const char *pnp;
! 436: {
! 437: struct ata_atapi_attach *aa_link = aux;
! 438: if (pnp)
! 439: printf("drive at %s", pnp);
! 440: printf(" channel %d drive %d", aa_link->aa_channel,
! 441: aa_link->aa_drv_data->drive);
! 442: return (UNCONF);
! 443: }
! 444:
! 445: void
! 446: wdc_disable_intr(chp)
! 447: struct channel_softc *chp;
! 448: {
! 449: CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_IDS);
! 450: }
! 451:
! 452: void
! 453: wdc_enable_intr(chp)
! 454: struct channel_softc *chp;
! 455: {
! 456: CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_4BIT);
! 457: }
! 458:
! 459: void
! 460: wdc_set_drive(struct channel_softc *chp, int drive)
! 461: {
! 462: CHP_WRITE_REG(chp, wdr_sdh, (drive << 4) | WDSD_IBM);
! 463: WDC_LOG_SET_DRIVE(chp, drive);
! 464: }
! 465:
! 466: int
! 467: wdc_floating_bus(chp, drive)
! 468: struct channel_softc *chp;
! 469: int drive;
! 470:
! 471: {
! 472: u_int8_t cumulative_status, status;
! 473: int iter;
! 474:
! 475: wdc_set_drive(chp, drive);
! 476: delay(10);
! 477:
! 478: /* Stolen from Phoenix BIOS Drive Autotyping document */
! 479: cumulative_status = 0;
! 480: for (iter = 0; iter < 100; iter++) {
! 481: CHP_WRITE_REG(chp, wdr_seccnt, 0x7f);
! 482: delay (1);
! 483:
! 484: status = CHP_READ_REG(chp, wdr_status);
! 485:
! 486: /* The other bits are meaningless if BSY is set */
! 487: if (status & WDCS_BSY)
! 488: continue;
! 489:
! 490: cumulative_status |= status;
! 491:
! 492: #define BAD_BIT_COMBO (WDCS_DRDY | WDCS_DSC | WDCS_DRQ | WDCS_ERR)
! 493: if ((cumulative_status & BAD_BIT_COMBO) == BAD_BIT_COMBO)
! 494: return 1;
! 495: }
! 496:
! 497:
! 498: return 0;
! 499: }
! 500:
! 501:
! 502: int
! 503: wdc_preata_drive(chp, drive)
! 504: struct channel_softc *chp;
! 505: int drive;
! 506:
! 507: {
! 508: if (wdc_floating_bus(chp, drive)) {
! 509: WDCDEBUG_PRINT(("%s:%d:%d: floating bus detected\n",
! 510: chp->wdc->sc_dev.dv_xname,
! 511: chp->channel, drive), DEBUG_PROBE);
! 512: return 0;
! 513: }
! 514:
! 515: wdc_set_drive(chp, drive);
! 516: delay(100);
! 517: if (wdcwait(chp, WDCS_DRDY | WDCS_DRQ, WDCS_DRDY, 10000) != 0) {
! 518: WDCDEBUG_PRINT(("%s:%d:%d: not ready\n",
! 519: chp->wdc->sc_dev.dv_xname,
! 520: chp->channel, drive), DEBUG_PROBE);
! 521: return 0;
! 522: }
! 523:
! 524: CHP_WRITE_REG(chp, wdr_command, WDCC_RECAL);
! 525: WDC_LOG_ATA_CMDSHORT(chp, WDCC_RECAL);
! 526: if (wdcwait(chp, WDCS_DRDY | WDCS_DRQ, WDCS_DRDY, 10000) != 0) {
! 527: WDCDEBUG_PRINT(("%s:%d:%d: WDCC_RECAL failed\n",
! 528: chp->wdc->sc_dev.dv_xname,
! 529: chp->channel, drive), DEBUG_PROBE);
! 530: return 0;
! 531: }
! 532:
! 533: return 1;
! 534: }
! 535:
! 536: int
! 537: wdc_ata_present(chp, drive)
! 538: struct channel_softc *chp;
! 539: int drive;
! 540: {
! 541: int time_to_done;
! 542: int retry_cnt = 0;
! 543:
! 544: wdc_set_drive(chp, drive);
! 545: delay(10);
! 546:
! 547: retry:
! 548: /*
! 549: You're actually supposed to wait up to 10 seconds
! 550: for DRDY. However, as a practical matter, most
! 551: drives assert DRDY very quickly after dropping BSY.
! 552:
! 553: The 10 seconds wait is sub-optimal because, according
! 554: to the ATA standard, the master should reply with 00
! 555: for any reads to a non-existent slave.
! 556: */
! 557: time_to_done = wdc_wait_for_status(chp,
! 558: (WDCS_DRDY | WDCS_DSC | WDCS_DRQ),
! 559: (WDCS_DRDY | WDCS_DSC), 1000);
! 560: if (time_to_done == -1) {
! 561: if (retry_cnt == 0 && chp->ch_status == 0x00) {
! 562: /* At least one flash card needs to be kicked */
! 563: wdccommandshort(chp, drive, WDCC_CHECK_PWR);
! 564: retry_cnt++;
! 565: goto retry;
! 566: }
! 567: WDCDEBUG_PRINT(("%s:%d:%d: DRDY test timed out with status"
! 568: " %02x\n",
! 569: chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe",
! 570: chp->channel, drive, chp->ch_status),
! 571: DEBUG_PROBE);
! 572: return 0;
! 573: }
! 574:
! 575: if ((chp->ch_status & 0xfc) != (WDCS_DRDY | WDCS_DSC)) {
! 576: WDCDEBUG_PRINT(("%s:%d:%d: status test for 0x50 failed with"
! 577: " %02x\n",
! 578: chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe",
! 579: chp->channel, drive, chp->ch_status),
! 580: DEBUG_PROBE);
! 581:
! 582: return 0;
! 583: }
! 584:
! 585: WDCDEBUG_PRINT(("%s:%d:%d: waiting for ready %d msec\n",
! 586: chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe",
! 587: chp->channel, drive, time_to_done), DEBUG_PROBE);
! 588:
! 589: /*
! 590: * Test register writability
! 591: */
! 592: CHP_WRITE_REG(chp, wdr_cyl_lo, 0xaa);
! 593: CHP_WRITE_REG(chp, wdr_cyl_hi, 0x55);
! 594: CHP_WRITE_REG(chp, wdr_seccnt, 0xff);
! 595: DELAY(10);
! 596:
! 597: if (CHP_READ_REG(chp, wdr_cyl_lo) != 0xaa &&
! 598: CHP_READ_REG(chp, wdr_cyl_hi) != 0x55) {
! 599: WDCDEBUG_PRINT(("%s:%d:%d: register writability failed\n",
! 600: chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe",
! 601: chp->channel, drive), DEBUG_PROBE);
! 602: return 0;
! 603: }
! 604:
! 605: return 1;
! 606: }
! 607:
! 608:
! 609: /*
! 610: * Test to see controller with at least one attached drive is there.
! 611: * Returns a bit for each possible drive found (0x01 for drive 0,
! 612: * 0x02 for drive 1).
! 613: * Logic:
! 614: * - If a status register is at 0x7f or 0xff, assume there is no drive here
! 615: * (ISA has pull-up resistors). Similarly if the status register has
! 616: * the value we last wrote to the bus (for IDE interfaces without pullups).
! 617: * If no drive at all -> return.
! 618: * - reset the controller, wait for it to complete (may take up to 31s !).
! 619: * If timeout -> return.
! 620: * - test ATA/ATAPI signatures. If at last one drive found -> return.
! 621: * - try an ATA command on the master.
! 622: */
! 623:
! 624: int
! 625: wdcprobe(chp)
! 626: struct channel_softc *chp;
! 627: {
! 628: u_int8_t st0, st1, sc, sn, cl, ch;
! 629: u_int8_t ret_value = 0x03;
! 630: u_int8_t drive;
! 631: #ifdef WDCDEBUG
! 632: int savedmask = wdcdebug_mask;
! 633: #endif
! 634:
! 635: if (chp->_vtbl == 0) {
! 636: int s = splbio();
! 637: chp->_vtbl = &wdc_default_vtbl;
! 638: splx(s);
! 639: }
! 640:
! 641: #ifdef WDCDEBUG
! 642: if ((chp->ch_flags & WDCF_VERBOSE_PROBE) ||
! 643: (chp->wdc &&
! 644: (chp->wdc->sc_dev.dv_cfdata->cf_flags & WDC_OPTION_PROBE_VERBOSE)))
! 645: wdcdebug_mask |= DEBUG_PROBE;
! 646: #endif /* WDCDEBUG */
! 647:
! 648: if (chp->wdc == NULL ||
! 649: (chp->wdc->cap & WDC_CAPABILITY_NO_EXTRA_RESETS) == 0) {
! 650: /* Sample the statuses of drive 0 and 1 into st0 and st1 */
! 651: wdc_set_drive(chp, 0);
! 652: delay(10);
! 653: st0 = CHP_READ_REG(chp, wdr_status);
! 654: WDC_LOG_STATUS(chp, st0);
! 655: wdc_set_drive(chp, 1);
! 656: delay(10);
! 657: st1 = CHP_READ_REG(chp, wdr_status);
! 658: WDC_LOG_STATUS(chp, st1);
! 659:
! 660: WDCDEBUG_PRINT(("%s:%d: before reset, st0=0x%b, st1=0x%b\n",
! 661: chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe",
! 662: chp->channel, st0, WDCS_BITS, st1, WDCS_BITS),
! 663: DEBUG_PROBE);
! 664:
! 665: if (st0 == 0xff || st0 == WDSD_IBM)
! 666: ret_value &= ~0x01;
! 667: if (st1 == 0xff || st1 == (WDSD_IBM | 0x10))
! 668: ret_value &= ~0x02;
! 669: if (ret_value == 0)
! 670: return 0;
! 671: }
! 672:
! 673: /* reset the channel */
! 674: wdc_do_reset(chp);
! 675:
! 676: ret_value = __wdcwait_reset(chp, ret_value);
! 677: WDCDEBUG_PRINT(("%s:%d: after reset, ret_value=0x%d\n",
! 678: chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe", chp->channel,
! 679: ret_value), DEBUG_PROBE);
! 680:
! 681: if (ret_value == 0)
! 682: return 0;
! 683:
! 684: /*
! 685: * Use signatures to find potential ATAPI drives
! 686: */
! 687: for (drive = 0; drive < 2; drive++) {
! 688: if ((ret_value & (0x01 << drive)) == 0)
! 689: continue;
! 690: wdc_set_drive(chp, drive);
! 691: delay(10);
! 692: /* Save registers contents */
! 693: st0 = CHP_READ_REG(chp, wdr_status);
! 694: sc = CHP_READ_REG(chp, wdr_seccnt);
! 695: sn = CHP_READ_REG(chp, wdr_sector);
! 696: cl = CHP_READ_REG(chp, wdr_cyl_lo);
! 697: ch = CHP_READ_REG(chp, wdr_cyl_hi);
! 698: WDC_LOG_REG(chp, wdr_cyl_lo, (ch << 8) | cl);
! 699:
! 700: WDCDEBUG_PRINT(("%s:%d:%d: after reset, st=0x%b, sc=0x%x"
! 701: " sn=0x%x cl=0x%x ch=0x%x\n",
! 702: chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe",
! 703: chp->channel, drive, st0, WDCS_BITS, sc, sn, cl, ch),
! 704: DEBUG_PROBE);
! 705: /*
! 706: * This is a simplification of the test in the ATAPI
! 707: * spec since not all drives seem to set the other regs
! 708: * correctly.
! 709: */
! 710: if (cl == 0x14 && ch == 0xeb)
! 711: chp->ch_drive[drive].drive_flags |= DRIVE_ATAPI;
! 712: }
! 713:
! 714: /*
! 715: * Detect ATA drives by poking around the registers
! 716: */
! 717: for (drive = 0; drive < 2; drive++) {
! 718: if ((ret_value & (0x01 << drive)) == 0)
! 719: continue;
! 720: if (chp->ch_drive[drive].drive_flags & DRIVE_ATAPI)
! 721: continue;
! 722:
! 723: wdc_disable_intr(chp);
! 724: /* ATA detect */
! 725: if (wdc_ata_present(chp, drive)) {
! 726: chp->ch_drive[drive].drive_flags |= DRIVE_ATA;
! 727: if (chp->wdc == NULL ||
! 728: (chp->wdc->cap & WDC_CAPABILITY_PREATA) != 0)
! 729: chp->ch_drive[drive].drive_flags |= DRIVE_OLD;
! 730: } else {
! 731: ret_value &= ~(1 << drive);
! 732: }
! 733: wdc_enable_intr(chp);
! 734: }
! 735:
! 736: #ifdef WDCDEBUG
! 737: wdcdebug_mask = savedmask;
! 738: #endif
! 739: return (ret_value);
! 740: }
! 741:
! 742: /*
! 743: * Call activate routine of underlying devices.
! 744: */
! 745: int
! 746: wdcactivate(self, act)
! 747: struct device *self;
! 748: enum devact act;
! 749: {
! 750: int error = 0;
! 751: int s;
! 752:
! 753: s = splbio();
! 754: config_activate_children(self, act);
! 755: splx(s);
! 756:
! 757: return (error);
! 758: }
! 759:
! 760: void
! 761: wdcattach(chp)
! 762: struct channel_softc *chp;
! 763: {
! 764: int channel_flags, ctrl_flags, i;
! 765: #ifndef __OpenBSD__
! 766: int error;
! 767: #endif
! 768: struct ata_atapi_attach aa_link;
! 769: static int inited = 0;
! 770: #ifdef WDCDEBUG
! 771: int savedmask = wdcdebug_mask;
! 772: #endif
! 773:
! 774: if (!cold)
! 775: at_poll = AT_WAIT;
! 776:
! 777: if (chp->wdc->reset == NULL)
! 778: chp->wdc->reset = wdc_do_reset;
! 779:
! 780: timeout_set(&chp->ch_timo, wdctimeout, chp);
! 781:
! 782: #ifndef __OpenBSD__
! 783: if ((error = wdc_addref(chp)) != 0) {
! 784: printf("%s: unable to enable controller\n",
! 785: chp->wdc->sc_dev.dv_xname);
! 786: return;
! 787: }
! 788: #endif /* __OpenBSD__ */
! 789: if (!chp->_vtbl)
! 790: chp->_vtbl = &wdc_default_vtbl;
! 791:
! 792: if (chp->wdc->drv_probe != NULL) {
! 793: chp->wdc->drv_probe(chp);
! 794: } else {
! 795: if (wdcprobe(chp) == 0) {
! 796: /* If no drives, abort attach here. */
! 797: #ifndef __OpenBSD__
! 798: wdc_delref(chp);
! 799: #endif
! 800: return;
! 801: }
! 802: }
! 803:
! 804: /* ATAPI drives need settling time. Give them 250ms */
! 805: if ((chp->ch_drive[0].drive_flags & DRIVE_ATAPI) ||
! 806: (chp->ch_drive[1].drive_flags & DRIVE_ATAPI)) {
! 807: delay(250 * 1000);
! 808: }
! 809:
! 810: #ifdef WDCDEBUG
! 811: if (chp->wdc->sc_dev.dv_cfdata->cf_flags & WDC_OPTION_PROBE_VERBOSE)
! 812: wdcdebug_mask |= DEBUG_PROBE;
! 813:
! 814: if ((chp->ch_drive[0].drive_flags & DRIVE_ATAPI) ||
! 815: (chp->ch_drive[1].drive_flags & DRIVE_ATAPI)) {
! 816: wdcdebug_mask = DEBUG_PROBE;
! 817: }
! 818: #endif /* WDCDEBUG */
! 819:
! 820: /* initialise global data */
! 821: if (inited == 0) {
! 822: /* Initialize the wdc_xfer pool. */
! 823: pool_init(&wdc_xfer_pool, sizeof(struct wdc_xfer), 0,
! 824: 0, 0, "wdcspl", NULL);
! 825: inited++;
! 826: }
! 827: TAILQ_INIT(&chp->ch_queue->sc_xfer);
! 828:
! 829: for (i = 0; i < 2; i++) {
! 830: struct ata_drive_datas *drvp = &chp->ch_drive[i];
! 831:
! 832: drvp->chnl_softc = chp;
! 833: drvp->drive = i;
! 834: /* If controller can't do 16bit flag the drives as 32bit */
! 835: if ((chp->wdc->cap &
! 836: (WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32)) ==
! 837: WDC_CAPABILITY_DATA32)
! 838: drvp->drive_flags |= DRIVE_CAP32;
! 839:
! 840: if ((drvp->drive_flags & DRIVE) == 0)
! 841: continue;
! 842:
! 843: if (i == 1 && ((chp->ch_drive[0].drive_flags & DRIVE) == 0))
! 844: chp->ch_flags |= WDCF_ONESLAVE;
! 845: /*
! 846: * Wait a bit, some devices are weird just after a reset.
! 847: * Then issue a IDENTIFY command, to try to detect slave ghost.
! 848: */
! 849: delay(5000);
! 850: if (ata_get_params(&chp->ch_drive[i], at_poll, &drvp->id) ==
! 851: CMD_OK) {
! 852: /* If IDENTIFY succeeded, this is not an OLD ctrl */
! 853: drvp->drive_flags &= ~DRIVE_OLD;
! 854: } else {
! 855: bzero(&drvp->id, sizeof(struct ataparams));
! 856: drvp->drive_flags &=
! 857: ~(DRIVE_ATA | DRIVE_ATAPI);
! 858: WDCDEBUG_PRINT(("%s:%d:%d: IDENTIFY failed\n",
! 859: chp->wdc->sc_dev.dv_xname,
! 860: chp->channel, i), DEBUG_PROBE);
! 861:
! 862: if ((drvp->drive_flags & DRIVE_OLD) &&
! 863: !wdc_preata_drive(chp, i))
! 864: drvp->drive_flags &= ~DRIVE_OLD;
! 865: }
! 866: }
! 867: ctrl_flags = chp->wdc->sc_dev.dv_cfdata->cf_flags;
! 868: channel_flags = (ctrl_flags >> (NBBY * chp->channel)) & 0xff;
! 869:
! 870: WDCDEBUG_PRINT(("wdcattach: ch_drive_flags 0x%x 0x%x\n",
! 871: chp->ch_drive[0].drive_flags, chp->ch_drive[1].drive_flags),
! 872: DEBUG_PROBE);
! 873:
! 874: /* If no drives, abort here */
! 875: if ((chp->ch_drive[0].drive_flags & DRIVE) == 0 &&
! 876: (chp->ch_drive[1].drive_flags & DRIVE) == 0)
! 877: goto exit;
! 878:
! 879: for (i = 0; i < 2; i++) {
! 880: if ((chp->ch_drive[i].drive_flags & DRIVE) == 0) {
! 881: continue;
! 882: }
! 883: bzero(&aa_link, sizeof(struct ata_atapi_attach));
! 884: if (chp->ch_drive[i].drive_flags & DRIVE_ATAPI)
! 885: aa_link.aa_type = T_ATAPI;
! 886: else
! 887: aa_link.aa_type = T_ATA;
! 888: aa_link.aa_channel = chp->channel;
! 889: aa_link.aa_openings = 1;
! 890: aa_link.aa_drv_data = &chp->ch_drive[i];
! 891: config_found(&chp->wdc->sc_dev, (void *)&aa_link, wdprint);
! 892: }
! 893:
! 894: /*
! 895: * reset drive_flags for unattached devices, reset state for attached
! 896: * ones
! 897: */
! 898: for (i = 0; i < 2; i++) {
! 899: if (chp->ch_drive[i].drive_name[0] == 0)
! 900: chp->ch_drive[i].drive_flags = 0;
! 901: }
! 902:
! 903: #ifndef __OpenBSD__
! 904: wdc_delref(chp);
! 905: #endif
! 906:
! 907: exit:
! 908: #ifdef WDCDEBUG
! 909: wdcdebug_mask = savedmask;
! 910: #endif
! 911: return; /* for the ``exit'' label above */
! 912: }
! 913:
! 914: /*
! 915: * Start I/O on a controller, for the given channel.
! 916: * The first xfer may be not for our channel if the channel queues
! 917: * are shared.
! 918: */
! 919: void
! 920: wdcstart(chp)
! 921: struct channel_softc *chp;
! 922: {
! 923: struct wdc_xfer *xfer;
! 924:
! 925: splassert(IPL_BIO);
! 926:
! 927: /* is there a xfer ? */
! 928: if ((xfer = TAILQ_FIRST(&chp->ch_queue->sc_xfer)) == NULL) {
! 929: return;
! 930: }
! 931:
! 932: /* adjust chp, in case we have a shared queue */
! 933: chp = xfer->chp;
! 934:
! 935: if ((chp->ch_flags & WDCF_ACTIVE) != 0 ) {
! 936: return; /* channel already active */
! 937: }
! 938: #ifdef DIAGNOSTIC
! 939: if ((chp->ch_flags & WDCF_IRQ_WAIT) != 0)
! 940: panic("wdcstart: channel waiting for irq");
! 941: #endif /* DIAGNOSTIC */
! 942: if (chp->wdc->cap & WDC_CAPABILITY_HWLOCK)
! 943: if (!(chp->wdc->claim_hw)(chp, 0))
! 944: return;
! 945:
! 946: WDCDEBUG_PRINT(("wdcstart: xfer %p channel %d drive %d\n", xfer,
! 947: chp->channel, xfer->drive), DEBUG_XFERS);
! 948: chp->ch_flags |= WDCF_ACTIVE;
! 949: if (chp->ch_drive[xfer->drive].drive_flags & DRIVE_RESET) {
! 950: chp->ch_drive[xfer->drive].drive_flags &= ~DRIVE_RESET;
! 951: chp->ch_drive[xfer->drive].state = 0;
! 952: }
! 953: xfer->c_start(chp, xfer);
! 954: }
! 955:
! 956: int
! 957: wdcdetach(chp, flags)
! 958: struct channel_softc *chp;
! 959: int flags;
! 960: {
! 961: int s, rv;
! 962:
! 963: s = splbio();
! 964: wdc_kill_pending(chp);
! 965:
! 966: rv = config_detach_children((struct device *)chp->wdc, flags);
! 967: splx(s);
! 968:
! 969: return (rv);
! 970: }
! 971:
! 972: /*
! 973: * Interrupt routine for the controller. Acknowledge the interrupt, check for
! 974: * errors on the current operation, mark it done if necessary, and start the
! 975: * next request. Also check for a partially done transfer, and continue with
! 976: * the next chunk if so.
! 977: */
! 978: int
! 979: wdcintr(arg)
! 980: void *arg;
! 981: {
! 982: struct channel_softc *chp = arg;
! 983: struct wdc_xfer *xfer;
! 984: int ret;
! 985:
! 986: if ((chp->ch_flags & WDCF_IRQ_WAIT) == 0) {
! 987: /* Acknowledge interrupt by reading status */
! 988: if (chp->_vtbl == 0) {
! 989: bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
! 990: wdr_status & _WDC_REGMASK);
! 991: } else {
! 992: CHP_READ_REG(chp, wdr_status);
! 993: }
! 994:
! 995: WDCDEBUG_PRINT(("wdcintr: inactive controller\n"), DEBUG_INTR);
! 996: return 0;
! 997: }
! 998:
! 999: WDCDEBUG_PRINT(("wdcintr\n"), DEBUG_INTR);
! 1000: xfer = TAILQ_FIRST(&chp->ch_queue->sc_xfer);
! 1001: if (chp->ch_flags & WDCF_DMA_WAIT) {
! 1002: chp->wdc->dma_status =
! 1003: (*chp->wdc->dma_finish)(chp->wdc->dma_arg, chp->channel,
! 1004: xfer->drive, 0);
! 1005: if (chp->wdc->dma_status & WDC_DMAST_NOIRQ) {
! 1006: /* IRQ not for us, not detected by DMA engine */
! 1007: return 0;
! 1008: }
! 1009: chp->ch_flags &= ~WDCF_DMA_WAIT;
! 1010: }
! 1011: chp->ch_flags &= ~WDCF_IRQ_WAIT;
! 1012: ret = xfer->c_intr(chp, xfer, 1);
! 1013: if (ret == 0) /* irq was not for us, still waiting for irq */
! 1014: chp->ch_flags |= WDCF_IRQ_WAIT;
! 1015: return (ret);
! 1016: }
! 1017:
! 1018: /* Put all disk in RESET state */
! 1019: void wdc_reset_channel(drvp)
! 1020: struct ata_drive_datas *drvp;
! 1021: {
! 1022: struct channel_softc *chp = drvp->chnl_softc;
! 1023: int drive;
! 1024: WDCDEBUG_PRINT(("ata_reset_channel %s:%d for drive %d\n",
! 1025: chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive),
! 1026: DEBUG_FUNCS);
! 1027: (void) wdcreset(chp, VERBOSE);
! 1028: for (drive = 0; drive < 2; drive++) {
! 1029: chp->ch_drive[drive].state = 0;
! 1030: }
! 1031: }
! 1032:
! 1033: int
! 1034: wdcreset(chp, verb)
! 1035: struct channel_softc *chp;
! 1036: int verb;
! 1037: {
! 1038: int drv_mask1, drv_mask2;
! 1039:
! 1040: if (!chp->_vtbl)
! 1041: chp->_vtbl = &wdc_default_vtbl;
! 1042:
! 1043: chp->wdc->reset(chp);
! 1044:
! 1045: drv_mask1 = (chp->ch_drive[0].drive_flags & DRIVE) ? 0x01:0x00;
! 1046: drv_mask1 |= (chp->ch_drive[1].drive_flags & DRIVE) ? 0x02:0x00;
! 1047: drv_mask2 = __wdcwait_reset(chp, drv_mask1);
! 1048: if (verb && drv_mask2 != drv_mask1) {
! 1049: printf("%s channel %d: reset failed for",
! 1050: chp->wdc->sc_dev.dv_xname, chp->channel);
! 1051: if ((drv_mask1 & 0x01) != 0 && (drv_mask2 & 0x01) == 0)
! 1052: printf(" drive 0");
! 1053: if ((drv_mask1 & 0x02) != 0 && (drv_mask2 & 0x02) == 0)
! 1054: printf(" drive 1");
! 1055: printf("\n");
! 1056: }
! 1057:
! 1058: return (drv_mask1 != drv_mask2) ? 1 : 0;
! 1059: }
! 1060:
! 1061: void
! 1062: wdc_do_reset(struct channel_softc *chp)
! 1063: {
! 1064: wdc_set_drive(chp, 0);
! 1065: DELAY(10);
! 1066: CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_4BIT | WDCTL_RST);
! 1067: delay(10000);
! 1068: CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_4BIT);
! 1069: delay(10000);
! 1070: }
! 1071:
! 1072: int
! 1073: __wdcwait_reset(chp, drv_mask)
! 1074: struct channel_softc *chp;
! 1075: int drv_mask;
! 1076: {
! 1077: int timeout;
! 1078: u_int8_t st0, er0, st1, er1;
! 1079:
! 1080: /* wait for BSY to deassert */
! 1081: for (timeout = 0; timeout < WDCNDELAY_RST; timeout++) {
! 1082: wdc_set_drive(chp, 0);
! 1083: delay(10);
! 1084: st0 = CHP_READ_REG(chp, wdr_status);
! 1085: er0 = CHP_READ_REG(chp, wdr_error);
! 1086: wdc_set_drive(chp, 1);
! 1087: delay(10);
! 1088: st1 = CHP_READ_REG(chp, wdr_status);
! 1089: er1 = CHP_READ_REG(chp, wdr_error);
! 1090:
! 1091: if ((drv_mask & 0x01) == 0) {
! 1092: /* no master */
! 1093: if ((drv_mask & 0x02) != 0 && (st1 & WDCS_BSY) == 0) {
! 1094: /* No master, slave is ready, it's done */
! 1095: goto end;
! 1096: }
! 1097: } else if ((drv_mask & 0x02) == 0) {
! 1098: /* no slave */
! 1099: if ((drv_mask & 0x01) != 0 && (st0 & WDCS_BSY) == 0) {
! 1100: /* No slave, master is ready, it's done */
! 1101: goto end;
! 1102: }
! 1103: } else {
! 1104: /* Wait for both master and slave to be ready */
! 1105: if ((st0 & WDCS_BSY) == 0 && (st1 & WDCS_BSY) == 0) {
! 1106: goto end;
! 1107: }
! 1108: }
! 1109: delay(WDCDELAY);
! 1110: }
! 1111: /* Reset timed out. Maybe it's because drv_mask was not right */
! 1112: if (st0 & WDCS_BSY)
! 1113: drv_mask &= ~0x01;
! 1114: if (st1 & WDCS_BSY)
! 1115: drv_mask &= ~0x02;
! 1116: end:
! 1117: WDCDEBUG_PRINT(("%s:%d: wdcwait_reset() end, st0=0x%b, er0=0x%x, "
! 1118: "st1=0x%b, er1=0x%x, reset time=%d msec\n",
! 1119: chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe", chp->channel,
! 1120: st0, WDCS_BITS, er0, st1, WDCS_BITS, er1,
! 1121: timeout * WDCDELAY / 1000), DEBUG_PROBE);
! 1122:
! 1123: return drv_mask;
! 1124: }
! 1125:
! 1126: /*
! 1127: * Wait for a drive to be !BSY, and have mask in its status register.
! 1128: * return -1 for a timeout after "timeout" ms.
! 1129: */
! 1130: int
! 1131: wdc_wait_for_status(chp, mask, bits, timeout)
! 1132: struct channel_softc *chp;
! 1133: int mask, bits, timeout;
! 1134: {
! 1135: u_char status;
! 1136: int time = 0;
! 1137:
! 1138: WDCDEBUG_PRINT(("wdcwait %s:%d\n", chp->wdc ?chp->wdc->sc_dev.dv_xname
! 1139: :"none", chp->channel), DEBUG_STATUS);
! 1140: chp->ch_error = 0;
! 1141:
! 1142: timeout = timeout * 1000 / WDCDELAY; /* delay uses microseconds */
! 1143:
! 1144: for (;;) {
! 1145: chp->ch_status = status = CHP_READ_REG(chp, wdr_status);
! 1146: WDC_LOG_STATUS(chp, chp->ch_status);
! 1147:
! 1148: if (status == 0xff && (chp->ch_flags & WDCF_ONESLAVE)) {
! 1149: wdc_set_drive(chp, 1);
! 1150: chp->ch_status = status =
! 1151: CHP_READ_REG(chp, wdr_status);
! 1152: WDC_LOG_STATUS(chp, chp->ch_status);
! 1153: }
! 1154: if ((status & WDCS_BSY) == 0 && (status & mask) == bits)
! 1155: break;
! 1156: if (++time > timeout) {
! 1157: WDCDEBUG_PRINT(("wdcwait: timeout, status 0x%b "
! 1158: "error 0x%x\n", status, WDCS_BITS,
! 1159: CHP_READ_REG(chp, wdr_error)),
! 1160: DEBUG_STATUSX | DEBUG_STATUS);
! 1161: return -1;
! 1162: }
! 1163: delay(WDCDELAY);
! 1164: }
! 1165: if (status & WDCS_ERR) {
! 1166: chp->ch_error = CHP_READ_REG(chp, wdr_error);
! 1167: WDC_LOG_ERROR(chp, chp->ch_error);
! 1168:
! 1169: WDCDEBUG_PRINT(("wdcwait: error %x\n", chp->ch_error),
! 1170: DEBUG_STATUSX | DEBUG_STATUS);
! 1171: }
! 1172:
! 1173: #ifdef WDCNDELAY_DEBUG
! 1174: /* After autoconfig, there should be no long delays. */
! 1175: if (!cold && time > WDCNDELAY_DEBUG) {
! 1176: struct wdc_xfer *xfer = TAILQ_FIRST(&chp->ch_queue->sc_xfer);
! 1177: if (xfer == NULL)
! 1178: printf("%s channel %d: warning: busy-wait took %dus\n",
! 1179: chp->wdc->sc_dev.dv_xname, chp->channel,
! 1180: WDCDELAY * time);
! 1181: else
! 1182: printf("%s:%d:%d: warning: busy-wait took %dus\n",
! 1183: chp->wdc->sc_dev.dv_xname, chp->channel,
! 1184: xfer->drive,
! 1185: WDCDELAY * time);
! 1186: }
! 1187: #endif /* WDCNDELAY_DEBUG */
! 1188: return time;
! 1189: }
! 1190:
! 1191: /*
! 1192: * Busy-wait for DMA to complete
! 1193: */
! 1194: int
! 1195: wdc_dmawait(chp, xfer, timeout)
! 1196: struct channel_softc *chp;
! 1197: struct wdc_xfer *xfer;
! 1198: int timeout;
! 1199: {
! 1200: int time;
! 1201: for (time = 0; time < timeout * 1000 / WDCDELAY; time++) {
! 1202: chp->wdc->dma_status =
! 1203: (*chp->wdc->dma_finish)(chp->wdc->dma_arg,
! 1204: chp->channel, xfer->drive, 0);
! 1205: if ((chp->wdc->dma_status & WDC_DMAST_NOIRQ) == 0)
! 1206: return 0;
! 1207: delay(WDCDELAY);
! 1208: }
! 1209: /* timeout, force a DMA halt */
! 1210: chp->wdc->dma_status = (*chp->wdc->dma_finish)(chp->wdc->dma_arg,
! 1211: chp->channel, xfer->drive, 1);
! 1212: return 1;
! 1213: }
! 1214:
! 1215: void
! 1216: wdctimeout(arg)
! 1217: void *arg;
! 1218: {
! 1219: struct channel_softc *chp = (struct channel_softc *)arg;
! 1220: struct wdc_xfer *xfer;
! 1221: int s;
! 1222:
! 1223: WDCDEBUG_PRINT(("wdctimeout\n"), DEBUG_FUNCS);
! 1224:
! 1225: s = splbio();
! 1226: xfer = TAILQ_FIRST(&chp->ch_queue->sc_xfer);
! 1227:
! 1228: /* Did we lose a race with the interrupt? */
! 1229: if (xfer == NULL ||
! 1230: !timeout_triggered(&chp->ch_timo)) {
! 1231: splx(s);
! 1232: return;
! 1233: }
! 1234: if ((chp->ch_flags & WDCF_IRQ_WAIT) != 0) {
! 1235: __wdcerror(chp, "timeout");
! 1236: printf("\ttype: %s\n", (xfer->c_flags & C_ATAPI) ?
! 1237: "atapi":"ata");
! 1238: printf("\tc_bcount: %d\n", xfer->c_bcount);
! 1239: printf("\tc_skip: %d\n", xfer->c_skip);
! 1240: if (chp->ch_flags & WDCF_DMA_WAIT) {
! 1241: chp->wdc->dma_status =
! 1242: (*chp->wdc->dma_finish)(chp->wdc->dma_arg,
! 1243: chp->channel, xfer->drive, 1);
! 1244: chp->ch_flags &= ~WDCF_DMA_WAIT;
! 1245: }
! 1246: /*
! 1247: * Call the interrupt routine. If we just missed and interrupt,
! 1248: * it will do what's needed. Else, it will take the needed
! 1249: * action (reset the device).
! 1250: */
! 1251: xfer->c_flags |= C_TIMEOU;
! 1252: chp->ch_flags &= ~WDCF_IRQ_WAIT;
! 1253: xfer->c_intr(chp, xfer, 1);
! 1254: } else
! 1255: __wdcerror(chp, "missing untimeout");
! 1256: splx(s);
! 1257: }
! 1258:
! 1259: /*
! 1260: * Probe drive's capabilities, for use by the controller later.
! 1261: * Assumes drvp points to an existing drive.
! 1262: * XXX this should be a controller-indep function
! 1263: */
! 1264: void
! 1265: wdc_probe_caps(drvp, params)
! 1266: struct ata_drive_datas *drvp;
! 1267: struct ataparams *params;
! 1268: {
! 1269: struct channel_softc *chp = drvp->chnl_softc;
! 1270: struct wdc_softc *wdc = chp->wdc;
! 1271: int i, valid_mode_found;
! 1272: int cf_flags = drvp->cf_flags;
! 1273:
! 1274: if ((wdc->cap & WDC_CAPABILITY_SATA) != 0 &&
! 1275: (params->atap_sata_caps != 0x0000 &&
! 1276: params->atap_sata_caps != 0xffff)) {
! 1277: WDCDEBUG_PRINT(("%s: atap_sata_caps=0x%x\n", __func__,
! 1278: params->atap_sata_caps), DEBUG_PROBE);
! 1279:
! 1280: /* Skip ATA modes detection for native SATA drives */
! 1281: drvp->PIO_mode = drvp->PIO_cap = 4;
! 1282: drvp->DMA_mode = drvp->DMA_cap = 2;
! 1283: drvp->UDMA_mode = drvp->UDMA_cap = 5;
! 1284: drvp->drive_flags |= DRIVE_SATA | DRIVE_MODE | DRIVE_UDMA;
! 1285: drvp->ata_vers = 4;
! 1286: return;
! 1287: }
! 1288:
! 1289: if ((wdc->cap & (WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32)) ==
! 1290: (WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32)) {
! 1291: struct ataparams params2;
! 1292:
! 1293: /*
! 1294: * Controller claims 16 and 32 bit transfers.
! 1295: * Re-do an IDENTIFY with 32-bit transfers,
! 1296: * and compare results.
! 1297: */
! 1298: drvp->drive_flags |= DRIVE_CAP32;
! 1299: ata_get_params(drvp, at_poll, ¶ms2);
! 1300: if (bcmp(params, ¶ms2, sizeof(struct ataparams)) != 0) {
! 1301: /* Not good. fall back to 16bits */
! 1302: drvp->drive_flags &= ~DRIVE_CAP32;
! 1303: }
! 1304: }
! 1305: #if 0 /* Some ultra-DMA drives claims to only support ATA-3. sigh */
! 1306: if (params->atap_ata_major > 0x01 &&
! 1307: params->atap_ata_major != 0xffff) {
! 1308: for (i = 14; i > 0; i--) {
! 1309: if (params->atap_ata_major & (1 << i)) {
! 1310: printf("%sATA version %d\n", sep, i);
! 1311: drvp->ata_vers = i;
! 1312: break;
! 1313: }
! 1314: }
! 1315: } else
! 1316: #endif /* 0 */
! 1317: /* Use PIO mode 3 as a default value for ATAPI devices */
! 1318: if (drvp->drive_flags & DRIVE_ATAPI)
! 1319: drvp->PIO_mode = 3;
! 1320:
! 1321: WDCDEBUG_PRINT(("wdc_probe_caps: wdc_cap 0x%x cf_flags 0x%x\n",
! 1322: wdc->cap, cf_flags), DEBUG_PROBE);
! 1323:
! 1324: valid_mode_found = 0;
! 1325:
! 1326: WDCDEBUG_PRINT(("%s: atap_oldpiotiming=%d\n", __func__,
! 1327: params->atap_oldpiotiming), DEBUG_PROBE);
! 1328: /*
! 1329: * ATA-4 compliant devices contain PIO mode
! 1330: * number in atap_oldpiotiming.
! 1331: */
! 1332: if (params->atap_oldpiotiming <= 2) {
! 1333: drvp->PIO_cap = params->atap_oldpiotiming;
! 1334: valid_mode_found = 1;
! 1335: drvp->drive_flags |= DRIVE_MODE;
! 1336: } else if (params->atap_oldpiotiming > 180) {
! 1337: /*
! 1338: * ATA-2 compliant devices contain cycle
! 1339: * time in atap_oldpiotiming.
! 1340: * A device with a cycle time of 180ns
! 1341: * or less is at least PIO mode 3 and
! 1342: * should be reporting that in
! 1343: * atap_piomode_supp, so ignore it here.
! 1344: */
! 1345: if (params->atap_oldpiotiming <= 240) {
! 1346: drvp->PIO_cap = 2;
! 1347: } else {
! 1348: drvp->PIO_cap = 1;
! 1349: }
! 1350: valid_mode_found = 1;
! 1351: drvp->drive_flags |= DRIVE_MODE;
! 1352: }
! 1353: if (valid_mode_found)
! 1354: drvp->PIO_mode = drvp->PIO_cap;
! 1355:
! 1356: WDCDEBUG_PRINT(("%s: atap_extensions=0x%x, atap_piomode_supp=0x%x, "
! 1357: "atap_dmamode_supp=0x%x, atap_udmamode_supp=0x%x\n",
! 1358: __func__, params->atap_extensions, params->atap_piomode_supp,
! 1359: params->atap_dmamode_supp, params->atap_udmamode_supp),
! 1360: DEBUG_PROBE);
! 1361:
! 1362: /*
! 1363: * It's not in the specs, but it seems that some drive
! 1364: * returns 0xffff in atap_extensions when this field is invalid
! 1365: */
! 1366: if (params->atap_extensions != 0xffff &&
! 1367: (params->atap_extensions & WDC_EXT_MODES)) {
! 1368: /*
! 1369: * XXX some drives report something wrong here (they claim to
! 1370: * support PIO mode 8 !). As mode is coded on 3 bits in
! 1371: * SET FEATURE, limit it to 7 (so limit i to 4).
! 1372: * If higher mode than 7 is found, abort.
! 1373: */
! 1374: for (i = 7; i >= 0; i--) {
! 1375: if ((params->atap_piomode_supp & (1 << i)) == 0)
! 1376: continue;
! 1377: if (i > 4)
! 1378: return;
! 1379:
! 1380: valid_mode_found = 1;
! 1381:
! 1382: if ((wdc->cap & WDC_CAPABILITY_MODE) == 0) {
! 1383: drvp->PIO_cap = i + 3;
! 1384: continue;
! 1385: }
! 1386:
! 1387: /*
! 1388: * See if mode is accepted.
! 1389: * If the controller can't set its PIO mode,
! 1390: * assume the BIOS set it up correctly
! 1391: */
! 1392: if (ata_set_mode(drvp, 0x08 | (i + 3),
! 1393: at_poll) != CMD_OK)
! 1394: continue;
! 1395:
! 1396: /*
! 1397: * If controller's driver can't set its PIO mode,
! 1398: * set the highest one the controller supports
! 1399: */
! 1400: if (wdc->PIO_cap >= i + 3) {
! 1401: drvp->PIO_mode = i + 3;
! 1402: drvp->PIO_cap = i + 3;
! 1403: break;
! 1404: }
! 1405: }
! 1406: if (!valid_mode_found) {
! 1407: /*
! 1408: * We didn't find a valid PIO mode.
! 1409: * Assume the values returned for DMA are buggy too
! 1410: */
! 1411: return;
! 1412: }
! 1413: drvp->drive_flags |= DRIVE_MODE;
! 1414:
! 1415: /* Some controllers don't support ATAPI DMA */
! 1416: if ((drvp->drive_flags & DRIVE_ATAPI) &&
! 1417: (wdc->cap & WDC_CAPABILITY_NO_ATAPI_DMA))
! 1418: return;
! 1419:
! 1420: valid_mode_found = 0;
! 1421: for (i = 7; i >= 0; i--) {
! 1422: if ((params->atap_dmamode_supp & (1 << i)) == 0)
! 1423: continue;
! 1424: if ((wdc->cap & WDC_CAPABILITY_DMA) &&
! 1425: (wdc->cap & WDC_CAPABILITY_MODE))
! 1426: if (ata_set_mode(drvp, 0x20 | i, at_poll)
! 1427: != CMD_OK)
! 1428: continue;
! 1429:
! 1430: valid_mode_found = 1;
! 1431:
! 1432: if (wdc->cap & WDC_CAPABILITY_DMA) {
! 1433: if ((wdc->cap & WDC_CAPABILITY_MODE) &&
! 1434: wdc->DMA_cap < i)
! 1435: continue;
! 1436: drvp->DMA_mode = i;
! 1437: drvp->DMA_cap = i;
! 1438: drvp->drive_flags |= DRIVE_DMA;
! 1439: }
! 1440: break;
! 1441: }
! 1442: if (params->atap_extensions & WDC_EXT_UDMA_MODES) {
! 1443: for (i = 7; i >= 0; i--) {
! 1444: if ((params->atap_udmamode_supp & (1 << i))
! 1445: == 0)
! 1446: continue;
! 1447: if ((wdc->cap & WDC_CAPABILITY_MODE) &&
! 1448: (wdc->cap & WDC_CAPABILITY_UDMA))
! 1449: if (ata_set_mode(drvp, 0x40 | i,
! 1450: at_poll) != CMD_OK)
! 1451: continue;
! 1452: if (wdc->cap & WDC_CAPABILITY_UDMA) {
! 1453: if ((wdc->cap & WDC_CAPABILITY_MODE) &&
! 1454: wdc->UDMA_cap < i)
! 1455: continue;
! 1456: drvp->UDMA_mode = i;
! 1457: drvp->UDMA_cap = i;
! 1458: drvp->drive_flags |= DRIVE_UDMA;
! 1459: }
! 1460: break;
! 1461: }
! 1462: }
! 1463: }
! 1464:
! 1465: /* Try to guess ATA version here, if it didn't get reported */
! 1466: if (drvp->ata_vers == 0) {
! 1467: if (drvp->drive_flags & DRIVE_UDMA)
! 1468: drvp->ata_vers = 4; /* should be at last ATA-4 */
! 1469: else if (drvp->PIO_cap > 2)
! 1470: drvp->ata_vers = 2; /* should be at last ATA-2 */
! 1471: }
! 1472: if (cf_flags & ATA_CONFIG_PIO_SET) {
! 1473: drvp->PIO_mode =
! 1474: (cf_flags & ATA_CONFIG_PIO_MODES) >> ATA_CONFIG_PIO_OFF;
! 1475: drvp->drive_flags |= DRIVE_MODE;
! 1476: }
! 1477: if ((wdc->cap & WDC_CAPABILITY_DMA) == 0) {
! 1478: /* don't care about DMA modes */
! 1479: return;
! 1480: }
! 1481: if (cf_flags & ATA_CONFIG_DMA_SET) {
! 1482: if ((cf_flags & ATA_CONFIG_DMA_MODES) ==
! 1483: ATA_CONFIG_DMA_DISABLE) {
! 1484: drvp->drive_flags &= ~DRIVE_DMA;
! 1485: } else {
! 1486: drvp->DMA_mode = (cf_flags & ATA_CONFIG_DMA_MODES) >>
! 1487: ATA_CONFIG_DMA_OFF;
! 1488: drvp->drive_flags |= DRIVE_DMA | DRIVE_MODE;
! 1489: }
! 1490: }
! 1491: if ((wdc->cap & WDC_CAPABILITY_UDMA) == 0) {
! 1492: /* don't care about UDMA modes */
! 1493: return;
! 1494: }
! 1495: if (cf_flags & ATA_CONFIG_UDMA_SET) {
! 1496: if ((cf_flags & ATA_CONFIG_UDMA_MODES) ==
! 1497: ATA_CONFIG_UDMA_DISABLE) {
! 1498: drvp->drive_flags &= ~DRIVE_UDMA;
! 1499: } else {
! 1500: drvp->UDMA_mode = (cf_flags & ATA_CONFIG_UDMA_MODES) >>
! 1501: ATA_CONFIG_UDMA_OFF;
! 1502: drvp->drive_flags |= DRIVE_UDMA | DRIVE_MODE;
! 1503: }
! 1504: }
! 1505: }
! 1506:
! 1507: void
! 1508: wdc_output_bytes(drvp, bytes, buflen)
! 1509: struct ata_drive_datas *drvp;
! 1510: void *bytes;
! 1511: unsigned int buflen;
! 1512: {
! 1513: struct channel_softc *chp = drvp->chnl_softc;
! 1514: unsigned int off = 0;
! 1515: unsigned int len = buflen, roundlen;
! 1516:
! 1517: if (drvp->drive_flags & DRIVE_CAP32) {
! 1518: roundlen = len & ~3;
! 1519:
! 1520: CHP_WRITE_RAW_MULTI_4(chp,
! 1521: (void *)((u_int8_t *)bytes + off), roundlen);
! 1522:
! 1523: off += roundlen;
! 1524: len -= roundlen;
! 1525: }
! 1526:
! 1527: if (len > 0) {
! 1528: roundlen = (len + 1) & ~0x1;
! 1529:
! 1530: CHP_WRITE_RAW_MULTI_2(chp,
! 1531: (void *)((u_int8_t *)bytes + off), roundlen);
! 1532: }
! 1533: }
! 1534:
! 1535: void
! 1536: wdc_input_bytes(drvp, bytes, buflen)
! 1537: struct ata_drive_datas *drvp;
! 1538: void *bytes;
! 1539: unsigned int buflen;
! 1540: {
! 1541: struct channel_softc *chp = drvp->chnl_softc;
! 1542: unsigned int off = 0;
! 1543: unsigned int len = buflen, roundlen;
! 1544:
! 1545: if (drvp->drive_flags & DRIVE_CAP32) {
! 1546: roundlen = len & ~3;
! 1547:
! 1548: CHP_READ_RAW_MULTI_4(chp,
! 1549: (void *)((u_int8_t *)bytes + off), roundlen);
! 1550:
! 1551: off += roundlen;
! 1552: len -= roundlen;
! 1553: }
! 1554:
! 1555: if (len > 0) {
! 1556: roundlen = (len + 1) & ~0x1;
! 1557:
! 1558: CHP_READ_RAW_MULTI_2(chp,
! 1559: (void *)((u_int8_t *)bytes + off), roundlen);
! 1560: }
! 1561: }
! 1562:
! 1563: void
! 1564: wdc_print_caps(drvp)
! 1565: struct ata_drive_datas *drvp;
! 1566: {
! 1567: /* This is actually a lie until we fix the _probe_caps
! 1568: algorithm. Don't print out lies */
! 1569: #if 0
! 1570: printf("%s: can use ", drvp->drive_name);
! 1571:
! 1572: if (drvp->drive_flags & DRIVE_CAP32) {
! 1573: printf("32-bit");
! 1574: } else
! 1575: printf("16-bit");
! 1576:
! 1577: printf(", PIO mode %d", drvp->PIO_cap);
! 1578:
! 1579: if (drvp->drive_flags & DRIVE_DMA) {
! 1580: printf(", DMA mode %d", drvp->DMA_cap);
! 1581: }
! 1582:
! 1583: if (drvp->drive_flags & DRIVE_UDMA) {
! 1584: printf(", Ultra-DMA mode %d", drvp->UDMA_cap);
! 1585: }
! 1586:
! 1587: printf("\n");
! 1588: #endif /* 0 */
! 1589: }
! 1590:
! 1591: void
! 1592: wdc_print_current_modes(chp)
! 1593: struct channel_softc *chp;
! 1594: {
! 1595: int drive;
! 1596: struct ata_drive_datas *drvp;
! 1597:
! 1598: for (drive = 0; drive < 2; drive++) {
! 1599: drvp = &chp->ch_drive[drive];
! 1600: if ((drvp->drive_flags & DRIVE) == 0)
! 1601: continue;
! 1602:
! 1603: printf("%s(%s:%d:%d):",
! 1604: drvp->drive_name,
! 1605: chp->wdc->sc_dev.dv_xname, chp->channel, drive);
! 1606:
! 1607: if ((chp->wdc->cap & WDC_CAPABILITY_MODE) == 0 &&
! 1608: !(drvp->cf_flags & ATA_CONFIG_PIO_SET))
! 1609: printf(" using BIOS timings");
! 1610: else
! 1611: printf(" using PIO mode %d", drvp->PIO_mode);
! 1612: if (drvp->drive_flags & DRIVE_DMA)
! 1613: printf(", DMA mode %d", drvp->DMA_mode);
! 1614: if (drvp->drive_flags & DRIVE_UDMA)
! 1615: printf(", Ultra-DMA mode %d", drvp->UDMA_mode);
! 1616: printf("\n");
! 1617: }
! 1618: }
! 1619:
! 1620: /*
! 1621: * downgrade the transfer mode of a drive after an error. return 1 if
! 1622: * downgrade was possible, 0 otherwise.
! 1623: */
! 1624: int
! 1625: wdc_downgrade_mode(drvp)
! 1626: struct ata_drive_datas *drvp;
! 1627: {
! 1628: struct channel_softc *chp = drvp->chnl_softc;
! 1629: struct wdc_softc *wdc = chp->wdc;
! 1630: int cf_flags = drvp->cf_flags;
! 1631:
! 1632: /* if drive or controller don't know its mode, we can't do much */
! 1633: if ((drvp->drive_flags & DRIVE_MODE) == 0 ||
! 1634: (wdc->cap & WDC_CAPABILITY_MODE) == 0)
! 1635: return 0;
! 1636: /* current drive mode was set by a config flag, let it this way */
! 1637: if ((cf_flags & ATA_CONFIG_PIO_SET) ||
! 1638: (cf_flags & ATA_CONFIG_DMA_SET) ||
! 1639: (cf_flags & ATA_CONFIG_UDMA_SET))
! 1640: return 0;
! 1641:
! 1642: /*
! 1643: * We'd ideally like to use an Ultra DMA mode since they have the
! 1644: * protection of a CRC. So we try each Ultra DMA mode and see if
! 1645: * we can find any working combo
! 1646: */
! 1647: if ((drvp->drive_flags & DRIVE_UDMA) && drvp->UDMA_mode > 0) {
! 1648: drvp->UDMA_mode = drvp->UDMA_mode - 1;
! 1649: printf("%s: transfer error, downgrading to Ultra-DMA mode %d\n",
! 1650: drvp->drive_name, drvp->UDMA_mode);
! 1651: } else if ((drvp->drive_flags & DRIVE_UDMA) &&
! 1652: (drvp->drive_flags & DRIVE_DMAERR) == 0) {
! 1653: /*
! 1654: * If we were using ultra-DMA, don't downgrade to
! 1655: * multiword DMA if we noticed a CRC error. It has
! 1656: * been noticed that CRC errors in ultra-DMA lead to
! 1657: * silent data corruption in multiword DMA. Data
! 1658: * corruption is less likely to occur in PIO mode.
! 1659: */
! 1660: drvp->drive_flags &= ~DRIVE_UDMA;
! 1661: drvp->drive_flags |= DRIVE_DMA;
! 1662: drvp->DMA_mode = drvp->DMA_cap;
! 1663: printf("%s: transfer error, downgrading to DMA mode %d\n",
! 1664: drvp->drive_name, drvp->DMA_mode);
! 1665: } else if (drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) {
! 1666: drvp->drive_flags &= ~(DRIVE_DMA | DRIVE_UDMA);
! 1667: drvp->PIO_mode = drvp->PIO_cap;
! 1668: printf("%s: transfer error, downgrading to PIO mode %d\n",
! 1669: drvp->drive_name, drvp->PIO_mode);
! 1670: } else /* already using PIO, can't downgrade */
! 1671: return 0;
! 1672:
! 1673: wdc->set_modes(chp);
! 1674: /* reset the channel, which will schedule all drives for setup */
! 1675: wdc_reset_channel(drvp);
! 1676: return 1;
! 1677: }
! 1678:
! 1679: int
! 1680: wdc_exec_command(drvp, wdc_c)
! 1681: struct ata_drive_datas *drvp;
! 1682: struct wdc_command *wdc_c;
! 1683: {
! 1684: struct channel_softc *chp = drvp->chnl_softc;
! 1685: struct wdc_xfer *xfer;
! 1686: int s, ret;
! 1687:
! 1688: WDCDEBUG_PRINT(("wdc_exec_command %s:%d:%d\n",
! 1689: chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive),
! 1690: DEBUG_FUNCS);
! 1691:
! 1692: /* set up an xfer and queue. Wait for completion */
! 1693: xfer = wdc_get_xfer(wdc_c->flags & AT_WAIT ? WDC_CANSLEEP :
! 1694: WDC_NOSLEEP);
! 1695: if (xfer == NULL) {
! 1696: return WDC_TRY_AGAIN;
! 1697: }
! 1698:
! 1699: if (wdc_c->flags & AT_POLL)
! 1700: xfer->c_flags |= C_POLL;
! 1701: xfer->drive = drvp->drive;
! 1702: xfer->databuf = wdc_c->data;
! 1703: xfer->c_bcount = wdc_c->bcount;
! 1704: xfer->cmd = wdc_c;
! 1705: xfer->c_start = __wdccommand_start;
! 1706: xfer->c_intr = __wdccommand_intr;
! 1707: xfer->c_kill_xfer = __wdccommand_done;
! 1708:
! 1709: s = splbio();
! 1710: wdc_exec_xfer(chp, xfer);
! 1711: #ifdef DIAGNOSTIC
! 1712: if ((wdc_c->flags & AT_POLL) != 0 &&
! 1713: (wdc_c->flags & AT_DONE) == 0)
! 1714: panic("wdc_exec_command: polled command not done");
! 1715: #endif /* DIAGNOSTIC */
! 1716: if (wdc_c->flags & AT_DONE) {
! 1717: ret = WDC_COMPLETE;
! 1718: } else {
! 1719: if (wdc_c->flags & AT_WAIT) {
! 1720: WDCDEBUG_PRINT(("wdc_exec_command sleeping\n"),
! 1721: DEBUG_FUNCS);
! 1722:
! 1723: while ((wdc_c->flags & AT_DONE) == 0) {
! 1724: tsleep(wdc_c, PRIBIO, "wdccmd", 0);
! 1725: }
! 1726: ret = WDC_COMPLETE;
! 1727: } else {
! 1728: ret = WDC_QUEUED;
! 1729: }
! 1730: }
! 1731: splx(s);
! 1732: return ret;
! 1733: }
! 1734:
! 1735: void
! 1736: __wdccommand_start(chp, xfer)
! 1737: struct channel_softc *chp;
! 1738: struct wdc_xfer *xfer;
! 1739: {
! 1740: int drive = xfer->drive;
! 1741: struct wdc_command *wdc_c = xfer->cmd;
! 1742:
! 1743: WDCDEBUG_PRINT(("__wdccommand_start %s:%d:%d\n",
! 1744: chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive),
! 1745: DEBUG_FUNCS);
! 1746:
! 1747: /*
! 1748: * Disable interrupts if we're polling
! 1749: */
! 1750: if (xfer->c_flags & C_POLL) {
! 1751: wdc_disable_intr(chp);
! 1752: }
! 1753:
! 1754: wdc_set_drive(chp, drive);
! 1755: DELAY(1);
! 1756:
! 1757: /*
! 1758: * For resets, we don't really care to make sure that
! 1759: * the bus is free
! 1760: */
! 1761: if (wdc_c->r_command != ATAPI_SOFT_RESET) {
! 1762: if (wdcwait(chp, wdc_c->r_st_bmask | WDCS_DRQ,
! 1763: wdc_c->r_st_bmask, wdc_c->timeout) != 0) {
! 1764: goto timeout;
! 1765: }
! 1766: } else
! 1767: DELAY(10);
! 1768:
! 1769: wdccommand(chp, drive, wdc_c->r_command, wdc_c->r_cyl, wdc_c->r_head,
! 1770: wdc_c->r_sector, wdc_c->r_count, wdc_c->r_precomp);
! 1771:
! 1772: if ((wdc_c->flags & AT_WRITE) == AT_WRITE) {
! 1773: /* wait at least 400ns before reading status register */
! 1774: DELAY(10);
! 1775: if (wait_for_unbusy(chp, wdc_c->timeout) != 0)
! 1776: goto timeout;
! 1777:
! 1778: if ((chp->ch_status & (WDCS_DRQ | WDCS_ERR)) == WDCS_ERR) {
! 1779: __wdccommand_done(chp, xfer);
! 1780: return;
! 1781: }
! 1782:
! 1783: if (wait_for_drq(chp, wdc_c->timeout) != 0)
! 1784: goto timeout;
! 1785:
! 1786: wdc_output_bytes(&chp->ch_drive[drive],
! 1787: wdc_c->data, wdc_c->bcount);
! 1788: }
! 1789:
! 1790: if ((wdc_c->flags & AT_POLL) == 0) {
! 1791: chp->ch_flags |= WDCF_IRQ_WAIT; /* wait for interrupt */
! 1792: timeout_add(&chp->ch_timo, wdc_c->timeout / 1000 * hz);
! 1793: return;
! 1794: }
! 1795:
! 1796: /*
! 1797: * Polled command. Wait for drive ready or drq. Done in intr().
! 1798: * Wait for at last 400ns for status bit to be valid.
! 1799: */
! 1800: delay(10);
! 1801: __wdccommand_intr(chp, xfer, 0);
! 1802: return;
! 1803:
! 1804: timeout:
! 1805: wdc_c->flags |= AT_TIMEOU;
! 1806: __wdccommand_done(chp, xfer);
! 1807: }
! 1808:
! 1809: int
! 1810: __wdccommand_intr(chp, xfer, irq)
! 1811: struct channel_softc *chp;
! 1812: struct wdc_xfer *xfer;
! 1813: int irq;
! 1814: {
! 1815: struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
! 1816: struct wdc_command *wdc_c = xfer->cmd;
! 1817: int bcount = wdc_c->bcount;
! 1818: char *data = wdc_c->data;
! 1819:
! 1820: WDCDEBUG_PRINT(("__wdccommand_intr %s:%d:%d\n",
! 1821: chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive), DEBUG_INTR);
! 1822: if (wdcwait(chp, wdc_c->r_st_pmask, wdc_c->r_st_pmask,
! 1823: (irq == 0) ? wdc_c->timeout : 0)) {
! 1824: if (irq && (xfer->c_flags & C_TIMEOU) == 0)
! 1825: return 0; /* IRQ was not for us */
! 1826: wdc_c->flags |= AT_TIMEOU;
! 1827: goto out;
! 1828: }
! 1829: if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
! 1830: chp->wdc->irqack(chp);
! 1831: if (wdc_c->flags & AT_READ) {
! 1832: if ((chp->ch_status & WDCS_DRQ) == 0) {
! 1833: wdc_c->flags |= AT_TIMEOU;
! 1834: goto out;
! 1835: }
! 1836: wdc_input_bytes(drvp, data, bcount);
! 1837: /* Should we wait for device to indicate idle? */
! 1838: }
! 1839: out:
! 1840: __wdccommand_done(chp, xfer);
! 1841: WDCDEBUG_PRINT(("__wdccommand_intr returned\n"), DEBUG_INTR);
! 1842: return 1;
! 1843: }
! 1844:
! 1845: void
! 1846: __wdccommand_done(chp, xfer)
! 1847: struct channel_softc *chp;
! 1848: struct wdc_xfer *xfer;
! 1849: {
! 1850: struct wdc_command *wdc_c = xfer->cmd;
! 1851:
! 1852: WDCDEBUG_PRINT(("__wdccommand_done %s:%d:%d %02x\n",
! 1853: chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
! 1854: chp->ch_status), DEBUG_FUNCS);
! 1855: if (chp->ch_status & WDCS_DWF)
! 1856: wdc_c->flags |= AT_DF;
! 1857: if (chp->ch_status & WDCS_ERR) {
! 1858: wdc_c->flags |= AT_ERROR;
! 1859: wdc_c->r_error = chp->ch_error;
! 1860: }
! 1861: wdc_c->flags |= AT_DONE;
! 1862: if ((wdc_c->flags & AT_READREG) != 0 &&
! 1863: (wdc_c->flags & (AT_ERROR | AT_DF)) == 0) {
! 1864: wdc_c->r_head = CHP_READ_REG(chp, wdr_sdh);
! 1865: wdc_c->r_cyl = CHP_READ_REG(chp, wdr_cyl_hi) << 8;
! 1866: wdc_c->r_cyl |= CHP_READ_REG(chp, wdr_cyl_lo);
! 1867: wdc_c->r_sector = CHP_READ_REG(chp, wdr_sector);
! 1868: wdc_c->r_count = CHP_READ_REG(chp, wdr_seccnt);
! 1869: wdc_c->r_error = CHP_READ_REG(chp, wdr_error);
! 1870: wdc_c->r_precomp = wdc_c->r_error;
! 1871: /* XXX CHP_READ_REG(chp, wdr_precomp); - precomp
! 1872: isn't a readable register */
! 1873: }
! 1874:
! 1875: if (xfer->c_flags & C_POLL) {
! 1876: wdc_enable_intr(chp);
! 1877: }
! 1878:
! 1879: wdc_free_xfer(chp, xfer);
! 1880: WDCDEBUG_PRINT(("__wdccommand_done before callback\n"), DEBUG_INTR);
! 1881:
! 1882: if (wdc_c->flags & AT_WAIT)
! 1883: wakeup(wdc_c);
! 1884: else
! 1885: if (wdc_c->callback)
! 1886: wdc_c->callback(wdc_c->callback_arg);
! 1887: wdcstart(chp);
! 1888: WDCDEBUG_PRINT(("__wdccommand_done returned\n"), DEBUG_INTR);
! 1889: }
! 1890:
! 1891: /*
! 1892: * Send a command. The drive should be ready.
! 1893: * Assumes interrupts are blocked.
! 1894: */
! 1895: void
! 1896: wdccommand(chp, drive, command, cylin, head, sector, count, precomp)
! 1897: struct channel_softc *chp;
! 1898: u_int8_t drive;
! 1899: u_int8_t command;
! 1900: u_int16_t cylin;
! 1901: u_int8_t head, sector, count, precomp;
! 1902: {
! 1903: WDCDEBUG_PRINT(("wdccommand %s:%d:%d: command=0x%x cylin=%d head=%d "
! 1904: "sector=%d count=%d precomp=%d\n", chp->wdc->sc_dev.dv_xname,
! 1905: chp->channel, drive, command, cylin, head, sector, count, precomp),
! 1906: DEBUG_FUNCS);
! 1907: WDC_LOG_ATA_CMDLONG(chp, head, precomp, cylin, cylin >> 8, sector,
! 1908: count, command);
! 1909:
! 1910: /* Select drive, head, and addressing mode. */
! 1911: CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (drive << 4) | head);
! 1912:
! 1913: /* Load parameters. wdr_features(ATA/ATAPI) = wdr_precomp(ST506) */
! 1914: CHP_WRITE_REG(chp, wdr_precomp, precomp);
! 1915: CHP_WRITE_REG(chp, wdr_cyl_lo, cylin);
! 1916: CHP_WRITE_REG(chp, wdr_cyl_hi, cylin >> 8);
! 1917: CHP_WRITE_REG(chp, wdr_sector, sector);
! 1918: CHP_WRITE_REG(chp, wdr_seccnt, count);
! 1919:
! 1920: /* Send command. */
! 1921: CHP_WRITE_REG(chp, wdr_command, command);
! 1922: }
! 1923:
! 1924: /*
! 1925: * Send a 48-bit addressing command. The drive should be ready.
! 1926: * Assumes interrupts are blocked.
! 1927: */
! 1928: void
! 1929: wdccommandext(chp, drive, command, blkno, count)
! 1930: struct channel_softc *chp;
! 1931: u_int8_t drive;
! 1932: u_int8_t command;
! 1933: u_int64_t blkno;
! 1934: u_int16_t count;
! 1935: {
! 1936: WDCDEBUG_PRINT(("wdccommandext %s:%d:%d: command=0x%x blkno=%llu "
! 1937: "count=%d\n", chp->wdc->sc_dev.dv_xname,
! 1938: chp->channel, drive, command, blkno, count),
! 1939: DEBUG_FUNCS);
! 1940: WDC_LOG_ATA_CMDEXT(chp, blkno >> 40, blkno >> 16, blkno >> 32,
! 1941: blkno >> 8, blkno >> 24, blkno, count >> 8, count, command);
! 1942:
! 1943: /* Select drive and LBA mode. */
! 1944: CHP_WRITE_REG(chp, wdr_sdh, (drive << 4) | WDSD_LBA);
! 1945:
! 1946: /* Load parameters. */
! 1947: CHP_LBA48_WRITE_REG(chp, wdr_lba_hi,
! 1948: ((blkno >> 32) & 0xff00) | ((blkno >> 16) & 0xff));
! 1949: CHP_LBA48_WRITE_REG(chp, wdr_lba_mi,
! 1950: ((blkno >> 24) & 0xff00) | ((blkno >> 8) & 0xff));
! 1951: CHP_LBA48_WRITE_REG(chp, wdr_lba_lo,
! 1952: ((blkno >> 16) & 0xff00) | (blkno & 0xff));
! 1953: CHP_LBA48_WRITE_REG(chp, wdr_seccnt, count);
! 1954:
! 1955: /* Send command. */
! 1956: CHP_WRITE_REG(chp, wdr_command, command);
! 1957: }
! 1958:
! 1959: /*
! 1960: * Simplified version of wdccommand(). Unbusy/ready/drq must be
! 1961: * tested by the caller.
! 1962: */
! 1963: void
! 1964: wdccommandshort(chp, drive, command)
! 1965: struct channel_softc *chp;
! 1966: int drive;
! 1967: int command;
! 1968: {
! 1969:
! 1970: WDCDEBUG_PRINT(("wdccommandshort %s:%d:%d command 0x%x\n",
! 1971: chp->wdc->sc_dev.dv_xname, chp->channel, drive, command),
! 1972: DEBUG_FUNCS);
! 1973: WDC_LOG_ATA_CMDSHORT(chp, command);
! 1974:
! 1975: /* Select drive. */
! 1976: CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (drive << 4));
! 1977: CHP_WRITE_REG(chp, wdr_command, command);
! 1978: }
! 1979:
! 1980: /* Add a command to the queue and start controller. Must be called at splbio */
! 1981:
! 1982: void
! 1983: wdc_exec_xfer(chp, xfer)
! 1984: struct channel_softc *chp;
! 1985: struct wdc_xfer *xfer;
! 1986: {
! 1987: WDCDEBUG_PRINT(("wdc_exec_xfer %p flags 0x%x channel %d drive %d\n",
! 1988: xfer, xfer->c_flags, chp->channel, xfer->drive), DEBUG_XFERS);
! 1989:
! 1990: /* complete xfer setup */
! 1991: xfer->chp = chp;
! 1992:
! 1993: /*
! 1994: * If we are a polled command, and the list is not empty,
! 1995: * we are doing a dump. Drop the list to allow the polled command
! 1996: * to complete, we're going to reboot soon anyway.
! 1997: */
! 1998: if ((xfer->c_flags & C_POLL) != 0 &&
! 1999: !TAILQ_EMPTY(&chp->ch_queue->sc_xfer)) {
! 2000: TAILQ_INIT(&chp->ch_queue->sc_xfer);
! 2001: }
! 2002: /* insert at the end of command list */
! 2003: TAILQ_INSERT_TAIL(&chp->ch_queue->sc_xfer,xfer , c_xferchain);
! 2004: WDCDEBUG_PRINT(("wdcstart from wdc_exec_xfer, flags 0x%x\n",
! 2005: chp->ch_flags), DEBUG_XFERS);
! 2006: wdcstart(chp);
! 2007: }
! 2008:
! 2009: struct wdc_xfer *
! 2010: wdc_get_xfer(flags)
! 2011: int flags;
! 2012: {
! 2013: struct wdc_xfer *xfer;
! 2014: int s;
! 2015:
! 2016: s = splbio();
! 2017: xfer = pool_get(&wdc_xfer_pool,
! 2018: ((flags & WDC_NOSLEEP) != 0 ? PR_NOWAIT : PR_WAITOK));
! 2019: splx(s);
! 2020: if (xfer != NULL)
! 2021: memset(xfer, 0, sizeof(struct wdc_xfer));
! 2022: return xfer;
! 2023: }
! 2024:
! 2025: void
! 2026: wdc_free_xfer(chp, xfer)
! 2027: struct channel_softc *chp;
! 2028: struct wdc_xfer *xfer;
! 2029: {
! 2030: struct wdc_softc *wdc = chp->wdc;
! 2031: int s;
! 2032:
! 2033: if (wdc->cap & WDC_CAPABILITY_HWLOCK)
! 2034: (*wdc->free_hw)(chp);
! 2035: s = splbio();
! 2036: chp->ch_flags &= ~WDCF_ACTIVE;
! 2037: TAILQ_REMOVE(&chp->ch_queue->sc_xfer, xfer, c_xferchain);
! 2038: pool_put(&wdc_xfer_pool, xfer);
! 2039: splx(s);
! 2040: }
! 2041:
! 2042:
! 2043: /*
! 2044: * Kill off all pending xfers for a channel_softc.
! 2045: *
! 2046: * Must be called at splbio().
! 2047: */
! 2048: void
! 2049: wdc_kill_pending(chp)
! 2050: struct channel_softc *chp;
! 2051: {
! 2052: struct wdc_xfer *xfer;
! 2053:
! 2054: while ((xfer = TAILQ_FIRST(&chp->ch_queue->sc_xfer)) != NULL) {
! 2055: chp = xfer->chp;
! 2056: (*xfer->c_kill_xfer)(chp, xfer);
! 2057: }
! 2058: }
! 2059:
! 2060: void
! 2061: __wdcerror(chp, msg)
! 2062: struct channel_softc *chp;
! 2063: char *msg;
! 2064: {
! 2065: struct wdc_xfer *xfer = TAILQ_FIRST(&chp->ch_queue->sc_xfer);
! 2066: if (xfer == NULL)
! 2067: printf("%s:%d: %s\n", chp->wdc->sc_dev.dv_xname, chp->channel,
! 2068: msg);
! 2069: else
! 2070: printf("%s(%s:%d:%d): %s\n",
! 2071: chp->ch_drive[xfer->drive].drive_name,
! 2072: chp->wdc->sc_dev.dv_xname,
! 2073: chp->channel, xfer->drive, msg);
! 2074: }
! 2075:
! 2076: /*
! 2077: * the bit bucket
! 2078: */
! 2079: void
! 2080: wdcbit_bucket(chp, size)
! 2081: struct channel_softc *chp;
! 2082: int size;
! 2083: {
! 2084: CHP_READ_RAW_MULTI_2(chp, NULL, size);
! 2085: }
! 2086:
! 2087:
! 2088: #include <sys/ataio.h>
! 2089: #include <sys/file.h>
! 2090: #include <sys/buf.h>
! 2091:
! 2092: /*
! 2093: * Glue necessary to hook ATAIOCCOMMAND into physio
! 2094: */
! 2095:
! 2096: struct wdc_ioctl {
! 2097: LIST_ENTRY(wdc_ioctl) wi_list;
! 2098: struct buf wi_bp;
! 2099: struct uio wi_uio;
! 2100: struct iovec wi_iov;
! 2101: atareq_t wi_atareq;
! 2102: struct ata_drive_datas *wi_drvp;
! 2103: };
! 2104:
! 2105: struct wdc_ioctl *wdc_ioctl_find(struct buf *);
! 2106: void wdc_ioctl_free(struct wdc_ioctl *);
! 2107: struct wdc_ioctl *wdc_ioctl_get(void);
! 2108: void wdc_ioctl_strategy(struct buf *);
! 2109:
! 2110: LIST_HEAD(, wdc_ioctl) wi_head;
! 2111:
! 2112: /*
! 2113: * Allocate space for a ioctl queue structure. Mostly taken from
! 2114: * scsipi_ioctl.c
! 2115: */
! 2116: struct wdc_ioctl *
! 2117: wdc_ioctl_get()
! 2118: {
! 2119: struct wdc_ioctl *wi;
! 2120: int s;
! 2121:
! 2122: wi = malloc(sizeof(struct wdc_ioctl), M_TEMP, M_WAITOK);
! 2123: bzero(wi, sizeof (struct wdc_ioctl));
! 2124: s = splbio();
! 2125: LIST_INSERT_HEAD(&wi_head, wi, wi_list);
! 2126: splx(s);
! 2127: return (wi);
! 2128: }
! 2129:
! 2130: /*
! 2131: * Free an ioctl structure and remove it from our list
! 2132: */
! 2133:
! 2134: void
! 2135: wdc_ioctl_free(wi)
! 2136: struct wdc_ioctl *wi;
! 2137: {
! 2138: int s;
! 2139:
! 2140: s = splbio();
! 2141: LIST_REMOVE(wi, wi_list);
! 2142: splx(s);
! 2143: free(wi, M_TEMP);
! 2144: }
! 2145:
! 2146: /*
! 2147: * Find a wdc_ioctl structure based on the struct buf.
! 2148: */
! 2149:
! 2150: struct wdc_ioctl *
! 2151: wdc_ioctl_find(bp)
! 2152: struct buf *bp;
! 2153: {
! 2154: struct wdc_ioctl *wi;
! 2155: int s;
! 2156:
! 2157: s = splbio();
! 2158: LIST_FOREACH(wi, &wi_head, wi_list)
! 2159: if (bp == &wi->wi_bp)
! 2160: break;
! 2161: splx(s);
! 2162: return (wi);
! 2163: }
! 2164:
! 2165: /*
! 2166: * Ioctl pseudo strategy routine
! 2167: *
! 2168: * This is mostly stolen from scsipi_ioctl.c:scsistrategy(). What
! 2169: * happens here is:
! 2170: *
! 2171: * - wdioctl() queues a wdc_ioctl structure.
! 2172: *
! 2173: * - wdioctl() calls physio/wdc_ioctl_strategy based on whether or not
! 2174: * user space I/O is required. If physio() is called, physio() eventually
! 2175: * calls wdc_ioctl_strategy().
! 2176: *
! 2177: * - In either case, wdc_ioctl_strategy() calls wdc_exec_command()
! 2178: * to perform the actual command
! 2179: *
! 2180: * The reason for the use of the pseudo strategy routine is because
! 2181: * when doing I/O to/from user space, physio _really_ wants to be in
! 2182: * the loop. We could put the entire buffer into the ioctl request
! 2183: * structure, but that won't scale if we want to do things like download
! 2184: * microcode.
! 2185: */
! 2186:
! 2187: void
! 2188: wdc_ioctl_strategy(bp)
! 2189: struct buf *bp;
! 2190: {
! 2191: struct wdc_ioctl *wi;
! 2192: struct wdc_command wdc_c;
! 2193: int error = 0;
! 2194: int s;
! 2195:
! 2196: wi = wdc_ioctl_find(bp);
! 2197: if (wi == NULL) {
! 2198: printf("user_strat: No ioctl\n");
! 2199: error = EINVAL;
! 2200: goto bad;
! 2201: }
! 2202:
! 2203: bzero(&wdc_c, sizeof(wdc_c));
! 2204:
! 2205: /*
! 2206: * Abort if physio broke up the transfer
! 2207: */
! 2208:
! 2209: if ((u_long)bp->b_bcount != wi->wi_atareq.datalen) {
! 2210: printf("physio split wd ioctl request... cannot proceed\n");
! 2211: error = EIO;
! 2212: goto bad;
! 2213: }
! 2214:
! 2215: /*
! 2216: * Make sure a timeout was supplied in the ioctl request
! 2217: */
! 2218:
! 2219: if (wi->wi_atareq.timeout == 0) {
! 2220: error = EINVAL;
! 2221: goto bad;
! 2222: }
! 2223:
! 2224: if (wi->wi_atareq.flags & ATACMD_READ)
! 2225: wdc_c.flags |= AT_READ;
! 2226: else if (wi->wi_atareq.flags & ATACMD_WRITE)
! 2227: wdc_c.flags |= AT_WRITE;
! 2228:
! 2229: if (wi->wi_atareq.flags & ATACMD_READREG)
! 2230: wdc_c.flags |= AT_READREG;
! 2231:
! 2232: wdc_c.flags |= AT_WAIT;
! 2233:
! 2234: wdc_c.timeout = wi->wi_atareq.timeout;
! 2235: wdc_c.r_command = wi->wi_atareq.command;
! 2236: wdc_c.r_head = wi->wi_atareq.head & 0x0f;
! 2237: wdc_c.r_cyl = wi->wi_atareq.cylinder;
! 2238: wdc_c.r_sector = wi->wi_atareq.sec_num;
! 2239: wdc_c.r_count = wi->wi_atareq.sec_count;
! 2240: wdc_c.r_precomp = wi->wi_atareq.features;
! 2241: if (wi->wi_drvp->drive_flags & DRIVE_ATAPI) {
! 2242: wdc_c.r_st_bmask = 0;
! 2243: wdc_c.r_st_pmask = 0;
! 2244: if (wdc_c.r_command == WDCC_IDENTIFY)
! 2245: wdc_c.r_command = ATAPI_IDENTIFY_DEVICE;
! 2246: } else {
! 2247: wdc_c.r_st_bmask = WDCS_DRDY;
! 2248: wdc_c.r_st_pmask = WDCS_DRDY;
! 2249: }
! 2250: wdc_c.data = wi->wi_bp.b_data;
! 2251: wdc_c.bcount = wi->wi_bp.b_bcount;
! 2252:
! 2253: if (wdc_exec_command(wi->wi_drvp, &wdc_c) != WDC_COMPLETE) {
! 2254: wi->wi_atareq.retsts = ATACMD_ERROR;
! 2255: goto bad;
! 2256: }
! 2257:
! 2258: if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
! 2259: if (wdc_c.flags & AT_ERROR) {
! 2260: wi->wi_atareq.retsts = ATACMD_ERROR;
! 2261: wi->wi_atareq.error = wdc_c.r_error;
! 2262: } else if (wdc_c.flags & AT_DF)
! 2263: wi->wi_atareq.retsts = ATACMD_DF;
! 2264: else
! 2265: wi->wi_atareq.retsts = ATACMD_TIMEOUT;
! 2266: } else {
! 2267: wi->wi_atareq.retsts = ATACMD_OK;
! 2268: if (wi->wi_atareq.flags & ATACMD_READREG) {
! 2269: wi->wi_atareq.head = wdc_c.r_head ;
! 2270: wi->wi_atareq.cylinder = wdc_c.r_cyl;
! 2271: wi->wi_atareq.sec_num = wdc_c.r_sector;
! 2272: wi->wi_atareq.sec_count = wdc_c.r_count;
! 2273: wi->wi_atareq.features = wdc_c.r_precomp;
! 2274: wi->wi_atareq.error = wdc_c.r_error;
! 2275: }
! 2276: }
! 2277:
! 2278: bp->b_error = 0;
! 2279: s = splbio();
! 2280: biodone(bp);
! 2281: splx(s);
! 2282: return;
! 2283: bad:
! 2284: bp->b_flags |= B_ERROR;
! 2285: bp->b_error = error;
! 2286: s = splbio();
! 2287: biodone(bp);
! 2288: splx(s);
! 2289: }
! 2290:
! 2291: int
! 2292: wdc_ioctl(drvp, xfer, addr, flag, p)
! 2293: struct ata_drive_datas *drvp;
! 2294: u_long xfer;
! 2295: caddr_t addr;
! 2296: int flag;
! 2297: struct proc *p;
! 2298: {
! 2299: int error = 0;
! 2300:
! 2301: switch (xfer) {
! 2302: case ATAIOGETTRACE: {
! 2303: atagettrace_t *agt = (atagettrace_t *)addr;
! 2304: unsigned int size = 0;
! 2305: char *log_to_copy;
! 2306:
! 2307: size = agt->buf_size;
! 2308: if (size > 65536) {
! 2309: size = 65536;
! 2310: }
! 2311:
! 2312: log_to_copy = wdc_get_log(&size, &agt->bytes_left);
! 2313:
! 2314: if (log_to_copy != NULL) {
! 2315: error = copyout(log_to_copy, agt->buf, size);
! 2316: free(log_to_copy, M_TEMP);
! 2317: }
! 2318:
! 2319: agt->bytes_copied = size;
! 2320: break;
! 2321: }
! 2322:
! 2323: case ATAIOCCOMMAND:
! 2324: /*
! 2325: * Make sure this command is (relatively) safe first
! 2326: */
! 2327: if ((((atareq_t *) addr)->flags & ATACMD_READ) == 0 &&
! 2328: (flag & FWRITE) == 0) {
! 2329: error = EBADF;
! 2330: goto exit;
! 2331: }
! 2332: {
! 2333: struct wdc_ioctl *wi;
! 2334: atareq_t *atareq = (atareq_t *) addr;
! 2335:
! 2336: wi = wdc_ioctl_get();
! 2337: wi->wi_drvp = drvp;
! 2338: wi->wi_atareq = *atareq;
! 2339:
! 2340: if (atareq->datalen && atareq->flags &
! 2341: (ATACMD_READ | ATACMD_WRITE)) {
! 2342: wi->wi_iov.iov_base = atareq->databuf;
! 2343: wi->wi_iov.iov_len = atareq->datalen;
! 2344: wi->wi_uio.uio_iov = &wi->wi_iov;
! 2345: wi->wi_uio.uio_iovcnt = 1;
! 2346: wi->wi_uio.uio_resid = atareq->datalen;
! 2347: wi->wi_uio.uio_offset = 0;
! 2348: wi->wi_uio.uio_segflg = UIO_USERSPACE;
! 2349: wi->wi_uio.uio_rw =
! 2350: (atareq->flags & ATACMD_READ) ? B_READ : B_WRITE;
! 2351: wi->wi_uio.uio_procp = curproc;
! 2352: error = physio(wdc_ioctl_strategy, &wi->wi_bp, 0,
! 2353: (atareq->flags & ATACMD_READ) ? B_READ : B_WRITE,
! 2354: minphys, &wi->wi_uio);
! 2355: } else {
! 2356: /* No need to call physio if we don't have any
! 2357: user data */
! 2358: wi->wi_bp.b_flags = 0;
! 2359: wi->wi_bp.b_data = 0;
! 2360: wi->wi_bp.b_bcount = 0;
! 2361: wi->wi_bp.b_dev = 0;
! 2362: wi->wi_bp.b_proc = curproc;
! 2363: LIST_INIT(&wi->wi_bp.b_dep);
! 2364: wdc_ioctl_strategy(&wi->wi_bp);
! 2365: error = wi->wi_bp.b_error;
! 2366: }
! 2367: *atareq = wi->wi_atareq;
! 2368: wdc_ioctl_free(wi);
! 2369: goto exit;
! 2370: }
! 2371: default:
! 2372: error = ENOTTY;
! 2373: goto exit;
! 2374: }
! 2375:
! 2376: exit:
! 2377: return (error);
! 2378: }
CVSweb