1 /* $OpenBSD: cac.c,v 1.48 2011/07/17 22:46:48 matthew 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 * 48 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 49 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 50 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 51 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 52 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 53 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 54 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 55 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 56 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 57 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 58 * POSSIBILITY OF SUCH DAMAGE. 59 */ 60 61 /* 62 * Driver for Compaq array controllers. 63 */ 64 65 #include "bio.h" 66 67 /* #define CAC_DEBUG */ 68 69 #include <sys/param.h> 70 #include <sys/systm.h> 71 #include <sys/kernel.h> 72 #include <sys/ioctl.h> 73 #include <sys/device.h> 74 #include <sys/queue.h> 75 #include <sys/proc.h> 76 #include <sys/buf.h> 77 #include <sys/endian.h> 78 #include <sys/malloc.h> 79 #include <sys/pool.h> 80 81 #include <machine/bus.h> 82 83 #include <scsi/scsi_all.h> 84 #include <scsi/scsi_disk.h> 85 #include <scsi/scsiconf.h> 86 87 #include <dev/ic/cacreg.h> 88 #include <dev/ic/cacvar.h> 89 90 #if NBIO > 0 91 #include <dev/biovar.h> 92 #endif 93 #include <sys/sensors.h> 94 95 struct cfdriver cac_cd = { 96 NULL, "cac", DV_DULL 97 }; 98 99 void cac_scsi_cmd(struct scsi_xfer *); 100 void cacminphys(struct buf *bp, struct scsi_link *sl); 101 102 struct scsi_adapter cac_switch = { 103 cac_scsi_cmd, cacminphys, 0, 0, 104 }; 105 106 void *cac_ccb_alloc(void *); 107 void cac_ccb_done(struct cac_softc *, struct cac_ccb *); 108 void cac_ccb_free(void *, void *); 109 int cac_ccb_poll(struct cac_softc *, struct cac_ccb *, int); 110 int cac_ccb_start(struct cac_softc *, struct cac_ccb *); 111 int cac_cmd(struct cac_softc *sc, int command, void *data, int datasize, 112 int drive, int blkno, int flags, struct scsi_xfer *xs); 113 int cac_get_dinfo(struct cac_softc *sc, int target); 114 int cac_flush(struct cac_softc *sc); 115 void cac_shutdown(void *); 116 void cac_copy_internal_data(struct scsi_xfer *xs, void *v, size_t size); 117 118 struct cac_ccb *cac_l0_completed(struct cac_softc *); 119 int cac_l0_fifo_full(struct cac_softc *); 120 void cac_l0_intr_enable(struct cac_softc *, int); 121 int cac_l0_intr_pending(struct cac_softc *); 122 void cac_l0_submit(struct cac_softc *, struct cac_ccb *); 123 124 #if NBIO > 0 125 int cac_ioctl(struct device *, u_long, caddr_t); 126 int cac_ioctl_vol(struct cac_softc *, struct bioc_vol *); 127 128 #ifndef SMALL_KERNEL 129 int cac_create_sensors(struct cac_softc *); 130 void cac_sensor_refresh(void *); 131 #endif 132 #endif /* NBIO > 0 */ 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 scsibus_attach_args saa; 152 struct cac_controller_info cinfo; 153 int error, rseg, size, i; 154 bus_dma_segment_t seg[1]; 155 struct cac_ccb *ccb; 156 157 SIMPLEQ_INIT(&sc->sc_ccb_free); 158 SIMPLEQ_INIT(&sc->sc_ccb_queue); 159 mtx_init(&sc->sc_ccb_mtx, IPL_BIO); 160 scsi_iopool_init(&sc->sc_iopool, sc, cac_ccb_alloc, cac_ccb_free); 161 162 size = sizeof(struct cac_ccb) * CAC_MAX_CCBS; 163 164 if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, seg, 1, 165 &rseg, BUS_DMA_NOWAIT | BUS_DMA_ZERO)) != 0) { 166 printf("%s: unable to allocate CCBs, error = %d\n", 167 sc->sc_dv.dv_xname, error); 168 return (-1); 169 } 170 171 if ((error = bus_dmamem_map(sc->sc_dmat, seg, rseg, size, 172 &sc->sc_ccbs, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { 173 printf("%s: unable to map CCBs, error = %d\n", 174 sc->sc_dv.dv_xname, error); 175 return (-1); 176 } 177 178 if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 179 BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) { 180 printf("%s: unable to create CCB DMA map, error = %d\n", 181 sc->sc_dv.dv_xname, error); 182 return (-1); 183 } 184 185 if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ccbs, 186 size, NULL, BUS_DMA_NOWAIT)) != 0) { 187 printf("%s: unable to load CCB DMA map, error = %d\n", 188 sc->sc_dv.dv_xname, error); 189 return (-1); 190 } 191 192 sc->sc_ccbs_paddr = sc->sc_dmamap->dm_segs[0].ds_addr; 193 ccb = (struct cac_ccb *)sc->sc_ccbs; 194 195 for (i = 0; i < CAC_MAX_CCBS; i++, ccb++) { 196 /* Create the DMA map for this CCB's data */ 197 error = bus_dmamap_create(sc->sc_dmat, CAC_MAX_XFER, 198 CAC_SG_SIZE, CAC_MAX_XFER, 0, 199 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 200 &ccb->ccb_dmamap_xfer); 201 202 if (error) { 203 printf("%s: can't create ccb dmamap (%d)\n", 204 sc->sc_dv.dv_xname, error); 205 break; 206 } 207 208 ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb); 209 mtx_enter(&sc->sc_ccb_mtx); 210 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain); 211 mtx_leave(&sc->sc_ccb_mtx); 212 } 213 214 /* Start firmware background tasks, if needed. */ 215 if (startfw) { 216 if (cac_cmd(sc, CAC_CMD_START_FIRMWARE, &cinfo, sizeof(cinfo), 217 0, 0, CAC_CCB_DATA_IN, NULL)) { 218 printf("%s: CAC_CMD_START_FIRMWARE failed\n", 219 sc->sc_dv.dv_xname); 220 return (-1); 221 } 222 } 223 224 if (cac_cmd(sc, CAC_CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), 0, 0, 225 CAC_CCB_DATA_IN, NULL)) { 226 printf("%s: CAC_CMD_GET_CTRL_INFO failed\n", 227 sc->sc_dv.dv_xname); 228 return (-1); 229 } 230 231 if (!cinfo.num_drvs) { 232 printf("%s: no volumes defined\n", sc->sc_dv.dv_xname); 233 return (-1); 234 } 235 236 sc->sc_nunits = cinfo.num_drvs; 237 sc->sc_dinfos = malloc(cinfo.num_drvs * sizeof(struct cac_drive_info), 238 M_DEVBUF, M_NOWAIT | M_ZERO); 239 if (sc->sc_dinfos == NULL) { 240 printf("%s: cannot allocate memory for drive_info\n", 241 sc->sc_dv.dv_xname); 242 return (-1); 243 } 244 245 sc->sc_link.adapter_softc = sc; 246 sc->sc_link.adapter = &cac_switch; 247 sc->sc_link.adapter_target = cinfo.num_drvs; 248 sc->sc_link.adapter_buswidth = cinfo.num_drvs; 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 sc->sc_link.pool = &sc->sc_iopool; 253 254 bzero(&saa, sizeof(saa)); 255 saa.saa_sc_link = &sc->sc_link; 256 257 config_found(&sc->sc_dv, &saa, scsiprint); 258 259 /* Set our `shutdownhook' before we start any device activity. */ 260 if (cac_sdh == NULL) 261 cac_sdh = shutdownhook_establish(cac_shutdown, NULL); 262 263 (*sc->sc_cl->cl_intr_enable)(sc, 1); 264 265 #if NBIO > 0 266 if (bio_register(&sc->sc_dv, cac_ioctl) != 0) 267 printf("%s: controller registration failed\n", 268 sc->sc_dv.dv_xname); 269 else 270 sc->sc_ioctl = cac_ioctl; 271 272 #ifndef SMALL_KERNEL 273 if (cac_create_sensors(sc) != 0) 274 printf("%s: unable to create sensors\n", sc->sc_dv.dv_xname); 275 #endif 276 #endif 277 278 279 return (0); 280 } 281 282 int 283 cac_flush(sc) 284 struct cac_softc *sc; 285 { 286 u_int8_t buf[512]; 287 288 memset(buf, 0, sizeof(buf)); 289 buf[0] = 1; 290 return cac_cmd(sc, CAC_CMD_FLUSH_CACHE, buf, sizeof(buf), 0, 0, 291 CAC_CCB_DATA_OUT, NULL); 292 } 293 294 /* 295 * Shut down all `cac' controllers. 296 */ 297 void 298 cac_shutdown(void *cookie) 299 { 300 extern struct cfdriver cac_cd; 301 struct cac_softc *sc; 302 int i; 303 304 for (i = 0; i < cac_cd.cd_ndevs; i++) { 305 if ((sc = (struct cac_softc *)device_lookup(&cac_cd, i)) == NULL) 306 continue; 307 cac_flush(sc); 308 } 309 } 310 311 /* 312 * Handle an interrupt from the controller: process finished CCBs and 313 * dequeue any waiting CCBs. 314 */ 315 int 316 cac_intr(v) 317 void *v; 318 { 319 struct cac_softc *sc = v; 320 struct cac_ccb *ccb; 321 int istat, ret = 0; 322 323 if (!(istat = (*sc->sc_cl->cl_intr_pending)(sc))) 324 return 0; 325 326 if (istat & CAC_INTR_FIFO_NEMPTY) 327 while ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL) { 328 ret = 1; 329 cac_ccb_done(sc, ccb); 330 } 331 cac_ccb_start(sc, NULL); 332 333 return (ret); 334 } 335 336 /* 337 * Execute a [polled] command. 338 */ 339 int 340 cac_cmd(struct cac_softc *sc, int command, void *data, int datasize, 341 int drive, int blkno, int flags, struct scsi_xfer *xs) 342 { 343 struct cac_ccb *ccb; 344 struct cac_sgb *sgb; 345 int i, rv, size, nsegs; 346 347 #ifdef CAC_DEBUG 348 printf("cac_cmd op=%x drv=%d blk=%d data=%p[%x] fl=%x xs=%p ", 349 command, drive, blkno, data, datasize, flags, xs); 350 #endif 351 352 if (xs) { 353 ccb = xs->io; 354 /* 355 * The xs may have been restarted by the scsi layer, so 356 * ensure the ccb starts in the proper state. 357 */ 358 ccb->ccb_flags = 0; 359 } else { 360 /* Internal command. Need to get our own ccb. */ 361 ccb = scsi_io_get(&sc->sc_iopool, SCSI_POLL | SCSI_NOSLEEP); 362 if (ccb == NULL) 363 return (EBUSY); 364 } 365 366 if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) { 367 bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer, 368 (void *)data, datasize, NULL, BUS_DMA_NOWAIT); 369 370 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0, 371 ccb->ccb_dmamap_xfer->dm_mapsize, 372 (flags & CAC_CCB_DATA_IN) != 0 ? BUS_DMASYNC_PREREAD : 373 BUS_DMASYNC_PREWRITE); 374 375 sgb = ccb->ccb_seg; 376 nsegs = ccb->ccb_dmamap_xfer->dm_nsegs; 377 if (nsegs > CAC_SG_SIZE) 378 panic("cac_cmd: nsegs botch"); 379 380 size = 0; 381 for (i = 0; i < nsegs; i++, sgb++) { 382 size += ccb->ccb_dmamap_xfer->dm_segs[i].ds_len; 383 sgb->length = 384 htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len); 385 sgb->addr = 386 htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr); 387 } 388 } else { 389 size = datasize; 390 nsegs = 0; 391 } 392 393 ccb->ccb_hdr.drive = drive; 394 ccb->ccb_hdr.priority = 0; 395 ccb->ccb_hdr.size = htole16((sizeof(struct cac_req) + 396 sizeof(struct cac_sgb) * CAC_SG_SIZE) >> 2); 397 398 ccb->ccb_req.next = 0; 399 ccb->ccb_req.command = command; 400 ccb->ccb_req.error = 0; 401 ccb->ccb_req.blkno = htole32(blkno); 402 ccb->ccb_req.bcount = htole16(howmany(size, DEV_BSIZE)); 403 ccb->ccb_req.sgcount = nsegs; 404 ccb->ccb_req.reserved = 0; 405 406 ccb->ccb_flags = flags; 407 ccb->ccb_datasize = size; 408 ccb->ccb_xs = xs; 409 410 if (!xs || xs->flags & SCSI_POLL) { 411 /* Synchronous commands musn't wait. */ 412 mtx_enter(&sc->sc_ccb_mtx); 413 if ((*sc->sc_cl->cl_fifo_full)(sc)) { 414 mtx_leave(&sc->sc_ccb_mtx); 415 rv = EBUSY; 416 } else { 417 mtx_leave(&sc->sc_ccb_mtx); 418 ccb->ccb_flags |= CAC_CCB_ACTIVE; 419 (*sc->sc_cl->cl_submit)(sc, ccb); 420 rv = cac_ccb_poll(sc, ccb, 2000); 421 } 422 } else 423 rv = cac_ccb_start(sc, ccb); 424 425 if (xs == NULL) 426 scsi_io_put(&sc->sc_iopool, ccb); 427 428 return (rv); 429 } 430 431 /* 432 * Wait for the specified CCB to complete. Must be called at splbio. 433 */ 434 int 435 cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo) 436 { 437 struct cac_ccb *ccb; 438 int t; 439 440 t = timo * 100; 441 do { 442 for (; t--; DELAY(10)) 443 if ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL) 444 break; 445 if (t < 0) { 446 printf("%s: timeout\n", sc->sc_dv.dv_xname); 447 return (EBUSY); 448 } 449 cac_ccb_done(sc, ccb); 450 } while (ccb != wantccb); 451 452 return (0); 453 } 454 455 /* 456 * Enqueue the specified command (if any) and attempt to start all enqueued 457 * commands. 458 */ 459 int 460 cac_ccb_start(struct cac_softc *sc, struct cac_ccb *ccb) 461 { 462 if (ccb != NULL) { 463 mtx_enter(&sc->sc_ccb_mtx); 464 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain); 465 mtx_leave(&sc->sc_ccb_mtx); 466 } 467 468 while (1) { 469 mtx_enter(&sc->sc_ccb_mtx); 470 if (SIMPLEQ_EMPTY(&sc->sc_ccb_queue) || 471 (*sc->sc_cl->cl_fifo_full)(sc)) { 472 mtx_leave(&sc->sc_ccb_mtx); 473 break; 474 } 475 ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue); 476 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain); 477 mtx_leave(&sc->sc_ccb_mtx); 478 479 ccb->ccb_flags |= CAC_CCB_ACTIVE; 480 (*sc->sc_cl->cl_submit)(sc, ccb); 481 } 482 483 return (0); 484 } 485 486 /* 487 * Process a finished CCB. 488 */ 489 void 490 cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb) 491 { 492 struct scsi_xfer *xs = ccb->ccb_xs; 493 int error = 0; 494 495 if ((ccb->ccb_flags & CAC_CCB_ACTIVE) == 0) { 496 printf("%s: CCB not active, xs=%p\n", sc->sc_dv.dv_xname, xs); 497 if (xs) { 498 xs->error = XS_DRIVER_STUFFUP; 499 scsi_done(xs); 500 } 501 return; 502 } 503 504 if ((ccb->ccb_flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) { 505 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0, 506 ccb->ccb_dmamap_xfer->dm_mapsize, 507 ccb->ccb_flags & CAC_CCB_DATA_IN ? 508 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 509 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer); 510 } 511 512 if ((ccb->ccb_req.error & CAC_RET_SOFT_ERROR) != 0) 513 printf("%s: soft error; corrected\n", sc->sc_dv.dv_xname); 514 if ((ccb->ccb_req.error & CAC_RET_HARD_ERROR) != 0) { 515 error = 1; 516 printf("%s: hard error\n", sc->sc_dv.dv_xname); 517 } 518 if ((ccb->ccb_req.error & CAC_RET_CMD_REJECTED) != 0) { 519 error = 1; 520 printf("%s: invalid request\n", sc->sc_dv.dv_xname); 521 } 522 523 if (xs) { 524 if (error) 525 xs->error = XS_DRIVER_STUFFUP; 526 else 527 xs->resid = 0; 528 529 scsi_done(xs); 530 } 531 } 532 533 /* 534 * Allocate a CCB. 535 */ 536 void * 537 cac_ccb_alloc(void *xsc) 538 { 539 struct cac_softc *sc = xsc; 540 struct cac_ccb *ccb = NULL; 541 542 mtx_enter(&sc->sc_ccb_mtx); 543 if (SIMPLEQ_EMPTY(&sc->sc_ccb_free)) { 544 #ifdef CAC_DEBUG 545 printf("%s: unable to alloc CCB\n", sc->sc_dv.dv_xname); 546 #endif 547 } else { 548 ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free); 549 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb_chain); 550 } 551 mtx_leave(&sc->sc_ccb_mtx); 552 553 return (ccb); 554 } 555 556 /* 557 * Put a CCB onto the freelist. 558 */ 559 void 560 cac_ccb_free(void *xsc, void *xccb) 561 { 562 struct cac_softc *sc = xsc; 563 struct cac_ccb *ccb = xccb; 564 565 ccb->ccb_flags = 0; 566 567 mtx_enter(&sc->sc_ccb_mtx); 568 SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain); 569 mtx_leave(&sc->sc_ccb_mtx); 570 } 571 572 int 573 cac_get_dinfo(sc, target) 574 struct cac_softc *sc; 575 int target; 576 { 577 if (sc->sc_dinfos[target].ncylinders) 578 return (0); 579 580 if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &sc->sc_dinfos[target], 581 sizeof(*sc->sc_dinfos), target, 0, CAC_CCB_DATA_IN, NULL)) { 582 printf("%s: CMD_GET_LOG_DRV_INFO failed\n", 583 sc->sc_dv.dv_xname); 584 return (-1); 585 } 586 587 return (0); 588 } 589 590 void 591 cacminphys(struct buf *bp, struct scsi_link *sl) 592 { 593 if (bp->b_bcount > CAC_MAX_XFER) 594 bp->b_bcount = CAC_MAX_XFER; 595 minphys(bp); 596 } 597 598 void 599 cac_copy_internal_data(xs, v, size) 600 struct scsi_xfer *xs; 601 void *v; 602 size_t size; 603 { 604 size_t copy_cnt; 605 606 if (!xs->datalen) 607 printf("uio move is not yet supported\n"); 608 else { 609 copy_cnt = MIN(size, xs->datalen); 610 bcopy(v, xs->data, copy_cnt); 611 } 612 } 613 614 void 615 cac_scsi_cmd(xs) 616 struct scsi_xfer *xs; 617 { 618 struct scsi_link *link = xs->sc_link; 619 struct cac_softc *sc = link->adapter_softc; 620 struct cac_drive_info *dinfo; 621 struct scsi_inquiry_data inq; 622 struct scsi_sense_data sd; 623 struct scsi_read_cap_data rcd; 624 u_int8_t target = link->target; 625 u_int32_t blockno, blockcnt, size; 626 struct scsi_rw *rw; 627 struct scsi_rw_big *rwb; 628 int op, flags, s, error; 629 const char *p; 630 631 if (target >= sc->sc_nunits || link->lun != 0) { 632 xs->error = XS_DRIVER_STUFFUP; 633 scsi_done(xs); 634 return; 635 } 636 637 s = splbio(); 638 xs->error = XS_NOERROR; 639 dinfo = &sc->sc_dinfos[target]; 640 641 switch (xs->cmd->opcode) { 642 case TEST_UNIT_READY: 643 case START_STOP: 644 #if 0 645 case VERIFY: 646 #endif 647 break; 648 649 case REQUEST_SENSE: 650 bzero(&sd, sizeof sd); 651 sd.error_code = SSD_ERRCODE_CURRENT; 652 sd.segment = 0; 653 sd.flags = SKEY_NO_SENSE; 654 *(u_int32_t*)sd.info = htole32(0); 655 sd.extra_len = 0; 656 cac_copy_internal_data(xs, &sd, sizeof sd); 657 break; 658 659 case INQUIRY: 660 if (cac_get_dinfo(sc, target)) { 661 xs->error = XS_DRIVER_STUFFUP; 662 break; 663 } 664 bzero(&inq, sizeof inq); 665 inq.device = T_DIRECT; 666 inq.dev_qual2 = 0; 667 inq.version = 2; 668 inq.response_format = 2; 669 inq.additional_length = 32; 670 inq.flags |= SID_CmdQue; 671 strlcpy(inq.vendor, "Compaq ", sizeof inq.vendor); 672 switch (CAC_GET1(dinfo->mirror)) { 673 case 0: p = "RAID0"; break; 674 case 1: p = "RAID4"; break; 675 case 2: p = "RAID1"; break; 676 case 3: p = "RAID5"; break; 677 default:p = "<UNK>"; break; 678 } 679 snprintf(inq.product, sizeof inq.product, "%s vol #%02d", 680 p, target); 681 strlcpy(inq.revision, " ", sizeof inq.revision); 682 cac_copy_internal_data(xs, &inq, sizeof inq); 683 break; 684 685 case READ_CAPACITY: 686 if (cac_get_dinfo(sc, target)) { 687 xs->error = XS_DRIVER_STUFFUP; 688 break; 689 } 690 bzero(&rcd, sizeof rcd); 691 _lto4b( CAC_GET2(dinfo->ncylinders) * CAC_GET1(dinfo->nheads) * 692 CAC_GET1(dinfo->nsectors) - 1, rcd.addr); 693 _lto4b(CAC_SECTOR_SIZE, rcd.length); 694 cac_copy_internal_data(xs, &rcd, sizeof rcd); 695 break; 696 697 case PREVENT_ALLOW: 698 break; 699 700 case SYNCHRONIZE_CACHE: 701 if (cac_flush(sc)) 702 xs->error = XS_DRIVER_STUFFUP; 703 break; 704 705 case READ_COMMAND: 706 case READ_BIG: 707 case WRITE_COMMAND: 708 case WRITE_BIG: 709 710 flags = 0; 711 /* A read or write operation. */ 712 if (xs->cmdlen == 6) { 713 rw = (struct scsi_rw *)xs->cmd; 714 blockno = _3btol(rw->addr) & 715 (SRW_TOPADDR << 16 | 0xffff); 716 blockcnt = rw->length ? rw->length : 0x100; 717 } else { 718 rwb = (struct scsi_rw_big *)xs->cmd; 719 blockno = _4btol(rwb->addr); 720 blockcnt = _2btol(rwb->length); 721 } 722 size = CAC_GET2(dinfo->ncylinders) * 723 CAC_GET1(dinfo->nheads) * CAC_GET1(dinfo->nsectors); 724 if (blockno >= size || blockno + blockcnt > size) { 725 printf("%s: out of bounds %u-%u >= %u\n", 726 sc->sc_dv.dv_xname, blockno, blockcnt, size); 727 xs->error = XS_DRIVER_STUFFUP; 728 break; 729 } 730 731 switch (xs->cmd->opcode) { 732 case READ_COMMAND: 733 case READ_BIG: 734 op = CAC_CMD_READ; 735 flags = CAC_CCB_DATA_IN; 736 break; 737 case WRITE_COMMAND: 738 case WRITE_BIG: 739 op = CAC_CMD_WRITE; 740 flags = CAC_CCB_DATA_OUT; 741 break; 742 } 743 744 if ((error = cac_cmd(sc, op, xs->data, blockcnt * DEV_BSIZE, 745 target, blockno, flags, xs))) { 746 splx(s); 747 if (error == EBUSY) 748 xs->error = XS_BUSY; 749 else 750 xs->error = XS_DRIVER_STUFFUP; 751 scsi_done(xs); 752 return; 753 } 754 755 splx(s); 756 return; 757 758 default: 759 SC_DEBUG(link, SDEV_DB1, ("unsupported scsi command %#x " 760 "tgt %d ", xs->cmd->opcode, target)); 761 xs->error = XS_DRIVER_STUFFUP; 762 } 763 764 splx(s); 765 scsi_done(xs); 766 } 767 768 /* 769 * Board specific linkage shared between multiple bus types. 770 */ 771 772 int 773 cac_l0_fifo_full(struct cac_softc *sc) 774 { 775 776 return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0); 777 } 778 779 void 780 cac_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb) 781 { 782 #ifdef CAC_DEBUG 783 printf("submit-%x ", ccb->ccb_paddr); 784 #endif 785 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0, 786 sc->sc_dmamap->dm_mapsize, 787 BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 788 cac_outl(sc, CAC_REG_CMD_FIFO, ccb->ccb_paddr); 789 } 790 791 struct cac_ccb * 792 cac_l0_completed(sc) 793 struct cac_softc *sc; 794 { 795 struct cac_ccb *ccb; 796 paddr_t off; 797 798 if (!(off = cac_inl(sc, CAC_REG_DONE_FIFO))) 799 return NULL; 800 #ifdef CAC_DEBUG 801 printf("compl-%x ", off); 802 #endif 803 if (off & 3 && ccb->ccb_req.error == 0) 804 ccb->ccb_req.error = CAC_RET_CMD_INVALID; 805 806 off = (off & ~3) - sc->sc_ccbs_paddr; 807 ccb = (struct cac_ccb *)(sc->sc_ccbs + off); 808 809 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0, 810 sc->sc_dmamap->dm_mapsize, 811 BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); 812 813 return (ccb); 814 } 815 816 int 817 cac_l0_intr_pending(struct cac_softc *sc) 818 { 819 820 return (cac_inl(sc, CAC_REG_INTR_PENDING)); 821 } 822 823 void 824 cac_l0_intr_enable(struct cac_softc *sc, int state) 825 { 826 827 cac_outl(sc, CAC_REG_INTR_MASK, 828 state ? CAC_INTR_ENABLE : CAC_INTR_DISABLE); 829 } 830 831 #if NBIO > 0 832 const int cac_level[] = { 0, 4, 1, 5, 51, 7 }; 833 const int cac_stat[] = { BIOC_SVONLINE, BIOC_SVOFFLINE, BIOC_SVOFFLINE, 834 BIOC_SVDEGRADED, BIOC_SVREBUILD, BIOC_SVREBUILD, BIOC_SVDEGRADED, 835 BIOC_SVDEGRADED, BIOC_SVINVALID, BIOC_SVINVALID, BIOC_SVBUILDING, 836 BIOC_SVOFFLINE, BIOC_SVBUILDING }; 837 838 int 839 cac_ioctl(struct device *dev, u_long cmd, caddr_t addr) 840 { 841 struct cac_softc *sc = (struct cac_softc *)dev; 842 struct bioc_inq *bi; 843 struct bioc_disk *bd; 844 cac_lock_t lock; 845 int error = 0; 846 847 lock = CAC_LOCK(sc); 848 switch (cmd) { 849 case BIOCINQ: 850 bi = (struct bioc_inq *)addr; 851 strlcpy(bi->bi_dev, sc->sc_dv.dv_xname, sizeof(bi->bi_dev)); 852 bi->bi_novol = sc->sc_nunits; 853 bi->bi_nodisk = 0; 854 break; 855 856 case BIOCVOL: 857 error = cac_ioctl_vol(sc, (struct bioc_vol *)addr); 858 break; 859 860 case BIOCDISK: 861 bd = (struct bioc_disk *)addr; 862 if (bd->bd_volid > sc->sc_nunits) { 863 error = EINVAL; 864 break; 865 } 866 /* No disk information yet */ 867 break; 868 869 case BIOCBLINK: 870 case BIOCALARM: 871 case BIOCSETSTATE: 872 default: 873 error = ENOTTY; 874 } 875 CAC_UNLOCK(sc, lock); 876 877 return (error); 878 } 879 880 int 881 cac_ioctl_vol(struct cac_softc *sc, struct bioc_vol *bv) 882 { 883 struct cac_drive_info dinfo; 884 struct cac_drive_status dstatus; 885 u_int32_t blks; 886 887 if (bv->bv_volid > sc->sc_nunits) 888 return (EINVAL); 889 if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &dinfo, sizeof(dinfo), 890 bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL)) 891 return (EIO); 892 if (cac_cmd(sc, CAC_CMD_SENSE_DRV_STATUS, &dstatus, sizeof(dstatus), 893 bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL)) 894 return (EIO); 895 bv->bv_status = BIOC_SVINVALID; 896 blks = CAC_GET2(dinfo.ncylinders) * CAC_GET1(dinfo.nheads) * 897 CAC_GET1(dinfo.nsectors); 898 bv->bv_size = (off_t)blks * CAC_GET2(dinfo.secsize); 899 bv->bv_level = cac_level[CAC_GET1(dinfo.mirror)]; /*XXX limit check */ 900 bv->bv_nodisk = 0; /* XXX */ 901 bv->bv_status = 0; /* XXX */ 902 bv->bv_percent = -1; 903 bv->bv_seconds = 0; 904 if (dstatus.stat < nitems(cac_stat)) 905 bv->bv_status = cac_stat[dstatus.stat]; 906 if (bv->bv_status == BIOC_SVREBUILD || 907 bv->bv_status == BIOC_SVBUILDING) 908 bv->bv_percent = ((blks - CAC_GET4(dstatus.prog)) * 1000ULL) / 909 blks; 910 911 return (0); 912 } 913 914 #ifndef SMALL_KERNEL 915 int 916 cac_create_sensors(struct cac_softc *sc) 917 { 918 struct device *dev; 919 struct scsibus_softc *ssc = NULL; 920 struct scsi_link *link; 921 int i; 922 923 TAILQ_FOREACH(dev, &alldevs, dv_list) { 924 if (dev->dv_parent != &sc->sc_dv) 925 continue; 926 927 /* check if this is the scsibus for the logical disks */ 928 ssc = (struct scsibus_softc *)dev; 929 if (ssc->adapter_link == &sc->sc_link) 930 break; 931 ssc = NULL; 932 } 933 934 if (ssc == NULL) 935 return (1); 936 937 sc->sc_sensors = malloc(sizeof(struct ksensor) * sc->sc_nunits, 938 M_DEVBUF, M_NOWAIT | M_ZERO); 939 if (sc->sc_sensors == NULL) 940 return (1); 941 942 strlcpy(sc->sc_sensordev.xname, sc->sc_dv.dv_xname, 943 sizeof(sc->sc_sensordev.xname)); 944 945 for (i = 0; i < sc->sc_nunits; i++) { 946 link = scsi_get_link(ssc, i, 0); 947 if (link == NULL) 948 goto bad; 949 950 dev = link->device_softc; 951 952 sc->sc_sensors[i].type = SENSOR_DRIVE; 953 sc->sc_sensors[i].status = SENSOR_S_UNKNOWN; 954 955 strlcpy(sc->sc_sensors[i].desc, dev->dv_xname, 956 sizeof(sc->sc_sensors[i].desc)); 957 958 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]); 959 } 960 961 if (sensor_task_register(sc, cac_sensor_refresh, 10) == NULL) 962 goto bad; 963 964 sensordev_install(&sc->sc_sensordev); 965 966 return (0); 967 968 bad: 969 free(sc->sc_sensors, M_DEVBUF); 970 971 return (1); 972 } 973 974 void 975 cac_sensor_refresh(void *arg) 976 { 977 struct cac_softc *sc = arg; 978 struct bioc_vol bv; 979 int i, s; 980 981 for (i = 0; i < sc->sc_nunits; i++) { 982 bzero(&bv, sizeof(bv)); 983 bv.bv_volid = i; 984 s = splbio(); 985 if (cac_ioctl_vol(sc, &bv)) { 986 splx(s); 987 return; 988 } 989 splx(s); 990 991 switch (bv.bv_status) { 992 case BIOC_SVOFFLINE: 993 sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL; 994 sc->sc_sensors[i].status = SENSOR_S_CRIT; 995 break; 996 997 case BIOC_SVDEGRADED: 998 sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL; 999 sc->sc_sensors[i].status = SENSOR_S_WARN; 1000 break; 1001 1002 case BIOC_SVSCRUB: 1003 case BIOC_SVONLINE: 1004 sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE; 1005 sc->sc_sensors[i].status = SENSOR_S_OK; 1006 break; 1007 1008 case BIOC_SVREBUILD: 1009 case BIOC_SVBUILDING: 1010 sc->sc_sensors[i].value = SENSOR_DRIVE_REBUILD; 1011 sc->sc_sensors[i].status = SENSOR_S_OK; 1012 break; 1013 1014 case BIOC_SVINVALID: 1015 /* FALLTRHOUGH */ 1016 default: 1017 sc->sc_sensors[i].value = 0; /* unknown */ 1018 sc->sc_sensors[i].status = SENSOR_S_UNKNOWN; 1019 } 1020 } 1021 } 1022 #endif /* SMALL_KERNEL */ 1023 #endif /* NBIO > 0 */ 1024