Annotation of sys/dev/atapiscsi/atapiscsi.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: atapiscsi.c,v 1.78 2007/08/06 08:28:09 tom Exp $ */
! 2:
! 3: /*
! 4: * This code is derived from code with the copyright below.
! 5: */
! 6:
! 7: /*
! 8: * Copyright (c) 1996, 1998 Manuel Bouyer.
! 9: *
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: * 1. Redistributions of source code must retain the above copyright
! 14: * notice, this list of conditions and the following disclaimer.
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: * 3. All advertising materials mentioning features or use of this software
! 19: * must display the following acknowledgement:
! 20: * This product includes software developed by Manuel Bouyer.
! 21: * 4. Neither the name of the University nor the names of its contributors
! 22: * may be used to endorse or promote products derived from this software
! 23: * without specific prior written permission.
! 24: *
! 25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 35: * SUCH DAMAGE.
! 36: *
! 37: */
! 38:
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/systm.h>
! 42: #include <sys/kernel.h>
! 43: #include <sys/device.h>
! 44: #include <sys/buf.h>
! 45: #include <sys/dkstat.h>
! 46: #include <sys/disklabel.h>
! 47: #include <sys/dkstat.h>
! 48: #include <sys/malloc.h>
! 49: #include <sys/proc.h>
! 50: #include <sys/reboot.h>
! 51: #include <sys/file.h>
! 52: #include <sys/ioctl.h>
! 53: #include <sys/timeout.h>
! 54: #include <scsi/scsi_all.h>
! 55: #include <scsi/scsi_disk.h>
! 56: #include <scsi/scsi_tape.h>
! 57: #include <scsi/scsiconf.h>
! 58:
! 59: #include <machine/bus.h>
! 60: #include <machine/cpu.h>
! 61: #include <machine/intr.h>
! 62:
! 63: #include <dev/ata/atareg.h>
! 64: #include <dev/ata/atavar.h>
! 65: #include <dev/ic/wdcreg.h>
! 66: #include <dev/ic/wdcvar.h>
! 67: #include <dev/ic/wdcevent.h>
! 68:
! 69: /* drive states stored in ata_drive_datas */
! 70: enum atapi_drive_states {
! 71: ATAPI_RESET_BASE_STATE = 0,
! 72: ATAPI_DEVICE_RESET_WAIT_STATE = 1,
! 73: ATAPI_IDENTIFY_STATE = 2,
! 74: ATAPI_IDENTIFY_WAIT_STATE = 3,
! 75: ATAPI_PIOMODE_STATE = 4,
! 76: ATAPI_PIOMODE_WAIT_STATE = 5,
! 77: ATAPI_DMAMODE_STATE = 6,
! 78: ATAPI_DMAMODE_WAIT_STATE = 7,
! 79: ATAPI_READY_STATE = 8
! 80: };
! 81:
! 82: #define DEBUG_INTR 0x01
! 83: #define DEBUG_XFERS 0x02
! 84: #define DEBUG_STATUS 0x04
! 85: #define DEBUG_FUNCS 0x08
! 86: #define DEBUG_PROBE 0x10
! 87: #define DEBUG_DSC 0x20
! 88: #define DEBUG_POLL 0x40
! 89: #define DEBUG_ERRORS 0x80 /* Debug error handling code */
! 90:
! 91: #if defined(WDCDEBUG)
! 92: #ifndef WDCDEBUG_ATAPI_MASK
! 93: #define WDCDEBUG_ATAPI_MASK 0x00
! 94: #endif
! 95: int wdcdebug_atapi_mask = WDCDEBUG_ATAPI_MASK;
! 96: #define WDCDEBUG_PRINT(args, level) do { \
! 97: if ((wdcdebug_atapi_mask & (level)) != 0) \
! 98: printf args; \
! 99: } while (0)
! 100: #else
! 101: #define WDCDEBUG_PRINT(args, level)
! 102: #endif
! 103:
! 104: /* 10 ms, this is used only before sending a cmd. */
! 105: #define ATAPI_DELAY 10
! 106: #define ATAPI_RESET_DELAY 1000
! 107: #define ATAPI_RESET_WAIT 2000
! 108: #define ATAPI_CTRL_WAIT 4000
! 109:
! 110: /* When polling, let the exponential backoff max out at 1 second's interval. */
! 111: #define ATAPI_POLL_MAXTIC (hz)
! 112:
! 113: void wdc_atapi_start(struct channel_softc *,struct wdc_xfer *);
! 114:
! 115: void wdc_atapi_timer_handler(void *);
! 116:
! 117: void wdc_atapi_real_start(struct channel_softc *, struct wdc_xfer *,
! 118: int, struct atapi_return_args *);
! 119: void wdc_atapi_real_start_2(struct channel_softc *, struct wdc_xfer *,
! 120: int, struct atapi_return_args *);
! 121: void wdc_atapi_intr_command(struct channel_softc *, struct wdc_xfer *,
! 122: int, struct atapi_return_args *);
! 123: void wdc_atapi_intr_data(struct channel_softc *, struct wdc_xfer *,
! 124: int, struct atapi_return_args *);
! 125: void wdc_atapi_intr_complete(struct channel_softc *, struct wdc_xfer *,
! 126: int, struct atapi_return_args *);
! 127: void wdc_atapi_pio_intr(struct channel_softc *, struct wdc_xfer *,
! 128: int, struct atapi_return_args *);
! 129: void wdc_atapi_send_packet(struct channel_softc *, struct wdc_xfer *,
! 130: int, struct atapi_return_args *);
! 131: void wdc_atapi_ctrl(struct channel_softc *, struct wdc_xfer *,
! 132: int, struct atapi_return_args *);
! 133:
! 134: char *wdc_atapi_in_data_phase(struct wdc_xfer *, int, int);
! 135:
! 136: int wdc_atapi_intr(struct channel_softc *, struct wdc_xfer *, int);
! 137: void wdc_atapi_done(struct channel_softc *, struct wdc_xfer *,
! 138: int, struct atapi_return_args *);
! 139: void wdc_atapi_reset(struct channel_softc *, struct wdc_xfer *,
! 140: int, struct atapi_return_args *);
! 141: void wdc_atapi_reset_2(struct channel_softc *, struct wdc_xfer *,
! 142: int, struct atapi_return_args *);
! 143:
! 144: void wdc_atapi_tape_done(struct channel_softc *, struct wdc_xfer *,
! 145: int, struct atapi_return_args *);
! 146: #define MAX_SIZE MAXPHYS
! 147:
! 148: struct atapiscsi_softc;
! 149: struct atapiscsi_xfer;
! 150:
! 151: int atapiscsi_match(struct device *, void *, void *);
! 152: void atapiscsi_attach(struct device *, struct device *, void *);
! 153: int atapiscsi_detach(struct device *, int);
! 154: int atapi_to_scsi_sense(struct scsi_xfer *, u_int8_t);
! 155:
! 156: enum atapi_state { as_none, as_data, as_completed };
! 157:
! 158: struct atapiscsi_softc {
! 159: struct device sc_dev;
! 160: struct scsi_link sc_adapterlink;
! 161: struct channel_softc *chp;
! 162: enum atapi_state protocol_phase;
! 163:
! 164: int drive;
! 165: };
! 166:
! 167: void wdc_atapi_minphys(struct buf *bp);
! 168: int wdc_atapi_ioctl(struct scsi_link *,
! 169: u_long, caddr_t, int, struct proc *);
! 170: int wdc_atapi_send_cmd(struct scsi_xfer *sc_xfer);
! 171:
! 172: static struct scsi_adapter atapiscsi_switch =
! 173: {
! 174: wdc_atapi_send_cmd,
! 175: wdc_atapi_minphys,
! 176: NULL,
! 177: NULL,
! 178: wdc_atapi_ioctl
! 179: };
! 180:
! 181: static struct scsi_device atapiscsi_dev =
! 182: {
! 183: NULL,
! 184: NULL,
! 185: NULL,
! 186: NULL,
! 187: };
! 188:
! 189: /* Inital version shares bus_link structure so it can easily
! 190: be "attached to current" wdc driver */
! 191:
! 192: struct cfattach atapiscsi_ca = {
! 193: sizeof(struct atapiscsi_softc), atapiscsi_match, atapiscsi_attach,
! 194: atapiscsi_detach
! 195: };
! 196:
! 197: struct cfdriver atapiscsi_cd = {
! 198: NULL, "atapiscsi", DV_DULL
! 199: };
! 200:
! 201:
! 202: int
! 203: atapiscsi_match(parent, match, aux)
! 204: struct device *parent;
! 205: void *match, *aux;
! 206:
! 207: {
! 208: struct ata_atapi_attach *aa_link = aux;
! 209: struct cfdata *cf = match;
! 210:
! 211: if (aa_link == NULL)
! 212: return (0);
! 213:
! 214: if (aa_link->aa_type != T_ATAPI)
! 215: return (0);
! 216:
! 217: if (cf->cf_loc[0] != aa_link->aa_channel &&
! 218: cf->cf_loc[0] != -1)
! 219: return (0);
! 220:
! 221: return (1);
! 222: }
! 223:
! 224: void
! 225: atapiscsi_attach(parent, self, aux)
! 226: struct device *parent, *self;
! 227: void *aux;
! 228: {
! 229: struct atapiscsi_softc *as = (struct atapiscsi_softc *)self;
! 230: struct ata_atapi_attach *aa_link = aux;
! 231: struct scsibus_attach_args saa;
! 232: struct ata_drive_datas *drvp = aa_link->aa_drv_data;
! 233: struct channel_softc *chp = drvp->chnl_softc;
! 234: struct ataparams *id = &drvp->id;
! 235: struct device *child;
! 236:
! 237: printf("\n");
! 238:
! 239: /* Initialize shared data. */
! 240: scsi_init();
! 241:
! 242: #ifdef WDCDEBUG
! 243: if (chp->wdc->sc_dev.dv_cfdata->cf_flags & WDC_OPTION_PROBE_VERBOSE)
! 244: wdcdebug_atapi_mask |= DEBUG_PROBE;
! 245: #endif
! 246:
! 247: as->chp = chp;
! 248: as->drive = drvp->drive;
! 249: as->sc_adapterlink.adapter_softc = as;
! 250: as->sc_adapterlink.adapter_target = 7;
! 251: as->sc_adapterlink.adapter_buswidth = 2;
! 252: as->sc_adapterlink.adapter = &atapiscsi_switch;
! 253: as->sc_adapterlink.device = &atapiscsi_dev;
! 254: as->sc_adapterlink.luns = 1;
! 255: as->sc_adapterlink.openings = 1;
! 256: as->sc_adapterlink.flags = SDEV_ATAPI;
! 257:
! 258: strlcpy(drvp->drive_name, as->sc_dev.dv_xname,
! 259: sizeof(drvp->drive_name));
! 260: drvp->cf_flags = as->sc_dev.dv_cfdata->cf_flags;
! 261:
! 262: wdc_probe_caps(drvp, id);
! 263:
! 264: WDCDEBUG_PRINT(
! 265: ("general config %04x capabilities %04x ",
! 266: id->atap_config, id->atap_capabilities1),
! 267: DEBUG_PROBE);
! 268:
! 269: if ((NERRS_MAX - 2) > 0)
! 270: drvp->n_dmaerrs = NERRS_MAX - 2;
! 271: else
! 272: drvp->n_dmaerrs = 0;
! 273: drvp->drive_flags |= DRIVE_DEVICE_RESET;
! 274:
! 275: /* Tape drives do funny DSC stuff */
! 276: if (ATAPI_CFG_TYPE(id->atap_config) ==
! 277: ATAPI_CFG_TYPE_SEQUENTIAL)
! 278: drvp->atapi_cap |= ACAP_DSC;
! 279:
! 280: if ((id->atap_config & ATAPI_CFG_CMD_MASK) ==
! 281: ATAPI_CFG_CMD_16)
! 282: drvp->atapi_cap |= ACAP_LEN;
! 283:
! 284: drvp->atapi_cap |=
! 285: (id->atap_config & ATAPI_CFG_DRQ_MASK);
! 286:
! 287: WDCDEBUG_PRINT(("driver caps %04x\n", drvp->atapi_cap),
! 288: DEBUG_PROBE);
! 289:
! 290: bzero(&saa, sizeof(saa));
! 291: saa.saa_sc_link = &as->sc_adapterlink;
! 292:
! 293: child = config_found((struct device *)as, &saa, scsiprint);
! 294:
! 295: if (child != NULL) {
! 296: struct scsibus_softc *scsi = (struct scsibus_softc *)child;
! 297: struct scsi_link *link = scsi->sc_link[0][0];
! 298:
! 299: if (link) {
! 300: strlcpy(drvp->drive_name,
! 301: ((struct device *)(link->device_softc))->dv_xname,
! 302: sizeof(drvp->drive_name));
! 303:
! 304: wdc_print_caps(drvp);
! 305: }
! 306: }
! 307:
! 308: #ifdef WDCDEBUG
! 309: if (chp->wdc->sc_dev.dv_cfdata->cf_flags & WDC_OPTION_PROBE_VERBOSE)
! 310: wdcdebug_atapi_mask &= ~DEBUG_PROBE;
! 311: #endif
! 312: }
! 313:
! 314: int
! 315: atapiscsi_detach(dev, flags)
! 316: struct device *dev;
! 317: int flags;
! 318: {
! 319: return (config_detach_children(dev, flags));
! 320: }
! 321:
! 322: int
! 323: wdc_atapi_send_cmd(sc_xfer)
! 324: struct scsi_xfer *sc_xfer;
! 325: {
! 326: struct atapiscsi_softc *as = sc_xfer->sc_link->adapter_softc;
! 327: struct channel_softc *chp = as->chp;
! 328: struct ata_drive_datas *drvp = &chp->ch_drive[as->drive];
! 329: struct wdc_xfer *xfer;
! 330: int s, ret;
! 331: int idx;
! 332:
! 333: WDCDEBUG_PRINT(("wdc_atapi_send_cmd %s:%d:%d start\n",
! 334: chp->wdc->sc_dev.dv_xname, chp->channel, as->drive), DEBUG_XFERS);
! 335:
! 336: if (sc_xfer->sc_link->target != 0) {
! 337: sc_xfer->error = XS_DRIVER_STUFFUP;
! 338: return (COMPLETE);
! 339: }
! 340:
! 341: xfer = wdc_get_xfer(sc_xfer->flags & SCSI_NOSLEEP
! 342: ? WDC_NOSLEEP : WDC_CANSLEEP);
! 343: if (xfer == NULL) {
! 344: return (TRY_AGAIN_LATER);
! 345: }
! 346: if (sc_xfer->flags & SCSI_POLL)
! 347: xfer->c_flags |= C_POLL;
! 348: xfer->drive = as->drive;
! 349: xfer->c_flags |= C_ATAPI;
! 350: xfer->cmd = sc_xfer;
! 351: xfer->databuf = sc_xfer->data;
! 352: xfer->c_bcount = sc_xfer->datalen;
! 353: xfer->c_start = wdc_atapi_start;
! 354: xfer->c_intr = wdc_atapi_intr;
! 355:
! 356: timeout_set(&xfer->atapi_poll_to, wdc_atapi_timer_handler, chp);
! 357:
! 358: WDCDEBUG_PRINT(("wdc_atapi_send_cmd %s:%d:%d ",
! 359: chp->wdc->sc_dev.dv_xname, chp->channel, as->drive),
! 360: DEBUG_XFERS | DEBUG_ERRORS);
! 361:
! 362: for (idx = 0; idx < sc_xfer->cmdlen; idx++) {
! 363: WDCDEBUG_PRINT((" %02x",
! 364: ((unsigned char *)sc_xfer->cmd)[idx]),
! 365: DEBUG_XFERS | DEBUG_ERRORS);
! 366: }
! 367: WDCDEBUG_PRINT(("\n"), DEBUG_XFERS | DEBUG_ERRORS);
! 368:
! 369: s = splbio();
! 370:
! 371: if (drvp->atapi_cap & ACAP_DSC) {
! 372: WDCDEBUG_PRINT(("about to send cmd 0x%x ",
! 373: sc_xfer->cmd->opcode), DEBUG_DSC);
! 374: switch (sc_xfer->cmd->opcode) {
! 375: case READ:
! 376: case WRITE:
! 377: xfer->c_flags |= C_MEDIA_ACCESS;
! 378:
! 379: /* If we are not in buffer availability mode,
! 380: we limit the first request to 0 bytes, which
! 381: gets us into buffer availability mode without
! 382: holding the bus. */
! 383: if (!(drvp->drive_flags & DRIVE_DSCBA)) {
! 384: xfer->c_bcount = 0;
! 385: xfer->transfer_len =
! 386: _3btol(((struct scsi_rw_tape *)
! 387: sc_xfer->cmd)->len);
! 388: _lto3b(0,
! 389: ((struct scsi_rw_tape *)
! 390: sc_xfer->cmd)->len);
! 391: xfer->c_done = wdc_atapi_tape_done;
! 392: WDCDEBUG_PRINT(
! 393: ("R/W in completion mode, do 0 blocks\n"),
! 394: DEBUG_DSC);
! 395: } else
! 396: WDCDEBUG_PRINT(("R/W %d blocks %d bytes\n",
! 397: _3btol(((struct scsi_rw_tape *)
! 398: sc_xfer->cmd)->len),
! 399: sc_xfer->datalen),
! 400: DEBUG_DSC);
! 401:
! 402: /* DSC will change to buffer availability mode.
! 403: We reflect this in wdc_atapi_intr. */
! 404: break;
! 405:
! 406: case ERASE: /* Media access commands */
! 407: case LOAD:
! 408: case REWIND:
! 409: case SPACE:
! 410: case WRITE_FILEMARKS:
! 411: #if 0
! 412: case LOCATE:
! 413: case READ_POSITION:
! 414: #endif
! 415:
! 416: xfer->c_flags |= C_MEDIA_ACCESS;
! 417: break;
! 418:
! 419: default:
! 420: WDCDEBUG_PRINT(("no media access\n"), DEBUG_DSC);
! 421: }
! 422: }
! 423:
! 424: wdc_exec_xfer(chp, xfer);
! 425: #ifdef DIAGNOSTIC
! 426: if ((xfer->c_flags & C_POLL) != 0 &&
! 427: (sc_xfer->flags & ITSDONE) == 0)
! 428: panic("wdc_atapi_send_cmd: polled command not done");
! 429: #endif
! 430: ret = (sc_xfer->flags & ITSDONE) ? COMPLETE : SUCCESSFULLY_QUEUED;
! 431: splx(s);
! 432: return (ret);
! 433: }
! 434:
! 435: void
! 436: wdc_atapi_minphys (struct buf *bp)
! 437: {
! 438: if(bp->b_bcount > MAX_SIZE)
! 439: bp->b_bcount = MAX_SIZE;
! 440: minphys(bp);
! 441: }
! 442:
! 443: int
! 444: wdc_atapi_ioctl (sc_link, cmd, addr, flag, p)
! 445: struct scsi_link *sc_link;
! 446: u_long cmd;
! 447: caddr_t addr;
! 448: int flag;
! 449: struct proc *p;
! 450: {
! 451: struct atapiscsi_softc *as = sc_link->adapter_softc;
! 452: struct channel_softc *chp = as->chp;
! 453: struct ata_drive_datas *drvp = &chp->ch_drive[as->drive];
! 454:
! 455: if (sc_link->target != 0)
! 456: return ENOTTY;
! 457:
! 458: return (wdc_ioctl(drvp, cmd, addr, flag, p));
! 459: }
! 460:
! 461:
! 462: /*
! 463: * Returns 1 if we experienced an ATA-level abort command
! 464: * (ABRT bit set but no additional sense)
! 465: * 0 if normal command processing
! 466: */
! 467: int
! 468: atapi_to_scsi_sense(xfer, flags)
! 469: struct scsi_xfer *xfer;
! 470: u_int8_t flags;
! 471: {
! 472: struct scsi_sense_data *sense = &xfer->sense;
! 473: int ret = 0;
! 474:
! 475: xfer->error = XS_SHORTSENSE;
! 476:
! 477: sense->error_code = SSD_ERRCODE_VALID | 0x70;
! 478: sense->flags = (flags >> 4);
! 479:
! 480: WDCDEBUG_PRINT(("Atapi error: %d ", (flags >> 4)), DEBUG_ERRORS);
! 481:
! 482: if ((flags & 4) && (sense->flags == 0)) {
! 483: sense->flags = SKEY_ABORTED_COMMAND;
! 484: WDCDEBUG_PRINT(("ABRT "), DEBUG_ERRORS);
! 485: ret = 1;
! 486: }
! 487:
! 488: if (flags & 0x1) {
! 489: sense->flags |= SSD_ILI;
! 490: WDCDEBUG_PRINT(("ILI "), DEBUG_ERRORS);
! 491: }
! 492:
! 493: if (flags & 0x2) {
! 494: sense->flags |= SSD_EOM;
! 495: WDCDEBUG_PRINT(("EOM "), DEBUG_ERRORS);
! 496: }
! 497:
! 498: /* Media change requested */
! 499: /* Let's ignore these in version 1 */
! 500: if (flags & 0x8) {
! 501: WDCDEBUG_PRINT(("MCR "), DEBUG_ERRORS);
! 502: if (sense->flags == 0)
! 503: xfer->error = XS_NOERROR;
! 504: }
! 505:
! 506: WDCDEBUG_PRINT(("\n"), DEBUG_ERRORS);
! 507: return (ret);
! 508: }
! 509:
! 510: int wdc_atapi_drive_selected(struct channel_softc *, int);
! 511:
! 512: int
! 513: wdc_atapi_drive_selected(chp, drive)
! 514: struct channel_softc *chp;
! 515: int drive;
! 516: {
! 517: u_int8_t reg = CHP_READ_REG(chp, wdr_sdh);
! 518:
! 519: WDC_LOG_REG(chp, wdr_sdh, reg);
! 520:
! 521: return ((reg & 0x10) == (drive << 4));
! 522: }
! 523:
! 524: enum atapi_context {
! 525: ctxt_process = 0,
! 526: ctxt_timer = 1,
! 527: ctxt_interrupt = 2
! 528: };
! 529:
! 530: void wdc_atapi_the_machine(struct channel_softc *, struct wdc_xfer *,
! 531: enum atapi_context);
! 532:
! 533: void wdc_atapi_the_poll_machine(struct channel_softc *, struct wdc_xfer *);
! 534:
! 535: void
! 536: wdc_atapi_start(chp, xfer)
! 537: struct channel_softc *chp;
! 538: struct wdc_xfer *xfer;
! 539: {
! 540: xfer->next = wdc_atapi_real_start;
! 541:
! 542: wdc_atapi_the_machine(chp, xfer, ctxt_process);
! 543: }
! 544:
! 545:
! 546: void
! 547: wdc_atapi_timer_handler(arg)
! 548: void *arg;
! 549: {
! 550: struct channel_softc *chp = arg;
! 551: struct wdc_xfer *xfer;
! 552: int s;
! 553:
! 554: s = splbio();
! 555: xfer = TAILQ_FIRST(&chp->ch_queue->sc_xfer);
! 556: if (xfer == NULL ||
! 557: !timeout_triggered(&xfer->atapi_poll_to)) {
! 558: splx(s);
! 559: return;
! 560: }
! 561: xfer->c_flags &= ~C_POLL_MACHINE;
! 562: timeout_del(&xfer->atapi_poll_to);
! 563: chp->ch_flags &= ~WDCF_IRQ_WAIT;
! 564: wdc_atapi_the_machine(chp, xfer, ctxt_timer);
! 565: splx(s);
! 566: }
! 567:
! 568:
! 569: int
! 570: wdc_atapi_intr(chp, xfer, irq)
! 571: struct channel_softc *chp;
! 572: struct wdc_xfer *xfer;
! 573: int irq;
! 574: {
! 575: timeout_del(&chp->ch_timo);
! 576:
! 577: /* XXX we should consider an alternate signaling regime here */
! 578: if (xfer->c_flags & C_TIMEOU) {
! 579: xfer->c_flags &= ~C_TIMEOU;
! 580: wdc_atapi_the_machine(chp, xfer, ctxt_timer);
! 581: return (0);
! 582: }
! 583:
! 584: wdc_atapi_the_machine(chp, xfer, ctxt_interrupt);
! 585:
! 586: return (-1);
! 587: }
! 588:
! 589: struct atapi_return_args {
! 590: int timeout;
! 591: int delay;
! 592: int expect_irq;
! 593: };
! 594:
! 595: #define ARGS_INIT {-1, 0, 0}
! 596:
! 597: void
! 598: wdc_atapi_the_poll_machine(chp, xfer)
! 599: struct channel_softc *chp;
! 600: struct wdc_xfer *xfer;
! 601: {
! 602: int idx = 0;
! 603: int current_timeout = 10;
! 604:
! 605:
! 606: while (1) {
! 607: struct atapi_return_args retargs = ARGS_INIT;
! 608: idx++;
! 609:
! 610: (xfer->next)(chp, xfer, (current_timeout * 1000 <= idx),
! 611: &retargs);
! 612:
! 613: if (xfer->next == NULL) {
! 614: wdc_free_xfer(chp, xfer);
! 615: wdcstart(chp);
! 616: return;
! 617: }
! 618:
! 619: if (retargs.timeout != -1) {
! 620: current_timeout = retargs.timeout;
! 621: idx = 0;
! 622: }
! 623:
! 624: if (retargs.delay != 0) {
! 625: delay (1000 * retargs.delay);
! 626: idx += 1000 * retargs.delay;
! 627: }
! 628:
! 629: DELAY(1);
! 630: }
! 631: }
! 632:
! 633:
! 634: void
! 635: wdc_atapi_the_machine(chp, xfer, ctxt)
! 636: struct channel_softc *chp;
! 637: struct wdc_xfer *xfer;
! 638: enum atapi_context ctxt;
! 639: {
! 640: int idx = 0;
! 641: extern int ticks;
! 642: int timeout_delay = hz / 10;
! 643:
! 644: if (xfer->c_flags & C_POLL) {
! 645: wdc_disable_intr(chp);
! 646:
! 647: if (ctxt != ctxt_process) {
! 648: if (ctxt == ctxt_interrupt)
! 649: xfer->endticks = 1;
! 650:
! 651: return;
! 652: }
! 653:
! 654: wdc_atapi_the_poll_machine(chp, xfer);
! 655: return;
! 656: }
! 657:
! 658: /* Don't go through more than 50 state machine steps
! 659: before yielding. This tries to limit the amount of time
! 660: spent at high SPL */
! 661: for (idx = 0; idx < 50; idx++) {
! 662: struct atapi_return_args retargs = ARGS_INIT;
! 663:
! 664: (xfer->next)(chp, xfer,
! 665: xfer->endticks && (ticks - xfer->endticks >= 0),
! 666: &retargs);
! 667:
! 668: if (retargs.timeout != -1)
! 669: /*
! 670: * Add 1 tick to compensate for the fact that we
! 671: * can be just microseconds before the tick changes.
! 672: */
! 673: xfer->endticks =
! 674: max((retargs.timeout * hz) / 1000, 1) + 1 + ticks;
! 675:
! 676: if (xfer->next == NULL) {
! 677: if (xfer->c_flags & C_POLL_MACHINE)
! 678: timeout_del(&xfer->atapi_poll_to);
! 679:
! 680: wdc_free_xfer(chp, xfer);
! 681: wdcstart(chp);
! 682:
! 683: return;
! 684: }
! 685:
! 686: if (retargs.expect_irq) {
! 687: chp->ch_flags |= WDCF_IRQ_WAIT;
! 688: timeout_add(&chp->ch_timo, xfer->endticks - ticks);
! 689: return;
! 690: }
! 691:
! 692: if (retargs.delay != 0) {
! 693: timeout_delay = max(retargs.delay * hz / 1000, 1);
! 694: break;
! 695: }
! 696:
! 697: DELAY(1);
! 698: }
! 699:
! 700: timeout_add(&xfer->atapi_poll_to, timeout_delay);
! 701: xfer->c_flags |= C_POLL_MACHINE;
! 702:
! 703: return;
! 704: }
! 705:
! 706:
! 707: void wdc_atapi_update_status(struct channel_softc *);
! 708:
! 709: void
! 710: wdc_atapi_update_status(chp)
! 711: struct channel_softc *chp;
! 712: {
! 713: chp->ch_status = CHP_READ_REG(chp, wdr_status);
! 714:
! 715: WDC_LOG_STATUS(chp, chp->ch_status);
! 716:
! 717: if (chp->ch_status == 0xff && (chp->ch_flags & WDCF_ONESLAVE)) {
! 718: wdc_set_drive(chp, 1);
! 719:
! 720: chp->ch_status = CHP_READ_REG(chp, wdr_status);
! 721: WDC_LOG_STATUS(chp, chp->ch_status);
! 722: }
! 723:
! 724: if ((chp->ch_status & (WDCS_BSY | WDCS_ERR)) == WDCS_ERR) {
! 725: chp->ch_error = CHP_READ_REG(chp, wdr_error);
! 726: WDC_LOG_ERROR(chp, chp->ch_error);
! 727: }
! 728: }
! 729:
! 730: void
! 731: wdc_atapi_real_start(chp, xfer, timeout, ret)
! 732: struct channel_softc *chp;
! 733: struct wdc_xfer *xfer;
! 734: int timeout;
! 735: struct atapi_return_args *ret;
! 736: {
! 737: #ifdef WDCDEBUG
! 738: struct scsi_xfer *sc_xfer = xfer->cmd;
! 739: #endif
! 740: struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
! 741:
! 742: /*
! 743: * Only set the DMA flag if the transfer is reasonably large.
! 744: * At least one older drive failed to complete a 4 byte DMA transfer.
! 745: */
! 746:
! 747: /* Turn off DMA flag on REQUEST SENSE */
! 748:
! 749: if (!(xfer->c_flags & (C_POLL | C_SENSE | C_MEDIA_ACCESS)) &&
! 750: (drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) &&
! 751: (xfer->c_bcount > 100))
! 752: xfer->c_flags |= C_DMA;
! 753: else
! 754: xfer->c_flags &= ~C_DMA;
! 755:
! 756:
! 757: wdc_set_drive(chp, xfer->drive);
! 758:
! 759: DELAY(1);
! 760:
! 761: xfer->next = wdc_atapi_real_start_2;
! 762: ret->timeout = ATAPI_DELAY;
! 763:
! 764: WDCDEBUG_PRINT(("wdc_atapi_start %s:%d:%d, scsi flags 0x%x, "
! 765: "ATA flags 0x%x\n",
! 766: chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive,
! 767: sc_xfer->flags, xfer->c_flags), DEBUG_XFERS);
! 768:
! 769:
! 770: return;
! 771: }
! 772:
! 773:
! 774: void
! 775: wdc_atapi_real_start_2(chp, xfer, timeout, ret)
! 776: struct channel_softc *chp;
! 777: struct wdc_xfer *xfer;
! 778: int timeout;
! 779: struct atapi_return_args *ret;
! 780: {
! 781: struct scsi_xfer *sc_xfer = xfer->cmd;
! 782: struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
! 783:
! 784: if (timeout) {
! 785: printf("wdc_atapi_start: not ready, st = %02x\n",
! 786: chp->ch_status);
! 787:
! 788: sc_xfer->error = XS_TIMEOUT;
! 789: xfer->next = wdc_atapi_reset;
! 790: return;
! 791: } else {
! 792: wdc_atapi_update_status(chp);
! 793:
! 794: if (chp->ch_status & (WDCS_BSY | WDCS_DRQ))
! 795: return;
! 796: }
! 797:
! 798: /* Do control operations specially. */
! 799: if (drvp->state < ATAPI_READY_STATE) {
! 800: xfer->next = wdc_atapi_ctrl;
! 801: return;
! 802: }
! 803:
! 804: xfer->next = wdc_atapi_send_packet;
! 805: return;
! 806: }
! 807:
! 808:
! 809: void
! 810: wdc_atapi_send_packet(chp, xfer, timeout, ret)
! 811: struct channel_softc *chp;
! 812: struct wdc_xfer *xfer;
! 813: int timeout;
! 814: struct atapi_return_args *ret;
! 815: {
! 816: struct scsi_xfer *sc_xfer = xfer->cmd;
! 817: struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
! 818:
! 819: /*
! 820: * Even with WDCS_ERR, the device should accept a command packet
! 821: * Limit length to what can be stuffed into the cylinder register
! 822: * (16 bits). Some CD-ROMs seem to interpret '0' as 65536,
! 823: * but not all devices do that and it's not obvious from the
! 824: * ATAPI spec that this behaviour should be expected. If more
! 825: * data is necessary, multiple data transfer phases will be done.
! 826: */
! 827:
! 828: wdccommand(chp, xfer->drive, ATAPI_PKT_CMD,
! 829: xfer->c_bcount <= 0xfffe ? xfer->c_bcount : 0xfffe,
! 830: 0, 0, 0,
! 831: (xfer->c_flags & C_DMA) ? ATAPI_PKT_CMD_FTRE_DMA : 0);
! 832:
! 833: if (xfer->c_flags & C_DMA)
! 834: drvp->n_xfers++;
! 835:
! 836: DELAY(1);
! 837:
! 838: xfer->next = wdc_atapi_intr_command;
! 839: ret->timeout = sc_xfer->timeout;
! 840:
! 841: if ((drvp->atapi_cap & ATAPI_CFG_DRQ_MASK) == ATAPI_CFG_IRQ_DRQ) {
! 842: /* We expect an IRQ to tell us of the next state */
! 843: ret->expect_irq = 1;
! 844: }
! 845:
! 846: WDCDEBUG_PRINT(("wdc_atapi_send_packet %s:%d:%d command sent\n",
! 847: chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive
! 848: ), DEBUG_XFERS);
! 849: return;
! 850: }
! 851:
! 852: void
! 853: wdc_atapi_intr_command(chp, xfer, timeout, ret)
! 854: struct channel_softc *chp;
! 855: struct wdc_xfer *xfer;
! 856: int timeout;
! 857: struct atapi_return_args *ret;
! 858: {
! 859: struct scsi_xfer *sc_xfer = xfer->cmd;
! 860: struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
! 861: struct atapiscsi_softc *as = sc_xfer->sc_link->adapter_softc;
! 862: int i;
! 863: u_int8_t cmd[16];
! 864: struct scsi_sense *cmd_reqsense;
! 865: int cmdlen = (drvp->atapi_cap & ACAP_LEN) ? 16 : 12;
! 866: int dma_flags = ((sc_xfer->flags & SCSI_DATA_IN) ||
! 867: (xfer->c_flags & C_SENSE)) ? WDC_DMA_READ : 0;
! 868:
! 869: wdc_atapi_update_status(chp);
! 870:
! 871: if ((chp->ch_status & WDCS_BSY) || !(chp->ch_status & WDCS_DRQ)) {
! 872: if (timeout)
! 873: goto timeout;
! 874:
! 875: return;
! 876: }
! 877:
! 878: if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
! 879: chp->wdc->irqack(chp);
! 880:
! 881: bzero(cmd, sizeof(cmd));
! 882:
! 883: if (xfer->c_flags & C_SENSE) {
! 884: cmd_reqsense = (struct scsi_sense *)&cmd[0];
! 885: cmd_reqsense->opcode = REQUEST_SENSE;
! 886: cmd_reqsense->length = xfer->c_bcount;
! 887: } else
! 888: bcopy(sc_xfer->cmd, cmd, sc_xfer->cmdlen);
! 889:
! 890: WDC_LOG_ATAPI_CMD(chp, xfer->drive, xfer->c_flags,
! 891: cmdlen, cmd);
! 892:
! 893: for (i = 0; i < 12; i++)
! 894: WDCDEBUG_PRINT(("%02x ", cmd[i]), DEBUG_INTR);
! 895: WDCDEBUG_PRINT((": PHASE_CMDOUT\n"), DEBUG_INTR);
! 896:
! 897: /* Init the DMA channel if necessary */
! 898: if (xfer->c_flags & C_DMA) {
! 899: if ((*chp->wdc->dma_init)(chp->wdc->dma_arg,
! 900: chp->channel, xfer->drive, xfer->databuf,
! 901: xfer->c_bcount, dma_flags) != 0) {
! 902: sc_xfer->error = XS_DRIVER_STUFFUP;
! 903:
! 904: xfer->next = wdc_atapi_reset;
! 905: return;
! 906: }
! 907: }
! 908:
! 909: wdc_output_bytes(drvp, cmd, cmdlen);
! 910:
! 911: /* Start the DMA channel if necessary */
! 912: if (xfer->c_flags & C_DMA) {
! 913: (*chp->wdc->dma_start)(chp->wdc->dma_arg,
! 914: chp->channel, xfer->drive);
! 915: xfer->next = wdc_atapi_intr_complete;
! 916: } else {
! 917: if (xfer->c_bcount == 0)
! 918: as->protocol_phase = as_completed;
! 919: else
! 920: as->protocol_phase = as_data;
! 921:
! 922: xfer->next = wdc_atapi_pio_intr;
! 923: }
! 924:
! 925: ret->expect_irq = 1;
! 926:
! 927: /* If we read/write to a tape we will get into buffer
! 928: availability mode. */
! 929: if (drvp->atapi_cap & ACAP_DSC) {
! 930: if ((sc_xfer->cmd->opcode == READ ||
! 931: sc_xfer->cmd->opcode == WRITE)) {
! 932: drvp->drive_flags |= DRIVE_DSCBA;
! 933: WDCDEBUG_PRINT(("set DSCBA\n"), DEBUG_DSC);
! 934: } else if ((xfer->c_flags & C_MEDIA_ACCESS) &&
! 935: (drvp->drive_flags & DRIVE_DSCBA)) {
! 936: /* Clause 3.2.4 of QIC-157 D.
! 937:
! 938: Any media access command other than read or
! 939: write will switch DSC back to completion
! 940: mode */
! 941: drvp->drive_flags &= ~DRIVE_DSCBA;
! 942: WDCDEBUG_PRINT(("clear DCSBA\n"), DEBUG_DSC);
! 943: }
! 944: }
! 945:
! 946: return;
! 947:
! 948: timeout:
! 949: printf ("%s:%d:%d: device timeout waiting to send SCSI packet\n",
! 950: chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive);
! 951:
! 952: sc_xfer->error = XS_TIMEOUT;
! 953: xfer->next = wdc_atapi_reset;
! 954: return;
! 955: }
! 956:
! 957:
! 958: char *
! 959: wdc_atapi_in_data_phase(xfer, len, ire)
! 960: struct wdc_xfer *xfer;
! 961: int len, ire;
! 962: {
! 963: struct scsi_xfer *sc_xfer = xfer->cmd;
! 964: struct atapiscsi_softc *as = sc_xfer->sc_link->adapter_softc;
! 965: char *message;
! 966:
! 967: if (as->protocol_phase != as_data) {
! 968: message = "unexpected data phase";
! 969: goto unexpected_state;
! 970: }
! 971:
! 972: if (ire & WDCI_CMD) {
! 973: message = "unexpectedly in command phase";
! 974: goto unexpected_state;
! 975: }
! 976:
! 977: if (!(xfer->c_flags & C_SENSE)) {
! 978: if (!(sc_xfer->flags & (SCSI_DATA_IN | SCSI_DATA_OUT))) {
! 979: message = "data phase where none expected";
! 980: goto unexpected_state;
! 981: }
! 982:
! 983: /* Make sure polarities match */
! 984: if (((ire & WDCI_IN) == WDCI_IN) ==
! 985: ((sc_xfer->flags & SCSI_DATA_OUT) == SCSI_DATA_OUT)) {
! 986: message = "data transfer direction disagreement";
! 987: goto unexpected_state;
! 988: }
! 989: } else {
! 990: if (!(ire & WDCI_IN)) {
! 991: message = "data transfer direction disagreement during sense";
! 992: goto unexpected_state;
! 993: }
! 994: }
! 995:
! 996: if (len == 0) {
! 997: message = "zero length transfer requested in data phase";
! 998: goto unexpected_state;
! 999: }
! 1000:
! 1001:
! 1002: return (0);
! 1003:
! 1004: unexpected_state:
! 1005:
! 1006: return (message);
! 1007: }
! 1008:
! 1009: void
! 1010: wdc_atapi_intr_data(chp, xfer, timeout, ret)
! 1011: struct channel_softc *chp;
! 1012: struct wdc_xfer *xfer;
! 1013: int timeout;
! 1014: struct atapi_return_args *ret;
! 1015: {
! 1016: struct scsi_xfer *sc_xfer = xfer->cmd;
! 1017: struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
! 1018: int len, ire;
! 1019: char *message;
! 1020: int tohost;
! 1021:
! 1022: len = (CHP_READ_REG(chp, wdr_cyl_hi) << 8) |
! 1023: CHP_READ_REG(chp, wdr_cyl_lo);
! 1024: WDC_LOG_REG(chp, wdr_cyl_lo, len);
! 1025:
! 1026: ire = CHP_READ_REG(chp, wdr_ireason);
! 1027: WDC_LOG_REG(chp, wdr_ireason, ire);
! 1028:
! 1029: if ((message = wdc_atapi_in_data_phase(xfer, len, ire))) {
! 1030: /* The drive has dropped BSY before setting up the
! 1031: registers correctly for DATA phase. This drive is
! 1032: not compliant with ATA/ATAPI-4.
! 1033:
! 1034: Give the drive 100ms to get its house in order
! 1035: before we try again. */
! 1036: WDCDEBUG_PRINT(("wdc_atapi_intr: %s\n", message),
! 1037: DEBUG_ERRORS);
! 1038:
! 1039: if (!timeout) {
! 1040: ret->delay = 100;
! 1041: return;
! 1042: }
! 1043: }
! 1044:
! 1045: tohost = ((sc_xfer->flags & SCSI_DATA_IN) != 0 ||
! 1046: (xfer->c_flags & C_SENSE) != 0);
! 1047:
! 1048: if (xfer->c_bcount >= len) {
! 1049: WDCDEBUG_PRINT(("wdc_atapi_intr: c_bcount %d len %d "
! 1050: "st 0x%b err 0x%x "
! 1051: "ire 0x%x\n", xfer->c_bcount,
! 1052: len, chp->ch_status, WDCS_BITS, chp->ch_error, ire),
! 1053: DEBUG_INTR);
! 1054:
! 1055: /* Common case */
! 1056: if (!tohost)
! 1057: wdc_output_bytes(drvp, (u_int8_t *)xfer->databuf +
! 1058: xfer->c_skip, len);
! 1059: else
! 1060: wdc_input_bytes(drvp, (u_int8_t *)xfer->databuf +
! 1061: xfer->c_skip, len);
! 1062:
! 1063: xfer->c_skip += len;
! 1064: xfer->c_bcount -= len;
! 1065: } else {
! 1066: /* Exceptional case - drive want to transfer more
! 1067: data than we have buffer for */
! 1068: if (!tohost) {
! 1069: /* Wouldn't it be better to just abort here rather
! 1070: than to write random stuff to drive? */
! 1071: printf("wdc_atapi_intr: warning: device requesting "
! 1072: "%d bytes, only %d left in buffer\n", len, xfer->c_bcount);
! 1073:
! 1074: wdc_output_bytes(drvp, (u_int8_t *)xfer->databuf +
! 1075: xfer->c_skip, xfer->c_bcount);
! 1076:
! 1077: CHP_WRITE_RAW_MULTI_2(chp, NULL,
! 1078: len - xfer->c_bcount);
! 1079: } else {
! 1080: printf("wdc_atapi_intr: warning: reading only "
! 1081: "%d of %d bytes\n", xfer->c_bcount, len);
! 1082:
! 1083: wdc_input_bytes(drvp,
! 1084: (char *)xfer->databuf + xfer->c_skip,
! 1085: xfer->c_bcount);
! 1086: wdcbit_bucket(chp, len - xfer->c_bcount);
! 1087: }
! 1088:
! 1089: xfer->c_skip += xfer->c_bcount;
! 1090: xfer->c_bcount = 0;
! 1091: }
! 1092:
! 1093: ret->expect_irq = 1;
! 1094: xfer->next = wdc_atapi_pio_intr;
! 1095:
! 1096: return;
! 1097: }
! 1098:
! 1099: void
! 1100: wdc_atapi_intr_complete(chp, xfer, timeout, ret)
! 1101: struct channel_softc *chp;
! 1102: struct wdc_xfer *xfer;
! 1103: int timeout;
! 1104: struct atapi_return_args *ret;
! 1105: {
! 1106: struct scsi_xfer *sc_xfer = xfer->cmd;
! 1107: struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
! 1108: struct atapiscsi_softc *as = sc_xfer->sc_link->adapter_softc;
! 1109:
! 1110: WDCDEBUG_PRINT(("PHASE_COMPLETED\n"), DEBUG_INTR);
! 1111:
! 1112: if (xfer->c_flags & C_DMA) {
! 1113: int retry;
! 1114:
! 1115: if (timeout) {
! 1116: sc_xfer->error = XS_TIMEOUT;
! 1117: ata_dmaerr(drvp);
! 1118:
! 1119: xfer->next = wdc_atapi_reset;
! 1120: return;
! 1121: }
! 1122:
! 1123: for (retry = 5; retry > 0; retry--) {
! 1124: wdc_atapi_update_status(chp);
! 1125: if ((chp->ch_status & (WDCS_BSY | WDCS_DRQ)) == 0)
! 1126: break;
! 1127: DELAY(5);
! 1128: }
! 1129: if (retry == 0) {
! 1130: ret->expect_irq = 1;
! 1131: return;
! 1132: }
! 1133:
! 1134: chp->wdc->dma_status =
! 1135: (*chp->wdc->dma_finish)
! 1136: (chp->wdc->dma_arg, chp->channel,
! 1137: xfer->drive, 1);
! 1138:
! 1139: if (chp->wdc->dma_status & WDC_DMAST_UNDER)
! 1140: xfer->c_bcount = 1;
! 1141: else
! 1142: xfer->c_bcount = 0;
! 1143: }
! 1144:
! 1145: as->protocol_phase = as_none;
! 1146:
! 1147: if (xfer->c_flags & C_SENSE) {
! 1148: if (chp->ch_status & WDCS_ERR) {
! 1149: if (chp->ch_error & WDCE_ABRT) {
! 1150: WDCDEBUG_PRINT(("wdc_atapi_intr: request_sense aborted, "
! 1151: "calling wdc_atapi_done()"
! 1152: ), DEBUG_INTR);
! 1153: xfer->next = wdc_atapi_done;
! 1154: return;
! 1155: }
! 1156:
! 1157: /*
! 1158: * request sense failed ! it's not supposed
! 1159: * to be possible
! 1160: */
! 1161: sc_xfer->error = XS_SHORTSENSE;
! 1162: } else if (xfer->c_bcount < sizeof(sc_xfer->sense)) {
! 1163: /* use the sense we just read */
! 1164: sc_xfer->error = XS_SENSE;
! 1165: } else {
! 1166: /*
! 1167: * command completed, but no data was read.
! 1168: * use the short sense we saved previously.
! 1169: */
! 1170: sc_xfer->error = XS_SHORTSENSE;
! 1171: }
! 1172: } else {
! 1173: sc_xfer->resid = xfer->c_bcount;
! 1174: if (chp->ch_status & WDCS_ERR) {
! 1175: if (!atapi_to_scsi_sense(sc_xfer, chp->ch_error) &&
! 1176: (sc_xfer->sc_link->quirks &
! 1177: ADEV_NOSENSE) == 0) {
! 1178: /*
! 1179: * let the driver issue a
! 1180: * 'request sense'
! 1181: */
! 1182: xfer->databuf = &sc_xfer->sense;
! 1183: xfer->c_bcount = sizeof(sc_xfer->sense);
! 1184: xfer->c_skip = 0;
! 1185: xfer->c_done = NULL;
! 1186: xfer->c_flags |= C_SENSE;
! 1187: xfer->next = wdc_atapi_real_start;
! 1188: return;
! 1189: }
! 1190: }
! 1191: }
! 1192:
! 1193: if ((xfer->c_flags & C_DMA) &&
! 1194: (chp->wdc->dma_status & ~WDC_DMAST_UNDER)) {
! 1195: ata_dmaerr(drvp);
! 1196: sc_xfer->error = XS_RESET;
! 1197:
! 1198: xfer->next = wdc_atapi_reset;
! 1199: return;
! 1200: }
! 1201:
! 1202:
! 1203: if (xfer->c_bcount != 0) {
! 1204: WDCDEBUG_PRINT(("wdc_atapi_intr: bcount value is "
! 1205: "%d after io\n", xfer->c_bcount), DEBUG_XFERS);
! 1206: }
! 1207: #ifdef DIAGNOSTIC
! 1208: if (xfer->c_bcount < 0) {
! 1209: printf("wdc_atapi_intr warning: bcount value "
! 1210: "is %d after io\n", xfer->c_bcount);
! 1211: }
! 1212: #endif
! 1213:
! 1214: WDCDEBUG_PRINT(("wdc_atapi_intr: wdc_atapi_done() (end), error 0x%x "
! 1215: "\n", sc_xfer->error),
! 1216: DEBUG_INTR);
! 1217:
! 1218:
! 1219: if (xfer->c_done)
! 1220: xfer->next = xfer->c_done;
! 1221: else
! 1222: xfer->next = wdc_atapi_done;
! 1223:
! 1224: return;
! 1225: }
! 1226:
! 1227: void
! 1228: wdc_atapi_pio_intr(chp, xfer, timeout, ret)
! 1229: struct channel_softc *chp;
! 1230: struct wdc_xfer *xfer;
! 1231: int timeout;
! 1232: struct atapi_return_args *ret;
! 1233: {
! 1234: struct scsi_xfer *sc_xfer = xfer->cmd;
! 1235: struct atapiscsi_softc *as = sc_xfer->sc_link->adapter_softc;
! 1236: u_int8_t ireason;
! 1237:
! 1238: wdc_atapi_update_status(chp);
! 1239:
! 1240: if (chp->ch_status & WDCS_BSY) {
! 1241: if (timeout)
! 1242: goto timeout;
! 1243:
! 1244: return;
! 1245: }
! 1246:
! 1247: if (!wdc_atapi_drive_selected(chp, xfer->drive)) {
! 1248: WDCDEBUG_PRINT(("wdc_atapi_intr_for_us: wrong drive selected\n"), DEBUG_INTR);
! 1249: wdc_set_drive(chp, xfer->drive);
! 1250: delay (1);
! 1251:
! 1252: if (!timeout)
! 1253: return;
! 1254: }
! 1255:
! 1256: if ((xfer->c_flags & C_MEDIA_ACCESS) &&
! 1257: !(chp->ch_status & (WDCS_DSC | WDCS_DRQ))) {
! 1258: if (timeout)
! 1259: goto timeout;
! 1260:
! 1261: ret->delay = 100;
! 1262: return;
! 1263: }
! 1264:
! 1265: if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
! 1266: chp->wdc->irqack(chp);
! 1267:
! 1268: ireason = CHP_READ_REG(chp, wdr_ireason);
! 1269: WDC_LOG_REG(chp, wdr_ireason, ireason);
! 1270:
! 1271: WDCDEBUG_PRINT(("Phase %d, (0x%b, 0x%x) ", as->protocol_phase,
! 1272: chp->ch_status, WDCS_BITS, ireason), DEBUG_INTR );
! 1273:
! 1274: switch (as->protocol_phase) {
! 1275: case as_data:
! 1276: if ((chp->ch_status & WDCS_DRQ) ||
! 1277: (ireason & 3) != 3) {
! 1278: if (timeout)
! 1279: goto timeout;
! 1280:
! 1281: wdc_atapi_intr_data(chp, xfer, timeout, ret);
! 1282: return;
! 1283: }
! 1284:
! 1285: case as_completed:
! 1286: if ((chp->ch_status & WDCS_DRQ) ||
! 1287: (ireason & 3) != 3) {
! 1288: if (timeout)
! 1289: goto timeout;
! 1290:
! 1291: ret->delay = 100;
! 1292: return;
! 1293: }
! 1294:
! 1295: wdc_atapi_intr_complete(chp, xfer, timeout, ret);
! 1296: return;
! 1297:
! 1298: default:
! 1299: printf ("atapiscsi: Shouldn't get here\n");
! 1300: sc_xfer->error = XS_DRIVER_STUFFUP;
! 1301: xfer->next = wdc_atapi_reset;
! 1302: return;
! 1303: }
! 1304:
! 1305: return;
! 1306: timeout:
! 1307: ireason = CHP_READ_REG(chp, wdr_ireason);
! 1308: WDC_LOG_REG(chp, wdr_ireason, ireason);
! 1309:
! 1310: printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip=%d, "
! 1311: "status=0x%b, ireason=0x%x\n",
! 1312: chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
! 1313: xfer->c_bcount, xfer->c_skip, chp->ch_status, WDCS_BITS, ireason);
! 1314:
! 1315: sc_xfer->error = XS_TIMEOUT;
! 1316: xfer->next = wdc_atapi_reset;
! 1317: return;
! 1318: }
! 1319:
! 1320:
! 1321:
! 1322: void
! 1323: wdc_atapi_ctrl(chp, xfer, timeout, ret)
! 1324: struct channel_softc *chp;
! 1325: struct wdc_xfer *xfer;
! 1326: int timeout;
! 1327: struct atapi_return_args *ret;
! 1328: {
! 1329: struct scsi_xfer *sc_xfer = xfer->cmd;
! 1330: struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
! 1331: char *errstring = NULL;
! 1332:
! 1333: wdc_atapi_update_status(chp);
! 1334:
! 1335: if (!timeout) {
! 1336: switch (drvp->state) {
! 1337: case ATAPI_IDENTIFY_WAIT_STATE:
! 1338: if (chp->ch_status & WDCS_BSY)
! 1339: return;
! 1340: break;
! 1341: default:
! 1342: if (chp->ch_status & (WDCS_BSY | WDCS_DRQ))
! 1343: return;
! 1344: break;
! 1345: }
! 1346: }
! 1347:
! 1348: if (!wdc_atapi_drive_selected(chp, xfer->drive))
! 1349: {
! 1350: wdc_set_drive(chp, xfer->drive);
! 1351: delay (1);
! 1352: }
! 1353:
! 1354: if (timeout) {
! 1355: int trigger_timeout = 1;
! 1356:
! 1357: switch (drvp->state) {
! 1358: case ATAPI_DEVICE_RESET_WAIT_STATE:
! 1359: errstring = "Device Reset Wait";
! 1360: drvp->drive_flags &= ~DRIVE_DEVICE_RESET;
! 1361: break;
! 1362:
! 1363: case ATAPI_IDENTIFY_WAIT_STATE:
! 1364: errstring = "Identify";
! 1365: if (!(chp->ch_status & WDCS_BSY) &&
! 1366: (chp->ch_status & (WDCS_DRQ | WDCS_ERR)))
! 1367: trigger_timeout = 0;
! 1368:
! 1369: break;
! 1370:
! 1371: case ATAPI_PIOMODE_STATE:
! 1372: errstring = "Post-Identify";
! 1373: if (!(chp->ch_status & (WDCS_BSY | WDCS_DRQ)))
! 1374: trigger_timeout = 0;
! 1375: break;
! 1376:
! 1377: case ATAPI_PIOMODE_WAIT_STATE:
! 1378: errstring = "PIOMODE";
! 1379: if (chp->ch_status & (WDCS_BSY | WDCS_DRQ))
! 1380: drvp->drive_flags &= ~DRIVE_MODE;
! 1381: else
! 1382: trigger_timeout = 0;
! 1383: break;
! 1384: case ATAPI_DMAMODE_WAIT_STATE:
! 1385: errstring = "dmamode";
! 1386: if (chp->ch_status & (WDCS_BSY | WDCS_DRQ))
! 1387: drvp->drive_flags &= ~(DRIVE_DMA | DRIVE_UDMA);
! 1388: else
! 1389: trigger_timeout = 0;
! 1390: break;
! 1391:
! 1392: default:
! 1393: errstring = "unknown state";
! 1394: break;
! 1395: }
! 1396:
! 1397: if (trigger_timeout)
! 1398: goto timeout;
! 1399: }
! 1400:
! 1401: WDCDEBUG_PRINT(("wdc_atapi_ctrl %s:%d:%d state %d\n",
! 1402: chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive, drvp->state),
! 1403: DEBUG_INTR | DEBUG_FUNCS);
! 1404:
! 1405: switch (drvp->state) {
! 1406: /* My ATAPI slave device likes to assert DASP-/PDIAG- until
! 1407: it is DEVICE RESET. This causes the LED to stay on.
! 1408:
! 1409: There is a trade-off here. This drive will cause any
! 1410: play-back or seeks happening to be interrupted.
! 1411:
! 1412: Note that the bus reset that triggered this state
! 1413: (which may have been caused by the other drive on
! 1414: the chain) need not interrupt this playback. It happens
! 1415: to on my Smart & Friendly CD burner.
! 1416:
! 1417: - csapuntz@
! 1418: */
! 1419: case ATAPI_RESET_BASE_STATE:
! 1420: if ((drvp->drive_flags & DRIVE_DEVICE_RESET) == 0) {
! 1421: drvp->state = ATAPI_IDENTIFY_STATE;
! 1422: break;
! 1423: }
! 1424:
! 1425: wdccommandshort(chp, drvp->drive, ATAPI_DEVICE_RESET);
! 1426: drvp->state = ATAPI_DEVICE_RESET_WAIT_STATE;
! 1427: ret->delay = ATAPI_RESET_DELAY;
! 1428: ret->timeout = ATAPI_RESET_WAIT;
! 1429: break;
! 1430:
! 1431: case ATAPI_DEVICE_RESET_WAIT_STATE:
! 1432: /* FALLTHROUGH */
! 1433:
! 1434: case ATAPI_IDENTIFY_STATE:
! 1435: wdccommandshort(chp, drvp->drive, ATAPI_IDENTIFY_DEVICE);
! 1436: drvp->state = ATAPI_IDENTIFY_WAIT_STATE;
! 1437: ret->delay = 10;
! 1438: ret->timeout = ATAPI_RESET_WAIT;
! 1439: break;
! 1440:
! 1441: case ATAPI_IDENTIFY_WAIT_STATE: {
! 1442: int idx = 0;
! 1443:
! 1444: while ((chp->ch_status & WDCS_DRQ) &&
! 1445: idx++ < 20) {
! 1446: wdcbit_bucket(chp, 512);
! 1447:
! 1448: DELAY(1);
! 1449: wdc_atapi_update_status(chp);
! 1450: }
! 1451:
! 1452: drvp->state = ATAPI_PIOMODE_STATE;
! 1453: /*
! 1454: * Note, we can't go directly to set PIO mode
! 1455: * because the drive is free to assert BSY
! 1456: * after the transfer
! 1457: */
! 1458: break;
! 1459: }
! 1460:
! 1461: case ATAPI_PIOMODE_STATE:
! 1462: /* Don't try to set mode if controller can't be adjusted */
! 1463: if ((chp->wdc->cap & WDC_CAPABILITY_MODE) == 0)
! 1464: goto ready;
! 1465: /* Also don't try if the drive didn't report its mode */
! 1466: if ((drvp->drive_flags & DRIVE_MODE) == 0)
! 1467: goto ready;
! 1468: /* SET FEATURES 0x08 is only for PIO mode > 2 */
! 1469: if (drvp->PIO_mode <= 2)
! 1470: goto ready;
! 1471: wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
! 1472: 0x08 | drvp->PIO_mode, WDSF_SET_MODE);
! 1473: drvp->state = ATAPI_PIOMODE_WAIT_STATE;
! 1474: ret->timeout = ATAPI_CTRL_WAIT;
! 1475: ret->expect_irq = 1;
! 1476: break;
! 1477: case ATAPI_PIOMODE_WAIT_STATE:
! 1478: if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
! 1479: chp->wdc->irqack(chp);
! 1480: if (chp->ch_status & WDCS_ERR) {
! 1481: /* Downgrade straight to PIO mode 3 */
! 1482: drvp->PIO_mode = 3;
! 1483: chp->wdc->set_modes(chp);
! 1484: }
! 1485: /* FALLTHROUGH */
! 1486:
! 1487: case ATAPI_DMAMODE_STATE:
! 1488: if (drvp->drive_flags & DRIVE_UDMA) {
! 1489: wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
! 1490: 0x40 | drvp->UDMA_mode, WDSF_SET_MODE);
! 1491: } else if (drvp->drive_flags & DRIVE_DMA) {
! 1492: wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
! 1493: 0x20 | drvp->DMA_mode, WDSF_SET_MODE);
! 1494: } else {
! 1495: goto ready;
! 1496: }
! 1497: drvp->state = ATAPI_DMAMODE_WAIT_STATE;
! 1498:
! 1499: ret->timeout = ATAPI_CTRL_WAIT;
! 1500: ret->expect_irq = 1;
! 1501: break;
! 1502:
! 1503: case ATAPI_DMAMODE_WAIT_STATE:
! 1504: if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
! 1505: chp->wdc->irqack(chp);
! 1506: if (chp->ch_status & WDCS_ERR)
! 1507: drvp->drive_flags &= ~(DRIVE_DMA | DRIVE_UDMA);
! 1508: /* FALLTHROUGH */
! 1509:
! 1510: case ATAPI_READY_STATE:
! 1511: ready:
! 1512: drvp->state = ATAPI_READY_STATE;
! 1513: xfer->next = wdc_atapi_real_start;
! 1514: break;
! 1515: }
! 1516: return;
! 1517:
! 1518: timeout:
! 1519: printf("%s:%d:%d: %s timed out\n",
! 1520: chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, errstring);
! 1521: sc_xfer->error = XS_TIMEOUT;
! 1522: xfer->next = wdc_atapi_reset;
! 1523: return;
! 1524:
! 1525: }
! 1526:
! 1527: void
! 1528: wdc_atapi_tape_done(chp, xfer, timeout, ret)
! 1529: struct channel_softc *chp;
! 1530: struct wdc_xfer *xfer;
! 1531: int timeout;
! 1532: struct atapi_return_args *ret;
! 1533: {
! 1534: struct scsi_xfer *sc_xfer = xfer->cmd;
! 1535:
! 1536: if (sc_xfer->error != XS_NOERROR) {
! 1537: xfer->next = wdc_atapi_done;
! 1538: return;
! 1539: }
! 1540:
! 1541: _lto3b(xfer->transfer_len,
! 1542: ((struct scsi_rw_tape *)
! 1543: sc_xfer->cmd)->len);
! 1544:
! 1545: xfer->c_bcount = sc_xfer->datalen;
! 1546: xfer->c_done = NULL;
! 1547: xfer->c_skip = 0;
! 1548:
! 1549: xfer->next = wdc_atapi_real_start;
! 1550: return;
! 1551: }
! 1552:
! 1553:
! 1554: void
! 1555: wdc_atapi_done(chp, xfer, timeout, ret)
! 1556: struct channel_softc *chp;
! 1557: struct wdc_xfer *xfer;
! 1558: int timeout;
! 1559: struct atapi_return_args *ret;
! 1560: {
! 1561: struct scsi_xfer *sc_xfer = xfer->cmd;
! 1562:
! 1563: WDCDEBUG_PRINT(("wdc_atapi_done %s:%d:%d: flags 0x%x error 0x%x\n",
! 1564: chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
! 1565: (u_int)xfer->c_flags, sc_xfer->error), DEBUG_XFERS);
! 1566: WDC_LOG_ATAPI_DONE(chp, xfer->drive, xfer->c_flags, sc_xfer->error);
! 1567:
! 1568: sc_xfer->flags |= ITSDONE;
! 1569:
! 1570: if (xfer->c_flags & C_POLL) {
! 1571: wdc_enable_intr(chp);
! 1572: } else {
! 1573: WDCDEBUG_PRINT(("wdc_atapi_done: scsi_done\n"), DEBUG_XFERS);
! 1574: scsi_done(sc_xfer);
! 1575: }
! 1576:
! 1577: xfer->next = NULL;
! 1578: return;
! 1579: }
! 1580:
! 1581:
! 1582: void
! 1583: wdc_atapi_reset(chp, xfer, timeout, ret)
! 1584: struct channel_softc *chp;
! 1585: struct wdc_xfer *xfer;
! 1586: int timeout;
! 1587: struct atapi_return_args *ret;
! 1588: {
! 1589: struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
! 1590:
! 1591: if (drvp->state == 0) {
! 1592: xfer->next = wdc_atapi_done;
! 1593: return;
! 1594: }
! 1595:
! 1596: WDCDEBUG_PRINT(("wdc_atapi_reset\n"), DEBUG_XFERS);
! 1597: wdccommandshort(chp, xfer->drive, ATAPI_SOFT_RESET);
! 1598: drvp->state = ATAPI_IDENTIFY_STATE;
! 1599:
! 1600: drvp->n_resets++;
! 1601: /* Some ATAPI devices need extra time to find their
! 1602: brains after a reset
! 1603: */
! 1604: xfer->next = wdc_atapi_reset_2;
! 1605: ret->delay = ATAPI_RESET_DELAY;
! 1606: ret->timeout = ATAPI_RESET_WAIT;
! 1607: return;
! 1608: }
! 1609:
! 1610: void
! 1611: wdc_atapi_reset_2(chp, xfer, timeout, ret)
! 1612: struct channel_softc *chp;
! 1613: struct wdc_xfer *xfer;
! 1614: int timeout;
! 1615: struct atapi_return_args *ret;
! 1616: {
! 1617: struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
! 1618: struct scsi_xfer *sc_xfer = xfer->cmd;
! 1619:
! 1620: if (timeout) {
! 1621: printf("%s:%d:%d: soft reset failed\n",
! 1622: chp->wdc->sc_dev.dv_xname, chp->channel,
! 1623: xfer->drive);
! 1624: sc_xfer->error = XS_SELTIMEOUT;
! 1625: wdc_reset_channel(drvp);
! 1626:
! 1627: xfer->next = wdc_atapi_done;
! 1628: return;
! 1629: }
! 1630:
! 1631: wdc_atapi_update_status(chp);
! 1632:
! 1633: if (chp->ch_status & (WDCS_BSY | WDCS_DRQ)) {
! 1634: return;
! 1635: }
! 1636:
! 1637: xfer->next = wdc_atapi_done;
! 1638: return;
! 1639: }
CVSweb