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