1 /* $NetBSD: ciss.c,v 1.18 2009/04/18 14:58:02 tsutsui Exp $ */
2 /* $OpenBSD: ciss.c,v 1.14 2006/03/13 16:02:23 mickey Exp $ */
5 * Copyright (c) 2005 Michael Shalayeff
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
17 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
18 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include <sys/cdefs.h>
22 __KERNEL_RCSID(0, "$NetBSD: ciss.c,v 1.18 2009/04/18 14:58:02 tsutsui Exp $");
26 /* #define CISS_DEBUG */
28 #include <sys/param.h>
29 #include <sys/systm.h>
31 #include <sys/ioctl.h>
32 #include <sys/device.h>
33 #include <sys/kernel.h>
34 #include <sys/malloc.h>
37 #include <uvm/uvm_extern.h>
41 #include <dev/scsipi/scsi_all.h>
42 #include <dev/scsipi/scsi_disk.h>
43 #include <dev/scsipi/scsiconf.h>
45 #include <dev/ic/cissreg.h>
46 #include <dev/ic/cissvar.h>
49 #include <dev/biovar.h>
53 #define CISS_DPRINTF(m,a) if (ciss_debug & (m)) printf a
54 #define CISS_D_CMD 0x0001
55 #define CISS_D_INTR 0x0002
56 #define CISS_D_MISC 0x0004
57 #define CISS_D_DMA 0x0008
58 #define CISS_D_IOCTL 0x0010
59 #define CISS_D_ERR 0x0020
69 #define CISS_DPRINTF(m,a) /* m, a */
72 static void ciss_scsi_cmd(struct scsipi_channel
*chan
,
73 scsipi_adapter_req_t req
, void *arg
);
74 static int ciss_scsi_ioctl(struct scsipi_channel
*chan
, u_long cmd
,
75 void *addr
, int flag
, struct proc
*p
);
76 static void cissminphys(struct buf
*bp
);
79 static void ciss_scsi_raw_cmd(struct scsipi_channel
*chan
,
80 scsipi_adapter_req_t req
, void *arg
);
83 static int ciss_sync(struct ciss_softc
*sc
);
84 static void ciss_heartbeat(void *v
);
85 static void ciss_shutdown(void *v
);
87 static struct ciss_ccb
*ciss_get_ccb(struct ciss_softc
*sc
);
88 static void ciss_put_ccb(struct ciss_ccb
*ccb
);
89 static int ciss_cmd(struct ciss_ccb
*ccb
, int flags
, int wait
);
90 static int ciss_done(struct ciss_ccb
*ccb
);
91 static int ciss_error(struct ciss_ccb
*ccb
);
92 struct ciss_ld
*ciss_pdscan(struct ciss_softc
*sc
, int ld
);
93 static int ciss_inq(struct ciss_softc
*sc
, struct ciss_inquiry
*inq
);
94 int ciss_ldid(struct ciss_softc
*, int, struct ciss_ldid
*);
95 int ciss_ldstat(struct ciss_softc
*, int, struct ciss_ldstat
*);
96 static int ciss_ldmap(struct ciss_softc
*sc
);
97 int ciss_pdid(struct ciss_softc
*, u_int8_t
, struct ciss_pdid
*, int);
100 int ciss_ioctl(device_t
, u_long
, void *);
101 int ciss_ioctl_vol(struct ciss_softc
*, struct bioc_vol
*);
102 int ciss_blink(struct ciss_softc
*, int, int, int, struct ciss_blink
*);
103 int ciss_create_sensors(struct ciss_softc
*);
104 void ciss_sensor_refresh(struct sysmon_envsys
*, envsys_data_t
*);
105 #endif /* NBIO > 0 */
107 static struct ciss_ccb
*
108 ciss_get_ccb(struct ciss_softc
*sc
)
110 struct ciss_ccb
*ccb
;
112 mutex_enter(&sc
->sc_mutex
);
113 if ((ccb
= TAILQ_LAST(&sc
->sc_free_ccb
, ciss_queue_head
))) {
114 TAILQ_REMOVE(&sc
->sc_free_ccb
, ccb
, ccb_link
);
115 ccb
->ccb_state
= CISS_CCB_READY
;
117 mutex_exit(&sc
->sc_mutex
);
122 ciss_put_ccb(struct ciss_ccb
*ccb
)
124 struct ciss_softc
*sc
= ccb
->ccb_sc
;
126 ccb
->ccb_state
= CISS_CCB_FREE
;
127 mutex_enter(&sc
->sc_mutex
);
128 TAILQ_INSERT_TAIL(&sc
->sc_free_ccb
, ccb
, ccb_link
);
129 mutex_exit(&sc
->sc_mutex
);
133 ciss_attach(struct ciss_softc
*sc
)
135 struct ciss_ccb
*ccb
;
136 struct ciss_cmd
*cmd
;
137 struct ciss_inquiry
*inq
;
138 bus_dma_segment_t seg
[1];
139 int error
, i
, total
, rseg
, maxfer
;
142 bus_space_read_region_4(sc
->sc_iot
, sc
->cfg_ioh
, sc
->cfgoff
,
143 (u_int32_t
*)&sc
->cfg
, sizeof(sc
->cfg
) / 4);
145 if (sc
->cfg
.signature
!= CISS_SIGNATURE
) {
146 printf(": bad sign 0x%08x\n", sc
->cfg
.signature
);
150 if (!(sc
->cfg
.methods
& CISS_METH_SIMPL
)) {
151 printf(": not simple 0x%08x\n", sc
->cfg
.methods
);
155 sc
->cfg
.rmethod
= CISS_METH_SIMPL
;
156 sc
->cfg
.paddr_lim
= 0; /* 32bit addrs */
157 sc
->cfg
.int_delay
= 0; /* disable coalescing */
158 sc
->cfg
.int_count
= 0;
159 strlcpy(sc
->cfg
.hostname
, "HUMPPA", sizeof(sc
->cfg
.hostname
));
160 sc
->cfg
.driverf
|= CISS_DRV_PRF
; /* enable prefetch */
162 sc
->cfg
.maxsg
= MAXPHYS
/ PAGE_SIZE
+ 1;
164 bus_space_write_region_4(sc
->sc_iot
, sc
->cfg_ioh
, sc
->cfgoff
,
165 (u_int32_t
*)&sc
->cfg
, sizeof(sc
->cfg
) / 4);
166 bus_space_barrier(sc
->sc_iot
, sc
->cfg_ioh
, sc
->cfgoff
, sizeof(sc
->cfg
),
167 BUS_SPACE_BARRIER_READ
|BUS_SPACE_BARRIER_WRITE
);
169 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
, CISS_IDB
, CISS_IDB_CFG
);
170 bus_space_barrier(sc
->sc_iot
, sc
->sc_ioh
, CISS_IDB
, 4,
171 BUS_SPACE_BARRIER_WRITE
);
172 for (i
= 1000; i
--; DELAY(1000)) {
173 /* XXX maybe IDB is really 64bit? - hp dl380 needs this */
174 (void)bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, CISS_IDB
+ 4);
175 if (!(bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, CISS_IDB
) & CISS_IDB_CFG
))
177 bus_space_barrier(sc
->sc_iot
, sc
->sc_ioh
, CISS_IDB
, 4,
178 BUS_SPACE_BARRIER_READ
);
181 if (bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, CISS_IDB
) & CISS_IDB_CFG
) {
182 printf(": cannot set config\n");
186 bus_space_read_region_4(sc
->sc_iot
, sc
->cfg_ioh
, sc
->cfgoff
,
187 (u_int32_t
*)&sc
->cfg
, sizeof(sc
->cfg
) / 4);
189 if (!(sc
->cfg
.amethod
& CISS_METH_SIMPL
)) {
190 printf(": cannot simplify 0x%08x\n", sc
->cfg
.amethod
);
194 /* i'm ready for you and i hope you're ready for me */
195 for (i
= 30000; i
--; DELAY(1000)) {
196 if (bus_space_read_4(sc
->sc_iot
, sc
->cfg_ioh
, sc
->cfgoff
+
197 offsetof(struct ciss_config
, amethod
)) & CISS_METH_READY
)
199 bus_space_barrier(sc
->sc_iot
, sc
->cfg_ioh
, sc
->cfgoff
+
200 offsetof(struct ciss_config
, amethod
), 4,
201 BUS_SPACE_BARRIER_READ
);
204 if (!(bus_space_read_4(sc
->sc_iot
, sc
->cfg_ioh
, sc
->cfgoff
+
205 offsetof(struct ciss_config
, amethod
)) & CISS_METH_READY
)) {
206 printf(": she never came ready for me 0x%08x\n",
211 mutex_init(&sc
->sc_mutex
, MUTEX_DEFAULT
, IPL_VM
);
212 mutex_init(&sc
->sc_mutex_scratch
, MUTEX_DEFAULT
, IPL_VM
);
213 cv_init(&sc
->sc_condvar
, "ciss_cmd");
214 sc
->maxcmd
= sc
->cfg
.maxcmd
;
215 sc
->maxsg
= sc
->cfg
.maxsg
;
216 if (sc
->maxsg
> MAXPHYS
/ PAGE_SIZE
+ 1)
217 sc
->maxsg
= MAXPHYS
/ PAGE_SIZE
+ 1;
218 i
= sizeof(struct ciss_ccb
) +
219 sizeof(ccb
->ccb_cmd
.sgl
[0]) * (sc
->maxsg
- 1);
220 for (sc
->ccblen
= 0x10; sc
->ccblen
< i
; sc
->ccblen
<<= 1);
222 total
= sc
->ccblen
* sc
->maxcmd
;
223 if ((error
= bus_dmamem_alloc(sc
->sc_dmat
, total
, PAGE_SIZE
, 0,
224 sc
->cmdseg
, 1, &rseg
, BUS_DMA_NOWAIT
))) {
225 printf(": cannot allocate CCBs (%d)\n", error
);
229 if ((error
= bus_dmamem_map(sc
->sc_dmat
, sc
->cmdseg
, rseg
, total
,
230 (void **)&sc
->ccbs
, BUS_DMA_NOWAIT
))) {
231 printf(": cannot map CCBs (%d)\n", error
);
234 memset(sc
->ccbs
, 0, total
);
236 if ((error
= bus_dmamap_create(sc
->sc_dmat
, total
, 1,
237 total
, 0, BUS_DMA_NOWAIT
| BUS_DMA_ALLOCNOW
, &sc
->cmdmap
))) {
238 printf(": cannot create CCBs dmamap (%d)\n", error
);
239 bus_dmamem_free(sc
->sc_dmat
, sc
->cmdseg
, 1);
243 if ((error
= bus_dmamap_load(sc
->sc_dmat
, sc
->cmdmap
, sc
->ccbs
, total
,
244 NULL
, BUS_DMA_NOWAIT
))) {
245 printf(": cannot load CCBs dmamap (%d)\n", error
);
246 bus_dmamem_free(sc
->sc_dmat
, sc
->cmdseg
, 1);
247 bus_dmamap_destroy(sc
->sc_dmat
, sc
->cmdmap
);
251 TAILQ_INIT(&sc
->sc_ccbq
);
252 TAILQ_INIT(&sc
->sc_ccbdone
);
253 TAILQ_INIT(&sc
->sc_free_ccb
);
255 maxfer
= sc
->maxsg
* PAGE_SIZE
;
256 for (i
= 0; total
> 0 && i
< sc
->maxcmd
; i
++, total
-= sc
->ccblen
) {
257 ccb
= (struct ciss_ccb
*) ((char *)sc
->ccbs
+ i
* sc
->ccblen
);
259 pa
= sc
->cmdseg
[0].ds_addr
+ i
* sc
->ccblen
;
262 ccb
->ccb_cmdpa
= pa
+ offsetof(struct ciss_ccb
, ccb_cmd
);
263 ccb
->ccb_state
= CISS_CCB_FREE
;
265 cmd
->id
= htole32(i
<< 2);
266 cmd
->id_hi
= htole32(0);
267 cmd
->sgin
= sc
->maxsg
;
268 cmd
->sglen
= htole16((u_int16_t
)cmd
->sgin
);
269 cmd
->err_len
= htole32(sizeof(ccb
->ccb_err
));
270 pa
+= offsetof(struct ciss_ccb
, ccb_err
);
271 cmd
->err_pa
= htole64((u_int64_t
)pa
);
273 if ((error
= bus_dmamap_create(sc
->sc_dmat
, maxfer
, sc
->maxsg
,
274 maxfer
, 0, BUS_DMA_NOWAIT
| BUS_DMA_ALLOCNOW
,
278 TAILQ_INSERT_TAIL(&sc
->sc_free_ccb
, ccb
, ccb_link
);
281 if (i
< sc
->maxcmd
) {
282 printf(": cannot create ccb#%d dmamap (%d)\n", i
, error
);
284 /* TODO leaking cmd's dmamaps and shitz */
285 bus_dmamem_free(sc
->sc_dmat
, sc
->cmdseg
, 1);
286 bus_dmamap_destroy(sc
->sc_dmat
, sc
->cmdmap
);
291 if ((error
= bus_dmamem_alloc(sc
->sc_dmat
, PAGE_SIZE
, PAGE_SIZE
, 0,
292 seg
, 1, &rseg
, BUS_DMA_NOWAIT
))) {
293 printf(": cannot allocate scratch buffer (%d)\n", error
);
297 if ((error
= bus_dmamem_map(sc
->sc_dmat
, seg
, rseg
, PAGE_SIZE
,
298 (void **)&sc
->scratch
, BUS_DMA_NOWAIT
))) {
299 printf(": cannot map scratch buffer (%d)\n", error
);
302 memset(sc
->scratch
, 0, PAGE_SIZE
);
303 sc
->sc_waitflag
= XS_CTL_NOSLEEP
; /* can't sleep yet */
305 mutex_enter(&sc
->sc_mutex_scratch
); /* is this really needed? */
307 if (ciss_inq(sc
, inq
)) {
308 printf(": adapter inquiry failed\n");
309 mutex_exit(&sc
->sc_mutex_scratch
);
310 bus_dmamem_free(sc
->sc_dmat
, sc
->cmdseg
, 1);
311 bus_dmamap_destroy(sc
->sc_dmat
, sc
->cmdmap
);
315 if (!(inq
->flags
& CISS_INQ_BIGMAP
)) {
316 printf(": big map is not supported, flags=0x%x\n",
318 mutex_exit(&sc
->sc_mutex_scratch
);
319 bus_dmamem_free(sc
->sc_dmat
, sc
->cmdseg
, 1);
320 bus_dmamap_destroy(sc
->sc_dmat
, sc
->cmdmap
);
324 sc
->maxunits
= inq
->numld
;
325 sc
->nbus
= inq
->nscsi_bus
;
326 sc
->ndrives
= inq
->buswidth
? inq
->buswidth
: 256;
327 printf(": %d LD%s, HW rev %d, FW %4.4s/%4.4s\n",
328 inq
->numld
, inq
->numld
== 1? "" : "s",
329 inq
->hw_rev
, inq
->fw_running
, inq
->fw_stored
);
331 mutex_exit(&sc
->sc_mutex_scratch
);
333 callout_init(&sc
->sc_hb
, 0);
334 callout_setfunc(&sc
->sc_hb
, ciss_heartbeat
, sc
);
335 callout_schedule(&sc
->sc_hb
, hz
* 3);
338 if (ciss_ldmap(sc
)) {
339 aprint_error_dev(&sc
->sc_dev
, "adapter LD map failed\n");
340 bus_dmamem_free(sc
->sc_dmat
, sc
->cmdseg
, 1);
341 bus_dmamap_destroy(sc
->sc_dmat
, sc
->cmdmap
);
345 if (!(sc
->sc_lds
= malloc(sc
->maxunits
* sizeof(*sc
->sc_lds
),
346 M_DEVBUF
, M_NOWAIT
))) {
347 bus_dmamem_free(sc
->sc_dmat
, sc
->cmdseg
, 1);
348 bus_dmamap_destroy(sc
->sc_dmat
, sc
->cmdmap
);
351 memset(sc
->sc_lds
, 0, sc
->maxunits
* sizeof(*sc
->sc_lds
));
353 sc
->sc_flush
= CISS_FLUSH_ENABLE
;
354 if (!(sc
->sc_sh
= shutdownhook_establish(ciss_shutdown
, sc
))) {
355 printf(": unable to establish shutdown hook\n");
356 bus_dmamem_free(sc
->sc_dmat
, sc
->cmdseg
, 1);
357 bus_dmamap_destroy(sc
->sc_dmat
, sc
->cmdmap
);
361 sc
->sc_channel
.chan_adapter
= &sc
->sc_adapter
;
362 sc
->sc_channel
.chan_bustype
= &scsi_bustype
;
363 sc
->sc_channel
.chan_channel
= 0;
364 sc
->sc_channel
.chan_ntargets
= sc
->maxunits
;
365 sc
->sc_channel
.chan_nluns
= 1; /* ciss doesn't really have SCSI luns */
366 sc
->sc_channel
.chan_openings
= sc
->maxcmd
/ (sc
->maxunits
? sc
->maxunits
: 1);
368 /* XXX Reserve some ccb's for sensor and bioctl. */
369 if (sc
->sc_channel
.chan_openings
> 2)
370 sc
->sc_channel
.chan_openings
-= 2;
372 sc
->sc_channel
.chan_flags
= 0;
373 sc
->sc_channel
.chan_id
= sc
->maxunits
;
375 sc
->sc_adapter
.adapt_dev
= (device_t
) sc
;
376 sc
->sc_adapter
.adapt_openings
= sc
->sc_channel
.chan_openings
;
377 sc
->sc_adapter
.adapt_max_periph
= sc
->maxunits
;
378 sc
->sc_adapter
.adapt_request
= ciss_scsi_cmd
;
379 sc
->sc_adapter
.adapt_minphys
= cissminphys
;
380 sc
->sc_adapter
.adapt_ioctl
= ciss_scsi_ioctl
;
381 sc
->sc_adapter
.adapt_nchannels
= 1;
382 config_found(&sc
->sc_dev
, &sc
->sc_channel
, scsiprint
);
385 sc
->sc_link_raw
.adapter_softc
= sc
;
386 sc
->sc_link
.openings
= sc
->sc_channel
.chan_openings
;
387 sc
->sc_link_raw
.adapter
= &ciss_raw_switch
;
388 sc
->sc_link_raw
.adapter_target
= sc
->ndrives
;
389 sc
->sc_link_raw
.adapter_buswidth
= sc
->ndrives
;
390 config_found(&sc
->sc_dev
, &sc
->sc_channel
, scsiprint
);
394 /* now map all the physdevs into their lds */
395 /* XXX currently we assign all of them into ld0 */
396 for (i
= 0; i
< sc
->maxunits
&& i
< 1; i
++)
397 if (!(sc
->sc_lds
[i
] = ciss_pdscan(sc
, i
))) {
398 sc
->sc_waitflag
= 0; /* we can sleep now */
402 if (bio_register(&sc
->sc_dev
, ciss_ioctl
) != 0)
403 aprint_error_dev(&sc
->sc_dev
, "controller registration failed");
405 sc
->sc_ioctl
= ciss_ioctl
;
406 if (ciss_create_sensors(sc
) != 0)
407 aprint_error_dev(&sc
->sc_dev
, "unable to create sensors");
409 sc
->sc_waitflag
= 0; /* we can sleep now */
415 ciss_shutdown(void *v
)
417 struct ciss_softc
*sc
= v
;
419 sc
->sc_flush
= CISS_FLUSH_DISABLE
;
420 /* timeout_del(&sc->sc_hb); */
425 cissminphys(struct buf
*bp
)
428 #define CISS_MAXFER (PAGE_SIZE * (sc->maxsg + 1))
429 if (bp
->b_bcount
> CISS_MAXFER
)
430 bp
->b_bcount
= CISS_MAXFER
;
436 * submit a command and optionally wait for completition.
437 * wait arg abuses XS_CTL_POLL|XS_CTL_NOSLEEP flags to request
438 * to wait (XS_CTL_POLL) and to allow tsleep() (!XS_CTL_NOSLEEP)
439 * instead of busy loop waiting
442 ciss_cmd(struct ciss_ccb
*ccb
, int flags
, int wait
)
444 struct ciss_softc
*sc
= ccb
->ccb_sc
;
445 struct ciss_cmd
*cmd
= &ccb
->ccb_cmd
;
446 struct ciss_ccb
*ccb1
;
447 bus_dmamap_t dmap
= ccb
->ccb_dmamap
;
449 int i
, tohz
, error
= 0;
451 if (ccb
->ccb_state
!= CISS_CCB_READY
) {
452 printf("%s: ccb %d not ready state=0x%x\n", device_xname(&sc
->sc_dev
),
453 cmd
->id
, ccb
->ccb_state
);
458 bus_dma_segment_t
*sgd
;
460 if ((error
= bus_dmamap_load(sc
->sc_dmat
, dmap
, ccb
->ccb_data
,
461 ccb
->ccb_len
, NULL
, flags
))) {
463 printf("more than %d dma segs\n", sc
->maxsg
);
465 printf("error %d loading dma map\n", error
);
469 cmd
->sgin
= dmap
->dm_nsegs
;
472 CISS_DPRINTF(CISS_D_DMA
, ("data=%p/%u<0x%lx/%lu",
473 ccb
->ccb_data
, ccb
->ccb_len
, sgd
->ds_addr
,
474 (u_long
)sgd
->ds_len
));
476 for (i
= 0; i
< dmap
->dm_nsegs
; sgd
++, i
++) {
477 cmd
->sgl
[i
].addr_lo
= htole32(sgd
->ds_addr
);
478 cmd
->sgl
[i
].addr_hi
=
479 htole32((u_int64_t
)sgd
->ds_addr
>> 32);
480 cmd
->sgl
[i
].len
= htole32(sgd
->ds_len
);
481 cmd
->sgl
[i
].flags
= htole32(0);
483 CISS_DPRINTF(CISS_D_DMA
,
484 (",0x%lx/%lu", sgd
->ds_addr
,
485 (u_long
)sgd
->ds_len
));
489 CISS_DPRINTF(CISS_D_DMA
, ("> "));
491 bus_dmamap_sync(sc
->sc_dmat
, dmap
, 0, dmap
->dm_mapsize
,
492 BUS_DMASYNC_PREREAD
|BUS_DMASYNC_PREWRITE
);
495 cmd
->sglen
= htole16((u_int16_t
)cmd
->sgin
);
496 memset(&ccb
->ccb_err
, 0, sizeof(ccb
->ccb_err
));
498 bus_dmamap_sync(sc
->sc_dmat
, sc
->cmdmap
, 0, sc
->cmdmap
->dm_mapsize
,
499 BUS_DMASYNC_PREWRITE
);
501 if ((wait
& (XS_CTL_POLL
|XS_CTL_NOSLEEP
)) == (XS_CTL_POLL
|XS_CTL_NOSLEEP
))
502 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
, CISS_IMR
,
503 bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, CISS_IMR
) | sc
->iem
);
505 mutex_enter(&sc
->sc_mutex
);
506 TAILQ_INSERT_TAIL(&sc
->sc_ccbq
, ccb
, ccb_link
);
507 mutex_exit(&sc
->sc_mutex
);
508 ccb
->ccb_state
= CISS_CCB_ONQ
;
509 CISS_DPRINTF(CISS_D_CMD
, ("submit=0x%x ", cmd
->id
));
510 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
, CISS_INQ
, ccb
->ccb_cmdpa
);
512 if (wait
& XS_CTL_POLL
) {
514 CISS_DPRINTF(CISS_D_CMD
, ("waiting "));
516 i
= ccb
->ccb_xs
? ccb
->ccb_xs
->timeout
: 60000;
517 tohz
= (i
/ 1000) * hz
+ (i
% 1000) * (hz
/ 1000);
520 for (i
*= 100, etick
= tick
+ tohz
; i
--; ) {
521 if (!(wait
& XS_CTL_NOSLEEP
)) {
522 ccb
->ccb_state
= CISS_CCB_POLL
;
523 CISS_DPRINTF(CISS_D_CMD
, ("cv_timedwait(%d) ", tohz
));
524 mutex_enter(&sc
->sc_mutex
);
525 if (cv_timedwait(&sc
->sc_condvar
,
526 &sc
->sc_mutex
, tohz
) == EWOULDBLOCK
) {
527 mutex_exit(&sc
->sc_mutex
);
530 mutex_exit(&sc
->sc_mutex
);
531 if (ccb
->ccb_state
!= CISS_CCB_ONQ
) {
535 CISS_DPRINTF(CISS_D_CMD
, ("T"));
542 if (!(bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
,
543 CISS_ISR
) & sc
->iem
)) {
544 CISS_DPRINTF(CISS_D_CMD
, ("N"));
548 if ((id
= bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
,
549 CISS_OUTQ
)) == 0xffffffff) {
550 CISS_DPRINTF(CISS_D_CMD
, ("Q"));
554 CISS_DPRINTF(CISS_D_CMD
, ("got=0x%x ", id
));
555 ccb1
= (struct ciss_ccb
*)
556 ((char *)sc
->ccbs
+ (id
>> 2) * sc
->ccblen
);
557 ccb1
->ccb_cmd
.id
= htole32(id
);
560 error
= ciss_done(ccb1
);
565 /* if never got a chance to be done above... */
566 if (ccb
->ccb_state
!= CISS_CCB_FREE
) {
567 ccb
->ccb_err
.cmd_stat
= CISS_ERR_TMO
;
568 error
= ciss_done(ccb
);
571 CISS_DPRINTF(CISS_D_CMD
, ("done %d:%d",
572 ccb
->ccb_err
.cmd_stat
, ccb
->ccb_err
.scsi_stat
));
575 if ((wait
& (XS_CTL_POLL
|XS_CTL_NOSLEEP
)) == (XS_CTL_POLL
|XS_CTL_NOSLEEP
))
576 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
, CISS_IMR
,
577 bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, CISS_IMR
) & ~sc
->iem
);
583 ciss_done(struct ciss_ccb
*ccb
)
585 struct ciss_softc
*sc
= ccb
->ccb_sc
;
586 struct scsipi_xfer
*xs
= ccb
->ccb_xs
;
587 struct ciss_cmd
*cmd
;
590 CISS_DPRINTF(CISS_D_CMD
, ("ciss_done(%p) ", ccb
));
592 if (ccb
->ccb_state
!= CISS_CCB_ONQ
) {
593 printf("%s: unqueued ccb %p ready, state=0x%x\n",
594 device_xname(&sc
->sc_dev
), ccb
, ccb
->ccb_state
);
598 ccb
->ccb_state
= CISS_CCB_READY
;
599 mutex_enter(&sc
->sc_mutex
);
600 TAILQ_REMOVE(&sc
->sc_ccbq
, ccb
, ccb_link
);
601 mutex_exit(&sc
->sc_mutex
);
603 if (ccb
->ccb_cmd
.id
& CISS_CMD_ERR
)
604 error
= ciss_error(ccb
);
608 bus_dmamap_sync(sc
->sc_dmat
, ccb
->ccb_dmamap
, 0,
609 ccb
->ccb_dmamap
->dm_mapsize
, (cmd
->flags
& CISS_CDB_IN
) ?
610 BUS_DMASYNC_POSTREAD
: BUS_DMASYNC_POSTWRITE
);
611 bus_dmamap_unload(sc
->sc_dmat
, ccb
->ccb_dmamap
);
613 ccb
->ccb_data
= NULL
;
620 CISS_DPRINTF(CISS_D_CMD
, ("scsipi_done(%p) ", xs
));
628 ciss_error(struct ciss_ccb
*ccb
)
630 struct ciss_softc
*sc
= ccb
->ccb_sc
;
631 struct ciss_error
*err
= &ccb
->ccb_err
;
632 struct scsipi_xfer
*xs
= ccb
->ccb_xs
;
635 switch ((rv
= le16toh(err
->cmd_stat
))) {
639 case CISS_ERR_INVCMD
:
640 printf("%s: invalid cmd 0x%x: 0x%x is not valid @ 0x%x[%d]\n",
641 device_xname(&sc
->sc_dev
), ccb
->ccb_cmd
.id
,
642 err
->err_info
, err
->err_type
[3], err
->err_type
[2]);
644 memset(&xs
->sense
, 0, sizeof(xs
->sense
));
645 xs
->sense
.scsi_sense
.response_code
=
646 SSD_RCODE_CURRENT
| SSD_RCODE_VALID
;
647 xs
->sense
.scsi_sense
.flags
= SKEY_ILLEGAL_REQUEST
;
648 xs
->sense
.scsi_sense
.asc
= 0x24; /* ill field */
649 xs
->sense
.scsi_sense
.ascq
= 0x0;
650 xs
->error
= XS_SENSE
;
655 xs
->error
= XS_TIMEOUT
;
660 xs
->resid
= le32toh(err
->resid
);
661 CISS_DPRINTF(CISS_D_CMD
, (" underrun resid=0x%x ",
666 CISS_DPRINTF(CISS_D_CMD
, ("scsi_stat=%x ", err
->scsi_stat
));
667 switch (err
->scsi_stat
) {
669 xs
->error
= XS_SENSE
;
670 memcpy(&xs
->sense
, &err
->sense
[0],
672 CISS_DPRINTF(CISS_D_CMD
, (" sense=%02x %02x %02x %02x ",
673 err
->sense
[0], err
->sense
[1], err
->sense
[2], err
->sense
[3]));
681 CISS_DPRINTF(CISS_D_ERR
, ("%s: "
682 "cmd_stat=%x scsi_stat=0x%x resid=0x%x\n",
683 device_xname(&sc
->sc_dev
), rv
, err
->scsi_stat
,
684 le32toh(err
->resid
)));
685 printf("ciss driver stuffup in %s:%d: %s()\n",
686 __FILE__
, __LINE__
, __func__
);
687 xs
->error
= XS_DRIVER_STUFFUP
;
690 xs
->resid
= le32toh(err
->resid
);
693 ccb
->ccb_cmd
.id
&= htole32(~3);
699 ciss_inq(struct ciss_softc
*sc
, struct ciss_inquiry
*inq
)
701 struct ciss_ccb
*ccb
;
702 struct ciss_cmd
*cmd
;
704 ccb
= ciss_get_ccb(sc
);
705 ccb
->ccb_len
= sizeof(*inq
);
709 cmd
->tgt
= htole32(CISS_CMD_MODE_PERIPH
);
712 cmd
->flags
= CISS_CDB_CMD
| CISS_CDB_SIMPL
| CISS_CDB_IN
;
713 cmd
->tmo
= htole16(0);
714 memset(&cmd
->cdb
[0], 0, sizeof(cmd
->cdb
));
715 cmd
->cdb
[0] = CISS_CMD_CTRL_GET
;
716 cmd
->cdb
[6] = CISS_CMS_CTRL_CTRL
;
717 cmd
->cdb
[7] = sizeof(*inq
) >> 8; /* biiiig endian */
718 cmd
->cdb
[8] = sizeof(*inq
) & 0xff;
720 return ciss_cmd(ccb
, BUS_DMA_NOWAIT
, XS_CTL_POLL
|XS_CTL_NOSLEEP
);
724 ciss_ldmap(struct ciss_softc
*sc
)
726 struct ciss_ccb
*ccb
;
727 struct ciss_cmd
*cmd
;
728 struct ciss_ldmap
*lmap
;
731 mutex_enter(&sc
->sc_mutex_scratch
);
733 lmap
->size
= htobe32(sc
->maxunits
* sizeof(lmap
->map
));
734 total
= sizeof(*lmap
) + (sc
->maxunits
- 1) * sizeof(lmap
->map
);
736 ccb
= ciss_get_ccb(sc
);
737 ccb
->ccb_len
= total
;
738 ccb
->ccb_data
= lmap
;
741 cmd
->tgt
= CISS_CMD_MODE_PERIPH
;
744 cmd
->flags
= CISS_CDB_CMD
| CISS_CDB_SIMPL
| CISS_CDB_IN
;
745 cmd
->tmo
= htole16(30);
746 memset(&cmd
->cdb
[0], 0, sizeof(cmd
->cdb
));
747 cmd
->cdb
[0] = CISS_CMD_LDMAP
;
748 cmd
->cdb
[8] = total
>> 8; /* biiiig endian */
749 cmd
->cdb
[9] = total
& 0xff;
751 rv
= ciss_cmd(ccb
, BUS_DMA_NOWAIT
, XS_CTL_POLL
|XS_CTL_NOSLEEP
);
754 mutex_exit(&sc
->sc_mutex_scratch
);
758 CISS_DPRINTF(CISS_D_MISC
, ("lmap %x:%x\n",
759 lmap
->map
[0].tgt
, lmap
->map
[0].tgt2
));
761 mutex_exit(&sc
->sc_mutex_scratch
);
766 ciss_sync(struct ciss_softc
*sc
)
768 struct ciss_ccb
*ccb
;
769 struct ciss_cmd
*cmd
;
770 struct ciss_flush
*flush
;
773 mutex_enter(&sc
->sc_mutex_scratch
);
775 memset(flush
, 0, sizeof(*flush
));
776 flush
->flush
= sc
->sc_flush
;
778 ccb
= ciss_get_ccb(sc
);
779 ccb
->ccb_len
= sizeof(*flush
);
780 ccb
->ccb_data
= flush
;
783 cmd
->tgt
= CISS_CMD_MODE_PERIPH
;
786 cmd
->flags
= CISS_CDB_CMD
| CISS_CDB_SIMPL
| CISS_CDB_OUT
;
788 memset(&cmd
->cdb
[0], 0, sizeof(cmd
->cdb
));
789 cmd
->cdb
[0] = CISS_CMD_CTRL_SET
;
790 cmd
->cdb
[6] = CISS_CMS_CTRL_FLUSH
;
791 cmd
->cdb
[7] = sizeof(*flush
) >> 8; /* biiiig endian */
792 cmd
->cdb
[8] = sizeof(*flush
) & 0xff;
794 rv
= ciss_cmd(ccb
, BUS_DMA_NOWAIT
, XS_CTL_POLL
|XS_CTL_NOSLEEP
);
795 mutex_exit(&sc
->sc_mutex_scratch
);
801 ciss_ldid(struct ciss_softc
*sc
, int target
, struct ciss_ldid
*id
)
803 struct ciss_ccb
*ccb
;
804 struct ciss_cmd
*cmd
;
806 ccb
= ciss_get_ccb(sc
);
809 ccb
->ccb_len
= sizeof(*id
);
813 cmd
->tgt
= htole32(CISS_CMD_MODE_PERIPH
);
816 cmd
->flags
= CISS_CDB_CMD
| CISS_CDB_SIMPL
| CISS_CDB_IN
;
817 cmd
->tmo
= htole16(0);
818 memset(&cmd
->cdb
[0], 0, sizeof(cmd
->cdb
));
819 cmd
->cdb
[0] = CISS_CMD_CTRL_GET
;
820 cmd
->cdb
[1] = target
;
821 cmd
->cdb
[6] = CISS_CMS_CTRL_LDIDEXT
;
822 cmd
->cdb
[7] = sizeof(*id
) >> 8; /* biiiig endian */
823 cmd
->cdb
[8] = sizeof(*id
) & 0xff;
825 return ciss_cmd(ccb
, BUS_DMA_NOWAIT
, XS_CTL_POLL
| sc
->sc_waitflag
);
829 ciss_ldstat(struct ciss_softc
*sc
, int target
, struct ciss_ldstat
*stat
)
831 struct ciss_ccb
*ccb
;
832 struct ciss_cmd
*cmd
;
834 ccb
= ciss_get_ccb(sc
);
837 ccb
->ccb_len
= sizeof(*stat
);
838 ccb
->ccb_data
= stat
;
841 cmd
->tgt
= htole32(CISS_CMD_MODE_PERIPH
);
844 cmd
->flags
= CISS_CDB_CMD
| CISS_CDB_SIMPL
| CISS_CDB_IN
;
845 cmd
->tmo
= htole16(0);
846 memset(&cmd
->cdb
[0], 0, sizeof(cmd
->cdb
));
847 cmd
->cdb
[0] = CISS_CMD_CTRL_GET
;
848 cmd
->cdb
[1] = target
;
849 cmd
->cdb
[6] = CISS_CMS_CTRL_LDSTAT
;
850 cmd
->cdb
[7] = sizeof(*stat
) >> 8; /* biiiig endian */
851 cmd
->cdb
[8] = sizeof(*stat
) & 0xff;
853 return ciss_cmd(ccb
, BUS_DMA_NOWAIT
, XS_CTL_POLL
| sc
->sc_waitflag
);
857 ciss_pdid(struct ciss_softc
*sc
, u_int8_t drv
, struct ciss_pdid
*id
, int wait
)
859 struct ciss_ccb
*ccb
;
860 struct ciss_cmd
*cmd
;
862 ccb
= ciss_get_ccb(sc
);
865 ccb
->ccb_len
= sizeof(*id
);
869 cmd
->tgt
= htole32(CISS_CMD_MODE_PERIPH
);
872 cmd
->flags
= CISS_CDB_CMD
| CISS_CDB_SIMPL
| CISS_CDB_IN
;
873 cmd
->tmo
= htole16(0);
874 memset(&cmd
->cdb
[0], 0, sizeof(cmd
->cdb
));
875 cmd
->cdb
[0] = CISS_CMD_CTRL_GET
;
877 cmd
->cdb
[6] = CISS_CMS_CTRL_PDID
;
878 cmd
->cdb
[7] = sizeof(*id
) >> 8; /* biiiig endian */
879 cmd
->cdb
[8] = sizeof(*id
) & 0xff;
881 return ciss_cmd(ccb
, BUS_DMA_NOWAIT
, wait
);
886 ciss_pdscan(struct ciss_softc
*sc
, int ld
)
888 struct ciss_pdid
*pdid
;
890 u_int8_t drv
, buf
[128];
893 mutex_enter(&sc
->sc_mutex_scratch
);
895 if (sc
->ndrives
== 256) {
896 for (i
= 0; i
< CISS_BIGBIT
; i
++)
897 if (!ciss_pdid(sc
, i
, pdid
,
898 XS_CTL_POLL
|XS_CTL_NOSLEEP
) &&
899 (pdid
->present
& CISS_PD_PRESENT
))
902 for (i
= 0; i
< sc
->nbus
; i
++)
903 for (j
= 0; j
< sc
->ndrives
; j
++) {
904 drv
= CISS_BIGBIT
+ i
* sc
->ndrives
+ j
;
905 if (!ciss_pdid(sc
, drv
, pdid
,
906 XS_CTL_POLL
|XS_CTL_NOSLEEP
))
909 mutex_exit(&sc
->sc_mutex_scratch
);
914 ldp
= malloc(sizeof(*ldp
) + (k
-1), M_DEVBUF
, M_NOWAIT
);
918 memset(&ldp
->bling
, 0, sizeof(ldp
->bling
));
921 memcpy(ldp
->tgts
, buf
, k
);
927 ciss_scsi_raw_cmd(struct scsipi_channel
*chan
, scsipi_adapter_req_t req
,
928 void *arg
) /* TODO */
930 struct scsipi_xfer
*xs
= (struct scsipi_xfer
*) arg
;
931 struct ciss_rawsoftc
*rsc
=
932 (struct ciss_rawsoftc
*) chan
->chan_adapter
->adapt_dev
;
933 struct ciss_softc
*sc
= rsc
->sc_softc
;
934 struct ciss_ccb
*ccb
;
935 struct ciss_cmd
*cmd
;
938 CISS_DPRINTF(CISS_D_CMD
, ("ciss_scsi_raw_cmd "));
942 case ADAPTER_REQ_RUN_XFER
:
943 if (xs
->cmdlen
> CISS_MAX_CDB
) {
944 CISS_DPRINTF(CISS_D_CMD
, ("CDB too big %p ", xs
));
945 memset(&xs
->sense
, 0, sizeof(xs
->sense
));
946 printf("ciss driver stuffup in %s:%d: %s()\n",
947 __FILE__
, __LINE__
, __func__
);
948 xs
->error
= XS_DRIVER_STUFFUP
;
954 xs
->error
= XS_NOERROR
;
956 /* TODO check this target has not yet employed w/ any volume */
958 ccb
= ciss_get_ccb(sc
);
960 ccb
->ccb_len
= xs
->datalen
;
961 ccb
->ccb_data
= xs
->data
;
964 cmd
->cdblen
= xs
->cmdlen
;
965 cmd
->flags
= CISS_CDB_CMD
| CISS_CDB_SIMPL
;
966 if (xs
->xs_control
& XS_CTL_DATA_IN
)
967 cmd
->flags
|= CISS_CDB_IN
;
968 else if (xs
->xs_control
& XS_CTL_DATA_OUT
)
969 cmd
->flags
|= CISS_CDB_OUT
;
970 cmd
->tmo
= xs
->timeout
< 1000? 1 : xs
->timeout
/ 1000;
971 memset(&cmd
->cdb
[0], 0, sizeof(cmd
->cdb
));
972 memcpy(&cmd
->cdb
[0], xs
->cmd
, CISS_MAX_CDB
);
974 if (ciss_cmd(ccb
, BUS_DMA_WAITOK
,
975 xs
->xs_control
& (XS_CTL_POLL
|XS_CTL_NOSLEEP
))) {
976 printf("ciss driver stuffup in %s:%d: %s()\n",
977 __FILE__
, __LINE__
, __func__
);
978 xs
->error
= XS_DRIVER_STUFFUP
;
985 case ADAPTER_REQ_GROW_RESOURCES
:
991 case ADAPTER_REQ_SET_XFER_MODE
:
993 * We can't change the transfer mode, but at least let
994 * scsipi know what the adapter has negociated.
996 /* Get xfer mode and return it */
1003 ciss_scsi_cmd(struct scsipi_channel
*chan
, scsipi_adapter_req_t req
,
1006 struct scsipi_xfer
*xs
= (struct scsipi_xfer
*) arg
;
1007 struct ciss_softc
*sc
=
1008 (struct ciss_softc
*) chan
->chan_adapter
->adapt_dev
;
1010 struct ciss_ccb
*ccb
;
1011 struct ciss_cmd
*cmd
;
1014 CISS_DPRINTF(CISS_D_CMD
, ("ciss_scsi_cmd "));
1018 case ADAPTER_REQ_RUN_XFER
:
1019 target
= xs
->xs_periph
->periph_target
;
1020 CISS_DPRINTF(CISS_D_CMD
, ("targ=%d ", target
));
1021 if (xs
->cmdlen
> CISS_MAX_CDB
) {
1022 CISS_DPRINTF(CISS_D_CMD
, ("CDB too big %p ", xs
));
1023 memset(&xs
->sense
, 0, sizeof(xs
->sense
));
1024 printf("ciss driver stuffup in %s:%d: %s()\n",
1025 __FILE__
, __LINE__
, __func__
);
1026 xs
->error
= XS_DRIVER_STUFFUP
;
1032 xs
->error
= XS_NOERROR
;
1034 /* XXX emulate SYNCHRONIZE_CACHE ??? */
1036 ccb
= ciss_get_ccb(sc
);
1037 cmd
= &ccb
->ccb_cmd
;
1038 ccb
->ccb_len
= xs
->datalen
;
1039 ccb
->ccb_data
= xs
->data
;
1041 cmd
->tgt
= CISS_CMD_MODE_LD
| target
;
1043 cmd
->cdblen
= xs
->cmdlen
;
1044 cmd
->flags
= CISS_CDB_CMD
| CISS_CDB_SIMPL
;
1045 if (xs
->xs_control
& XS_CTL_DATA_IN
)
1046 cmd
->flags
|= CISS_CDB_IN
;
1047 else if (xs
->xs_control
& XS_CTL_DATA_OUT
)
1048 cmd
->flags
|= CISS_CDB_OUT
;
1049 cmd
->tmo
= xs
->timeout
< 1000? 1 : xs
->timeout
/ 1000;
1050 memset(&cmd
->cdb
[0], 0, sizeof(cmd
->cdb
));
1051 memcpy(&cmd
->cdb
[0], xs
->cmd
, CISS_MAX_CDB
);
1052 CISS_DPRINTF(CISS_D_CMD
, ("cmd=%02x %02x %02x %02x %02x %02x ",
1053 cmd
->cdb
[0], cmd
->cdb
[1], cmd
->cdb
[2],
1054 cmd
->cdb
[3], cmd
->cdb
[4], cmd
->cdb
[5]));
1056 if (ciss_cmd(ccb
, BUS_DMA_WAITOK
,
1057 xs
->xs_control
& (XS_CTL_POLL
|XS_CTL_NOSLEEP
))) {
1058 printf("ciss driver stuffup in %s:%d: %s()\n",
1059 __FILE__
, __LINE__
, __func__
);
1060 xs
->error
= XS_DRIVER_STUFFUP
;
1066 case ADAPTER_REQ_GROW_RESOURCES
:
1071 case ADAPTER_REQ_SET_XFER_MODE
:
1073 * We can't change the transfer mode, but at least let
1074 * scsipi know what the adapter has negociated.
1076 /* FIXME: get xfer mode and write it into arg */
1084 struct ciss_softc
*sc
= v
;
1085 struct ciss_ccb
*ccb
;
1089 CISS_DPRINTF(CISS_D_INTR
, ("intr "));
1091 if (!(bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, CISS_ISR
) & sc
->iem
))
1094 while ((id
= bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, CISS_OUTQ
)) !=
1097 ccb
= (struct ciss_ccb
*) ((char *)sc
->ccbs
+ (id
>> 2) * sc
->ccblen
);
1098 ccb
->ccb_cmd
.id
= htole32(id
);
1099 if (ccb
->ccb_state
== CISS_CCB_POLL
) {
1100 ccb
->ccb_state
= CISS_CCB_ONQ
;
1101 mutex_enter(&sc
->sc_mutex
);
1102 cv_broadcast(&sc
->sc_condvar
);
1103 mutex_exit(&sc
->sc_mutex
);
1110 CISS_DPRINTF(CISS_D_INTR
, ("exit\n"));
1115 ciss_heartbeat(void *v
)
1117 struct ciss_softc
*sc
= v
;
1120 hb
= bus_space_read_4(sc
->sc_iot
, sc
->cfg_ioh
,
1121 sc
->cfgoff
+ offsetof(struct ciss_config
, heartbeat
));
1122 if (hb
== sc
->heartbeat
)
1123 panic("ciss: dead"); /* XX reset! */
1127 callout_schedule(&sc
->sc_hb
, hz
* 3);
1131 ciss_scsi_ioctl(struct scsipi_channel
*chan
, u_long cmd
,
1132 void *addr
, int flag
, struct proc
*p
)
1135 return ciss_ioctl(chan
->chan_adapter
->adapt_dev
, cmd
, addr
);
1142 const int ciss_level
[] = { 0, 4, 1, 5, 51, 7 };
1143 const int ciss_stat
[] = { BIOC_SVONLINE
, BIOC_SVOFFLINE
, BIOC_SVOFFLINE
,
1144 BIOC_SVDEGRADED
, BIOC_SVREBUILD
, BIOC_SVREBUILD
, BIOC_SVDEGRADED
,
1145 BIOC_SVDEGRADED
, BIOC_SVINVALID
, BIOC_SVINVALID
, BIOC_SVBUILDING
,
1146 BIOC_SVOFFLINE
, BIOC_SVBUILDING
};
1149 ciss_ioctl(device_t dev
, u_long cmd
, void *addr
)
1151 struct ciss_softc
*sc
= (struct ciss_softc
*)dev
;
1152 struct bioc_inq
*bi
;
1153 struct bioc_disk
*bd
;
1154 struct bioc_blink
*bb
;
1155 struct ciss_ldstat
*ldstat
;
1156 struct ciss_pdid
*pdid
;
1157 struct ciss_blink
*blink
;
1158 struct ciss_ld
*ldp
;
1160 int ld
, pd
, error
= 0;
1164 bi
= (struct bioc_inq
*)addr
;
1165 strlcpy(bi
->bi_dev
, device_xname(&sc
->sc_dev
), sizeof(bi
->bi_dev
));
1166 bi
->bi_novol
= sc
->maxunits
;
1167 bi
->bi_nodisk
= sc
->sc_lds
[0]->ndrives
;
1171 error
= ciss_ioctl_vol(sc
, (struct bioc_vol
*)addr
);
1174 case BIOCDISK_NOVOL
:
1176 * XXX since we don't know how to associate physical drives with logical drives
1177 * yet, BIOCDISK_NOVOL is equivalent to BIOCDISK to the volume that we've
1178 * associated all physical drives to.
1179 * Maybe assoicate all physical drives to all logical volumes, but only return
1180 * physical drives on one logical volume. Which one? Either 1st volume that
1181 * is degraded, rebuilding, or failed?
1183 bd
= (struct bioc_disk
*)addr
;
1185 bd
->bd_disknovol
= true;
1188 bd
= (struct bioc_disk
*)addr
;
1189 if (bd
->bd_volid
> sc
->maxunits
) {
1193 ldp
= sc
->sc_lds
[0];
1194 if (!ldp
|| (pd
= bd
->bd_diskid
) > ldp
->ndrives
) {
1198 ldstat
= sc
->scratch
;
1199 if ((error
= ciss_ldstat(sc
, bd
->bd_volid
, ldstat
))) {
1203 if (ldstat
->stat
== CISS_LD_REBLD
&&
1204 ldstat
->bigrebuild
== ldp
->tgts
[pd
])
1205 bd
->bd_status
= BIOC_SDREBUILD
;
1206 if (ciss_bitset(ldp
->tgts
[pd
] & (~CISS_BIGBIT
),
1207 ldstat
->bigfailed
)) {
1208 bd
->bd_status
= BIOC_SDFAILED
;
1210 bd
->bd_channel
= (ldp
->tgts
[pd
] & (~CISS_BIGBIT
)) /
1212 bd
->bd_target
= ldp
->tgts
[pd
] % sc
->ndrives
;
1214 bd
->bd_vendor
[0] = '\0';
1215 bd
->bd_serial
[0] = '\0';
1216 bd
->bd_procdev
[0] = '\0';
1219 if ((error
= ciss_pdid(sc
, ldp
->tgts
[pd
], pdid
,
1221 bd
->bd_status
= BIOC_SDFAILED
;
1223 bd
->bd_channel
= (ldp
->tgts
[pd
] & (~CISS_BIGBIT
)) /
1225 bd
->bd_target
= ldp
->tgts
[pd
] % sc
->ndrives
;
1227 bd
->bd_vendor
[0] = '\0';
1228 bd
->bd_serial
[0] = '\0';
1229 bd
->bd_procdev
[0] = '\0';
1233 if (bd
->bd_status
< 0) {
1234 if (pdid
->config
& CISS_PD_SPARE
)
1235 bd
->bd_status
= BIOC_SDHOTSPARE
;
1236 else if (pdid
->present
& CISS_PD_PRESENT
)
1237 bd
->bd_status
= BIOC_SDONLINE
;
1239 bd
->bd_status
= BIOC_SDINVALID
;
1241 bd
->bd_size
= (u_int64_t
)le32toh(pdid
->nblocks
) *
1242 le16toh(pdid
->blksz
);
1243 bd
->bd_channel
= pdid
->bus
;
1244 bd
->bd_target
= pdid
->target
;
1246 strlcpy(bd
->bd_vendor
, pdid
->model
,
1247 sizeof(bd
->bd_vendor
));
1248 strlcpy(bd
->bd_serial
, pdid
->serial
,
1249 sizeof(bd
->bd_serial
));
1250 bd
->bd_procdev
[0] = '\0';
1255 bb
= (struct bioc_blink
*)addr
;
1256 blink
= sc
->scratch
;
1258 /* XXX workaround completely dumb scsi addressing */
1259 for (ld
= 0; ld
< sc
->maxunits
; ld
++) {
1260 ldp
= sc
->sc_lds
[ld
];
1263 if (sc
->ndrives
== 256)
1264 drv
= bb
->bb_target
;
1267 bb
->bb_channel
* sc
->ndrives
+
1269 for (pd
= 0; pd
< ldp
->ndrives
; pd
++)
1270 if (ldp
->tgts
[pd
] == drv
)
1271 error
= ciss_blink(sc
, ld
, pd
,
1272 bb
->bb_status
, blink
);
1286 ciss_ioctl_vol(struct ciss_softc
*sc
, struct bioc_vol
*bv
)
1288 struct ciss_ldid
*ldid
;
1289 struct ciss_ld
*ldp
;
1290 struct ciss_ldstat
*ldstat
;
1291 struct ciss_pdid
*pdid
;
1295 if (bv
->bv_volid
> sc
->maxunits
) {
1298 ldp
= sc
->sc_lds
[bv
->bv_volid
];
1300 if ((error
= ciss_ldid(sc
, bv
->bv_volid
, ldid
))) {
1303 bv
->bv_status
= BIOC_SVINVALID
;
1304 blks
= (u_int
)le16toh(ldid
->nblocks
[1]) << 16 |
1305 le16toh(ldid
->nblocks
[0]);
1306 bv
->bv_size
= blks
* (u_quad_t
)le16toh(ldid
->blksize
);
1307 bv
->bv_level
= ciss_level
[ldid
->type
];
1309 * XXX Should only return bv_nodisk for logigal volume that we've associated
1310 * the physical drives to: either the 1st degraded, rebuilding, or failed
1311 * volume else volume 0?
1314 bv
->bv_nodisk
= ldp
->ndrives
;
1315 strlcpy(bv
->bv_dev
, ldp
->xname
, sizeof(bv
->bv_dev
));
1317 strlcpy(bv
->bv_vendor
, "CISS", sizeof(bv
->bv_vendor
));
1318 ldstat
= sc
->scratch
;
1319 memset(ldstat
, 0, sizeof(*ldstat
));
1320 if ((error
= ciss_ldstat(sc
, bv
->bv_volid
, ldstat
))) {
1323 bv
->bv_percent
= -1;
1325 if (ldstat
->stat
< sizeof(ciss_stat
)/sizeof(ciss_stat
[0]))
1326 bv
->bv_status
= ciss_stat
[ldstat
->stat
];
1327 if (bv
->bv_status
== BIOC_SVREBUILD
||
1328 bv
->bv_status
== BIOC_SVBUILDING
) {
1331 ldp
= sc
->sc_lds
[0];
1333 bv
->bv_nodisk
= ldp
->ndrives
;
1334 strlcpy(bv
->bv_dev
, ldp
->xname
, sizeof(bv
->bv_dev
));
1337 * XXX ldstat->prog is blocks remaining on physical drive being rebuilt
1338 * blks is only correct for a RAID1 set; RAID5 needs to determine the
1339 * size of the physical device - which we don't yet know.
1340 * ldstat->bigrebuild has physical device target, so could be used with
1341 * pdid to get size. Another way is to save pd information in sc so it's
1342 * easy to reference.
1344 prog
= (u_int64_t
)((ldstat
->prog
[3] << 24) |
1345 (ldstat
->prog
[2] << 16) | (ldstat
->prog
[1] << 8) |
1348 if (!ciss_pdid(sc
, ldstat
->bigrebuild
, pdid
, XS_CTL_POLL
)) {
1349 blks
= le32toh(pdid
->nblocks
);
1350 bv
->bv_percent
= (blks
- prog
) * 1000ULL / blks
;
1357 ciss_blink(struct ciss_softc
*sc
, int ld
, int pd
, int stat
,
1358 struct ciss_blink
*blink
)
1360 struct ciss_ccb
*ccb
;
1361 struct ciss_cmd
*cmd
;
1362 struct ciss_ld
*ldp
;
1364 if (ld
> sc
->maxunits
)
1367 ldp
= sc
->sc_lds
[ld
];
1368 if (!ldp
|| pd
> ldp
->ndrives
)
1371 ldp
->bling
.pdtab
[ldp
->tgts
[pd
]] = stat
== BIOC_SBUNBLINK
? 0 :
1373 memcpy(blink
, &ldp
->bling
, sizeof(*blink
));
1375 ccb
= ciss_get_ccb(sc
);
1378 ccb
->ccb_len
= sizeof(*blink
);
1379 ccb
->ccb_data
= blink
;
1381 cmd
= &ccb
->ccb_cmd
;
1382 cmd
->tgt
= htole32(CISS_CMD_MODE_PERIPH
);
1385 cmd
->flags
= CISS_CDB_CMD
| CISS_CDB_SIMPL
| CISS_CDB_OUT
;
1386 cmd
->tmo
= htole16(0);
1387 memset(&cmd
->cdb
[0], 0, sizeof(cmd
->cdb
));
1388 cmd
->cdb
[0] = CISS_CMD_CTRL_SET
;
1389 cmd
->cdb
[6] = CISS_CMS_CTRL_PDBLINK
;
1390 cmd
->cdb
[7] = sizeof(*blink
) >> 8; /* biiiig endian */
1391 cmd
->cdb
[8] = sizeof(*blink
) & 0xff;
1393 return ciss_cmd(ccb
, BUS_DMA_NOWAIT
, XS_CTL_POLL
);
1397 ciss_create_sensors(struct ciss_softc
*sc
)
1400 int nsensors
= sc
->maxunits
;
1402 sc
->sc_sme
= sysmon_envsys_create();
1403 sc
->sc_sensor
= malloc(sizeof(envsys_data_t
) * nsensors
,
1404 M_DEVBUF
, M_NOWAIT
| M_ZERO
);
1405 if (sc
->sc_sensor
== NULL
) {
1406 aprint_error_dev(&sc
->sc_dev
, "can't allocate envsys_data");
1410 for (i
= 0; i
< nsensors
; i
++) {
1411 sc
->sc_sensor
[i
].units
= ENVSYS_DRIVE
;
1412 sc
->sc_sensor
[i
].monitor
= true;
1413 /* Enable monitoring for drive state changes */
1414 sc
->sc_sensor
[i
].flags
|= ENVSYS_FMONSTCHANGED
;
1415 /* logical drives */
1416 snprintf(sc
->sc_sensor
[i
].desc
,
1417 sizeof(sc
->sc_sensor
[i
].desc
), "%s:%d",
1418 device_xname(&sc
->sc_dev
), i
);
1419 if (sysmon_envsys_sensor_attach(sc
->sc_sme
,
1424 sc
->sc_sme
->sme_name
= device_xname(&sc
->sc_dev
);
1425 sc
->sc_sme
->sme_cookie
= sc
;
1426 sc
->sc_sme
->sme_refresh
= ciss_sensor_refresh
;
1427 if (sysmon_envsys_register(sc
->sc_sme
)) {
1428 printf("%s: unable to register with sysmon\n", device_xname(&sc
->sc_dev
));
1434 free(sc
->sc_sensor
, M_DEVBUF
);
1435 sysmon_envsys_destroy(sc
->sc_sme
);
1440 ciss_sensor_refresh(struct sysmon_envsys
*sme
, envsys_data_t
*edata
)
1442 struct ciss_softc
*sc
= sme
->sme_cookie
;
1445 if (edata
->sensor
>= sc
->maxunits
)
1448 memset(&bv
, 0, sizeof(bv
));
1449 bv
.bv_volid
= edata
->sensor
;
1450 if (ciss_ioctl_vol(sc
, &bv
)) {
1454 switch(bv
.bv_status
) {
1455 case BIOC_SVOFFLINE
:
1456 edata
->value_cur
= ENVSYS_DRIVE_FAIL
;
1457 edata
->state
= ENVSYS_SCRITICAL
;
1460 case BIOC_SVDEGRADED
:
1461 edata
->value_cur
= ENVSYS_DRIVE_PFAIL
;
1462 edata
->state
= ENVSYS_SCRITICAL
;
1467 edata
->value_cur
= ENVSYS_DRIVE_ONLINE
;
1468 edata
->state
= ENVSYS_SVALID
;
1471 case BIOC_SVREBUILD
:
1472 case BIOC_SVBUILDING
:
1473 edata
->value_cur
= ENVSYS_DRIVE_REBUILD
;
1474 edata
->state
= ENVSYS_SVALID
;
1477 case BIOC_SVINVALID
:
1480 edata
->value_cur
= 0; /* unknown */
1481 edata
->state
= ENVSYS_SINVALID
;
1484 #endif /* NBIO > 0 */