1 /* $OpenBSD: cac.c,v 1.5 2001/04/23 10:47:56 art Exp $ */ 2 /* $NetBSD: cac.c,v 1.15 2000/11/08 19:20:35 ad Exp $ */ 3 4 /* 5 * Copyright (c) 2000 Michael Shalayeff 6 * All rights reserved. 7 * 8 * The SCSI emulation layer is derived from gdt(4) driver, 9 * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by Michael Shalayeff. 22 * 4. The name of the author may not be used to endorse or promote products 23 * derived from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 34 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 35 * THE POSSIBILITY OF SUCH DAMAGE. 36 */ 37 /*- 38 * Copyright (c) 2000 The NetBSD Foundation, Inc. 39 * All rights reserved. 40 * 41 * This code is derived from software contributed to The NetBSD Foundation 42 * by Andrew Doran. 43 * 44 * Redistribution and use in source and binary forms, with or without 45 * modification, are permitted provided that the following conditions 46 * are met: 47 * 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 49 * 2. Redistributions in binary form must reproduce the above copyright 50 * notice, this list of conditions and the following disclaimer in the 51 * documentation and/or other materials provided with the distribution. 52 * 3. All advertising materials mentioning features or use of this software 53 * must display the following acknowledgement: 54 * This product includes software developed by the NetBSD 55 * Foundation, Inc. and its contributors. 56 * 4. Neither the name of The NetBSD Foundation nor the names of its 57 * contributors may be used to endorse or promote products derived 58 * from this software without specific prior written permission. 59 * 60 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 61 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 62 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 63 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 64 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 65 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 66 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 67 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 68 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 69 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 70 * POSSIBILITY OF SUCH DAMAGE. 71 */ 72 73 /* 74 * Driver for Compaq array controllers. 75 */ 76 #undef CAC_DEBUG 77 78 #include <sys/param.h> 79 #include <sys/systm.h> 80 #include <sys/kernel.h> 81 #include <sys/device.h> 82 #include <sys/queue.h> 83 #include <sys/proc.h> 84 #include <sys/buf.h> 85 #include <sys/endian.h> 86 #include <sys/malloc.h> 87 #include <sys/pool.h> 88 89 #include <vm/vm.h> 90 #include <uvm/uvm_extern.h> 91 92 #include <machine/bus.h> 93 94 #include <scsi/scsi_all.h> 95 #include <scsi/scsi_disk.h> 96 #include <scsi/scsiconf.h> 97 98 #include <dev/ic/cacreg.h> 99 #include <dev/ic/cacvar.h> 100 101 struct cfdriver cac_cd = { 102 NULL, "cac", DV_DULL 103 }; 104 105 int cac_scsi_cmd __P((struct scsi_xfer *)); 106 void cacminphys __P((struct buf *bp)); 107 108 struct scsi_adapter cac_switch = { 109 cac_scsi_cmd, cacminphys, 0, 0, 110 }; 111 112 struct scsi_device cac_dev = { 113 NULL, NULL, NULL, NULL 114 }; 115 116 struct cac_ccb *cac_ccb_alloc(struct cac_softc *, int); 117 void cac_ccb_done(struct cac_softc *, struct cac_ccb *); 118 void cac_ccb_free(struct cac_softc *, struct cac_ccb *); 119 int cac_ccb_poll(struct cac_softc *, struct cac_ccb *, int); 120 int cac_ccb_start(struct cac_softc *, struct cac_ccb *); 121 int cac_cmd(struct cac_softc *sc, int command, void *data, int datasize, 122 int drive, int blkno, int flags, struct scsi_xfer *xs); 123 int cac_get_dinfo __P((struct cac_softc *sc, int target)); 124 int cac_flush __P((struct cac_softc *sc)); 125 void cac_shutdown __P((void *)); 126 void cac_copy_internal_data __P((struct scsi_xfer *xs, void *v, size_t size)); 127 128 struct cac_ccb *cac_l0_completed(struct cac_softc *); 129 int cac_l0_fifo_full(struct cac_softc *); 130 void cac_l0_intr_enable(struct cac_softc *, int); 131 int cac_l0_intr_pending(struct cac_softc *); 132 void cac_l0_submit(struct cac_softc *, struct cac_ccb *); 133 134 void *cac_sdh; /* shutdown hook */ 135 136 const 137 struct cac_linkage cac_l0 = { 138 cac_l0_completed, 139 cac_l0_fifo_full, 140 cac_l0_intr_enable, 141 cac_l0_intr_pending, 142 cac_l0_submit 143 }; 144 145 /* 146 * Initialise our interface to the controller. 147 */ 148 int 149 cac_init(struct cac_softc *sc, int startfw) 150 { 151 struct cac_controller_info cinfo; 152 int error, rseg, size, i; 153 bus_dma_segment_t seg; 154 struct cac_ccb *ccb; 155 156 SIMPLEQ_INIT(&sc->sc_ccb_free); 157 SIMPLEQ_INIT(&sc->sc_ccb_queue); 158 159 size = sizeof(struct cac_ccb) * CAC_MAX_CCBS; 160 161 if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &seg, 1, 162 &rseg, BUS_DMA_NOWAIT)) != 0) { 163 printf("%s: unable to allocate CCBs, error = %d\n", 164 sc->sc_dv.dv_xname, error); 165 return (-1); 166 } 167 168 if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, 169 (caddr_t *)&sc->sc_ccbs, 170 BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { 171 printf("%s: unable to map CCBs, error = %d\n", 172 sc->sc_dv.dv_xname, error); 173 return (-1); 174 } 175 176 if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 177 BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) { 178 printf("%s: unable to create CCB DMA map, error = %d\n", 179 sc->sc_dv.dv_xname, error); 180 return (-1); 181 } 182 183 if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ccbs, 184 size, NULL, BUS_DMA_NOWAIT)) != 0) { 185 printf("%s: unable to load CCB DMA map, error = %d\n", 186 sc->sc_dv.dv_xname, error); 187 return (-1); 188 } 189 190 sc->sc_ccbs_paddr = sc->sc_dmamap->dm_segs[0].ds_addr; 191 memset(sc->sc_ccbs, 0, size); 192 ccb = (struct cac_ccb *)sc->sc_ccbs; 193 194 for (i = 0; i < CAC_MAX_CCBS; i++, ccb++) { 195 /* Create the DMA map for this CCB's data */ 196 error = bus_dmamap_create(sc->sc_dmat, CAC_MAX_XFER, 197 CAC_SG_SIZE, CAC_MAX_XFER, 0, 198 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 199 &ccb->ccb_dmamap_xfer); 200 201 if (error) { 202 printf("%s: can't create ccb dmamap (%d)\n", 203 sc->sc_dv.dv_xname, error); 204 break; 205 } 206 207 ccb->ccb_flags = 0; 208 ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb); 209 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain); 210 } 211 212 /* Start firmware background tasks, if needed. */ 213 if (startfw) { 214 if (cac_cmd(sc, CAC_CMD_START_FIRMWARE, &cinfo, sizeof(cinfo), 215 0, 0, CAC_CCB_DATA_IN, NULL)) { 216 printf("%s: CAC_CMD_START_FIRMWARE failed\n", 217 sc->sc_dv.dv_xname); 218 return (-1); 219 } 220 } 221 222 if (cac_cmd(sc, CAC_CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), 0, 0, 223 CAC_CCB_DATA_IN, NULL)) { 224 printf("%s: CAC_CMD_GET_CTRL_INFO failed\n", 225 sc->sc_dv.dv_xname); 226 return (-1); 227 } 228 229 if (!cinfo.num_drvs) { 230 printf("%s: no volumes defined\n", sc->sc_dv.dv_xname); 231 return (-1); 232 } 233 234 sc->sc_nunits = cinfo.num_drvs; 235 sc->sc_dinfos = malloc(cinfo.num_drvs * sizeof(struct cac_drive_info), 236 M_DEVBUF, M_NOWAIT); 237 if (sc->sc_dinfos == NULL) { 238 printf("%s: cannot allocate memory for drive_info\n", 239 sc->sc_dv.dv_xname); 240 return (-1); 241 } 242 bzero(sc->sc_dinfos, cinfo.num_drvs * sizeof(struct cac_drive_info)); 243 244 sc->sc_link.adapter_softc = sc; 245 sc->sc_link.adapter = &cac_switch; 246 sc->sc_link.adapter_target = cinfo.num_drvs; 247 sc->sc_link.adapter_buswidth = cinfo.num_drvs; 248 sc->sc_link.device = &cac_dev; 249 sc->sc_link.openings = CAC_MAX_CCBS / sc->sc_nunits; 250 if (sc->sc_link.openings < 4 ) 251 sc->sc_link.openings = 4; 252 253 config_found(&sc->sc_dv, &sc->sc_link, scsiprint); 254 255 /* Set our `shutdownhook' before we start any device activity. */ 256 if (cac_sdh == NULL) 257 cac_sdh = shutdownhook_establish(cac_shutdown, NULL); 258 259 (*sc->sc_cl->cl_intr_enable)(sc, 1); 260 return (0); 261 } 262 263 int 264 cac_flush(sc) 265 struct cac_softc *sc; 266 { 267 u_int8_t buf[512]; 268 269 memset(buf, 0, sizeof(buf)); 270 buf[0] = 1; 271 return cac_cmd(sc, CAC_CMD_FLUSH_CACHE, buf, sizeof(buf), 0, 0, 272 CAC_CCB_DATA_OUT, NULL); 273 } 274 275 /* 276 * Shut down all `cac' controllers. 277 */ 278 void 279 cac_shutdown(void *cookie) 280 { 281 extern struct cfdriver cac_cd; 282 struct cac_softc *sc; 283 int i; 284 285 for (i = 0; i < cac_cd.cd_ndevs; i++) { 286 if ((sc = (struct cac_softc *)device_lookup(&cac_cd, i)) == NULL) 287 continue; 288 cac_flush(sc); 289 } 290 } 291 292 /* 293 * Handle an interrupt from the controller: process finished CCBs and 294 * dequeue any waiting CCBs. 295 */ 296 int 297 cac_intr(v) 298 void *v; 299 { 300 struct cac_softc *sc = v; 301 struct cac_ccb *ccb; 302 int ret = 0; 303 304 if (!(sc->sc_cl->cl_intr_pending)(sc)) 305 return 0; 306 307 while ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL) { 308 ret++; 309 cac_ccb_done(sc, ccb); 310 cac_ccb_start(sc, NULL); 311 } 312 313 return (ret); 314 } 315 316 /* 317 * Execute a [polled] command. 318 */ 319 int 320 cac_cmd(struct cac_softc *sc, int command, void *data, int datasize, 321 int drive, int blkno, int flags, struct scsi_xfer *xs) 322 { 323 struct cac_ccb *ccb; 324 struct cac_sgb *sgb; 325 int i, rv, size, nsegs; 326 327 #ifdef CAC_DEBUG 328 printf("cac_cmd op=%x drv=%d blk=%d data=%p[%x] fl=%x xs=%p ", 329 command, drive, blkno, data, datasize, flags, xs); 330 #endif 331 332 if ((ccb = cac_ccb_alloc(sc, 0)) == NULL) { 333 printf("%s: unable to alloc CCB", sc->sc_dv.dv_xname); 334 return (ENOMEM); 335 } 336 337 if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) { 338 bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer, 339 (void *)data, datasize, NULL, BUS_DMA_NOWAIT); 340 341 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 342 (flags & CAC_CCB_DATA_IN) != 0 ? BUS_DMASYNC_PREREAD : 343 BUS_DMASYNC_PREWRITE); 344 345 sgb = ccb->ccb_seg; 346 nsegs = min(ccb->ccb_dmamap_xfer->dm_nsegs, CAC_SG_SIZE); 347 348 size = 0; 349 for (i = 0; i < nsegs; i++, sgb++) { 350 size += ccb->ccb_dmamap_xfer->dm_segs[i].ds_len; 351 sgb->length = 352 htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len); 353 sgb->addr = 354 htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr); 355 } 356 } else { 357 size = datasize; 358 nsegs = 0; 359 } 360 361 ccb->ccb_hdr.drive = drive; 362 ccb->ccb_hdr.size = htole16((sizeof(struct cac_req) + 363 sizeof(struct cac_sgb) * CAC_SG_SIZE) >> 2); 364 365 ccb->ccb_req.bcount = htole16(howmany(size, DEV_BSIZE)); 366 ccb->ccb_req.command = command; 367 ccb->ccb_req.sgcount = nsegs; 368 ccb->ccb_req.blkno = htole32(blkno); 369 370 ccb->ccb_flags = flags; 371 ccb->ccb_datasize = size; 372 ccb->ccb_xs = xs; 373 374 if (!xs || xs->flags & SCSI_POLL) { 375 int s; 376 377 s = splbio(); 378 379 /* Synchronous commands musn't wait. */ 380 if ((*sc->sc_cl->cl_fifo_full)(sc)) { 381 cac_ccb_free(sc, ccb); 382 rv = -1; 383 } else { 384 ccb->ccb_flags |= CAC_CCB_ACTIVE; 385 (*sc->sc_cl->cl_submit)(sc, ccb); 386 rv = cac_ccb_poll(sc, ccb, 2000); 387 } 388 splx(s); 389 } else 390 rv = cac_ccb_start(sc, ccb); 391 392 return (rv); 393 } 394 395 /* 396 * Wait for the specified CCB to complete. Must be called at splbio. 397 */ 398 int 399 cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo) 400 { 401 struct cac_ccb *ccb; 402 403 timo *= 10; 404 405 do { 406 for (; timo > 0; timo--) { 407 if ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL) 408 break; 409 DELAY(100); 410 } 411 412 if (timo <= 0) { 413 printf("%s: timeout\n", sc->sc_dv.dv_xname); 414 return (EBUSY); 415 } 416 cac_ccb_done(sc, ccb); 417 } while (ccb != wantccb); 418 419 return (0); 420 } 421 422 /* 423 * Enqueue the specifed command (if any) and attempt to start all enqueued 424 * commands. Must be called at splbio. 425 */ 426 int 427 cac_ccb_start(struct cac_softc *sc, struct cac_ccb *ccb) 428 { 429 430 if (ccb != NULL) 431 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain); 432 433 while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue)) != NULL) { 434 if ((*sc->sc_cl->cl_fifo_full)(sc)) 435 return (EBUSY); 436 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb, ccb_chain); 437 ccb->ccb_flags |= CAC_CCB_ACTIVE; 438 (*sc->sc_cl->cl_submit)(sc, ccb); 439 } 440 441 return (0); 442 } 443 444 /* 445 * Process a finished CCB. 446 */ 447 void 448 cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb) 449 { 450 struct scsi_xfer *xs = ccb->ccb_xs; 451 int error = 0; 452 453 if ((ccb->ccb_flags & CAC_CCB_ACTIVE) == 0) { 454 #ifdef CAC_DEBUG 455 printf("%s: CCB not active, xs=%p\n", sc->sc_dv.dv_xname, xs); 456 #endif 457 if (xs) { 458 xs->error = XS_DRIVER_STUFFUP; 459 scsi_done(xs); 460 } 461 return; 462 } 463 ccb->ccb_flags &= ~CAC_CCB_ACTIVE; 464 465 if ((ccb->ccb_flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) { 466 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 467 ccb->ccb_flags & CAC_CCB_DATA_IN ? 468 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 469 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer); 470 } 471 472 if ((ccb->ccb_req.error & CAC_RET_SOFT_ERROR) != 0) 473 printf("%s: soft error; corrected\n", sc->sc_dv.dv_xname); 474 if ((ccb->ccb_req.error & CAC_RET_HARD_ERROR) != 0) { 475 error = 1; 476 printf("%s: hard error\n", sc->sc_dv.dv_xname); 477 } 478 if ((ccb->ccb_req.error & CAC_RET_CMD_REJECTED) != 0) { 479 error = 1; 480 printf("%s: invalid request\n", sc->sc_dv.dv_xname); 481 } 482 483 if (xs) { 484 if (error) 485 xs->error = XS_DRIVER_STUFFUP; 486 else { 487 xs->resid = 0; 488 xs->flags |= ITSDONE; 489 } 490 491 scsi_done(xs); 492 } 493 cac_ccb_free(sc, ccb); 494 } 495 496 /* 497 * Allocate a CCB. 498 */ 499 struct cac_ccb * 500 cac_ccb_alloc(struct cac_softc *sc, int nosleep) 501 { 502 struct cac_ccb *ccb; 503 int s; 504 505 s = splbio(); 506 507 for (;;) { 508 if ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free)) != NULL) { 509 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb, ccb_chain); 510 break; 511 } 512 if (nosleep) { 513 ccb = NULL; 514 break; 515 } 516 tsleep(&sc->sc_ccb_free, PRIBIO, "cacccb", 0); 517 } 518 519 splx(s); 520 return (ccb); 521 } 522 523 /* 524 * Put a CCB onto the freelist. 525 */ 526 void 527 cac_ccb_free(struct cac_softc *sc, struct cac_ccb *ccb) 528 { 529 int s; 530 531 ccb->ccb_flags = 0; 532 s = splbio(); 533 SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain); 534 if (SIMPLEQ_NEXT(ccb, ccb_chain) == NULL) 535 wakeup(&sc->sc_ccb_free); 536 splx(s); 537 } 538 539 int 540 cac_get_dinfo(sc, target) 541 struct cac_softc *sc; 542 int target; 543 { 544 if (sc->sc_dinfos[target].ncylinders) 545 return (0); 546 547 if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &sc->sc_dinfos[target], 548 sizeof(*sc->sc_dinfos), target, 0, CAC_CCB_DATA_IN, NULL)) { 549 printf("%s: CMD_GET_LOG_DRV_INFO failed\n", 550 sc->sc_dv.dv_xname); 551 return (-1); 552 } 553 554 return (0); 555 } 556 557 void 558 cacminphys(bp) 559 struct buf *bp; 560 { 561 if (bp->b_bcount > CAC_MAX_XFER) 562 bp->b_bcount = CAC_MAX_XFER; 563 minphys(bp); 564 } 565 566 void 567 cac_copy_internal_data(xs, v, size) 568 struct scsi_xfer *xs; 569 void *v; 570 size_t size; 571 { 572 size_t copy_cnt; 573 574 if (!xs->datalen) 575 printf("uio move is not yet supported\n"); 576 else { 577 copy_cnt = MIN(size, xs->datalen); 578 bcopy(v, xs->data, copy_cnt); 579 } 580 } 581 582 int 583 cac_scsi_cmd(xs) 584 struct scsi_xfer *xs; 585 { 586 struct scsi_link *link = xs->sc_link; 587 struct cac_softc *sc = link->adapter_softc; 588 struct cac_drive_info *dinfo; 589 struct scsi_inquiry_data inq; 590 struct scsi_sense_data sd; 591 struct { 592 struct scsi_mode_header hd; 593 struct scsi_blk_desc bd; 594 union scsi_disk_pages dp; 595 } mpd; 596 struct scsi_read_cap_data rcd; 597 u_int8_t target = link->target; 598 u_int32_t blockno, blockcnt, size; 599 struct scsi_rw *rw; 600 struct scsi_rw_big *rwb; 601 int op, flags, s; 602 const char *p; 603 604 if (target >= sc->sc_nunits || link->lun != 0) { 605 xs->error = XS_DRIVER_STUFFUP; 606 return (COMPLETE); 607 } 608 609 xs->error = XS_NOERROR; 610 dinfo = &sc->sc_dinfos[target]; 611 612 switch (xs->cmd->opcode) { 613 case TEST_UNIT_READY: 614 case START_STOP: 615 #if 0 616 case VERIFY: 617 #endif 618 break; 619 620 case REQUEST_SENSE: 621 bzero(&sd, sizeof sd); 622 sd.error_code = 0x70; 623 sd.segment = 0; 624 sd.flags = SKEY_NO_SENSE; 625 *(u_int32_t*)sd.info = htole32(0); 626 sd.extra_len = 0; 627 cac_copy_internal_data(xs, &sd, sizeof sd); 628 break; 629 630 case INQUIRY: 631 if (cac_get_dinfo(sc, target)) { 632 xs->error = XS_DRIVER_STUFFUP; 633 scsi_done(xs); 634 return (COMPLETE); 635 } 636 bzero(&inq, sizeof inq); 637 inq.device = T_DIRECT; 638 inq.dev_qual2 = 0; 639 inq.version = 2; 640 inq.response_format = 2; 641 inq.additional_length = 32; 642 strcpy(inq.vendor, "Compaq "); 643 switch (CAC_GET1(dinfo->mirror)) { 644 case 0: p = "RAID0"; break; 645 case 1: p = "RAID4"; break; 646 case 2: p = "RAID1"; break; 647 case 3: p = "RAID5"; break; 648 default:p = "<UNK>"; break; 649 } 650 sprintf(inq.product, "%s volume #%02d", p, target); 651 strcpy(inq.revision, " "); 652 cac_copy_internal_data(xs, &inq, sizeof inq); 653 break; 654 655 case MODE_SENSE: 656 if (cac_get_dinfo(sc, target)) { 657 xs->error = XS_DRIVER_STUFFUP; 658 scsi_done(xs); 659 return (COMPLETE); 660 } 661 bzero(&mpd, sizeof mpd); 662 switch (((struct scsi_mode_sense *)xs->cmd)->page) { 663 case 4: 664 /* scsi_disk.h says this should be 0x16 */ 665 mpd.dp.rigid_geometry.pg_length = 0x16; 666 mpd.hd.data_length = sizeof mpd.hd + sizeof mpd.bd + 667 mpd.dp.rigid_geometry.pg_length; 668 mpd.hd.blk_desc_len = sizeof mpd.bd; 669 670 /* XXX */ 671 mpd.hd.dev_spec = 0; 672 _lto3b(CAC_SECTOR_SIZE, mpd.bd.blklen); 673 mpd.dp.rigid_geometry.pg_code = 4; 674 _lto3b(CAC_GET2(dinfo->ncylinders), 675 mpd.dp.rigid_geometry.ncyl); 676 mpd.dp.rigid_geometry.nheads = 677 CAC_GET1(dinfo->nheads); 678 cac_copy_internal_data(xs, (u_int8_t *)&mpd, 679 sizeof mpd); 680 break; 681 682 default: 683 printf("%s: mode sense page %d not simulated\n", 684 sc->sc_dv.dv_xname, 685 ((struct scsi_mode_sense *)xs->cmd)->page); 686 xs->error = XS_DRIVER_STUFFUP; 687 return (TRY_AGAIN_LATER); 688 } 689 break; 690 691 case READ_CAPACITY: 692 if (cac_get_dinfo(sc, target)) { 693 xs->error = XS_DRIVER_STUFFUP; 694 scsi_done(xs); 695 return (COMPLETE); 696 } 697 bzero(&rcd, sizeof rcd); 698 _lto4b( CAC_GET2(dinfo->ncylinders) * CAC_GET1(dinfo->nheads) * 699 CAC_GET1(dinfo->nsectors), rcd.addr); 700 _lto4b(CAC_SECTOR_SIZE, rcd.length); 701 cac_copy_internal_data(xs, &rcd, sizeof rcd); 702 break; 703 704 case PREVENT_ALLOW: 705 return (COMPLETE); 706 707 case SYNCHRONIZE_CACHE: 708 s = splbio(); 709 if (cac_flush(sc)) { 710 splx(s); 711 xs->error = XS_DRIVER_STUFFUP; 712 scsi_done(xs); 713 } else 714 splx(s); 715 return (COMPLETE); 716 717 718 case READ_COMMAND: 719 case READ_BIG: 720 case WRITE_COMMAND: 721 case WRITE_BIG: 722 s = splbio(); 723 724 flags = 0; 725 if (xs->cmd->opcode != SYNCHRONIZE_CACHE) { 726 /* A read or write operation. */ 727 if (xs->cmdlen == 6) { 728 rw = (struct scsi_rw *)xs->cmd; 729 blockno = _3btol(rw->addr) & 730 (SRW_TOPADDR << 16 | 0xffff); 731 blockcnt = rw->length ? rw->length : 0x100; 732 } else { 733 rwb = (struct scsi_rw_big *)xs->cmd; 734 blockno = _4btol(rwb->addr); 735 blockcnt = _2btol(rwb->length); 736 } 737 size = CAC_GET2(dinfo->ncylinders) * 738 CAC_GET1(dinfo->nheads) * 739 CAC_GET1(dinfo->nsectors); 740 if (blockno >= size || blockno + blockcnt > size) { 741 splx(s); 742 printf("%s: out of bounds %u-%u >= %u\n", 743 sc->sc_dv.dv_xname, blockno, blockcnt, 744 size); 745 xs->error = XS_DRIVER_STUFFUP; 746 scsi_done(xs); 747 return (COMPLETE); 748 } 749 } 750 751 switch (xs->cmd->opcode) { 752 case READ_COMMAND: 753 case READ_BIG: 754 op = CAC_CMD_READ; 755 flags = CAC_CCB_DATA_IN; 756 break; 757 case WRITE_COMMAND: 758 case WRITE_BIG: 759 op = CAC_CMD_WRITE; 760 flags = CAC_CCB_DATA_OUT; 761 break; 762 } 763 764 if (cac_cmd(sc, op, xs->data, blockcnt * DEV_BSIZE, target, 765 blockno, flags, xs)) { 766 767 splx(s); 768 if (xs->flags & SCSI_POLL) { 769 xs->error = XS_TIMEOUT; 770 return (TRY_AGAIN_LATER); 771 } else { 772 xs->error = XS_DRIVER_STUFFUP; 773 scsi_done(xs); 774 return (COMPLETE); 775 } 776 } 777 778 splx(s); 779 780 if (xs->flags & SCSI_POLL) 781 return (COMPLETE); 782 else 783 return (SUCCESSFULLY_QUEUED); 784 785 default: 786 xs->error = XS_DRIVER_STUFFUP; 787 } 788 789 return (COMPLETE); 790 } 791 792 /* 793 * Board specific linkage shared between multiple bus types. 794 */ 795 796 int 797 cac_l0_fifo_full(struct cac_softc *sc) 798 { 799 800 return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0); 801 } 802 803 void 804 cac_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb) 805 { 806 #ifdef CAC_DEBUG 807 printf("submit-%x ", ccb->ccb_paddr); 808 #endif 809 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 810 BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 811 cac_outl(sc, CAC_REG_CMD_FIFO, ccb->ccb_paddr); 812 } 813 814 struct cac_ccb * 815 cac_l0_completed(sc) 816 struct cac_softc *sc; 817 { 818 struct cac_ccb *ccb; 819 paddr_t off; 820 821 if (!(off = cac_inl(sc, CAC_REG_DONE_FIFO))) 822 return NULL; 823 #ifdef CAC_DEBUG 824 printf("compl-%x ", off); 825 #endif 826 ccb = (struct cac_ccb *)(sc->sc_ccbs + 827 ((off & ~3) - sc->sc_ccbs_paddr)); 828 829 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 830 BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); 831 832 return (ccb); 833 } 834 835 int 836 cac_l0_intr_pending(struct cac_softc *sc) 837 { 838 839 return (cac_inl(sc, CAC_REG_INTR_PENDING)); 840 } 841 842 void 843 cac_l0_intr_enable(struct cac_softc *sc, int state) 844 { 845 846 cac_outl(sc, CAC_REG_INTR_MASK, 847 state ? CAC_INTR_ENABLE : CAC_INTR_DISABLE); 848 } 849