1 /* $NetBSD: cac.c,v 1.48 2009/03/18 16:00:18 cegger Exp $ */
4 * Copyright (c) 2000, 2006, 2007 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
33 * Driver for Compaq array controllers.
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: cac.c,v 1.48 2009/03/18 16:00:18 cegger Exp $");
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>
48 #include <sys/endian.h>
49 #include <sys/malloc.h>
52 #include <uvm/uvm_extern.h>
54 #include <sys/bswap.h>
57 #include <dev/ic/cacreg.h>
58 #include <dev/ic/cacvar.h>
61 #include <dev/biovar.h>
66 static struct cac_ccb
*cac_ccb_alloc(struct cac_softc
*, int);
67 static void cac_ccb_done(struct cac_softc
*, struct cac_ccb
*);
68 static void cac_ccb_free(struct cac_softc
*, struct cac_ccb
*);
69 static int cac_ccb_poll(struct cac_softc
*, struct cac_ccb
*, int);
70 static int cac_ccb_start(struct cac_softc
*, struct cac_ccb
*);
71 static int cac_print(void *, const char *);
72 static void cac_shutdown(void *);
74 static struct cac_ccb
*cac_l0_completed(struct cac_softc
*);
75 static int cac_l0_fifo_full(struct cac_softc
*);
76 static void cac_l0_intr_enable(struct cac_softc
*, int);
77 static int cac_l0_intr_pending(struct cac_softc
*);
78 static void cac_l0_submit(struct cac_softc
*, struct cac_ccb
*);
80 static void *cac_sdh
; /* shutdown hook */
83 int cac_ioctl(device_t
, u_long
, void *);
84 int cac_ioctl_vol(struct cac_softc
*, struct bioc_vol
*);
85 int cac_create_sensors(struct cac_softc
*);
86 void cac_sensor_refresh(struct sysmon_envsys
*, envsys_data_t
*);
89 const struct cac_linkage cac_l0
= {
98 * Initialise our interface to the controller.
101 cac_init(struct cac_softc
*sc
, const char *intrstr
, int startfw
)
103 struct cac_controller_info cinfo
;
104 struct cac_attach_args caca
;
105 int error
, rseg
, size
, i
;
106 bus_dma_segment_t seg
;
108 int locs
[CACCF_NLOCS
];
112 aprint_normal_dev(&sc
->sc_dv
, "interrupting at %s\n",
115 SIMPLEQ_INIT(&sc
->sc_ccb_free
);
116 SIMPLEQ_INIT(&sc
->sc_ccb_queue
);
117 mutex_init(&sc
->sc_mutex
, MUTEX_DEFAULT
, IPL_VM
);
118 cv_init(&sc
->sc_ccb_cv
, "cacccb");
120 size
= sizeof(struct cac_ccb
) * CAC_MAX_CCBS
;
122 if ((error
= bus_dmamem_alloc(sc
->sc_dmat
, size
, PAGE_SIZE
, 0, &seg
, 1,
123 &rseg
, BUS_DMA_NOWAIT
)) != 0) {
124 aprint_error_dev(&sc
->sc_dv
, "unable to allocate CCBs, error = %d\n",
129 if ((error
= bus_dmamem_map(sc
->sc_dmat
, &seg
, rseg
, size
,
130 (void **)&sc
->sc_ccbs
,
131 BUS_DMA_NOWAIT
| BUS_DMA_COHERENT
)) != 0) {
132 aprint_error_dev(&sc
->sc_dv
, "unable to map CCBs, error = %d\n",
137 if ((error
= bus_dmamap_create(sc
->sc_dmat
, size
, 1, size
, 0,
138 BUS_DMA_NOWAIT
, &sc
->sc_dmamap
)) != 0) {
139 aprint_error_dev(&sc
->sc_dv
, "unable to create CCB DMA map, error = %d\n",
144 if ((error
= bus_dmamap_load(sc
->sc_dmat
, sc
->sc_dmamap
, sc
->sc_ccbs
,
145 size
, NULL
, BUS_DMA_NOWAIT
)) != 0) {
146 aprint_error_dev(&sc
->sc_dv
, "unable to load CCB DMA map, error = %d\n",
151 sc
->sc_ccbs_paddr
= sc
->sc_dmamap
->dm_segs
[0].ds_addr
;
152 memset(sc
->sc_ccbs
, 0, size
);
153 ccb
= (struct cac_ccb
*)sc
->sc_ccbs
;
155 for (i
= 0; i
< CAC_MAX_CCBS
; i
++, ccb
++) {
156 /* Create the DMA map for this CCB's data */
157 error
= bus_dmamap_create(sc
->sc_dmat
, CAC_MAX_XFER
,
158 CAC_SG_SIZE
, CAC_MAX_XFER
, 0,
159 BUS_DMA_NOWAIT
| BUS_DMA_ALLOCNOW
,
160 &ccb
->ccb_dmamap_xfer
);
163 aprint_error_dev(&sc
->sc_dv
, "can't create ccb dmamap (%d)\n",
169 ccb
->ccb_paddr
= sc
->sc_ccbs_paddr
+ i
* sizeof(struct cac_ccb
);
170 SIMPLEQ_INSERT_TAIL(&sc
->sc_ccb_free
, ccb
, ccb_chain
);
173 /* Start firmware background tasks, if needed. */
175 if (cac_cmd(sc
, CAC_CMD_START_FIRMWARE
, &cinfo
, sizeof(cinfo
),
176 0, 0, CAC_CCB_DATA_IN
, NULL
)) {
177 aprint_error_dev(&sc
->sc_dv
, "CAC_CMD_START_FIRMWARE failed\n");
182 if (cac_cmd(sc
, CAC_CMD_GET_CTRL_INFO
, &cinfo
, sizeof(cinfo
), 0, 0,
183 CAC_CCB_DATA_IN
, NULL
)) {
184 aprint_error_dev(&sc
->sc_dv
, "CAC_CMD_GET_CTRL_INFO failed\n");
188 strlcpy(firm
, cinfo
.firm_rev
, 4+1);
189 printf("%s: %d channels, firmware <%s>\n", device_xname(&sc
->sc_dv
),
190 cinfo
.scsi_chips
, firm
);
192 sc
->sc_nunits
= cinfo
.num_drvs
;
193 for (i
= 0; i
< cinfo
.num_drvs
; i
++) {
196 locs
[CACCF_UNIT
] = i
;
198 config_found_sm_loc(&sc
->sc_dv
, "cac", locs
, &caca
,
199 cac_print
, config_stdsubmatch
);
202 /* Set our `shutdownhook' before we start any device activity. */
204 cac_sdh
= shutdownhook_establish(cac_shutdown
, NULL
);
206 mutex_enter(&sc
->sc_mutex
);
207 (*sc
->sc_cl
.cl_intr_enable
)(sc
, CAC_INTR_ENABLE
);
208 mutex_exit(&sc
->sc_mutex
);
211 if (bio_register(&sc
->sc_dv
, cac_ioctl
) != 0)
212 aprint_error_dev(&sc
->sc_dv
, "controller registration failed");
214 sc
->sc_ioctl
= cac_ioctl
;
215 if (cac_create_sensors(sc
) != 0)
216 aprint_error_dev(&sc
->sc_dv
, "unable to create sensors\n");
223 * Shut down all `cac' controllers.
226 cac_shutdown(void *cookie
)
228 extern struct cfdriver cac_cd
;
229 struct cac_softc
*sc
;
233 for (i
= 0; i
< cac_cd
.cd_ndevs
; i
++) {
234 if ((sc
= device_lookup_private(&cac_cd
, i
)) == NULL
)
236 memset(tbuf
, 0, sizeof(tbuf
));
238 cac_cmd(sc
, CAC_CMD_FLUSH_CACHE
, tbuf
, sizeof(tbuf
), 0, 0,
239 CAC_CCB_DATA_OUT
, NULL
);
244 * Print autoconfiguration message for a sub-device.
247 cac_print(void *aux
, const char *pnp
)
249 struct cac_attach_args
*caca
;
251 caca
= (struct cac_attach_args
*)aux
;
254 aprint_normal("block device at %s", pnp
);
255 aprint_normal(" unit %d", caca
->caca_unit
);
260 * Handle an interrupt from the controller: process finished CCBs and
261 * dequeue any waiting CCBs.
264 cac_intr(void *cookie
)
266 struct cac_softc
*sc
;
270 sc
= (struct cac_softc
*)cookie
;
272 mutex_enter(&sc
->sc_mutex
);
274 if ((*sc
->sc_cl
.cl_intr_pending
)(sc
)) {
275 while ((ccb
= (*sc
->sc_cl
.cl_completed
)(sc
)) != NULL
) {
276 cac_ccb_done(sc
, ccb
);
277 cac_ccb_start(sc
, NULL
);
283 mutex_exit(&sc
->sc_mutex
);
289 * Execute a [polled] command.
292 cac_cmd(struct cac_softc
*sc
, int command
, void *data
, int datasize
,
293 int drive
, int blkno
, int flags
, struct cac_context
*context
)
297 int i
, rv
, size
, nsegs
;
301 if ((ccb
= cac_ccb_alloc(sc
, 1)) == NULL
) {
302 aprint_error_dev(&sc
->sc_dv
, "unable to alloc CCB");
306 if ((flags
& (CAC_CCB_DATA_IN
| CAC_CCB_DATA_OUT
)) != 0) {
307 bus_dmamap_load(sc
->sc_dmat
, ccb
->ccb_dmamap_xfer
,
308 (void *)data
, datasize
, NULL
, BUS_DMA_NOWAIT
|
309 BUS_DMA_STREAMING
| ((flags
& CAC_CCB_DATA_IN
) ?
310 BUS_DMA_READ
: BUS_DMA_WRITE
));
312 bus_dmamap_sync(sc
->sc_dmat
, ccb
->ccb_dmamap_xfer
, 0, datasize
,
313 (flags
& CAC_CCB_DATA_IN
) != 0 ? BUS_DMASYNC_PREREAD
:
314 BUS_DMASYNC_PREWRITE
);
317 nsegs
= min(ccb
->ccb_dmamap_xfer
->dm_nsegs
, CAC_SG_SIZE
);
319 for (i
= 0; i
< nsegs
; i
++, sgb
++) {
320 size
+= ccb
->ccb_dmamap_xfer
->dm_segs
[i
].ds_len
;
322 htole32(ccb
->ccb_dmamap_xfer
->dm_segs
[i
].ds_len
);
324 htole32(ccb
->ccb_dmamap_xfer
->dm_segs
[i
].ds_addr
);
331 ccb
->ccb_hdr
.drive
= drive
;
332 ccb
->ccb_hdr
.priority
= 0;
333 ccb
->ccb_hdr
.size
= htole16((sizeof(struct cac_req
) +
334 sizeof(struct cac_sgb
) * CAC_SG_SIZE
) >> 2);
336 ccb
->ccb_req
.next
= 0;
337 ccb
->ccb_req
.error
= 0;
338 ccb
->ccb_req
.reserved
= 0;
339 ccb
->ccb_req
.bcount
= htole16(howmany(size
, DEV_BSIZE
));
340 ccb
->ccb_req
.command
= command
;
341 ccb
->ccb_req
.sgcount
= nsegs
;
342 ccb
->ccb_req
.blkno
= htole32(blkno
);
344 ccb
->ccb_flags
= flags
;
345 ccb
->ccb_datasize
= size
;
347 mutex_enter(&sc
->sc_mutex
);
349 if (context
== NULL
) {
350 memset(&ccb
->ccb_context
, 0, sizeof(struct cac_context
));
352 /* Synchronous commands musn't wait. */
353 if ((*sc
->sc_cl
.cl_fifo_full
)(sc
)) {
354 cac_ccb_free(sc
, ccb
);
358 ccb
->ccb_flags
|= CAC_CCB_ACTIVE
;
360 (*sc
->sc_cl
.cl_submit
)(sc
, ccb
);
361 rv
= cac_ccb_poll(sc
, ccb
, 2000);
362 cac_ccb_free(sc
, ccb
);
365 memcpy(&ccb
->ccb_context
, context
, sizeof(struct cac_context
));
366 (void)cac_ccb_start(sc
, ccb
);
370 mutex_exit(&sc
->sc_mutex
);
375 * Wait for the specified CCB to complete.
378 cac_ccb_poll(struct cac_softc
*sc
, struct cac_ccb
*wantccb
, int timo
)
382 KASSERT(mutex_owned(&sc
->sc_mutex
));
387 for (; timo
!= 0; timo
--) {
388 ccb
= (*sc
->sc_cl
.cl_completed
)(sc
);
395 printf("%s: timeout\n", device_xname(&sc
->sc_dv
));
398 cac_ccb_done(sc
, ccb
);
399 } while (ccb
!= wantccb
);
405 * Enqueue the specified command (if any) and attempt to start all enqueued
409 cac_ccb_start(struct cac_softc
*sc
, struct cac_ccb
*ccb
)
412 KASSERT(mutex_owned(&sc
->sc_mutex
));
415 SIMPLEQ_INSERT_TAIL(&sc
->sc_ccb_queue
, ccb
, ccb_chain
);
417 while ((ccb
= SIMPLEQ_FIRST(&sc
->sc_ccb_queue
)) != NULL
) {
418 if ((*sc
->sc_cl
.cl_fifo_full
)(sc
))
420 SIMPLEQ_REMOVE_HEAD(&sc
->sc_ccb_queue
, ccb_chain
);
422 ccb
->ccb_flags
|= CAC_CCB_ACTIVE
;
424 (*sc
->sc_cl
.cl_submit
)(sc
, ccb
);
431 * Process a finished CCB.
434 cac_ccb_done(struct cac_softc
*sc
, struct cac_ccb
*ccb
)
442 KASSERT(mutex_owned(&sc
->sc_mutex
));
445 if ((ccb
->ccb_flags
& CAC_CCB_ACTIVE
) == 0)
446 panic("cac_ccb_done: CCB not active");
447 ccb
->ccb_flags
&= ~CAC_CCB_ACTIVE
;
450 if ((ccb
->ccb_flags
& (CAC_CCB_DATA_IN
| CAC_CCB_DATA_OUT
)) != 0) {
451 bus_dmamap_sync(sc
->sc_dmat
, ccb
->ccb_dmamap_xfer
, 0,
452 ccb
->ccb_datasize
, ccb
->ccb_flags
& CAC_CCB_DATA_IN
?
453 BUS_DMASYNC_POSTREAD
: BUS_DMASYNC_POSTWRITE
);
454 bus_dmamap_unload(sc
->sc_dmat
, ccb
->ccb_dmamap_xfer
);
457 error
= ccb
->ccb_req
.error
;
458 if (ccb
->ccb_context
.cc_handler
!= NULL
) {
459 dv
= ccb
->ccb_context
.cc_dv
;
460 context
= ccb
->ccb_context
.cc_context
;
461 cac_ccb_free(sc
, ccb
);
462 (*ccb
->ccb_context
.cc_handler
)(dv
, context
, error
);
464 if ((error
& CAC_RET_SOFT_ERROR
) != 0)
465 aprint_error_dev(&sc
->sc_dv
, "soft error; array may be degraded\n");
466 if ((error
& CAC_RET_HARD_ERROR
) != 0)
467 aprint_error_dev(&sc
->sc_dv
, "hard error\n");
468 if ((error
& CAC_RET_CMD_REJECTED
) != 0) {
470 aprint_error_dev(&sc
->sc_dv
, "invalid request\n");
478 static struct cac_ccb
*
479 cac_ccb_alloc(struct cac_softc
*sc
, int nosleep
)
483 mutex_enter(&sc
->sc_mutex
);
486 if ((ccb
= SIMPLEQ_FIRST(&sc
->sc_ccb_free
)) != NULL
) {
487 SIMPLEQ_REMOVE_HEAD(&sc
->sc_ccb_free
, ccb_chain
);
494 cv_wait(&sc
->sc_ccb_cv
, &sc
->sc_mutex
);
497 mutex_exit(&sc
->sc_mutex
);
502 * Put a CCB onto the freelist.
505 cac_ccb_free(struct cac_softc
*sc
, struct cac_ccb
*ccb
)
508 KASSERT(mutex_owned(&sc
->sc_mutex
));
511 if (SIMPLEQ_EMPTY(&sc
->sc_ccb_free
))
512 cv_signal(&sc
->sc_ccb_cv
);
513 SIMPLEQ_INSERT_HEAD(&sc
->sc_ccb_free
, ccb
, ccb_chain
);
517 * Board specific linkage shared between multiple bus types.
521 cac_l0_fifo_full(struct cac_softc
*sc
)
524 KASSERT(mutex_owned(&sc
->sc_mutex
));
526 return (cac_inl(sc
, CAC_REG_CMD_FIFO
) == 0);
530 cac_l0_submit(struct cac_softc
*sc
, struct cac_ccb
*ccb
)
533 KASSERT(mutex_owned(&sc
->sc_mutex
));
535 bus_dmamap_sync(sc
->sc_dmat
, sc
->sc_dmamap
,
536 (char *)ccb
- (char *)sc
->sc_ccbs
,
537 sizeof(struct cac_ccb
), BUS_DMASYNC_PREWRITE
| BUS_DMASYNC_PREREAD
);
538 cac_outl(sc
, CAC_REG_CMD_FIFO
, ccb
->ccb_paddr
);
541 static struct cac_ccb
*
542 cac_l0_completed(struct cac_softc
*sc
)
547 KASSERT(mutex_owned(&sc
->sc_mutex
));
549 if ((off
= cac_inl(sc
, CAC_REG_DONE_FIFO
)) == 0)
553 aprint_error_dev(&sc
->sc_dv
, "failed command list returned: %lx\n",
556 off
= (off
& ~3) - sc
->sc_ccbs_paddr
;
557 ccb
= (struct cac_ccb
*)((char *)sc
->sc_ccbs
+ off
);
559 bus_dmamap_sync(sc
->sc_dmat
, sc
->sc_dmamap
, off
, sizeof(struct cac_ccb
),
560 BUS_DMASYNC_POSTWRITE
| BUS_DMASYNC_POSTREAD
);
562 if ((off
& 3) != 0 && ccb
->ccb_req
.error
== 0)
563 ccb
->ccb_req
.error
= CAC_RET_CMD_REJECTED
;
569 cac_l0_intr_pending(struct cac_softc
*sc
)
572 KASSERT(mutex_owned(&sc
->sc_mutex
));
574 return (cac_inl(sc
, CAC_REG_INTR_PENDING
) & CAC_INTR_ENABLE
);
578 cac_l0_intr_enable(struct cac_softc
*sc
, int state
)
581 KASSERT(mutex_owned(&sc
->sc_mutex
));
583 cac_outl(sc
, CAC_REG_INTR_MASK
,
584 state
? CAC_INTR_ENABLE
: CAC_INTR_DISABLE
);
588 const int cac_level
[] = { 0, 4, 1, 5, 51, 7 };
589 const int cac_stat
[] = { BIOC_SVONLINE
, BIOC_SVOFFLINE
, BIOC_SVOFFLINE
,
590 BIOC_SVDEGRADED
, BIOC_SVREBUILD
, BIOC_SVREBUILD
, BIOC_SVDEGRADED
,
591 BIOC_SVDEGRADED
, BIOC_SVINVALID
, BIOC_SVINVALID
, BIOC_SVBUILDING
,
592 BIOC_SVOFFLINE
, BIOC_SVBUILDING
};
595 cac_ioctl(device_t dev
, u_long cmd
, void *addr
)
597 struct cac_softc
*sc
= (struct cac_softc
*)dev
;
599 struct bioc_disk
*bd
;
606 bi
= (struct bioc_inq
*)addr
;
607 strlcpy(bi
->bi_dev
, device_xname(&sc
->sc_dv
), sizeof(bi
->bi_dev
));
608 bi
->bi_novol
= sc
->sc_nunits
;
613 error
= cac_ioctl_vol(sc
, (struct bioc_vol
*)addr
);
618 bd
= (struct bioc_disk
*)addr
;
619 if (bd
->bd_volid
> sc
->sc_nunits
) {
623 /* No disk information yet */
632 CAC_UNLOCK(sc
, lock
);
638 cac_ioctl_vol(struct cac_softc
*sc
, struct bioc_vol
*bv
)
640 struct cac_drive_info dinfo
;
641 struct cac_drive_status dstatus
;
644 if (bv
->bv_volid
> sc
->sc_nunits
) {
647 if (cac_cmd(sc
, CAC_CMD_GET_LOG_DRV_INFO
, &dinfo
, sizeof(dinfo
),
648 bv
->bv_volid
, 0, CAC_CCB_DATA_IN
, NULL
)) {
651 if (cac_cmd(sc
, CAC_CMD_SENSE_DRV_STATUS
, &dstatus
, sizeof(dstatus
),
652 bv
->bv_volid
, 0, CAC_CCB_DATA_IN
, NULL
)) {
655 blks
= CAC_GET2(dinfo
.ncylinders
) * CAC_GET1(dinfo
.nheads
) *
656 CAC_GET1(dinfo
.nsectors
);
657 bv
->bv_size
= (off_t
)blks
* CAC_GET2(dinfo
.secsize
);
658 bv
->bv_level
= cac_level
[CAC_GET1(dinfo
.mirror
)]; /*XXX limit check */
659 bv
->bv_nodisk
= 0; /* XXX */
660 bv
->bv_status
= 0; /* XXX */
663 if (dstatus
.stat
< sizeof(cac_stat
)/sizeof(cac_stat
[0]))
664 bv
->bv_status
= cac_stat
[dstatus
.stat
];
665 if (bv
->bv_status
== BIOC_SVREBUILD
||
666 bv
->bv_status
== BIOC_SVBUILDING
)
667 bv
->bv_percent
= ((blks
- CAC_GET4(dstatus
.prog
)) * 1000ULL) /
673 cac_create_sensors(struct cac_softc
*sc
)
676 int nsensors
= sc
->sc_nunits
;
678 sc
->sc_sme
= sysmon_envsys_create();
679 sc
->sc_sensor
= malloc(sizeof(envsys_data_t
) * nsensors
,
680 M_DEVBUF
, M_NOWAIT
| M_ZERO
);
681 if (sc
->sc_sensor
== NULL
) {
682 aprint_error_dev(&sc
->sc_dv
, "can't allocate envsys_data_t\n");
686 for (i
= 0; i
< nsensors
; i
++) {
687 sc
->sc_sensor
[i
].units
= ENVSYS_DRIVE
;
688 sc
->sc_sensor
[i
].monitor
= true;
689 /* Enable monitoring for drive state changes */
690 sc
->sc_sensor
[i
].flags
|= ENVSYS_FMONSTCHANGED
;
692 snprintf(sc
->sc_sensor
[i
].desc
,
693 sizeof(sc
->sc_sensor
[i
].desc
), "%s:%d",
694 device_xname(&sc
->sc_dv
), i
);
695 if (sysmon_envsys_sensor_attach(sc
->sc_sme
,
699 sc
->sc_sme
->sme_name
= device_xname(&sc
->sc_dv
);
700 sc
->sc_sme
->sme_cookie
= sc
;
701 sc
->sc_sme
->sme_refresh
= cac_sensor_refresh
;
702 if (sysmon_envsys_register(sc
->sc_sme
)) {
703 aprint_error_dev(&sc
->sc_dv
, "unable to register with sysmon\n");
709 free(sc
->sc_sensor
, M_DEVBUF
);
710 sysmon_envsys_destroy(sc
->sc_sme
);
715 cac_sensor_refresh(struct sysmon_envsys
*sme
, envsys_data_t
*edata
)
717 struct cac_softc
*sc
= sme
->sme_cookie
;
721 if (edata
->sensor
>= sc
->sc_nunits
)
724 memset(&bv
, 0, sizeof(bv
));
725 bv
.bv_volid
= edata
->sensor
;
727 if (cac_ioctl_vol(sc
, &bv
)) {
733 switch(bv
.bv_status
) {
735 edata
->value_cur
= ENVSYS_DRIVE_FAIL
;
736 edata
->state
= ENVSYS_SCRITICAL
;
739 case BIOC_SVDEGRADED
:
740 edata
->value_cur
= ENVSYS_DRIVE_PFAIL
;
741 edata
->state
= ENVSYS_SCRITICAL
;
746 edata
->value_cur
= ENVSYS_DRIVE_ONLINE
;
747 edata
->state
= ENVSYS_SVALID
;
751 case BIOC_SVBUILDING
:
752 edata
->value_cur
= ENVSYS_DRIVE_REBUILD
;
753 edata
->state
= ENVSYS_SVALID
;
759 edata
->value_cur
= 0; /* unknown */
760 edata
->state
= ENVSYS_SINVALID
;
763 #endif /* NBIO > 0 */