1 /* $NetBSD: cac.c,v 1.55 2015/03/12 15:33:10 christos 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.55 2015/03/12 15:33:10 christos Exp $"); 38 39 #include "bio.h" 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/device.h> 45 #include <sys/queue.h> 46 #include <sys/proc.h> 47 #include <sys/buf.h> 48 #include <sys/endian.h> 49 #include <sys/malloc.h> 50 #include <sys/pool.h> 51 52 #include <sys/bswap.h> 53 #include <sys/bus.h> 54 55 #include <dev/ic/cacreg.h> 56 #include <dev/ic/cacvar.h> 57 58 #if NBIO > 0 59 #include <dev/biovar.h> 60 #endif /* NBIO > 0 */ 61 62 #include "locators.h" 63 64 static struct cac_ccb *cac_ccb_alloc(struct cac_softc *, int); 65 static void cac_ccb_done(struct cac_softc *, struct cac_ccb *); 66 static void cac_ccb_free(struct cac_softc *, struct cac_ccb *); 67 static int cac_ccb_poll(struct cac_softc *, struct cac_ccb *, int); 68 static int cac_ccb_start(struct cac_softc *, struct cac_ccb *); 69 static int cac_print(void *, const char *); 70 static void cac_shutdown(void *); 71 72 static struct cac_ccb *cac_l0_completed(struct cac_softc *); 73 static int cac_l0_fifo_full(struct cac_softc *); 74 static void cac_l0_intr_enable(struct cac_softc *, int); 75 static int cac_l0_intr_pending(struct cac_softc *); 76 static void cac_l0_submit(struct cac_softc *, struct cac_ccb *); 77 78 static void *cac_sdh; /* shutdown hook */ 79 80 #if NBIO > 0 81 int cac_ioctl(device_t, u_long, void *); 82 int cac_ioctl_vol(struct cac_softc *, struct bioc_vol *); 83 int cac_create_sensors(struct cac_softc *); 84 void cac_sensor_refresh(struct sysmon_envsys *, envsys_data_t *); 85 #endif /* NBIO > 0 */ 86 87 const struct cac_linkage cac_l0 = { 88 cac_l0_completed, 89 cac_l0_fifo_full, 90 cac_l0_intr_enable, 91 cac_l0_intr_pending, 92 cac_l0_submit 93 }; 94 95 /* 96 * Initialise our interface to the controller. 97 */ 98 int 99 cac_init(struct cac_softc *sc, const char *intrstr, int startfw) 100 { 101 struct cac_controller_info cinfo; 102 struct cac_attach_args caca; 103 int error, rseg, size, i; 104 bus_dma_segment_t seg; 105 struct cac_ccb *ccb; 106 int locs[CACCF_NLOCS]; 107 char firm[8]; 108 109 if (intrstr != NULL) 110 aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", 111 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 sc->sc_nunits = cinfo.num_drvs; 191 for (i = 0; i < cinfo.num_drvs; i++) { 192 caca.caca_unit = i; 193 194 locs[CACCF_UNIT] = i; 195 196 config_found_sm_loc(sc->sc_dev, "cac", locs, &caca, 197 cac_print, config_stdsubmatch); 198 } 199 200 /* Set our `shutdownhook' before we start any device activity. */ 201 if (cac_sdh == NULL) 202 cac_sdh = shutdownhook_establish(cac_shutdown, NULL); 203 204 mutex_enter(&sc->sc_mutex); 205 (*sc->sc_cl.cl_intr_enable)(sc, CAC_INTR_ENABLE); 206 mutex_exit(&sc->sc_mutex); 207 208 #if NBIO > 0 209 if (bio_register(sc->sc_dev, cac_ioctl) != 0) 210 aprint_error_dev(sc->sc_dev, "controller registration failed"); 211 else 212 sc->sc_ioctl = cac_ioctl; 213 if (cac_create_sensors(sc) != 0) 214 aprint_error_dev(sc->sc_dev, "unable to create sensors\n"); 215 #endif 216 217 return (0); 218 } 219 220 /* 221 * Shut down all `cac' controllers. 222 */ 223 static void 224 cac_shutdown(void *cookie) 225 { 226 extern struct cfdriver cac_cd; 227 struct cac_softc *sc; 228 u_int8_t tbuf[512]; 229 int i; 230 231 for (i = 0; i < cac_cd.cd_ndevs; i++) { 232 if ((sc = device_lookup_private(&cac_cd, i)) == NULL) 233 continue; 234 memset(tbuf, 0, sizeof(tbuf)); 235 tbuf[0] = 1; 236 cac_cmd(sc, CAC_CMD_FLUSH_CACHE, tbuf, sizeof(tbuf), 0, 0, 237 CAC_CCB_DATA_OUT, NULL); 238 } 239 } 240 241 /* 242 * Print autoconfiguration message for a sub-device. 243 */ 244 static int 245 cac_print(void *aux, const char *pnp) 246 { 247 struct cac_attach_args *caca; 248 249 caca = (struct cac_attach_args *)aux; 250 251 if (pnp != NULL) 252 aprint_normal("block device at %s", pnp); 253 aprint_normal(" unit %d", caca->caca_unit); 254 return (UNCONF); 255 } 256 257 /* 258 * Handle an interrupt from the controller: process finished CCBs and 259 * dequeue any waiting CCBs. 260 */ 261 int 262 cac_intr(void *cookie) 263 { 264 struct cac_softc *sc; 265 struct cac_ccb *ccb; 266 int rv; 267 268 sc = cookie; 269 270 mutex_enter(&sc->sc_mutex); 271 272 if ((*sc->sc_cl.cl_intr_pending)(sc)) { 273 while ((ccb = (*sc->sc_cl.cl_completed)(sc)) != NULL) { 274 cac_ccb_done(sc, ccb); 275 cac_ccb_start(sc, NULL); 276 } 277 rv = 1; 278 } else 279 rv = 0; 280 281 mutex_exit(&sc->sc_mutex); 282 283 return (rv); 284 } 285 286 /* 287 * Execute a [polled] command. 288 */ 289 int 290 cac_cmd(struct cac_softc *sc, int command, void *data, int datasize, 291 int drive, int blkno, int flags, struct cac_context *context) 292 { 293 struct cac_ccb *ccb; 294 struct cac_sgb *sgb; 295 int i, rv, size, nsegs; 296 297 size = 0; 298 299 if ((ccb = cac_ccb_alloc(sc, 1)) == NULL) { 300 aprint_error_dev(sc->sc_dev, "unable to alloc CCB"); 301 return (EAGAIN); 302 } 303 304 if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) { 305 bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer, 306 (void *)data, datasize, NULL, BUS_DMA_NOWAIT | 307 BUS_DMA_STREAMING | ((flags & CAC_CCB_DATA_IN) ? 308 BUS_DMA_READ : BUS_DMA_WRITE)); 309 310 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0, datasize, 311 (flags & CAC_CCB_DATA_IN) != 0 ? BUS_DMASYNC_PREREAD : 312 BUS_DMASYNC_PREWRITE); 313 314 sgb = ccb->ccb_seg; 315 nsegs = min(ccb->ccb_dmamap_xfer->dm_nsegs, CAC_SG_SIZE); 316 317 for (i = 0; i < nsegs; i++, sgb++) { 318 size += ccb->ccb_dmamap_xfer->dm_segs[i].ds_len; 319 sgb->length = 320 htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len); 321 sgb->addr = 322 htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr); 323 } 324 } else { 325 size = datasize; 326 nsegs = 0; 327 } 328 329 ccb->ccb_hdr.drive = drive; 330 ccb->ccb_hdr.priority = 0; 331 ccb->ccb_hdr.size = htole16((sizeof(struct cac_req) + 332 sizeof(struct cac_sgb) * CAC_SG_SIZE) >> 2); 333 334 ccb->ccb_req.next = 0; 335 ccb->ccb_req.error = 0; 336 ccb->ccb_req.reserved = 0; 337 ccb->ccb_req.bcount = htole16(howmany(size, DEV_BSIZE)); 338 ccb->ccb_req.command = command; 339 ccb->ccb_req.sgcount = nsegs; 340 ccb->ccb_req.blkno = htole32(blkno); 341 342 ccb->ccb_flags = flags; 343 ccb->ccb_datasize = size; 344 345 mutex_enter(&sc->sc_mutex); 346 347 if (context == NULL) { 348 memset(&ccb->ccb_context, 0, sizeof(struct cac_context)); 349 350 /* Synchronous commands musn't wait. */ 351 if ((*sc->sc_cl.cl_fifo_full)(sc)) { 352 cac_ccb_free(sc, ccb); 353 rv = EAGAIN; 354 } else { 355 #ifdef DIAGNOSTIC 356 ccb->ccb_flags |= CAC_CCB_ACTIVE; 357 #endif 358 (*sc->sc_cl.cl_submit)(sc, ccb); 359 rv = cac_ccb_poll(sc, ccb, 2000); 360 cac_ccb_free(sc, ccb); 361 } 362 } else { 363 memcpy(&ccb->ccb_context, context, sizeof(struct cac_context)); 364 (void)cac_ccb_start(sc, ccb); 365 rv = 0; 366 } 367 368 mutex_exit(&sc->sc_mutex); 369 return (rv); 370 } 371 372 /* 373 * Wait for the specified CCB to complete. 374 */ 375 static int 376 cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo) 377 { 378 struct cac_ccb *ccb; 379 380 KASSERT(mutex_owned(&sc->sc_mutex)); 381 382 timo *= 1000; 383 384 do { 385 for (; timo != 0; timo--) { 386 ccb = (*sc->sc_cl.cl_completed)(sc); 387 if (ccb != NULL) 388 break; 389 DELAY(1); 390 } 391 392 if (timo == 0) { 393 printf("%s: timeout\n", device_xname(sc->sc_dev)); 394 return (EBUSY); 395 } 396 cac_ccb_done(sc, ccb); 397 } while (ccb != wantccb); 398 399 return (0); 400 } 401 402 /* 403 * Enqueue the specified command (if any) and attempt to start all enqueued 404 * commands. 405 */ 406 static int 407 cac_ccb_start(struct cac_softc *sc, struct cac_ccb *ccb) 408 { 409 410 KASSERT(mutex_owned(&sc->sc_mutex)); 411 412 if (ccb != NULL) 413 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain); 414 415 while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue)) != NULL) { 416 if ((*sc->sc_cl.cl_fifo_full)(sc)) 417 return (EAGAIN); 418 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain); 419 #ifdef DIAGNOSTIC 420 ccb->ccb_flags |= CAC_CCB_ACTIVE; 421 #endif 422 (*sc->sc_cl.cl_submit)(sc, ccb); 423 } 424 425 return (0); 426 } 427 428 /* 429 * Process a finished CCB. 430 */ 431 static void 432 cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb) 433 { 434 device_t dv; 435 void *context; 436 int error; 437 438 error = 0; 439 440 KASSERT(mutex_owned(&sc->sc_mutex)); 441 442 #ifdef DIAGNOSTIC 443 if ((ccb->ccb_flags & CAC_CCB_ACTIVE) == 0) 444 panic("cac_ccb_done: CCB not active"); 445 ccb->ccb_flags &= ~CAC_CCB_ACTIVE; 446 #endif 447 448 if ((ccb->ccb_flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) { 449 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0, 450 ccb->ccb_datasize, ccb->ccb_flags & CAC_CCB_DATA_IN ? 451 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 452 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer); 453 } 454 455 error = ccb->ccb_req.error; 456 if (ccb->ccb_context.cc_handler != NULL) { 457 dv = ccb->ccb_context.cc_dv; 458 context = ccb->ccb_context.cc_context; 459 cac_ccb_free(sc, ccb); 460 (*ccb->ccb_context.cc_handler)(dv, context, error); 461 } else { 462 if ((error & CAC_RET_SOFT_ERROR) != 0) 463 aprint_error_dev(sc->sc_dev, "soft error; array may be degraded\n"); 464 if ((error & CAC_RET_HARD_ERROR) != 0) 465 aprint_error_dev(sc->sc_dev, "hard error\n"); 466 if ((error & CAC_RET_CMD_REJECTED) != 0) { 467 error = 1; 468 aprint_error_dev(sc->sc_dev, "invalid request\n"); 469 } 470 } 471 } 472 473 /* 474 * Allocate a CCB. 475 */ 476 static struct cac_ccb * 477 cac_ccb_alloc(struct cac_softc *sc, int nosleep) 478 { 479 struct cac_ccb *ccb; 480 481 mutex_enter(&sc->sc_mutex); 482 483 for (;;) { 484 if ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free)) != NULL) { 485 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb_chain); 486 break; 487 } 488 if (nosleep) { 489 ccb = NULL; 490 break; 491 } 492 cv_wait(&sc->sc_ccb_cv, &sc->sc_mutex); 493 } 494 495 mutex_exit(&sc->sc_mutex); 496 return (ccb); 497 } 498 499 /* 500 * Put a CCB onto the freelist. 501 */ 502 static void 503 cac_ccb_free(struct cac_softc *sc, struct cac_ccb *ccb) 504 { 505 506 KASSERT(mutex_owned(&sc->sc_mutex)); 507 508 ccb->ccb_flags = 0; 509 if (SIMPLEQ_EMPTY(&sc->sc_ccb_free)) 510 cv_signal(&sc->sc_ccb_cv); 511 SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain); 512 } 513 514 /* 515 * Board specific linkage shared between multiple bus types. 516 */ 517 518 static int 519 cac_l0_fifo_full(struct cac_softc *sc) 520 { 521 522 KASSERT(mutex_owned(&sc->sc_mutex)); 523 524 return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0); 525 } 526 527 static void 528 cac_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb) 529 { 530 531 KASSERT(mutex_owned(&sc->sc_mutex)); 532 533 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 534 (char *)ccb - (char *)sc->sc_ccbs, 535 sizeof(struct cac_ccb), BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 536 cac_outl(sc, CAC_REG_CMD_FIFO, ccb->ccb_paddr); 537 } 538 539 static struct cac_ccb * 540 cac_l0_completed(struct cac_softc *sc) 541 { 542 struct cac_ccb *ccb; 543 paddr_t off; 544 545 KASSERT(mutex_owned(&sc->sc_mutex)); 546 547 if ((off = cac_inl(sc, CAC_REG_DONE_FIFO)) == 0) 548 return (NULL); 549 550 if ((off & 3) != 0) 551 aprint_error_dev(sc->sc_dev, "failed command list returned: %lx\n", 552 (long)off); 553 554 off = (off & ~3) - sc->sc_ccbs_paddr; 555 ccb = (struct cac_ccb *)((char *)sc->sc_ccbs + off); 556 557 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, off, sizeof(struct cac_ccb), 558 BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); 559 560 if ((off & 3) != 0 && ccb->ccb_req.error == 0) 561 ccb->ccb_req.error = CAC_RET_CMD_REJECTED; 562 563 return (ccb); 564 } 565 566 static int 567 cac_l0_intr_pending(struct cac_softc *sc) 568 { 569 570 KASSERT(mutex_owned(&sc->sc_mutex)); 571 572 return (cac_inl(sc, CAC_REG_INTR_PENDING) & CAC_INTR_ENABLE); 573 } 574 575 static void 576 cac_l0_intr_enable(struct cac_softc *sc, int state) 577 { 578 579 KASSERT(mutex_owned(&sc->sc_mutex)); 580 581 cac_outl(sc, CAC_REG_INTR_MASK, 582 state ? CAC_INTR_ENABLE : CAC_INTR_DISABLE); 583 } 584 585 #if NBIO > 0 586 const int cac_level[] = { 0, 4, 1, 5, 51, 7 }; 587 const int cac_stat[] = { BIOC_SVONLINE, BIOC_SVOFFLINE, BIOC_SVOFFLINE, 588 BIOC_SVDEGRADED, BIOC_SVREBUILD, BIOC_SVREBUILD, BIOC_SVDEGRADED, 589 BIOC_SVDEGRADED, BIOC_SVINVALID, BIOC_SVINVALID, BIOC_SVBUILDING, 590 BIOC_SVOFFLINE, BIOC_SVBUILDING }; 591 592 int 593 cac_ioctl(device_t dev, u_long cmd, void *addr) 594 { 595 struct cac_softc *sc = device_private(dev); 596 struct bioc_inq *bi; 597 struct bioc_disk *bd; 598 cac_lock_t lock; 599 int error = 0; 600 601 lock = CAC_LOCK(sc); 602 switch (cmd) { 603 case BIOCINQ: 604 bi = (struct bioc_inq *)addr; 605 strlcpy(bi->bi_dev, device_xname(sc->sc_dev), sizeof(bi->bi_dev)); 606 bi->bi_novol = sc->sc_nunits; 607 bi->bi_nodisk = 0; 608 break; 609 610 case BIOCVOL: 611 error = cac_ioctl_vol(sc, (struct bioc_vol *)addr); 612 break; 613 614 case BIOCDISK: 615 case BIOCDISK_NOVOL: 616 bd = (struct bioc_disk *)addr; 617 if (bd->bd_volid > sc->sc_nunits) { 618 error = EINVAL; 619 break; 620 } 621 /* No disk information yet */ 622 break; 623 624 case BIOCBLINK: 625 case BIOCALARM: 626 case BIOCSETSTATE: 627 default: 628 error = EINVAL; 629 } 630 CAC_UNLOCK(sc, lock); 631 632 return (error); 633 } 634 635 int 636 cac_ioctl_vol(struct cac_softc *sc, struct bioc_vol *bv) 637 { 638 struct cac_drive_info dinfo; 639 struct cac_drive_status dstatus; 640 u_int32_t blks; 641 642 if (bv->bv_volid > sc->sc_nunits) { 643 return EINVAL; 644 } 645 if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &dinfo, sizeof(dinfo), 646 bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL)) { 647 return EIO; 648 } 649 if (cac_cmd(sc, CAC_CMD_SENSE_DRV_STATUS, &dstatus, sizeof(dstatus), 650 bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL)) { 651 return EIO; 652 } 653 blks = CAC_GET2(dinfo.ncylinders) * CAC_GET1(dinfo.nheads) * 654 CAC_GET1(dinfo.nsectors); 655 bv->bv_size = (off_t)blks * CAC_GET2(dinfo.secsize); 656 bv->bv_level = cac_level[CAC_GET1(dinfo.mirror)]; /*XXX limit check */ 657 bv->bv_nodisk = 0; /* XXX */ 658 bv->bv_status = 0; /* XXX */ 659 bv->bv_percent = -1; 660 bv->bv_seconds = 0; 661 if (dstatus.stat < sizeof(cac_stat)/sizeof(cac_stat[0])) 662 bv->bv_status = cac_stat[dstatus.stat]; 663 if (bv->bv_status == BIOC_SVREBUILD || 664 bv->bv_status == BIOC_SVBUILDING) 665 bv->bv_percent = ((blks - CAC_GET4(dstatus.prog)) * 1000ULL) / 666 blks; 667 return 0; 668 } 669 670 int 671 cac_create_sensors(struct cac_softc *sc) 672 { 673 int i; 674 int nsensors = sc->sc_nunits; 675 676 sc->sc_sme = sysmon_envsys_create(); 677 sc->sc_sensor = malloc(sizeof(envsys_data_t) * nsensors, 678 M_DEVBUF, M_NOWAIT | M_ZERO); 679 if (sc->sc_sensor == NULL) { 680 aprint_error_dev(sc->sc_dev, "can't allocate envsys_data_t\n"); 681 return(ENOMEM); 682 } 683 684 for (i = 0; i < nsensors; i++) { 685 sc->sc_sensor[i].units = ENVSYS_DRIVE; 686 sc->sc_sensor[i].state = ENVSYS_SINVALID; 687 sc->sc_sensor[i].value_cur = ENVSYS_DRIVE_EMPTY; 688 /* Enable monitoring for drive state changes */ 689 sc->sc_sensor[i].flags |= ENVSYS_FMONSTCHANGED; 690 /* logical drives */ 691 snprintf(sc->sc_sensor[i].desc, 692 sizeof(sc->sc_sensor[i].desc), "%s:%d", 693 device_xname(sc->sc_dev), i); 694 if (sysmon_envsys_sensor_attach(sc->sc_sme, 695 &sc->sc_sensor[i])) 696 goto out; 697 } 698 sc->sc_sme->sme_name = device_xname(sc->sc_dev); 699 sc->sc_sme->sme_cookie = sc; 700 sc->sc_sme->sme_refresh = cac_sensor_refresh; 701 if (sysmon_envsys_register(sc->sc_sme)) { 702 aprint_error_dev(sc->sc_dev, "unable to register with sysmon\n"); 703 return(1); 704 } 705 return (0); 706 707 out: 708 free(sc->sc_sensor, M_DEVBUF); 709 sysmon_envsys_destroy(sc->sc_sme); 710 return EINVAL; 711 } 712 713 void 714 cac_sensor_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 715 { 716 struct cac_softc *sc = sme->sme_cookie; 717 struct bioc_vol bv; 718 int s; 719 720 if (edata->sensor >= sc->sc_nunits) 721 return; 722 723 memset(&bv, 0, sizeof(bv)); 724 bv.bv_volid = edata->sensor; 725 s = splbio(); 726 if (cac_ioctl_vol(sc, &bv)) 727 bv.bv_status = BIOC_SVINVALID; 728 splx(s); 729 730 bio_vol_to_envsys(edata, &bv); 731 } 732 #endif /* NBIO > 0 */ 733