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