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