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