Annotation of sys/dev/ata/atascsi.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: atascsi.c,v 1.41 2007/04/22 05:11:45 dlg Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2007 David Gwynne <dlg@openbsd.org>
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18:
! 19: #include <sys/param.h>
! 20: #include <sys/systm.h>
! 21: #include <sys/buf.h>
! 22: #include <sys/kernel.h>
! 23: #include <sys/malloc.h>
! 24: #include <sys/device.h>
! 25: #include <sys/proc.h>
! 26: #include <sys/queue.h>
! 27:
! 28: #include <scsi/scsi_all.h>
! 29: #include <scsi/scsi_disk.h>
! 30: #include <scsi/scsiconf.h>
! 31:
! 32: #include <dev/ata/atascsi.h>
! 33:
! 34: struct atascsi {
! 35: struct device *as_dev;
! 36: void *as_cookie;
! 37:
! 38: struct ata_port **as_ports;
! 39:
! 40: struct atascsi_methods *as_methods;
! 41: struct scsi_adapter as_switch;
! 42: struct scsi_link as_link;
! 43: struct scsibus_softc *as_scsibus;
! 44:
! 45: int as_capability;
! 46: };
! 47:
! 48: int atascsi_cmd(struct scsi_xfer *);
! 49:
! 50: /* template */
! 51: struct scsi_adapter atascsi_switch = {
! 52: atascsi_cmd, /* scsi_cmd */
! 53: minphys, /* scsi_minphys */
! 54: NULL,
! 55: NULL,
! 56: NULL /* ioctl */
! 57: };
! 58:
! 59: struct scsi_device atascsi_device = {
! 60: NULL, NULL, NULL, NULL
! 61: };
! 62:
! 63: int atascsi_probe(struct atascsi *, int);
! 64:
! 65: struct ata_xfer *ata_setup_identify(struct ata_port *, int);
! 66: void ata_free_identify(struct ata_xfer *);
! 67: void ata_complete_identify(struct ata_xfer *,
! 68: struct ata_identify *);
! 69:
! 70: int atascsi_disk_cmd(struct scsi_xfer *);
! 71: void atascsi_disk_cmd_done(struct ata_xfer *);
! 72: int atascsi_disk_inq(struct scsi_xfer *);
! 73: void atascsi_disk_inq_done(struct ata_xfer *);
! 74: int atascsi_disk_capacity(struct scsi_xfer *);
! 75: void atascsi_disk_capacity_done(struct ata_xfer *);
! 76: int atascsi_disk_sync(struct scsi_xfer *);
! 77: void atascsi_disk_sync_done(struct ata_xfer *);
! 78: int atascsi_disk_sense(struct scsi_xfer *);
! 79:
! 80: void atascsi_empty_done(struct ata_xfer *);
! 81:
! 82: int atascsi_atapi_cmd(struct scsi_xfer *);
! 83: void atascsi_atapi_cmd_done(struct ata_xfer *);
! 84:
! 85: int atascsi_stuffup(struct scsi_xfer *);
! 86:
! 87:
! 88: int ata_running = 0;
! 89:
! 90: int ata_exec(struct atascsi *, struct ata_xfer *);
! 91:
! 92: struct ata_xfer *ata_get_xfer(struct ata_port *, int);
! 93: void ata_put_xfer(struct ata_xfer *);
! 94:
! 95: struct atascsi *
! 96: atascsi_attach(struct device *self, struct atascsi_attach_args *aaa)
! 97: {
! 98: struct scsibus_attach_args saa;
! 99: struct atascsi *as;
! 100: int i;
! 101:
! 102: as = malloc(sizeof(struct atascsi), M_DEVBUF, M_WAITOK);
! 103: bzero(as, sizeof(struct atascsi));
! 104:
! 105: as->as_dev = self;
! 106: as->as_cookie = aaa->aaa_cookie;
! 107: as->as_methods = aaa->aaa_methods;
! 108: as->as_capability = aaa->aaa_capability;
! 109:
! 110: /* copy from template and modify for ourselves */
! 111: as->as_switch = atascsi_switch;
! 112: as->as_switch.scsi_minphys = aaa->aaa_minphys;
! 113:
! 114: /* fill in our scsi_link */
! 115: as->as_link.device = &atascsi_device;
! 116: as->as_link.adapter = &as->as_switch;
! 117: as->as_link.adapter_softc = as;
! 118: as->as_link.adapter_buswidth = aaa->aaa_nports;
! 119: as->as_link.luns = 1; /* XXX port multiplier as luns */
! 120: as->as_link.adapter_target = aaa->aaa_nports;
! 121: as->as_link.openings = aaa->aaa_ncmds;
! 122: if (as->as_capability & ASAA_CAP_NEEDS_RESERVED)
! 123: as->as_link.openings--;
! 124:
! 125: as->as_ports = malloc(sizeof(struct ata_port *) * aaa->aaa_nports,
! 126: M_DEVBUF, M_WAITOK);
! 127: bzero(as->as_ports, sizeof(struct ata_port *) * aaa->aaa_nports);
! 128:
! 129: /* fill in the port array with the type of devices there */
! 130: for (i = 0; i < as->as_link.adapter_buswidth; i++)
! 131: atascsi_probe(as, i);
! 132:
! 133: bzero(&saa, sizeof(saa));
! 134: saa.saa_sc_link = &as->as_link;
! 135:
! 136: /* stash the scsibus so we can do hotplug on it */
! 137: as->as_scsibus = (struct scsibus_softc *)config_found(self, &saa,
! 138: scsiprint);
! 139:
! 140: return (as);
! 141: }
! 142:
! 143: int
! 144: atascsi_detach(struct atascsi *as)
! 145: {
! 146: return (0);
! 147: }
! 148:
! 149: int
! 150: atascsi_probe(struct atascsi *as, int port)
! 151: {
! 152: struct ata_port *ap;
! 153: struct ata_xfer *xa;
! 154: int type, s;
! 155:
! 156: if (port > as->as_link.adapter_buswidth)
! 157: return (ENXIO);
! 158:
! 159: type = as->as_methods->probe(as->as_cookie, port);
! 160: switch (type) {
! 161: case ATA_PORT_T_DISK:
! 162: break;
! 163: case ATA_PORT_T_ATAPI:
! 164: as->as_link.flags |= SDEV_ATAPI;
! 165: as->as_link.quirks |= SDEV_ONLYBIG;
! 166: break;
! 167: default:
! 168: return (ENODEV);
! 169: }
! 170:
! 171: ap = malloc(sizeof(struct ata_port), M_DEVBUF, M_WAITOK);
! 172: bzero(ap, sizeof(struct ata_port));
! 173: ap->ap_as = as;
! 174: ap->ap_port = port;
! 175: ap->ap_type = type;
! 176:
! 177: as->as_ports[port] = ap;
! 178:
! 179: s = splbio();
! 180: xa = ata_get_xfer(ap, 1);
! 181: splx(s);
! 182: if (xa == NULL)
! 183: return (EBUSY);
! 184:
! 185: /*
! 186: * FREEZE LOCK the device so malicous users can't lock it on us.
! 187: * As there is no harm in issuing this to devices that don't
! 188: * support the security feature set we just send it, and don't bother
! 189: * checking if the device sends a command abort to tell us it doesn't
! 190: * support it
! 191: */
! 192: xa->fis->command = ATA_C_SEC_FREEZE_LOCK;
! 193: xa->fis->flags = ATA_H2D_FLAGS_CMD;
! 194: xa->complete = atascsi_empty_done;
! 195: xa->flags = ATA_F_POLL | ATA_F_PIO;
! 196: xa->timeout = 1000;
! 197: ata_exec(as, xa);
! 198:
! 199: return (0);
! 200: }
! 201:
! 202: struct ata_xfer *
! 203: ata_setup_identify(struct ata_port *ap, int nosleep)
! 204: {
! 205: struct ata_xfer *xa;
! 206: int s;
! 207:
! 208: s = splbio();
! 209: xa = ata_get_xfer(ap, nosleep);
! 210: splx(s);
! 211: if (xa == NULL)
! 212: return (NULL);
! 213:
! 214: xa->data = malloc(512, M_TEMP, nosleep ? M_NOWAIT : M_WAITOK);
! 215: if (xa->data == NULL) {
! 216: s = splbio();
! 217: xa->state = ATA_S_ERROR;
! 218: ata_put_xfer(xa);
! 219: splx(s);
! 220: return (NULL);
! 221: }
! 222: bzero(xa->data, 512);
! 223: xa->datalen = 512;
! 224:
! 225: xa->fis->flags = ATA_H2D_FLAGS_CMD;
! 226: xa->fis->command = ATA_C_IDENTIFY;
! 227: xa->fis->device = 0;
! 228:
! 229: xa->flags = ATA_F_READ | ATA_F_PIO;
! 230:
! 231: return (xa);
! 232: }
! 233:
! 234: void
! 235: ata_free_identify(struct ata_xfer *xa)
! 236: {
! 237: free(xa->data, M_TEMP);
! 238: ata_put_xfer(xa);
! 239: }
! 240:
! 241: void
! 242: ata_complete_identify(struct ata_xfer *xa, struct ata_identify *id)
! 243: {
! 244: u_int16_t *swap;
! 245: int i;
! 246:
! 247: bcopy(xa->data, id, sizeof(struct ata_identify));
! 248: ata_free_identify(xa);
! 249:
! 250: swap = (u_int16_t *)id->serial;
! 251: for (i = 0; i < sizeof(id->serial) / sizeof(u_int16_t); i++)
! 252: swap[i] = swap16(swap[i]);
! 253:
! 254: swap = (u_int16_t *)id->firmware;
! 255: for (i = 0; i < sizeof(id->firmware) / sizeof(u_int16_t); i++)
! 256: swap[i] = swap16(swap[i]);
! 257:
! 258: swap = (u_int16_t *)id->model;
! 259: for (i = 0; i < sizeof(id->model) / sizeof(u_int16_t); i++)
! 260: swap[i] = swap16(swap[i]);
! 261: }
! 262:
! 263: int
! 264: atascsi_cmd(struct scsi_xfer *xs)
! 265: {
! 266: struct scsi_link *link = xs->sc_link;
! 267: struct atascsi *as = link->adapter_softc;
! 268: struct ata_port *ap = as->as_ports[link->target];
! 269:
! 270: if (ap == NULL)
! 271: return (atascsi_stuffup(xs));
! 272:
! 273: switch (ap->ap_type) {
! 274: case ATA_PORT_T_DISK:
! 275: return (atascsi_disk_cmd(xs));
! 276: case ATA_PORT_T_ATAPI:
! 277: return (atascsi_atapi_cmd(xs));
! 278:
! 279: case ATA_PORT_T_NONE:
! 280: default:
! 281: return (atascsi_stuffup(xs));
! 282: }
! 283: }
! 284:
! 285: int
! 286: atascsi_disk_cmd(struct scsi_xfer *xs)
! 287: {
! 288: struct scsi_link *link = xs->sc_link;
! 289: struct atascsi *as = link->adapter_softc;
! 290: struct ata_port *ap = as->as_ports[link->target];
! 291: int s, flags = 0;
! 292: struct scsi_rw *rw;
! 293: struct scsi_rw_big *rwb;
! 294: struct ata_xfer *xa;
! 295: struct ata_fis_h2d *fis;
! 296: u_int64_t lba;
! 297: u_int32_t sector_count;
! 298:
! 299: switch (xs->cmd->opcode) {
! 300: case READ_BIG:
! 301: case READ_COMMAND:
! 302: flags = ATA_F_READ;
! 303: break;
! 304: case WRITE_BIG:
! 305: case WRITE_COMMAND:
! 306: flags = ATA_F_WRITE;
! 307: /* deal with io outside the switch */
! 308: break;
! 309:
! 310: case SYNCHRONIZE_CACHE:
! 311: return (atascsi_disk_sync(xs));
! 312: case REQUEST_SENSE:
! 313: return (atascsi_disk_sense(xs));
! 314: case INQUIRY:
! 315: return (atascsi_disk_inq(xs));
! 316: case READ_CAPACITY:
! 317: return (atascsi_disk_capacity(xs));
! 318:
! 319: case TEST_UNIT_READY:
! 320: case START_STOP:
! 321: case PREVENT_ALLOW:
! 322: return (COMPLETE);
! 323:
! 324: default:
! 325: return (atascsi_stuffup(xs));
! 326: }
! 327:
! 328: s = splbio();
! 329: xa = ata_get_xfer(ap, xs->flags & SCSI_NOSLEEP);
! 330: splx(s);
! 331: if (xa == NULL)
! 332: return (NO_CCB);
! 333:
! 334: xa->flags = flags;
! 335: if (xs->cmdlen == 6) {
! 336: rw = (struct scsi_rw *)xs->cmd;
! 337: lba = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff);
! 338: sector_count = rw->length ? rw->length : 0x100;
! 339: } else {
! 340: rwb = (struct scsi_rw_big *)xs->cmd;
! 341: lba = _4btol(rwb->addr);
! 342: sector_count = _2btol(rwb->length);
! 343: }
! 344:
! 345: fis = xa->fis;
! 346:
! 347: fis->flags = ATA_H2D_FLAGS_CMD;
! 348: fis->lba_low = lba & 0xff;
! 349: fis->lba_mid = (lba >> 8) & 0xff;
! 350: fis->lba_high = (lba >> 16) & 0xff;
! 351:
! 352: if (ap->ap_ncqdepth && !(xs->flags & SCSI_POLL)) {
! 353: /* Use NCQ */
! 354: xa->flags |= ATA_F_NCQ;
! 355: fis->command = (xa->flags & ATA_F_WRITE) ?
! 356: ATA_C_WRITE_FPDMA : ATA_C_READ_FPDMA;
! 357: fis->device = ATA_H2D_DEVICE_LBA;
! 358: fis->lba_low_exp = (lba >> 24) & 0xff;
! 359: fis->lba_mid_exp = (lba >> 32) & 0xff;
! 360: fis->lba_high_exp = (lba >> 40) & 0xff;
! 361: fis->sector_count = xa->tag << 3;
! 362: fis->features = sector_count & 0xff;
! 363: fis->features_exp = (sector_count >> 8) & 0xff;
! 364: } else if (sector_count > 0x100 || lba > 0xfffffff) {
! 365: /* Use LBA48 */
! 366: fis->command = (xa->flags & ATA_F_WRITE) ?
! 367: ATA_C_WRITEDMA_EXT : ATA_C_READDMA_EXT;
! 368: fis->device = ATA_H2D_DEVICE_LBA;
! 369: fis->lba_low_exp = (lba >> 24) & 0xff;
! 370: fis->lba_mid_exp = (lba >> 32) & 0xff;
! 371: fis->lba_high_exp = (lba >> 40) & 0xff;
! 372: fis->sector_count = sector_count & 0xff;
! 373: fis->sector_count_exp = (sector_count >> 8) & 0xff;
! 374: } else {
! 375: /* Use LBA */
! 376: fis->command = (xa->flags & ATA_F_WRITE) ?
! 377: ATA_C_WRITEDMA : ATA_C_READDMA;
! 378: fis->device = ATA_H2D_DEVICE_LBA | ((lba >> 24) & 0x0f);
! 379: fis->sector_count = sector_count & 0xff;
! 380: }
! 381:
! 382: xa->data = xs->data;
! 383: xa->datalen = xs->datalen;
! 384: xa->complete = atascsi_disk_cmd_done;
! 385: xa->timeout = xs->timeout;
! 386: xa->atascsi_private = xs;
! 387: if (xs->flags & SCSI_POLL)
! 388: xa->flags |= ATA_F_POLL;
! 389:
! 390: return (ata_exec(as, xa));
! 391: }
! 392:
! 393: void
! 394: atascsi_empty_done(struct ata_xfer *xa)
! 395: {
! 396: ata_put_xfer(xa);
! 397: }
! 398:
! 399: void
! 400: atascsi_disk_cmd_done(struct ata_xfer *xa)
! 401: {
! 402: struct scsi_xfer *xs = xa->atascsi_private;
! 403:
! 404: switch (xa->state) {
! 405: case ATA_S_COMPLETE:
! 406: xs->error = XS_NOERROR;
! 407: break;
! 408: case ATA_S_ERROR:
! 409: /* fake sense? */
! 410: xs->error = XS_DRIVER_STUFFUP;
! 411: break;
! 412: case ATA_S_TIMEOUT:
! 413: xs->error = XS_TIMEOUT;
! 414: break;
! 415: default:
! 416: panic("atascsi_disk_cmd_done: unexpected ata_xfer state (%d)",
! 417: xa->state);
! 418: }
! 419:
! 420: xs->resid = xa->resid;
! 421: ata_put_xfer(xa);
! 422:
! 423: xs->flags |= ITSDONE;
! 424: scsi_done(xs);
! 425: }
! 426:
! 427: int
! 428: atascsi_disk_inq(struct scsi_xfer *xs)
! 429: {
! 430: struct scsi_link *link = xs->sc_link;
! 431: struct atascsi *as = link->adapter_softc;
! 432: struct ata_port *ap = as->as_ports[link->target];
! 433: struct ata_xfer *xa;
! 434:
! 435: xa = ata_setup_identify(ap, xs->flags & SCSI_NOSLEEP);
! 436: if (xa == NULL)
! 437: return (NO_CCB);
! 438:
! 439: xa->complete = atascsi_disk_inq_done;
! 440: xa->timeout = xs->timeout;
! 441: xa->atascsi_private = xs;
! 442: if (xs->flags & SCSI_POLL)
! 443: xa->flags |= ATA_F_POLL;
! 444:
! 445: return (ata_exec(as, xa));
! 446: }
! 447:
! 448: void
! 449: atascsi_disk_inq_done(struct ata_xfer *xa)
! 450: {
! 451: struct scsi_xfer *xs = xa->atascsi_private;
! 452: struct scsi_link *link = xs->sc_link;
! 453: struct atascsi *as = link->adapter_softc;
! 454: struct ata_port *ap = as->as_ports[link->target];
! 455: struct ata_identify id;
! 456: struct scsi_inquiry_data inq;
! 457: int host_ncqdepth, complete = 0;
! 458:
! 459: switch (xa->state) {
! 460: case ATA_S_COMPLETE:
! 461: ata_complete_identify(xa, &id);
! 462:
! 463: bzero(&inq, sizeof(inq));
! 464:
! 465: inq.device = T_DIRECT;
! 466: inq.version = 2;
! 467: inq.response_format = 2;
! 468: inq.additional_length = 32;
! 469: bcopy("ATA ", inq.vendor, sizeof(inq.vendor));
! 470: bcopy(id.model, inq.product, sizeof(inq.product));
! 471: bcopy(id.firmware, inq.revision, sizeof(inq.revision));
! 472:
! 473: bcopy(&inq, xs->data, MIN(sizeof(inq), xs->datalen));
! 474: xs->error = XS_NOERROR;
! 475: complete = 1;
! 476: break;
! 477:
! 478: case ATA_S_ERROR:
! 479: case ATA_S_TIMEOUT:
! 480: ata_free_identify(xa);
! 481: xs->error = (xa->state == ATA_S_TIMEOUT ? XS_TIMEOUT :
! 482: XS_DRIVER_STUFFUP);
! 483: break;
! 484:
! 485: default:
! 486: panic("atascsi_disk_inq_done: unexpected ata_xfer state (%d)",
! 487: xa->state);
! 488: }
! 489:
! 490: xs->flags |= ITSDONE;
! 491: scsi_done(xs);
! 492:
! 493: if (!complete || (ap->ap_features & ATA_PORT_F_PROBED))
! 494: return;
! 495:
! 496: ap->ap_features = ATA_PORT_F_PROBED;
! 497:
! 498: if (as->as_capability & ASAA_CAP_NCQ && (letoh16(id.satacap) &
! 499: (1 << 8))) {
! 500: /*
! 501: * At this point, openings should be the number of commands the
! 502: * host controller supports, less the one that is outstanding
! 503: * as a result of this inquiry, less any reserved slot the
! 504: * host controller needs for recovery.
! 505: */
! 506: host_ncqdepth = link->openings + 1 + ((as->as_capability &
! 507: ASAA_CAP_NEEDS_RESERVED) ? 1 : 0);
! 508:
! 509: ap->ap_ncqdepth = (letoh16(id.qdepth) & 0x1f) + 1;
! 510:
! 511: /* Limit the number of openings to what the device supports. */
! 512: if (host_ncqdepth > ap->ap_ncqdepth)
! 513: link->openings -= (host_ncqdepth - ap->ap_ncqdepth);
! 514:
! 515: /*
! 516: * XXX throw away any xfers that have tag numbers higher than
! 517: * what the device supports.
! 518: */
! 519: while (host_ncqdepth--) {
! 520: struct ata_xfer *xa;
! 521:
! 522: xa = ata_get_xfer(ap, 1);
! 523: if (xa->tag < ap->ap_ncqdepth) {
! 524: xa->state = ATA_S_COMPLETE;
! 525: ata_put_xfer(xa);
! 526: }
! 527: }
! 528: }
! 529: }
! 530:
! 531: int
! 532: atascsi_disk_sync(struct scsi_xfer *xs)
! 533: {
! 534: struct scsi_link *link = xs->sc_link;
! 535: struct atascsi *as = link->adapter_softc;
! 536: struct ata_port *ap = as->as_ports[link->target];
! 537: struct ata_xfer *xa;
! 538: int s;
! 539:
! 540: s = splbio();
! 541: xa = ata_get_xfer(ap, xs->flags & SCSI_NOSLEEP);
! 542: splx(s);
! 543: if (xa == NULL)
! 544: return (NO_CCB);
! 545:
! 546: xa->datalen = 0;
! 547: xa->flags = ATA_F_READ;
! 548: xa->complete = atascsi_disk_sync_done;
! 549: /* Spec says flush cache can take >30 sec, so give it at least 45. */
! 550: xa->timeout = (xs->timeout < 45000) ? 45000 : xs->timeout;
! 551: xa->atascsi_private = xs;
! 552: if (xs->flags & SCSI_POLL)
! 553: xa->flags |= ATA_F_POLL;
! 554:
! 555: xa->fis->flags = ATA_H2D_FLAGS_CMD;
! 556: xa->fis->command = ATA_C_FLUSH_CACHE;
! 557: xa->fis->device = 0;
! 558:
! 559: return (ata_exec(as, xa));
! 560: }
! 561:
! 562: void
! 563: atascsi_disk_sync_done(struct ata_xfer *xa)
! 564: {
! 565: struct scsi_xfer *xs = xa->atascsi_private;
! 566:
! 567: switch (xa->state) {
! 568: case ATA_S_COMPLETE:
! 569: xs->error = XS_NOERROR;
! 570: break;
! 571:
! 572: case ATA_S_ERROR:
! 573: case ATA_S_TIMEOUT:
! 574: printf("atascsi_disk_sync_done: %s\n",
! 575: xa->state == ATA_S_TIMEOUT ? "timeout" : "error");
! 576: xs->error = (xa->state == ATA_S_TIMEOUT ? XS_TIMEOUT :
! 577: XS_DRIVER_STUFFUP);
! 578: break;
! 579:
! 580: default:
! 581: panic("atascsi_disk_sync_done: unexpected ata_xfer state (%d)",
! 582: xa->state);
! 583: }
! 584:
! 585: ata_put_xfer(xa);
! 586:
! 587: xs->flags |= ITSDONE;
! 588: scsi_done(xs);
! 589: }
! 590:
! 591: int
! 592: atascsi_disk_capacity(struct scsi_xfer *xs)
! 593: {
! 594: struct scsi_link *link = xs->sc_link;
! 595: struct atascsi *as = link->adapter_softc;
! 596: struct ata_port *ap = as->as_ports[link->target];
! 597: struct ata_xfer *xa;
! 598:
! 599: xa = ata_setup_identify(ap, xs->flags & SCSI_NOSLEEP);
! 600: if (xa == NULL)
! 601: return (NO_CCB);
! 602:
! 603: xa->complete = atascsi_disk_capacity_done;
! 604: xa->timeout = xs->timeout;
! 605: xa->atascsi_private = xs;
! 606: if (xs->flags & SCSI_POLL)
! 607: xa->flags |= ATA_F_POLL;
! 608:
! 609: return (ata_exec(as, xa));
! 610: }
! 611:
! 612: void
! 613: atascsi_disk_capacity_done(struct ata_xfer *xa)
! 614: {
! 615: struct scsi_xfer *xs = xa->atascsi_private;
! 616: struct ata_identify id;
! 617: struct scsi_read_cap_data rcd;
! 618: u_int64_t capacity;
! 619: int i;
! 620:
! 621: switch (xa->state) {
! 622: case ATA_S_COMPLETE:
! 623: ata_complete_identify(xa, &id);
! 624:
! 625: bzero(&rcd, sizeof(rcd));
! 626: if (letoh16(id.cmdset83) & 0x0400) {
! 627: /* LBA48 feature set supported */
! 628: for (i = 3; i >= 0; --i) {
! 629: capacity <<= 16;
! 630: capacity += letoh16(id.addrsecxt[i]);
! 631: }
! 632: } else {
! 633: capacity = letoh16(id.addrsec[1]);
! 634: capacity <<= 16;
! 635: capacity += letoh16(id.addrsec[0]);
! 636: }
! 637:
! 638: /* XXX SCSI layer can't handle a device this big yet */
! 639: if (capacity > 0xffffffff)
! 640: capacity = 0xffffffff;
! 641:
! 642: _lto4b(capacity - 1, rcd.addr);
! 643: _lto4b(512, rcd.length);
! 644:
! 645: bcopy(&rcd, xs->data, MIN(sizeof(rcd), xs->datalen));
! 646: xs->error = XS_NOERROR;
! 647: break;
! 648:
! 649: case ATA_S_ERROR:
! 650: case ATA_S_TIMEOUT:
! 651: ata_free_identify(xa);
! 652: xs->error = (xa->state == ATA_S_TIMEOUT ? XS_TIMEOUT :
! 653: XS_DRIVER_STUFFUP);
! 654: break;
! 655:
! 656: default:
! 657: panic("atascsi_disk_capacity_done: "
! 658: "unexpected ata_xfer state (%d)", xa->state);
! 659: }
! 660:
! 661: xs->flags |= ITSDONE;
! 662: scsi_done(xs);
! 663: }
! 664:
! 665: int
! 666: atascsi_disk_sense(struct scsi_xfer *xs)
! 667: {
! 668: struct scsi_sense_data *sd = (struct scsi_sense_data *)xs->data;
! 669: int s;
! 670:
! 671: bzero(xs->data, xs->datalen);
! 672: /* check datalen > sizeof(struct scsi_sense_data)? */
! 673: sd->error_code = 0x70; /* XXX magic */
! 674: sd->flags = SKEY_NO_SENSE;
! 675:
! 676: xs->error = XS_NOERROR;
! 677: xs->flags |= ITSDONE;
! 678:
! 679: s = splbio();
! 680: scsi_done(xs);
! 681: splx(s);
! 682: return (COMPLETE);
! 683: }
! 684:
! 685: int
! 686: atascsi_atapi_cmd(struct scsi_xfer *xs)
! 687: {
! 688: struct scsi_link *link = xs->sc_link;
! 689: struct atascsi *as = link->adapter_softc;
! 690: struct ata_port *ap = as->as_ports[link->target];
! 691: int s;
! 692: struct ata_xfer *xa;
! 693: struct ata_fis_h2d *fis;
! 694:
! 695: s = splbio();
! 696: xa = ata_get_xfer(ap, xs->flags & SCSI_NOSLEEP);
! 697: splx(s);
! 698: if (xa == NULL)
! 699: return (NO_CCB);
! 700:
! 701: switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
! 702: case SCSI_DATA_IN:
! 703: xa->flags = ATA_F_PACKET | ATA_F_READ;
! 704: break;
! 705: case SCSI_DATA_OUT:
! 706: xa->flags = ATA_F_PACKET | ATA_F_WRITE;
! 707: break;
! 708: default:
! 709: xa->flags = ATA_F_PACKET;
! 710: }
! 711:
! 712: xa->data = xs->data;
! 713: xa->datalen = xs->datalen;
! 714: xa->complete = atascsi_atapi_cmd_done;
! 715: xa->timeout = xs->timeout;
! 716: xa->atascsi_private = xs;
! 717: if (xs->flags & SCSI_POLL)
! 718: xa->flags |= ATA_F_POLL;
! 719:
! 720: fis = xa->fis;
! 721: fis->flags = ATA_H2D_FLAGS_CMD;
! 722: fis->command = ATA_C_PACKET;
! 723: fis->device = 0;
! 724: fis->sector_count = xa->tag << 3;
! 725: fis->features = ATA_H2D_FEATURES_DMA | ((xa->flags & ATA_F_WRITE) ?
! 726: ATA_H2D_FEATURES_DIR_WRITE : ATA_H2D_FEATURES_DIR_READ);
! 727: fis->lba_mid = 0x00;
! 728: fis->lba_high = 0x20;
! 729:
! 730: /* Copy SCSI command into ATAPI packet. */
! 731: memcpy(xa->packetcmd, xs->cmd, xs->cmdlen);
! 732:
! 733: return (ata_exec(as, xa));
! 734: }
! 735:
! 736: void
! 737: atascsi_atapi_cmd_done(struct ata_xfer *xa)
! 738: {
! 739: struct scsi_xfer *xs = xa->atascsi_private;
! 740: struct scsi_sense_data *sd = &xs->sense;
! 741:
! 742: switch (xa->state) {
! 743: case ATA_S_COMPLETE:
! 744: xs->error = XS_NOERROR;
! 745: break;
! 746: case ATA_S_ERROR:
! 747: /* Return PACKET sense data */
! 748: sd->error_code = SSD_ERRCODE_CURRENT;
! 749: sd->flags = (xa->rfis.error & 0xf0) >> 4;
! 750: if (xa->rfis.error & 0x04)
! 751: sd->flags = SKEY_ILLEGAL_REQUEST;
! 752: if (xa->rfis.error & 0x02)
! 753: sd->flags |= SSD_EOM;
! 754: if (xa->rfis.error & 0x01)
! 755: sd->flags |= SSD_ILI;
! 756: xs->error = XS_SENSE;
! 757: break;
! 758: case ATA_S_TIMEOUT:
! 759: printf("atascsi_atapi_cmd_done, timeout\n");
! 760: xs->error = XS_TIMEOUT;
! 761: break;
! 762: default:
! 763: panic("atascsi_atapi_cmd_done: unexpected ata_xfer state (%d)",
! 764: xa->state);
! 765: }
! 766:
! 767: xs->resid = xa->resid;
! 768: ata_put_xfer(xa);
! 769:
! 770: xs->flags |= ITSDONE;
! 771: scsi_done(xs);
! 772: }
! 773:
! 774: int
! 775: atascsi_stuffup(struct scsi_xfer *xs)
! 776: {
! 777: int s;
! 778:
! 779: xs->error = XS_DRIVER_STUFFUP;
! 780: xs->flags |= ITSDONE;
! 781:
! 782: s = splbio();
! 783: scsi_done(xs);
! 784: splx(s);
! 785: return (COMPLETE);
! 786: }
! 787:
! 788: int
! 789: ata_exec(struct atascsi *as, struct ata_xfer *xa)
! 790: {
! 791: int polled = xa->flags & ATA_F_POLL;
! 792:
! 793: switch (as->as_methods->ata_cmd(xa)) {
! 794: case ATA_COMPLETE:
! 795: case ATA_ERROR:
! 796: return (COMPLETE);
! 797: case ATA_QUEUED:
! 798: if (!polled)
! 799: return (SUCCESSFULLY_QUEUED);
! 800: default:
! 801: panic("unexpected return from ata_exec");
! 802: }
! 803: }
! 804:
! 805: struct ata_xfer *
! 806: ata_get_xfer(struct ata_port *ap, int nosleep /* XXX unused */)
! 807: {
! 808: struct atascsi *as = ap->ap_as;
! 809: struct ata_xfer *xa;
! 810:
! 811: xa = as->as_methods->ata_get_xfer(as->as_cookie, ap->ap_port);
! 812: if (xa != NULL)
! 813: xa->fis->type = ATA_FIS_TYPE_H2D;
! 814:
! 815: return (xa);
! 816: }
! 817:
! 818: void
! 819: ata_put_xfer(struct ata_xfer *xa)
! 820: {
! 821: xa->ata_put_xfer(xa);
! 822: }
CVSweb