1 /* $NetBSD: cac.c,v 1.62 2021/04/24 23:36:55 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2000, 2006, 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Driver for Compaq array controllers. 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: cac.c,v 1.62 2021/04/24 23:36:55 thorpej Exp $"); 38 39 #if defined(_KERNEL_OPT) 40 #include "bio.h" 41 #endif 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kernel.h> 46 #include <sys/device.h> 47 #include <sys/queue.h> 48 #include <sys/proc.h> 49 #include <sys/buf.h> 50 #include <sys/endian.h> 51 #include <sys/malloc.h> 52 #include <sys/pool.h> 53 #include <sys/module.h> 54 #include <sys/bswap.h> 55 #include <sys/bus.h> 56 57 #include <dev/ic/cacreg.h> 58 #include <dev/ic/cacvar.h> 59 60 #if NBIO > 0 61 #include <dev/biovar.h> 62 #endif /* NBIO > 0 */ 63 64 #include "ioconf.h" 65 #include "locators.h" 66 67 static struct cac_ccb *cac_ccb_alloc(struct cac_softc *, int); 68 static void cac_ccb_done(struct cac_softc *, struct cac_ccb *); 69 static void cac_ccb_free(struct cac_softc *, struct cac_ccb *); 70 static int cac_ccb_poll(struct cac_softc *, struct cac_ccb *, int); 71 static int cac_ccb_start(struct cac_softc *, struct cac_ccb *); 72 static int cac_print(void *, const char *); 73 static void cac_shutdown(void *); 74 75 static struct cac_ccb *cac_l0_completed(struct cac_softc *); 76 static int cac_l0_fifo_full(struct cac_softc *); 77 static void cac_l0_intr_enable(struct cac_softc *, int); 78 static int cac_l0_intr_pending(struct cac_softc *); 79 static void cac_l0_submit(struct cac_softc *, struct cac_ccb *); 80 81 static void *cac_sdh; /* shutdown hook */ 82 83 #if NBIO > 0 84 int cac_ioctl(device_t, u_long, void *); 85 int cac_ioctl_vol(struct cac_softc *, struct bioc_vol *); 86 int cac_create_sensors(struct cac_softc *); 87 void cac_sensor_refresh(struct sysmon_envsys *, envsys_data_t *); 88 #endif /* NBIO > 0 */ 89 90 const struct cac_linkage cac_l0 = { 91 cac_l0_completed, 92 cac_l0_fifo_full, 93 cac_l0_intr_enable, 94 cac_l0_intr_pending, 95 cac_l0_submit 96 }; 97 98 /* 99 * Initialise our interface to the controller. 100 */ 101 int 102 cac_init(struct cac_softc *sc, const char *intrstr, int startfw) 103 { 104 struct cac_controller_info cinfo; 105 int error, rseg, size, i; 106 bus_dma_segment_t seg; 107 struct cac_ccb *ccb; 108 char firm[8]; 109 110 if (intrstr != NULL) 111 aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr); 112 113 SIMPLEQ_INIT(&sc->sc_ccb_free); 114 SIMPLEQ_INIT(&sc->sc_ccb_queue); 115 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM); 116 cv_init(&sc->sc_ccb_cv, "cacccb"); 117 118 size = sizeof(struct cac_ccb) * CAC_MAX_CCBS; 119 120 if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &seg, 1, 121 &rseg, BUS_DMA_NOWAIT)) != 0) { 122 aprint_error_dev(sc->sc_dev, "unable to allocate CCBs, error = %d\n", 123 error); 124 return (-1); 125 } 126 127 if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, 128 (void **)&sc->sc_ccbs, 129 BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { 130 aprint_error_dev(sc->sc_dev, "unable to map CCBs, error = %d\n", 131 error); 132 return (-1); 133 } 134 135 if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 136 BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) { 137 aprint_error_dev(sc->sc_dev, "unable to create CCB DMA map, error = %d\n", 138 error); 139 return (-1); 140 } 141 142 if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ccbs, 143 size, NULL, BUS_DMA_NOWAIT)) != 0) { 144 aprint_error_dev(sc->sc_dev, "unable to load CCB DMA map, error = %d\n", 145 error); 146 return (-1); 147 } 148 149 sc->sc_ccbs_paddr = sc->sc_dmamap->dm_segs[0].ds_addr; 150 memset(sc->sc_ccbs, 0, size); 151 ccb = (struct cac_ccb *)sc->sc_ccbs; 152 153 for (i = 0; i < CAC_MAX_CCBS; i++, ccb++) { 154 /* Create the DMA map for this CCB's data */ 155 error = bus_dmamap_create(sc->sc_dmat, CAC_MAX_XFER, 156 CAC_SG_SIZE, CAC_MAX_XFER, 0, 157 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 158 &ccb->ccb_dmamap_xfer); 159 160 if (error) { 161 aprint_error_dev(sc->sc_dev, "can't create ccb dmamap (%d)\n", 162 error); 163 break; 164 } 165 166 ccb->ccb_flags = 0; 167 ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb); 168 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain); 169 } 170 171 /* Start firmware background tasks, if needed. */ 172 if (startfw) { 173 if (cac_cmd(sc, CAC_CMD_START_FIRMWARE, &cinfo, sizeof(cinfo), 174 0, 0, CAC_CCB_DATA_IN, NULL)) { 175 aprint_error_dev(sc->sc_dev, "CAC_CMD_START_FIRMWARE failed\n"); 176 return (-1); 177 } 178 } 179 180 if (cac_cmd(sc, CAC_CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), 0, 0, 181 CAC_CCB_DATA_IN, NULL)) { 182 aprint_error_dev(sc->sc_dev, "CAC_CMD_GET_CTRL_INFO failed\n"); 183 return (-1); 184 } 185 186 strlcpy(firm, cinfo.firm_rev, 4+1); 187 printf("%s: %d channels, firmware <%s>\n", device_xname(sc->sc_dev), 188 cinfo.scsi_chips, firm); 189 190 /* Limit number of units to size of our sc_unitmask */ 191 sc->sc_nunits = cinfo.num_drvs; 192 if (sc->sc_nunits > sizeof(sc->sc_unitmask) * NBBY) 193 sc->sc_nunits = sizeof(sc->sc_unitmask) * NBBY; 194 195 /* Attach our units */ 196 sc->sc_unitmask = 0; 197 cac_rescan(sc->sc_dev, NULL, NULL); 198 199 /* Set our `shutdownhook' before we start any device activity. */ 200 if (cac_sdh == NULL) 201 cac_sdh = shutdownhook_establish(cac_shutdown, NULL); 202 203 mutex_enter(&sc->sc_mutex); 204 (*sc->sc_cl.cl_intr_enable)(sc, CAC_INTR_ENABLE); 205 mutex_exit(&sc->sc_mutex); 206 207 #if NBIO > 0 208 if (bio_register(sc->sc_dev, cac_ioctl) != 0) 209 aprint_error_dev(sc->sc_dev, "controller registration failed"); 210 else 211 sc->sc_ioctl = cac_ioctl; 212 if (cac_create_sensors(sc) != 0) 213 aprint_error_dev(sc->sc_dev, "unable to create sensors\n"); 214 #endif 215 216 return (0); 217 } 218 219 int 220 cac_rescan(device_t self, const char *attr, const int *locs) 221 { 222 struct cac_softc *sc; 223 struct cac_attach_args caca; 224 int mlocs[CACCF_NLOCS]; 225 int i; 226 227 sc = device_private(self); 228 for (i = 0; i < sc->sc_nunits; i++) { 229 if (sc->sc_unitmask & (1 << i)) 230 continue; 231 caca.caca_unit = i; 232 233 mlocs[CACCF_UNIT] = i; 234 235 if (config_found(self, &caca, cac_print, 236 CFARG_SUBMATCH, config_stdsubmatch, 237 CFARG_LOCATORS, mlocs, 238 CFARG_EOL) != NULL) 239 sc->sc_unitmask |= 1 << i; 240 } 241 return 0; 242 } 243 244 /* 245 * Shut down all `cac' controllers. 246 */ 247 static void 248 cac_shutdown(void *cookie) 249 { 250 struct cac_softc *sc; 251 u_int8_t tbuf[512]; 252 int i; 253 254 for (i = 0; i < cac_cd.cd_ndevs; i++) { 255 if ((sc = device_lookup_private(&cac_cd, i)) == NULL) 256 continue; 257 memset(tbuf, 0, sizeof(tbuf)); 258 tbuf[0] = 1; 259 cac_cmd(sc, CAC_CMD_FLUSH_CACHE, tbuf, sizeof(tbuf), 0, 0, 260 CAC_CCB_DATA_OUT, NULL); 261 } 262 } 263 264 /* 265 * Print autoconfiguration message for a sub-device. 266 */ 267 static int 268 cac_print(void *aux, const char *pnp) 269 { 270 struct cac_attach_args *caca; 271 272 caca = (struct cac_attach_args *)aux; 273 274 if (pnp != NULL) 275 aprint_normal("block device at %s", pnp); 276 aprint_normal(" unit %d", caca->caca_unit); 277 return (UNCONF); 278 } 279 280 /* 281 * Handle an interrupt from the controller: process finished CCBs and 282 * dequeue any waiting CCBs. 283 */ 284 int 285 cac_intr(void *cookie) 286 { 287 struct cac_softc *sc; 288 struct cac_ccb *ccb; 289 int rv; 290 291 sc = cookie; 292 293 mutex_enter(&sc->sc_mutex); 294 295 if ((*sc->sc_cl.cl_intr_pending)(sc)) { 296 while ((ccb = (*sc->sc_cl.cl_completed)(sc)) != NULL) { 297 cac_ccb_done(sc, ccb); 298 cac_ccb_start(sc, NULL); 299 } 300 rv = 1; 301 } else 302 rv = 0; 303 304 mutex_exit(&sc->sc_mutex); 305 306 return (rv); 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 cac_context *context) 315 { 316 struct cac_ccb *ccb; 317 struct cac_sgb *sgb; 318 int i, rv, size, nsegs; 319 320 size = 0; 321 322 if ((ccb = cac_ccb_alloc(sc, 1)) == NULL) { 323 aprint_error_dev(sc->sc_dev, "unable to alloc CCB"); 324 return (EAGAIN); 325 } 326 327 if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) { 328 bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer, 329 (void *)data, datasize, NULL, BUS_DMA_NOWAIT | 330 BUS_DMA_STREAMING | ((flags & CAC_CCB_DATA_IN) ? 331 BUS_DMA_READ : BUS_DMA_WRITE)); 332 333 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0, datasize, 334 (flags & CAC_CCB_DATA_IN) != 0 ? BUS_DMASYNC_PREREAD : 335 BUS_DMASYNC_PREWRITE); 336 337 sgb = ccb->ccb_seg; 338 nsegs = uimin(ccb->ccb_dmamap_xfer->dm_nsegs, CAC_SG_SIZE); 339 340 for (i = 0; i < nsegs; i++, sgb++) { 341 size += ccb->ccb_dmamap_xfer->dm_segs[i].ds_len; 342 sgb->length = 343 htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len); 344 sgb->addr = 345 htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr); 346 } 347 } else { 348 size = datasize; 349 nsegs = 0; 350 } 351 352 ccb->ccb_hdr.drive = drive; 353 ccb->ccb_hdr.priority = 0; 354 ccb->ccb_hdr.size = htole16((sizeof(struct cac_req) + 355 sizeof(struct cac_sgb) * CAC_SG_SIZE) >> 2); 356 357 ccb->ccb_req.next = 0; 358 ccb->ccb_req.error = 0; 359 ccb->ccb_req.reserved = 0; 360 ccb->ccb_req.bcount = htole16(howmany(size, DEV_BSIZE)); 361 ccb->ccb_req.command = command; 362 ccb->ccb_req.sgcount = nsegs; 363 ccb->ccb_req.blkno = htole32(blkno); 364 365 ccb->ccb_flags = flags; 366 ccb->ccb_datasize = size; 367 368 mutex_enter(&sc->sc_mutex); 369 370 if (context == NULL) { 371 memset(&ccb->ccb_context, 0, sizeof(struct cac_context)); 372 373 /* Synchronous commands musn't wait. */ 374 if ((*sc->sc_cl.cl_fifo_full)(sc)) { 375 cac_ccb_free(sc, ccb); 376 rv = EAGAIN; 377 } else { 378 #ifdef DIAGNOSTIC 379 ccb->ccb_flags |= CAC_CCB_ACTIVE; 380 #endif 381 (*sc->sc_cl.cl_submit)(sc, ccb); 382 rv = cac_ccb_poll(sc, ccb, 2000); 383 cac_ccb_free(sc, ccb); 384 } 385 } else { 386 memcpy(&ccb->ccb_context, context, sizeof(struct cac_context)); 387 (void)cac_ccb_start(sc, ccb); 388 rv = 0; 389 } 390 391 mutex_exit(&sc->sc_mutex); 392 return (rv); 393 } 394 395 /* 396 * Wait for the specified CCB to complete. 397 */ 398 static int 399 cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo) 400 { 401 struct cac_ccb *ccb; 402 403 KASSERT(mutex_owned(&sc->sc_mutex)); 404 405 timo *= 1000; 406 407 do { 408 for (; timo != 0; timo--) { 409 ccb = (*sc->sc_cl.cl_completed)(sc); 410 if (ccb != NULL) 411 break; 412 DELAY(1); 413 } 414 415 if (timo == 0) { 416 printf("%s: timeout\n", device_xname(sc->sc_dev)); 417 return (EBUSY); 418 } 419 cac_ccb_done(sc, ccb); 420 } while (ccb != wantccb); 421 422 return (0); 423 } 424 425 /* 426 * Enqueue the specified command (if any) and attempt to start all enqueued 427 * commands. 428 */ 429 static int 430 cac_ccb_start(struct cac_softc *sc, struct cac_ccb *ccb) 431 { 432 433 KASSERT(mutex_owned(&sc->sc_mutex)); 434 435 if (ccb != NULL) 436 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain); 437 438 while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue)) != NULL) { 439 if ((*sc->sc_cl.cl_fifo_full)(sc)) 440 return (EAGAIN); 441 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain); 442 #ifdef DIAGNOSTIC 443 ccb->ccb_flags |= CAC_CCB_ACTIVE; 444 #endif 445 (*sc->sc_cl.cl_submit)(sc, ccb); 446 } 447 448 return (0); 449 } 450 451 /* 452 * Process a finished CCB. 453 */ 454 static void 455 cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb) 456 { 457 device_t dv; 458 void *context; 459 int error; 460 461 error = 0; 462 463 KASSERT(mutex_owned(&sc->sc_mutex)); 464 465 #ifdef DIAGNOSTIC 466 if ((ccb->ccb_flags & CAC_CCB_ACTIVE) == 0) 467 panic("cac_ccb_done: CCB not active"); 468 ccb->ccb_flags &= ~CAC_CCB_ACTIVE; 469 #endif 470 471 if ((ccb->ccb_flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) { 472 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0, 473 ccb->ccb_datasize, ccb->ccb_flags & CAC_CCB_DATA_IN ? 474 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 475 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer); 476 } 477 478 error = ccb->ccb_req.error; 479 if (ccb->ccb_context.cc_handler != NULL) { 480 dv = ccb->ccb_context.cc_dv; 481 context = ccb->ccb_context.cc_context; 482 cac_ccb_free(sc, ccb); 483 (*ccb->ccb_context.cc_handler)(dv, context, error); 484 } else { 485 if ((error & CAC_RET_SOFT_ERROR) != 0) 486 aprint_error_dev(sc->sc_dev, "soft error; array may be degraded\n"); 487 if ((error & CAC_RET_HARD_ERROR) != 0) 488 aprint_error_dev(sc->sc_dev, "hard error\n"); 489 if ((error & CAC_RET_CMD_REJECTED) != 0) { 490 error = 1; 491 aprint_error_dev(sc->sc_dev, "invalid request\n"); 492 } 493 } 494 } 495 496 /* 497 * Allocate a CCB. 498 */ 499 static struct cac_ccb * 500 cac_ccb_alloc(struct cac_softc *sc, int nosleep) 501 { 502 struct cac_ccb *ccb; 503 504 mutex_enter(&sc->sc_mutex); 505 506 for (;;) { 507 if ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free)) != NULL) { 508 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb_chain); 509 break; 510 } 511 if (nosleep) { 512 ccb = NULL; 513 break; 514 } 515 cv_wait(&sc->sc_ccb_cv, &sc->sc_mutex); 516 } 517 518 mutex_exit(&sc->sc_mutex); 519 return (ccb); 520 } 521 522 /* 523 * Put a CCB onto the freelist. 524 */ 525 static void 526 cac_ccb_free(struct cac_softc *sc, struct cac_ccb *ccb) 527 { 528 529 KASSERT(mutex_owned(&sc->sc_mutex)); 530 531 ccb->ccb_flags = 0; 532 if (SIMPLEQ_EMPTY(&sc->sc_ccb_free)) 533 cv_signal(&sc->sc_ccb_cv); 534 SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain); 535 } 536 537 /* 538 * Board specific linkage shared between multiple bus types. 539 */ 540 541 static int 542 cac_l0_fifo_full(struct cac_softc *sc) 543 { 544 545 KASSERT(mutex_owned(&sc->sc_mutex)); 546 547 return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0); 548 } 549 550 static void 551 cac_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb) 552 { 553 554 KASSERT(mutex_owned(&sc->sc_mutex)); 555 556 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 557 (char *)ccb - (char *)sc->sc_ccbs, 558 sizeof(struct cac_ccb), BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 559 cac_outl(sc, CAC_REG_CMD_FIFO, ccb->ccb_paddr); 560 } 561 562 static struct cac_ccb * 563 cac_l0_completed(struct cac_softc *sc) 564 { 565 struct cac_ccb *ccb; 566 paddr_t off; 567 568 KASSERT(mutex_owned(&sc->sc_mutex)); 569 570 if ((off = cac_inl(sc, CAC_REG_DONE_FIFO)) == 0) 571 return (NULL); 572 573 if ((off & 3) != 0) 574 aprint_error_dev(sc->sc_dev, "failed command list returned: %lx\n", 575 (long)off); 576 577 off = (off & ~3) - sc->sc_ccbs_paddr; 578 ccb = (struct cac_ccb *)((char *)sc->sc_ccbs + off); 579 580 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, off, sizeof(struct cac_ccb), 581 BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); 582 583 if ((off & 3) != 0 && ccb->ccb_req.error == 0) 584 ccb->ccb_req.error = CAC_RET_CMD_REJECTED; 585 586 return (ccb); 587 } 588 589 static int 590 cac_l0_intr_pending(struct cac_softc *sc) 591 { 592 593 KASSERT(mutex_owned(&sc->sc_mutex)); 594 595 return (cac_inl(sc, CAC_REG_INTR_PENDING) & CAC_INTR_ENABLE); 596 } 597 598 static void 599 cac_l0_intr_enable(struct cac_softc *sc, int state) 600 { 601 602 KASSERT(mutex_owned(&sc->sc_mutex)); 603 604 cac_outl(sc, CAC_REG_INTR_MASK, 605 state ? CAC_INTR_ENABLE : CAC_INTR_DISABLE); 606 } 607 608 #if NBIO > 0 609 const int cac_level[] = { 0, 4, 1, 5, 51, 7 }; 610 const int cac_stat[] = { BIOC_SVONLINE, BIOC_SVOFFLINE, BIOC_SVOFFLINE, 611 BIOC_SVDEGRADED, BIOC_SVREBUILD, BIOC_SVREBUILD, BIOC_SVDEGRADED, 612 BIOC_SVDEGRADED, BIOC_SVINVALID, BIOC_SVINVALID, BIOC_SVBUILDING, 613 BIOC_SVOFFLINE, BIOC_SVBUILDING }; 614 615 int 616 cac_ioctl(device_t dev, u_long cmd, void *addr) 617 { 618 struct cac_softc *sc = device_private(dev); 619 struct bioc_inq *bi; 620 struct bioc_disk *bd; 621 cac_lock_t lock; 622 int error = 0; 623 624 lock = CAC_LOCK(sc); 625 switch (cmd) { 626 case BIOCINQ: 627 bi = (struct bioc_inq *)addr; 628 strlcpy(bi->bi_dev, device_xname(sc->sc_dev), sizeof(bi->bi_dev)); 629 bi->bi_novol = sc->sc_nunits; 630 bi->bi_nodisk = 0; 631 break; 632 633 case BIOCVOL: 634 error = cac_ioctl_vol(sc, (struct bioc_vol *)addr); 635 break; 636 637 case BIOCDISK: 638 case BIOCDISK_NOVOL: 639 bd = (struct bioc_disk *)addr; 640 if (bd->bd_volid > sc->sc_nunits) { 641 error = EINVAL; 642 break; 643 } 644 /* No disk information yet */ 645 break; 646 647 default: 648 error = EINVAL; 649 } 650 CAC_UNLOCK(sc, lock); 651 652 return (error); 653 } 654 655 int 656 cac_ioctl_vol(struct cac_softc *sc, struct bioc_vol *bv) 657 { 658 struct cac_drive_info dinfo; 659 struct cac_drive_status dstatus; 660 u_int32_t blks; 661 662 if (bv->bv_volid > sc->sc_nunits) { 663 return EINVAL; 664 } 665 if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &dinfo, sizeof(dinfo), 666 bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL)) { 667 return EIO; 668 } 669 if (cac_cmd(sc, CAC_CMD_SENSE_DRV_STATUS, &dstatus, sizeof(dstatus), 670 bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL)) { 671 return EIO; 672 } 673 blks = CAC_GET2(dinfo.ncylinders) * CAC_GET1(dinfo.nheads) * 674 CAC_GET1(dinfo.nsectors); 675 bv->bv_size = (off_t)blks * CAC_GET2(dinfo.secsize); 676 bv->bv_level = cac_level[CAC_GET1(dinfo.mirror)]; /*XXX limit check */ 677 bv->bv_nodisk = 0; /* XXX */ 678 bv->bv_status = 0; /* XXX */ 679 bv->bv_percent = -1; 680 bv->bv_seconds = 0; 681 if (dstatus.stat < sizeof(cac_stat)/sizeof(cac_stat[0])) 682 bv->bv_status = cac_stat[dstatus.stat]; 683 if (bv->bv_status == BIOC_SVREBUILD || 684 bv->bv_status == BIOC_SVBUILDING) 685 bv->bv_percent = ((blks - CAC_GET4(dstatus.prog)) * 1000ULL) / 686 blks; 687 return 0; 688 } 689 690 int 691 cac_create_sensors(struct cac_softc *sc) 692 { 693 int i; 694 int nsensors = sc->sc_nunits; 695 696 sc->sc_sme = sysmon_envsys_create(); 697 sc->sc_sensor = malloc(sizeof(envsys_data_t) * nsensors, 698 M_DEVBUF, M_WAITOK | M_ZERO); 699 for (i = 0; i < nsensors; i++) { 700 sc->sc_sensor[i].units = ENVSYS_DRIVE; 701 sc->sc_sensor[i].state = ENVSYS_SINVALID; 702 sc->sc_sensor[i].value_cur = ENVSYS_DRIVE_EMPTY; 703 /* Enable monitoring for drive state changes */ 704 sc->sc_sensor[i].flags |= ENVSYS_FMONSTCHANGED; 705 /* logical drives */ 706 snprintf(sc->sc_sensor[i].desc, 707 sizeof(sc->sc_sensor[i].desc), "%s:%d", 708 device_xname(sc->sc_dev), i); 709 if (sysmon_envsys_sensor_attach(sc->sc_sme, 710 &sc->sc_sensor[i])) 711 goto out; 712 } 713 sc->sc_sme->sme_name = device_xname(sc->sc_dev); 714 sc->sc_sme->sme_cookie = sc; 715 sc->sc_sme->sme_refresh = cac_sensor_refresh; 716 if (sysmon_envsys_register(sc->sc_sme)) { 717 aprint_error_dev(sc->sc_dev, "unable to register with sysmon\n"); 718 return(1); 719 } 720 return (0); 721 722 out: 723 free(sc->sc_sensor, M_DEVBUF); 724 sysmon_envsys_destroy(sc->sc_sme); 725 return EINVAL; 726 } 727 728 void 729 cac_sensor_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 730 { 731 struct cac_softc *sc = sme->sme_cookie; 732 struct bioc_vol bv; 733 int s; 734 735 if (edata->sensor >= sc->sc_nunits) 736 return; 737 738 memset(&bv, 0, sizeof(bv)); 739 bv.bv_volid = edata->sensor; 740 s = splbio(); 741 if (cac_ioctl_vol(sc, &bv)) 742 bv.bv_status = BIOC_SVINVALID; 743 splx(s); 744 745 bio_vol_to_envsys(edata, &bv); 746 } 747 #endif /* NBIO > 0 */ 748 749 MODULE(MODULE_CLASS_DRIVER, cac, NULL); 750 751 #ifdef _MODULE 752 CFDRIVER_DECL(cac, DV_DISK, NULL); 753 #endif 754 755 static int 756 cac_modcmd(modcmd_t cmd, void *opaque) 757 { 758 int error = 0; 759 760 #ifdef _MODULE 761 switch (cmd) { 762 case MODULE_CMD_INIT: 763 error = config_cfdriver_attach(&cac_cd); 764 break; 765 case MODULE_CMD_FINI: 766 error = config_cfdriver_detach(&cac_cd); 767 break; 768 default: 769 error = ENOTTY; 770 break; 771 } 772 #endif 773 return error; 774 } 775