Line data Source code
1 : /* $OpenBSD: mfi.c,v 1.169 2018/08/14 05:22:21 jmatthew Exp $ */
2 : /*
3 : * Copyright (c) 2006 Marco Peereboom <marco@peereboom.us>
4 : *
5 : * Permission to use, copy, modify, and distribute this software for any
6 : * purpose with or without fee is hereby granted, provided that the above
7 : * copyright notice and this permission notice appear in all copies.
8 : *
9 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 : */
17 :
18 : #include "bio.h"
19 :
20 : #include <sys/param.h>
21 : #include <sys/systm.h>
22 : #include <sys/buf.h>
23 : #include <sys/device.h>
24 : #include <sys/kernel.h>
25 : #include <sys/malloc.h>
26 : #include <sys/rwlock.h>
27 : #include <sys/sensors.h>
28 : #include <sys/dkio.h>
29 : #include <sys/pool.h>
30 :
31 : #include <machine/bus.h>
32 :
33 : #include <scsi/scsi_all.h>
34 : #include <scsi/scsi_disk.h>
35 : #include <scsi/scsiconf.h>
36 :
37 : #include <dev/biovar.h>
38 : #include <dev/ic/mfireg.h>
39 : #include <dev/ic/mfivar.h>
40 :
41 : #ifdef MFI_DEBUG
42 : uint32_t mfi_debug = 0
43 : /* | MFI_D_CMD */
44 : /* | MFI_D_INTR */
45 : /* | MFI_D_MISC */
46 : /* | MFI_D_DMA */
47 : /* | MFI_D_IOCTL */
48 : /* | MFI_D_RW */
49 : /* | MFI_D_MEM */
50 : /* | MFI_D_CCB */
51 : ;
52 : #endif
53 :
54 : struct cfdriver mfi_cd = {
55 : NULL, "mfi", DV_DULL
56 : };
57 :
58 : void mfi_scsi_cmd(struct scsi_xfer *);
59 : int mfi_scsi_ioctl(struct scsi_link *, u_long, caddr_t, int);
60 : int mfi_ioctl_cache(struct scsi_link *, u_long, struct dk_cache *);
61 : void mfiminphys(struct buf *bp, struct scsi_link *sl);
62 :
63 : void mfi_pd_scsi_cmd(struct scsi_xfer *);
64 : int mfi_pd_scsi_probe(struct scsi_link *);
65 :
66 : struct scsi_adapter mfi_switch = {
67 : mfi_scsi_cmd, mfiminphys, 0, 0, mfi_scsi_ioctl
68 : };
69 :
70 : struct scsi_adapter mfi_pd_switch = {
71 : mfi_pd_scsi_cmd,
72 : mfiminphys,
73 : mfi_pd_scsi_probe,
74 : 0,
75 : mfi_scsi_ioctl
76 : };
77 :
78 : void * mfi_get_ccb(void *);
79 : void mfi_put_ccb(void *, void *);
80 : void mfi_scrub_ccb(struct mfi_ccb *);
81 : int mfi_init_ccb(struct mfi_softc *);
82 :
83 : struct mfi_mem *mfi_allocmem(struct mfi_softc *, size_t);
84 : void mfi_freemem(struct mfi_softc *, struct mfi_mem *);
85 :
86 : int mfi_transition_firmware(struct mfi_softc *);
87 : int mfi_initialize_firmware(struct mfi_softc *);
88 : int mfi_get_info(struct mfi_softc *);
89 : uint32_t mfi_read(struct mfi_softc *, bus_size_t);
90 : void mfi_write(struct mfi_softc *, bus_size_t, uint32_t);
91 : void mfi_poll(struct mfi_softc *, struct mfi_ccb *);
92 : void mfi_exec(struct mfi_softc *, struct mfi_ccb *);
93 : void mfi_exec_done(struct mfi_softc *, struct mfi_ccb *);
94 : int mfi_create_sgl(struct mfi_softc *, struct mfi_ccb *, int);
95 : u_int mfi_default_sgd_load(struct mfi_softc *, struct mfi_ccb *);
96 : int mfi_syspd(struct mfi_softc *);
97 :
98 : /* commands */
99 : int mfi_scsi_ld(struct mfi_softc *sc, struct mfi_ccb *,
100 : struct scsi_xfer *);
101 : int mfi_scsi_io(struct mfi_softc *sc, struct mfi_ccb *,
102 : struct scsi_xfer *, uint64_t, uint32_t);
103 : void mfi_scsi_xs_done(struct mfi_softc *sc, struct mfi_ccb *);
104 : int mfi_mgmt(struct mfi_softc *, uint32_t, uint32_t, uint32_t,
105 : void *, const union mfi_mbox *);
106 : int mfi_do_mgmt(struct mfi_softc *, struct mfi_ccb * , uint32_t,
107 : uint32_t, uint32_t, void *, const union mfi_mbox *);
108 : void mfi_empty_done(struct mfi_softc *, struct mfi_ccb *);
109 :
110 : #if NBIO > 0
111 : int mfi_ioctl(struct device *, u_long, caddr_t);
112 : int mfi_bio_getitall(struct mfi_softc *);
113 : int mfi_ioctl_inq(struct mfi_softc *, struct bioc_inq *);
114 : int mfi_ioctl_vol(struct mfi_softc *, struct bioc_vol *);
115 : int mfi_ioctl_disk(struct mfi_softc *, struct bioc_disk *);
116 : int mfi_ioctl_alarm(struct mfi_softc *, struct bioc_alarm *);
117 : int mfi_ioctl_blink(struct mfi_softc *sc, struct bioc_blink *);
118 : int mfi_ioctl_setstate(struct mfi_softc *, struct bioc_setstate *);
119 : int mfi_ioctl_patrol(struct mfi_softc *sc, struct bioc_patrol *);
120 : int mfi_bio_hs(struct mfi_softc *, int, int, void *);
121 : #ifndef SMALL_KERNEL
122 : int mfi_create_sensors(struct mfi_softc *);
123 : void mfi_refresh_sensors(void *);
124 : int mfi_bbu(struct mfi_softc *);
125 : #endif /* SMALL_KERNEL */
126 : #endif /* NBIO > 0 */
127 :
128 : void mfi_start(struct mfi_softc *, struct mfi_ccb *);
129 : void mfi_done(struct mfi_softc *, struct mfi_ccb *);
130 : u_int32_t mfi_xscale_fw_state(struct mfi_softc *);
131 : void mfi_xscale_intr_ena(struct mfi_softc *);
132 : int mfi_xscale_intr(struct mfi_softc *);
133 : void mfi_xscale_post(struct mfi_softc *, struct mfi_ccb *);
134 :
135 : static const struct mfi_iop_ops mfi_iop_xscale = {
136 : mfi_xscale_fw_state,
137 : mfi_xscale_intr_ena,
138 : mfi_xscale_intr,
139 : mfi_xscale_post,
140 : mfi_default_sgd_load,
141 : 0,
142 : };
143 :
144 : u_int32_t mfi_ppc_fw_state(struct mfi_softc *);
145 : void mfi_ppc_intr_ena(struct mfi_softc *);
146 : int mfi_ppc_intr(struct mfi_softc *);
147 : void mfi_ppc_post(struct mfi_softc *, struct mfi_ccb *);
148 :
149 : static const struct mfi_iop_ops mfi_iop_ppc = {
150 : mfi_ppc_fw_state,
151 : mfi_ppc_intr_ena,
152 : mfi_ppc_intr,
153 : mfi_ppc_post,
154 : mfi_default_sgd_load,
155 : MFI_IDB,
156 : 0
157 : };
158 :
159 : u_int32_t mfi_gen2_fw_state(struct mfi_softc *);
160 : void mfi_gen2_intr_ena(struct mfi_softc *);
161 : int mfi_gen2_intr(struct mfi_softc *);
162 : void mfi_gen2_post(struct mfi_softc *, struct mfi_ccb *);
163 :
164 : static const struct mfi_iop_ops mfi_iop_gen2 = {
165 : mfi_gen2_fw_state,
166 : mfi_gen2_intr_ena,
167 : mfi_gen2_intr,
168 : mfi_gen2_post,
169 : mfi_default_sgd_load,
170 : MFI_IDB,
171 : 0
172 : };
173 :
174 : u_int32_t mfi_skinny_fw_state(struct mfi_softc *);
175 : void mfi_skinny_intr_ena(struct mfi_softc *);
176 : int mfi_skinny_intr(struct mfi_softc *);
177 : void mfi_skinny_post(struct mfi_softc *, struct mfi_ccb *);
178 : u_int mfi_skinny_sgd_load(struct mfi_softc *, struct mfi_ccb *);
179 :
180 : static const struct mfi_iop_ops mfi_iop_skinny = {
181 : mfi_skinny_fw_state,
182 : mfi_skinny_intr_ena,
183 : mfi_skinny_intr,
184 : mfi_skinny_post,
185 : mfi_skinny_sgd_load,
186 : MFI_SKINNY_IDB,
187 : MFI_IOP_F_SYSPD
188 : };
189 :
190 : #define mfi_fw_state(_s) ((_s)->sc_iop->mio_fw_state(_s))
191 : #define mfi_intr_enable(_s) ((_s)->sc_iop->mio_intr_ena(_s))
192 : #define mfi_my_intr(_s) ((_s)->sc_iop->mio_intr(_s))
193 : #define mfi_post(_s, _c) ((_s)->sc_iop->mio_post((_s), (_c)))
194 : #define mfi_sgd_load(_s, _c) ((_s)->sc_iop->mio_sgd_load((_s), (_c)))
195 :
196 : void *
197 0 : mfi_get_ccb(void *cookie)
198 : {
199 0 : struct mfi_softc *sc = cookie;
200 : struct mfi_ccb *ccb;
201 :
202 0 : KERNEL_UNLOCK();
203 :
204 0 : mtx_enter(&sc->sc_ccb_mtx);
205 0 : ccb = SLIST_FIRST(&sc->sc_ccb_freeq);
206 0 : if (ccb != NULL) {
207 0 : SLIST_REMOVE_HEAD(&sc->sc_ccb_freeq, ccb_link);
208 0 : ccb->ccb_state = MFI_CCB_READY;
209 0 : }
210 0 : mtx_leave(&sc->sc_ccb_mtx);
211 :
212 : DNPRINTF(MFI_D_CCB, "%s: mfi_get_ccb: %p\n", DEVNAME(sc), ccb);
213 0 : KERNEL_LOCK();
214 :
215 0 : return (ccb);
216 : }
217 :
218 : void
219 0 : mfi_put_ccb(void *cookie, void *io)
220 : {
221 0 : struct mfi_softc *sc = cookie;
222 0 : struct mfi_ccb *ccb = io;
223 :
224 : DNPRINTF(MFI_D_CCB, "%s: mfi_put_ccb: %p\n", DEVNAME(sc), ccb);
225 :
226 0 : KERNEL_UNLOCK();
227 0 : mtx_enter(&sc->sc_ccb_mtx);
228 0 : SLIST_INSERT_HEAD(&sc->sc_ccb_freeq, ccb, ccb_link);
229 0 : mtx_leave(&sc->sc_ccb_mtx);
230 0 : KERNEL_LOCK();
231 0 : }
232 :
233 : void
234 0 : mfi_scrub_ccb(struct mfi_ccb *ccb)
235 : {
236 0 : struct mfi_frame_header *hdr = &ccb->ccb_frame->mfr_header;
237 :
238 0 : hdr->mfh_cmd_status = 0x0;
239 0 : hdr->mfh_flags = 0x0;
240 0 : ccb->ccb_state = MFI_CCB_FREE;
241 0 : ccb->ccb_cookie = NULL;
242 0 : ccb->ccb_flags = 0;
243 0 : ccb->ccb_done = NULL;
244 0 : ccb->ccb_direction = 0;
245 0 : ccb->ccb_frame_size = 0;
246 0 : ccb->ccb_extra_frames = 0;
247 0 : ccb->ccb_sgl = NULL;
248 0 : ccb->ccb_data = NULL;
249 0 : ccb->ccb_len = 0;
250 0 : }
251 :
252 : int
253 0 : mfi_init_ccb(struct mfi_softc *sc)
254 : {
255 : struct mfi_ccb *ccb;
256 : uint32_t i;
257 : int error;
258 :
259 : DNPRINTF(MFI_D_CCB, "%s: mfi_init_ccb\n", DEVNAME(sc));
260 :
261 0 : sc->sc_ccb = mallocarray(sc->sc_max_cmds, sizeof(struct mfi_ccb),
262 : M_DEVBUF, M_WAITOK|M_ZERO);
263 :
264 0 : for (i = 0; i < sc->sc_max_cmds; i++) {
265 0 : ccb = &sc->sc_ccb[i];
266 :
267 : /* select i'th frame */
268 0 : ccb->ccb_frame = (union mfi_frame *)
269 0 : (MFIMEM_KVA(sc->sc_frames) + sc->sc_frames_size * i);
270 0 : ccb->ccb_pframe =
271 0 : MFIMEM_DVA(sc->sc_frames) + sc->sc_frames_size * i;
272 0 : ccb->ccb_pframe_offset = sc->sc_frames_size * i;
273 0 : ccb->ccb_frame->mfr_header.mfh_context = i;
274 :
275 : /* select i'th sense */
276 0 : ccb->ccb_sense = (struct mfi_sense *)
277 0 : (MFIMEM_KVA(sc->sc_sense) + MFI_SENSE_SIZE * i);
278 0 : ccb->ccb_psense =
279 0 : (MFIMEM_DVA(sc->sc_sense) + MFI_SENSE_SIZE * i);
280 :
281 : /* create a dma map for transfer */
282 0 : error = bus_dmamap_create(sc->sc_dmat,
283 : MAXPHYS, sc->sc_max_sgl, MAXPHYS, 0,
284 : BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap);
285 0 : if (error) {
286 0 : printf("%s: cannot create ccb dmamap (%d)\n",
287 0 : DEVNAME(sc), error);
288 : goto destroy;
289 : }
290 :
291 : DNPRINTF(MFI_D_CCB,
292 : "ccb(%d): %p frame: %#x (%#x) sense: %#x (%#x) map: %#x\n",
293 : ccb->ccb_frame->mfr_header.mfh_context, ccb,
294 : ccb->ccb_frame, ccb->ccb_pframe,
295 : ccb->ccb_sense, ccb->ccb_psense,
296 : ccb->ccb_dmamap);
297 :
298 : /* add ccb to queue */
299 0 : mfi_put_ccb(sc, ccb);
300 : }
301 :
302 0 : return (0);
303 : destroy:
304 : /* free dma maps and ccb memory */
305 0 : while ((ccb = mfi_get_ccb(sc)) != NULL)
306 0 : bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
307 :
308 0 : free(sc->sc_ccb, M_DEVBUF, 0);
309 :
310 0 : return (1);
311 0 : }
312 :
313 : uint32_t
314 0 : mfi_read(struct mfi_softc *sc, bus_size_t r)
315 : {
316 : uint32_t rv;
317 :
318 0 : bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
319 : BUS_SPACE_BARRIER_READ);
320 0 : rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, r);
321 :
322 : DNPRINTF(MFI_D_RW, "%s: mr 0x%x 0x08%x ", DEVNAME(sc), r, rv);
323 0 : return (rv);
324 : }
325 :
326 : void
327 0 : mfi_write(struct mfi_softc *sc, bus_size_t r, uint32_t v)
328 : {
329 : DNPRINTF(MFI_D_RW, "%s: mw 0x%x 0x%08x", DEVNAME(sc), r, v);
330 :
331 0 : bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v);
332 0 : bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
333 : BUS_SPACE_BARRIER_WRITE);
334 0 : }
335 :
336 : struct mfi_mem *
337 0 : mfi_allocmem(struct mfi_softc *sc, size_t size)
338 : {
339 : struct mfi_mem *mm;
340 0 : int nsegs;
341 :
342 : DNPRINTF(MFI_D_MEM, "%s: mfi_allocmem: %d\n", DEVNAME(sc),
343 : size);
344 :
345 0 : mm = malloc(sizeof(struct mfi_mem), M_DEVBUF, M_NOWAIT|M_ZERO);
346 0 : if (mm == NULL)
347 0 : return (NULL);
348 :
349 0 : mm->am_size = size;
350 :
351 0 : if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
352 0 : BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &mm->am_map) != 0)
353 : goto amfree;
354 :
355 0 : if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &mm->am_seg, 1,
356 0 : &nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO) != 0)
357 : goto destroy;
358 :
359 0 : if (bus_dmamem_map(sc->sc_dmat, &mm->am_seg, nsegs, size, &mm->am_kva,
360 0 : BUS_DMA_NOWAIT) != 0)
361 : goto free;
362 :
363 0 : if (bus_dmamap_load(sc->sc_dmat, mm->am_map, mm->am_kva, size, NULL,
364 0 : BUS_DMA_NOWAIT) != 0)
365 : goto unmap;
366 :
367 : DNPRINTF(MFI_D_MEM, " kva: %p dva: %p map: %p\n",
368 : mm->am_kva, mm->am_map->dm_segs[0].ds_addr, mm->am_map);
369 :
370 0 : return (mm);
371 :
372 : unmap:
373 0 : bus_dmamem_unmap(sc->sc_dmat, mm->am_kva, size);
374 : free:
375 0 : bus_dmamem_free(sc->sc_dmat, &mm->am_seg, 1);
376 : destroy:
377 0 : bus_dmamap_destroy(sc->sc_dmat, mm->am_map);
378 : amfree:
379 0 : free(mm, M_DEVBUF, sizeof *mm);
380 :
381 0 : return (NULL);
382 0 : }
383 :
384 : void
385 0 : mfi_freemem(struct mfi_softc *sc, struct mfi_mem *mm)
386 : {
387 : DNPRINTF(MFI_D_MEM, "%s: mfi_freemem: %p\n", DEVNAME(sc), mm);
388 :
389 0 : bus_dmamap_unload(sc->sc_dmat, mm->am_map);
390 0 : bus_dmamem_unmap(sc->sc_dmat, mm->am_kva, mm->am_size);
391 0 : bus_dmamem_free(sc->sc_dmat, &mm->am_seg, 1);
392 0 : bus_dmamap_destroy(sc->sc_dmat, mm->am_map);
393 0 : free(mm, M_DEVBUF, sizeof *mm);
394 0 : }
395 :
396 : int
397 0 : mfi_transition_firmware(struct mfi_softc *sc)
398 : {
399 : int32_t fw_state, cur_state;
400 0 : u_int32_t idb = sc->sc_iop->mio_idb;
401 : int max_wait, i;
402 :
403 0 : fw_state = mfi_fw_state(sc) & MFI_STATE_MASK;
404 :
405 : DNPRINTF(MFI_D_CMD, "%s: mfi_transition_firmware: %#x\n", DEVNAME(sc),
406 : fw_state);
407 :
408 0 : while (fw_state != MFI_STATE_READY) {
409 : DNPRINTF(MFI_D_MISC,
410 : "%s: waiting for firmware to become ready\n",
411 : DEVNAME(sc));
412 : cur_state = fw_state;
413 0 : switch (fw_state) {
414 : case MFI_STATE_FAULT:
415 0 : printf("%s: firmware fault\n", DEVNAME(sc));
416 0 : return (1);
417 : case MFI_STATE_WAIT_HANDSHAKE:
418 0 : mfi_write(sc, idb, MFI_INIT_CLEAR_HANDSHAKE);
419 : max_wait = 2;
420 0 : break;
421 : case MFI_STATE_OPERATIONAL:
422 0 : mfi_write(sc, idb, MFI_INIT_READY);
423 : max_wait = 10;
424 0 : break;
425 : case MFI_STATE_UNDEFINED:
426 : case MFI_STATE_BB_INIT:
427 : max_wait = 2;
428 0 : break;
429 : case MFI_STATE_FW_INIT:
430 : case MFI_STATE_DEVICE_SCAN:
431 : case MFI_STATE_FLUSH_CACHE:
432 : max_wait = 20;
433 0 : break;
434 : default:
435 0 : printf("%s: unknown firmware state %d\n",
436 0 : DEVNAME(sc), fw_state);
437 0 : return (1);
438 : }
439 0 : for (i = 0; i < (max_wait * 10); i++) {
440 0 : fw_state = mfi_fw_state(sc) & MFI_STATE_MASK;
441 0 : if (fw_state == cur_state)
442 0 : DELAY(100000);
443 : else
444 : break;
445 : }
446 0 : if (fw_state == cur_state) {
447 0 : printf("%s: firmware stuck in state %#x\n",
448 0 : DEVNAME(sc), fw_state);
449 0 : return (1);
450 : }
451 : }
452 :
453 0 : return (0);
454 0 : }
455 :
456 : int
457 0 : mfi_initialize_firmware(struct mfi_softc *sc)
458 : {
459 : struct mfi_ccb *ccb;
460 : struct mfi_init_frame *init;
461 : struct mfi_init_qinfo *qinfo;
462 : int rv = 0;
463 :
464 : DNPRINTF(MFI_D_MISC, "%s: mfi_initialize_firmware\n", DEVNAME(sc));
465 :
466 0 : ccb = scsi_io_get(&sc->sc_iopool, 0);
467 0 : mfi_scrub_ccb(ccb);
468 :
469 0 : init = &ccb->ccb_frame->mfr_init;
470 0 : qinfo = (struct mfi_init_qinfo *)((uint8_t *)init + MFI_FRAME_SIZE);
471 :
472 0 : memset(qinfo, 0, sizeof(*qinfo));
473 0 : qinfo->miq_rq_entries = htole32(sc->sc_max_cmds + 1);
474 :
475 0 : qinfo->miq_rq_addr = htole64(MFIMEM_DVA(sc->sc_pcq) +
476 : offsetof(struct mfi_prod_cons, mpc_reply_q));
477 :
478 0 : qinfo->miq_pi_addr = htole64(MFIMEM_DVA(sc->sc_pcq) +
479 : offsetof(struct mfi_prod_cons, mpc_producer));
480 :
481 0 : qinfo->miq_ci_addr = htole64(MFIMEM_DVA(sc->sc_pcq) +
482 : offsetof(struct mfi_prod_cons, mpc_consumer));
483 :
484 0 : init->mif_header.mfh_cmd = MFI_CMD_INIT;
485 0 : init->mif_header.mfh_data_len = htole32(sizeof(*qinfo));
486 0 : init->mif_qinfo_new_addr = htole64(ccb->ccb_pframe + MFI_FRAME_SIZE);
487 :
488 0 : bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_pcq),
489 : 0, MFIMEM_LEN(sc->sc_pcq),
490 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
491 :
492 0 : ccb->ccb_done = mfi_empty_done;
493 0 : mfi_poll(sc, ccb);
494 0 : if (init->mif_header.mfh_cmd_status != MFI_STAT_OK)
495 0 : rv = 1;
496 :
497 0 : mfi_put_ccb(sc, ccb);
498 :
499 0 : return (rv);
500 : }
501 :
502 : void
503 0 : mfi_empty_done(struct mfi_softc *sc, struct mfi_ccb *ccb)
504 : {
505 : /* nop */
506 0 : }
507 :
508 : int
509 0 : mfi_get_info(struct mfi_softc *sc)
510 : {
511 : #ifdef MFI_DEBUG
512 : int i;
513 : #endif
514 : DNPRINTF(MFI_D_MISC, "%s: mfi_get_info\n", DEVNAME(sc));
515 :
516 0 : if (mfi_mgmt(sc, MR_DCMD_CTRL_GET_INFO, MFI_DATA_IN,
517 0 : sizeof(sc->sc_info), &sc->sc_info, NULL))
518 0 : return (1);
519 :
520 : #ifdef MFI_DEBUG
521 : for (i = 0; i < sc->sc_info.mci_image_component_count; i++) {
522 : printf("%s: active FW %s Version %s date %s time %s\n",
523 : DEVNAME(sc),
524 : sc->sc_info.mci_image_component[i].mic_name,
525 : sc->sc_info.mci_image_component[i].mic_version,
526 : sc->sc_info.mci_image_component[i].mic_build_date,
527 : sc->sc_info.mci_image_component[i].mic_build_time);
528 : }
529 :
530 : for (i = 0; i < sc->sc_info.mci_pending_image_component_count; i++) {
531 : printf("%s: pending FW %s Version %s date %s time %s\n",
532 : DEVNAME(sc),
533 : sc->sc_info.mci_pending_image_component[i].mic_name,
534 : sc->sc_info.mci_pending_image_component[i].mic_version,
535 : sc->sc_info.mci_pending_image_component[i].mic_build_date,
536 : sc->sc_info.mci_pending_image_component[i].mic_build_time);
537 : }
538 :
539 : printf("%s: max_arms %d max_spans %d max_arrs %d max_lds %d name %s\n",
540 : DEVNAME(sc),
541 : sc->sc_info.mci_max_arms,
542 : sc->sc_info.mci_max_spans,
543 : sc->sc_info.mci_max_arrays,
544 : sc->sc_info.mci_max_lds,
545 : sc->sc_info.mci_product_name);
546 :
547 : printf("%s: serial %s present %#x fw time %d max_cmds %d max_sg %d\n",
548 : DEVNAME(sc),
549 : sc->sc_info.mci_serial_number,
550 : sc->sc_info.mci_hw_present,
551 : sc->sc_info.mci_current_fw_time,
552 : sc->sc_info.mci_max_cmds,
553 : sc->sc_info.mci_max_sg_elements);
554 :
555 : printf("%s: max_rq %d lds_pres %d lds_deg %d lds_off %d pd_pres %d\n",
556 : DEVNAME(sc),
557 : sc->sc_info.mci_max_request_size,
558 : sc->sc_info.mci_lds_present,
559 : sc->sc_info.mci_lds_degraded,
560 : sc->sc_info.mci_lds_offline,
561 : sc->sc_info.mci_pd_present);
562 :
563 : printf("%s: pd_dsk_prs %d pd_dsk_pred_fail %d pd_dsk_fail %d\n",
564 : DEVNAME(sc),
565 : sc->sc_info.mci_pd_disks_present,
566 : sc->sc_info.mci_pd_disks_pred_failure,
567 : sc->sc_info.mci_pd_disks_failed);
568 :
569 : printf("%s: nvram %d mem %d flash %d\n",
570 : DEVNAME(sc),
571 : sc->sc_info.mci_nvram_size,
572 : sc->sc_info.mci_memory_size,
573 : sc->sc_info.mci_flash_size);
574 :
575 : printf("%s: ram_cor %d ram_uncor %d clus_all %d clus_act %d\n",
576 : DEVNAME(sc),
577 : sc->sc_info.mci_ram_correctable_errors,
578 : sc->sc_info.mci_ram_uncorrectable_errors,
579 : sc->sc_info.mci_cluster_allowed,
580 : sc->sc_info.mci_cluster_active);
581 :
582 : printf("%s: max_strps_io %d raid_lvl %#x adapt_ops %#x ld_ops %#x\n",
583 : DEVNAME(sc),
584 : sc->sc_info.mci_max_strips_per_io,
585 : sc->sc_info.mci_raid_levels,
586 : sc->sc_info.mci_adapter_ops,
587 : sc->sc_info.mci_ld_ops);
588 :
589 : printf("%s: strp_sz_min %d strp_sz_max %d pd_ops %#x pd_mix %#x\n",
590 : DEVNAME(sc),
591 : sc->sc_info.mci_stripe_sz_ops.min,
592 : sc->sc_info.mci_stripe_sz_ops.max,
593 : sc->sc_info.mci_pd_ops,
594 : sc->sc_info.mci_pd_mix_support);
595 :
596 : printf("%s: ecc_bucket %d pckg_prop %s\n",
597 : DEVNAME(sc),
598 : sc->sc_info.mci_ecc_bucket_count,
599 : sc->sc_info.mci_package_version);
600 :
601 : printf("%s: sq_nm %d prd_fail_poll %d intr_thrtl %d intr_thrtl_to %d\n",
602 : DEVNAME(sc),
603 : sc->sc_info.mci_properties.mcp_seq_num,
604 : sc->sc_info.mci_properties.mcp_pred_fail_poll_interval,
605 : sc->sc_info.mci_properties.mcp_intr_throttle_cnt,
606 : sc->sc_info.mci_properties.mcp_intr_throttle_timeout);
607 :
608 : printf("%s: rbld_rate %d patr_rd_rate %d bgi_rate %d cc_rate %d\n",
609 : DEVNAME(sc),
610 : sc->sc_info.mci_properties.mcp_rebuild_rate,
611 : sc->sc_info.mci_properties.mcp_patrol_read_rate,
612 : sc->sc_info.mci_properties.mcp_bgi_rate,
613 : sc->sc_info.mci_properties.mcp_cc_rate);
614 :
615 : printf("%s: rc_rate %d ch_flsh %d spin_cnt %d spin_dly %d clus_en %d\n",
616 : DEVNAME(sc),
617 : sc->sc_info.mci_properties.mcp_recon_rate,
618 : sc->sc_info.mci_properties.mcp_cache_flush_interval,
619 : sc->sc_info.mci_properties.mcp_spinup_drv_cnt,
620 : sc->sc_info.mci_properties.mcp_spinup_delay,
621 : sc->sc_info.mci_properties.mcp_cluster_enable);
622 :
623 : printf("%s: coerc %d alarm %d dis_auto_rbld %d dis_bat_wrn %d ecc %d\n",
624 : DEVNAME(sc),
625 : sc->sc_info.mci_properties.mcp_coercion_mode,
626 : sc->sc_info.mci_properties.mcp_alarm_enable,
627 : sc->sc_info.mci_properties.mcp_disable_auto_rebuild,
628 : sc->sc_info.mci_properties.mcp_disable_battery_warn,
629 : sc->sc_info.mci_properties.mcp_ecc_bucket_size);
630 :
631 : printf("%s: ecc_leak %d rest_hs %d exp_encl_dev %d\n",
632 : DEVNAME(sc),
633 : sc->sc_info.mci_properties.mcp_ecc_bucket_leak_rate,
634 : sc->sc_info.mci_properties.mcp_restore_hotspare_on_insertion,
635 : sc->sc_info.mci_properties.mcp_expose_encl_devices);
636 :
637 : printf("%s: vendor %#x device %#x subvendor %#x subdevice %#x\n",
638 : DEVNAME(sc),
639 : sc->sc_info.mci_pci.mip_vendor,
640 : sc->sc_info.mci_pci.mip_device,
641 : sc->sc_info.mci_pci.mip_subvendor,
642 : sc->sc_info.mci_pci.mip_subdevice);
643 :
644 : printf("%s: type %#x port_count %d port_addr ",
645 : DEVNAME(sc),
646 : sc->sc_info.mci_host.mih_type,
647 : sc->sc_info.mci_host.mih_port_count);
648 :
649 : for (i = 0; i < 8; i++)
650 : printf("%.0llx ", sc->sc_info.mci_host.mih_port_addr[i]);
651 : printf("\n");
652 :
653 : printf("%s: type %.x port_count %d port_addr ",
654 : DEVNAME(sc),
655 : sc->sc_info.mci_device.mid_type,
656 : sc->sc_info.mci_device.mid_port_count);
657 :
658 : for (i = 0; i < 8; i++)
659 : printf("%.0llx ", sc->sc_info.mci_device.mid_port_addr[i]);
660 : printf("\n");
661 : #endif /* MFI_DEBUG */
662 :
663 0 : return (0);
664 0 : }
665 :
666 : void
667 0 : mfiminphys(struct buf *bp, struct scsi_link *sl)
668 : {
669 : DNPRINTF(MFI_D_MISC, "mfiminphys: %d\n", bp->b_bcount);
670 :
671 : /* XXX currently using MFI_MAXFER = MAXPHYS */
672 0 : if (bp->b_bcount > MFI_MAXFER)
673 0 : bp->b_bcount = MFI_MAXFER;
674 0 : minphys(bp);
675 0 : }
676 :
677 : int
678 0 : mfi_attach(struct mfi_softc *sc, enum mfi_iop iop)
679 : {
680 0 : struct scsibus_attach_args saa;
681 : uint32_t status, frames, max_sgl;
682 : int i;
683 :
684 0 : switch (iop) {
685 : case MFI_IOP_XSCALE:
686 0 : sc->sc_iop = &mfi_iop_xscale;
687 0 : break;
688 : case MFI_IOP_PPC:
689 0 : sc->sc_iop = &mfi_iop_ppc;
690 0 : break;
691 : case MFI_IOP_GEN2:
692 0 : sc->sc_iop = &mfi_iop_gen2;
693 0 : break;
694 : case MFI_IOP_SKINNY:
695 0 : sc->sc_iop = &mfi_iop_skinny;
696 0 : break;
697 : default:
698 0 : panic("%s: unknown iop %d", DEVNAME(sc), iop);
699 : }
700 :
701 : DNPRINTF(MFI_D_MISC, "%s: mfi_attach\n", DEVNAME(sc));
702 :
703 0 : if (mfi_transition_firmware(sc))
704 0 : return (1);
705 :
706 0 : SLIST_INIT(&sc->sc_ccb_freeq);
707 0 : mtx_init(&sc->sc_ccb_mtx, IPL_BIO);
708 0 : scsi_iopool_init(&sc->sc_iopool, sc, mfi_get_ccb, mfi_put_ccb);
709 :
710 0 : rw_init(&sc->sc_lock, "mfi_lock");
711 :
712 0 : status = mfi_fw_state(sc);
713 0 : sc->sc_max_cmds = status & MFI_STATE_MAXCMD_MASK;
714 0 : max_sgl = (status & MFI_STATE_MAXSGL_MASK) >> 16;
715 0 : if (sc->sc_64bit_dma) {
716 0 : sc->sc_max_sgl = min(max_sgl, (128 * 1024) / PAGE_SIZE + 1);
717 0 : sc->sc_sgl_size = sizeof(struct mfi_sg64);
718 0 : sc->sc_sgl_flags = MFI_FRAME_SGL64;
719 0 : } else {
720 0 : sc->sc_max_sgl = max_sgl;
721 0 : sc->sc_sgl_size = sizeof(struct mfi_sg32);
722 0 : sc->sc_sgl_flags = MFI_FRAME_SGL32;
723 : }
724 0 : if (iop == MFI_IOP_SKINNY)
725 0 : sc->sc_sgl_size = sizeof(struct mfi_sg_skinny);
726 : DNPRINTF(MFI_D_MISC, "%s: 64bit: %d max commands: %u, max sgl: %u\n",
727 : DEVNAME(sc), sc->sc_64bit_dma, sc->sc_max_cmds, sc->sc_max_sgl);
728 :
729 : /* consumer/producer and reply queue memory */
730 0 : sc->sc_pcq = mfi_allocmem(sc, (sizeof(uint32_t) * sc->sc_max_cmds) +
731 : sizeof(struct mfi_prod_cons));
732 0 : if (sc->sc_pcq == NULL) {
733 0 : printf("%s: unable to allocate reply queue memory\n",
734 0 : DEVNAME(sc));
735 0 : goto nopcq;
736 : }
737 :
738 : /* frame memory */
739 : /* we are not doing 64 bit IO so only calculate # of 32 bit frames */
740 0 : frames = (sc->sc_sgl_size * sc->sc_max_sgl + MFI_FRAME_SIZE - 1) /
741 0 : MFI_FRAME_SIZE + 1;
742 0 : sc->sc_frames_size = frames * MFI_FRAME_SIZE;
743 0 : sc->sc_frames = mfi_allocmem(sc, sc->sc_frames_size * sc->sc_max_cmds);
744 0 : if (sc->sc_frames == NULL) {
745 0 : printf("%s: unable to allocate frame memory\n", DEVNAME(sc));
746 0 : goto noframe;
747 : }
748 : /* XXX hack, fix this */
749 0 : if (MFIMEM_DVA(sc->sc_frames) & 0x3f) {
750 0 : printf("%s: improper frame alignment (%#lx) FIXME\n",
751 0 : DEVNAME(sc), MFIMEM_DVA(sc->sc_frames));
752 0 : goto noframe;
753 : }
754 :
755 : /* sense memory */
756 0 : sc->sc_sense = mfi_allocmem(sc, sc->sc_max_cmds * MFI_SENSE_SIZE);
757 0 : if (sc->sc_sense == NULL) {
758 0 : printf("%s: unable to allocate sense memory\n", DEVNAME(sc));
759 0 : goto nosense;
760 : }
761 :
762 : /* now that we have all memory bits go initialize ccbs */
763 0 : if (mfi_init_ccb(sc)) {
764 0 : printf("%s: could not init ccb list\n", DEVNAME(sc));
765 0 : goto noinit;
766 : }
767 :
768 : /* kickstart firmware with all addresses and pointers */
769 0 : if (mfi_initialize_firmware(sc)) {
770 0 : printf("%s: could not initialize firmware\n", DEVNAME(sc));
771 0 : goto noinit;
772 : }
773 :
774 0 : if (mfi_get_info(sc)) {
775 0 : printf("%s: could not retrieve controller information\n",
776 : DEVNAME(sc));
777 0 : goto noinit;
778 : }
779 :
780 0 : printf("%s: \"%s\", firmware %s", DEVNAME(sc),
781 0 : sc->sc_info.mci_product_name, sc->sc_info.mci_package_version);
782 0 : if (letoh16(sc->sc_info.mci_memory_size) > 0)
783 0 : printf(", %uMB cache", letoh16(sc->sc_info.mci_memory_size));
784 0 : printf("\n");
785 :
786 0 : sc->sc_ld_cnt = sc->sc_info.mci_lds_present;
787 0 : for (i = 0; i < sc->sc_ld_cnt; i++)
788 0 : sc->sc_ld[i].ld_present = 1;
789 :
790 0 : sc->sc_link.adapter = &mfi_switch;
791 0 : sc->sc_link.adapter_softc = sc;
792 0 : sc->sc_link.adapter_buswidth = sc->sc_info.mci_max_lds;
793 0 : sc->sc_link.adapter_target = -1;
794 0 : sc->sc_link.luns = 1;
795 0 : sc->sc_link.openings = sc->sc_max_cmds - 1;
796 0 : sc->sc_link.pool = &sc->sc_iopool;
797 :
798 0 : bzero(&saa, sizeof(saa));
799 0 : saa.saa_sc_link = &sc->sc_link;
800 :
801 0 : sc->sc_scsibus = (struct scsibus_softc *)
802 0 : config_found(&sc->sc_dev, &saa, scsiprint);
803 :
804 0 : if (ISSET(sc->sc_iop->mio_flags, MFI_IOP_F_SYSPD))
805 0 : mfi_syspd(sc);
806 :
807 : /* enable interrupts */
808 0 : mfi_intr_enable(sc);
809 :
810 : #if NBIO > 0
811 0 : if (bio_register(&sc->sc_dev, mfi_ioctl) != 0)
812 0 : panic("%s: controller registration failed", DEVNAME(sc));
813 : else
814 0 : sc->sc_ioctl = mfi_ioctl;
815 :
816 : #ifndef SMALL_KERNEL
817 0 : if (mfi_create_sensors(sc) != 0)
818 0 : printf("%s: unable to create sensors\n", DEVNAME(sc));
819 : #endif
820 : #endif /* NBIO > 0 */
821 :
822 0 : return (0);
823 : noinit:
824 0 : mfi_freemem(sc, sc->sc_sense);
825 : nosense:
826 0 : mfi_freemem(sc, sc->sc_frames);
827 : noframe:
828 0 : mfi_freemem(sc, sc->sc_pcq);
829 : nopcq:
830 0 : return (1);
831 0 : }
832 :
833 : int
834 0 : mfi_syspd(struct mfi_softc *sc)
835 : {
836 0 : struct scsibus_attach_args saa;
837 : struct scsi_link *link;
838 : struct mfi_pd_link *pl;
839 : struct mfi_pd_list *pd;
840 : u_int npds, i;
841 :
842 0 : sc->sc_pd = malloc(sizeof(*sc->sc_pd), M_DEVBUF, M_WAITOK|M_ZERO);
843 0 : if (sc->sc_pd == NULL)
844 0 : return (1);
845 :
846 0 : pd = malloc(sizeof(*pd), M_TEMP, M_WAITOK|M_ZERO);
847 0 : if (pd == NULL)
848 : goto nopdsc;
849 :
850 0 : if (mfi_mgmt(sc, MR_DCMD_PD_GET_LIST, MFI_DATA_IN,
851 0 : sizeof(*pd), pd, NULL) != 0)
852 : goto nopd;
853 :
854 0 : npds = letoh32(pd->mpl_no_pd);
855 0 : for (i = 0; i < npds; i++) {
856 0 : pl = malloc(sizeof(*pl), M_DEVBUF, M_WAITOK|M_ZERO);
857 0 : if (pl == NULL)
858 : goto nopl;
859 :
860 0 : pl->pd_id = pd->mpl_address[i].mpa_pd_id;
861 0 : sc->sc_pd->pd_links[i] = pl;
862 : }
863 :
864 0 : free(pd, M_TEMP, sizeof *pd);
865 :
866 0 : link = &sc->sc_pd->pd_link;
867 0 : link->adapter = &mfi_pd_switch;
868 0 : link->adapter_softc = sc;
869 0 : link->adapter_buswidth = MFI_MAX_PD;
870 0 : link->adapter_target = -1;
871 0 : link->openings = sc->sc_max_cmds - 1;
872 0 : link->pool = &sc->sc_iopool;
873 :
874 0 : bzero(&saa, sizeof(saa));
875 0 : saa.saa_sc_link = link;
876 :
877 0 : sc->sc_pd->pd_scsibus = (struct scsibus_softc *)
878 0 : config_found(&sc->sc_dev, &saa, scsiprint);
879 :
880 0 : return (0);
881 : nopl:
882 0 : for (i = 0; i < npds; i++) {
883 0 : pl = sc->sc_pd->pd_links[i];
884 0 : if (pl == NULL)
885 : break;
886 :
887 0 : free(pl, M_DEVBUF, sizeof *pl);
888 : }
889 : nopd:
890 0 : free(pd, M_TEMP, sizeof *pd);
891 : nopdsc:
892 0 : free(sc->sc_pd, M_DEVBUF, sizeof *sc->sc_pd);
893 0 : return (1);
894 0 : }
895 :
896 : void
897 0 : mfi_poll(struct mfi_softc *sc, struct mfi_ccb *ccb)
898 : {
899 : struct mfi_frame_header *hdr;
900 : int to = 0;
901 :
902 : DNPRINTF(MFI_D_CMD, "%s: mfi_poll\n", DEVNAME(sc));
903 :
904 0 : hdr = &ccb->ccb_frame->mfr_header;
905 0 : hdr->mfh_cmd_status = 0xff;
906 0 : hdr->mfh_flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
907 :
908 0 : mfi_start(sc, ccb);
909 :
910 0 : for (;;) {
911 0 : delay(1000);
912 :
913 0 : bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_frames),
914 : ccb->ccb_pframe_offset, sc->sc_frames_size,
915 : BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
916 :
917 0 : if (hdr->mfh_cmd_status != 0xff)
918 : break;
919 :
920 0 : if (to++ > 5000) {
921 0 : printf("%s: timeout on ccb %d\n", DEVNAME(sc),
922 0 : hdr->mfh_context);
923 0 : ccb->ccb_flags |= MFI_CCB_F_ERR;
924 0 : break;
925 : }
926 :
927 0 : bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_frames),
928 : ccb->ccb_pframe_offset, sc->sc_frames_size,
929 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
930 : }
931 :
932 0 : if (ccb->ccb_len > 0) {
933 0 : bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
934 : ccb->ccb_dmamap->dm_mapsize,
935 : (ccb->ccb_direction & MFI_DATA_IN) ?
936 : BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
937 :
938 0 : bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
939 0 : }
940 :
941 0 : ccb->ccb_done(sc, ccb);
942 0 : }
943 :
944 : void
945 0 : mfi_exec(struct mfi_softc *sc, struct mfi_ccb *ccb)
946 : {
947 0 : struct mutex m = MUTEX_INITIALIZER(IPL_BIO);
948 :
949 : #ifdef DIAGNOSTIC
950 0 : if (ccb->ccb_cookie != NULL || ccb->ccb_done != NULL)
951 0 : panic("mfi_exec called with cookie or done set");
952 : #endif
953 :
954 0 : ccb->ccb_cookie = &m;
955 0 : ccb->ccb_done = mfi_exec_done;
956 :
957 0 : mfi_start(sc, ccb);
958 :
959 0 : mtx_enter(&m);
960 0 : while (ccb->ccb_cookie != NULL)
961 0 : msleep(ccb, &m, PRIBIO, "mfiexec", 0);
962 0 : mtx_leave(&m);
963 0 : }
964 :
965 : void
966 0 : mfi_exec_done(struct mfi_softc *sc, struct mfi_ccb *ccb)
967 : {
968 0 : struct mutex *m = ccb->ccb_cookie;
969 :
970 0 : mtx_enter(m);
971 0 : ccb->ccb_cookie = NULL;
972 0 : wakeup_one(ccb);
973 0 : mtx_leave(m);
974 0 : }
975 :
976 : int
977 0 : mfi_intr(void *arg)
978 : {
979 0 : struct mfi_softc *sc = arg;
980 0 : struct mfi_prod_cons *pcq = MFIMEM_KVA(sc->sc_pcq);
981 : struct mfi_ccb *ccb;
982 : uint32_t producer, consumer, ctx;
983 : int claimed = 0;
984 :
985 0 : if (!mfi_my_intr(sc))
986 0 : return (0);
987 :
988 0 : bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_pcq),
989 : 0, MFIMEM_LEN(sc->sc_pcq),
990 : BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
991 :
992 0 : producer = letoh32(pcq->mpc_producer);
993 0 : consumer = letoh32(pcq->mpc_consumer);
994 :
995 : DNPRINTF(MFI_D_INTR, "%s: mfi_intr %#x %#x\n", DEVNAME(sc), sc, pcq);
996 :
997 0 : while (consumer != producer) {
998 : DNPRINTF(MFI_D_INTR, "%s: mfi_intr pi %#x ci %#x\n",
999 : DEVNAME(sc), producer, consumer);
1000 :
1001 0 : ctx = pcq->mpc_reply_q[consumer];
1002 0 : pcq->mpc_reply_q[consumer] = MFI_INVALID_CTX;
1003 0 : if (ctx == MFI_INVALID_CTX)
1004 0 : printf("%s: invalid context, p: %d c: %d\n",
1005 0 : DEVNAME(sc), producer, consumer);
1006 : else {
1007 : /* XXX remove from queue and call scsi_done */
1008 0 : ccb = &sc->sc_ccb[ctx];
1009 : DNPRINTF(MFI_D_INTR, "%s: mfi_intr context %#x\n",
1010 : DEVNAME(sc), ctx);
1011 0 : mfi_done(sc, ccb);
1012 :
1013 : claimed = 1;
1014 : }
1015 0 : consumer++;
1016 0 : if (consumer == (sc->sc_max_cmds + 1))
1017 : consumer = 0;
1018 : }
1019 :
1020 0 : pcq->mpc_consumer = htole32(consumer);
1021 :
1022 0 : bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_pcq),
1023 : 0, MFIMEM_LEN(sc->sc_pcq),
1024 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1025 :
1026 0 : return (claimed);
1027 0 : }
1028 :
1029 : int
1030 0 : mfi_scsi_io(struct mfi_softc *sc, struct mfi_ccb *ccb,
1031 : struct scsi_xfer *xs, uint64_t blockno, uint32_t blockcnt)
1032 : {
1033 0 : struct scsi_link *link = xs->sc_link;
1034 : struct mfi_io_frame *io;
1035 :
1036 : DNPRINTF(MFI_D_CMD, "%s: mfi_scsi_io: %d\n",
1037 : DEVNAME((struct mfi_softc *)link->adapter_softc), link->target);
1038 :
1039 0 : if (!xs->data)
1040 0 : return (1);
1041 :
1042 0 : io = &ccb->ccb_frame->mfr_io;
1043 0 : if (xs->flags & SCSI_DATA_IN) {
1044 0 : io->mif_header.mfh_cmd = MFI_CMD_LD_READ;
1045 0 : ccb->ccb_direction = MFI_DATA_IN;
1046 0 : } else {
1047 0 : io->mif_header.mfh_cmd = MFI_CMD_LD_WRITE;
1048 0 : ccb->ccb_direction = MFI_DATA_OUT;
1049 : }
1050 0 : io->mif_header.mfh_target_id = link->target;
1051 0 : io->mif_header.mfh_timeout = 0;
1052 0 : io->mif_header.mfh_flags = 0;
1053 0 : io->mif_header.mfh_sense_len = MFI_SENSE_SIZE;
1054 0 : io->mif_header.mfh_data_len = htole32(blockcnt);
1055 0 : io->mif_lba = htole64(blockno);
1056 0 : io->mif_sense_addr = htole64(ccb->ccb_psense);
1057 :
1058 0 : ccb->ccb_done = mfi_scsi_xs_done;
1059 0 : ccb->ccb_cookie = xs;
1060 0 : ccb->ccb_frame_size = MFI_IO_FRAME_SIZE;
1061 0 : ccb->ccb_sgl = &io->mif_sgl;
1062 0 : ccb->ccb_data = xs->data;
1063 0 : ccb->ccb_len = xs->datalen;
1064 :
1065 0 : if (mfi_create_sgl(sc, ccb, (xs->flags & SCSI_NOSLEEP) ?
1066 : BUS_DMA_NOWAIT : BUS_DMA_WAITOK))
1067 0 : return (1);
1068 :
1069 0 : return (0);
1070 0 : }
1071 :
1072 : void
1073 0 : mfi_scsi_xs_done(struct mfi_softc *sc, struct mfi_ccb *ccb)
1074 : {
1075 0 : struct scsi_xfer *xs = ccb->ccb_cookie;
1076 0 : struct mfi_frame_header *hdr = &ccb->ccb_frame->mfr_header;
1077 :
1078 : DNPRINTF(MFI_D_INTR, "%s: mfi_scsi_xs_done %#x %#x\n",
1079 : DEVNAME(sc), ccb, ccb->ccb_frame);
1080 :
1081 0 : switch (hdr->mfh_cmd_status) {
1082 : case MFI_STAT_OK:
1083 0 : xs->resid = 0;
1084 0 : break;
1085 :
1086 : case MFI_STAT_SCSI_DONE_WITH_ERROR:
1087 0 : xs->error = XS_SENSE;
1088 0 : xs->resid = 0;
1089 0 : memset(&xs->sense, 0, sizeof(xs->sense));
1090 0 : memcpy(&xs->sense, ccb->ccb_sense, sizeof(xs->sense));
1091 0 : break;
1092 :
1093 : case MFI_STAT_DEVICE_NOT_FOUND:
1094 0 : xs->error = XS_SELTIMEOUT;
1095 0 : break;
1096 :
1097 : default:
1098 0 : xs->error = XS_DRIVER_STUFFUP;
1099 : DPRINTF(MFI_D_CMD,
1100 : "%s: mfi_scsi_xs_done stuffup %02x on %02x\n",
1101 : DEVNAME(sc), hdr->mfh_cmd_status, xs->cmd->opcode);
1102 :
1103 0 : if (hdr->mfh_scsi_status != 0) {
1104 : DNPRINTF(MFI_D_INTR,
1105 : "%s: mfi_scsi_xs_done sense %#x %x %x\n",
1106 : DEVNAME(sc), hdr->mfh_scsi_status,
1107 : &xs->sense, ccb->ccb_sense);
1108 0 : memset(&xs->sense, 0, sizeof(xs->sense));
1109 0 : memcpy(&xs->sense, ccb->ccb_sense,
1110 : sizeof(struct scsi_sense_data));
1111 0 : xs->error = XS_SENSE;
1112 0 : }
1113 : break;
1114 : }
1115 :
1116 0 : KERNEL_LOCK();
1117 0 : scsi_done(xs);
1118 0 : KERNEL_UNLOCK();
1119 0 : }
1120 :
1121 : int
1122 0 : mfi_scsi_ld(struct mfi_softc *sc, struct mfi_ccb *ccb, struct scsi_xfer *xs)
1123 : {
1124 0 : struct scsi_link *link = xs->sc_link;
1125 : struct mfi_pass_frame *pf;
1126 :
1127 : DNPRINTF(MFI_D_CMD, "%s: mfi_scsi_ld: %d\n",
1128 : DEVNAME((struct mfi_softc *)link->adapter_softc), link->target);
1129 :
1130 0 : pf = &ccb->ccb_frame->mfr_pass;
1131 0 : pf->mpf_header.mfh_cmd = MFI_CMD_LD_SCSI_IO;
1132 0 : pf->mpf_header.mfh_target_id = link->target;
1133 0 : pf->mpf_header.mfh_lun_id = 0;
1134 0 : pf->mpf_header.mfh_cdb_len = xs->cmdlen;
1135 0 : pf->mpf_header.mfh_timeout = 0;
1136 0 : pf->mpf_header.mfh_data_len = htole32(xs->datalen); /* XXX */
1137 0 : pf->mpf_header.mfh_sense_len = MFI_SENSE_SIZE;
1138 :
1139 0 : pf->mpf_sense_addr = htole64(ccb->ccb_psense);
1140 :
1141 0 : memset(pf->mpf_cdb, 0, 16);
1142 0 : memcpy(pf->mpf_cdb, xs->cmd, xs->cmdlen);
1143 :
1144 0 : ccb->ccb_done = mfi_scsi_xs_done;
1145 0 : ccb->ccb_cookie = xs;
1146 0 : ccb->ccb_frame_size = MFI_PASS_FRAME_SIZE;
1147 0 : ccb->ccb_sgl = &pf->mpf_sgl;
1148 :
1149 0 : if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT))
1150 0 : ccb->ccb_direction = xs->flags & SCSI_DATA_IN ?
1151 : MFI_DATA_IN : MFI_DATA_OUT;
1152 : else
1153 0 : ccb->ccb_direction = MFI_DATA_NONE;
1154 :
1155 0 : if (xs->data) {
1156 0 : ccb->ccb_data = xs->data;
1157 0 : ccb->ccb_len = xs->datalen;
1158 :
1159 0 : if (mfi_create_sgl(sc, ccb, (xs->flags & SCSI_NOSLEEP) ?
1160 : BUS_DMA_NOWAIT : BUS_DMA_WAITOK))
1161 0 : return (1);
1162 : }
1163 :
1164 0 : return (0);
1165 0 : }
1166 :
1167 : void
1168 0 : mfi_scsi_cmd(struct scsi_xfer *xs)
1169 : {
1170 0 : struct scsi_link *link = xs->sc_link;
1171 0 : struct mfi_softc *sc = link->adapter_softc;
1172 0 : struct mfi_ccb *ccb = xs->io;
1173 : struct scsi_rw *rw;
1174 : struct scsi_rw_big *rwb;
1175 : struct scsi_rw_16 *rw16;
1176 : uint64_t blockno;
1177 : uint32_t blockcnt;
1178 0 : uint8_t target = link->target;
1179 0 : union mfi_mbox mbox;
1180 :
1181 : DNPRINTF(MFI_D_CMD, "%s: mfi_scsi_cmd opcode: %#x\n",
1182 : DEVNAME(sc), xs->cmd->opcode);
1183 :
1184 0 : KERNEL_UNLOCK();
1185 :
1186 0 : if (!sc->sc_ld[target].ld_present) {
1187 : DNPRINTF(MFI_D_CMD, "%s: invalid target %d\n",
1188 : DEVNAME(sc), target);
1189 : goto stuffup;
1190 : }
1191 :
1192 0 : mfi_scrub_ccb(ccb);
1193 :
1194 0 : xs->error = XS_NOERROR;
1195 :
1196 0 : switch (xs->cmd->opcode) {
1197 : /* IO path */
1198 : case READ_BIG:
1199 : case WRITE_BIG:
1200 0 : rwb = (struct scsi_rw_big *)xs->cmd;
1201 0 : blockno = (uint64_t)_4btol(rwb->addr);
1202 0 : blockcnt = _2btol(rwb->length);
1203 0 : if (mfi_scsi_io(sc, ccb, xs, blockno, blockcnt))
1204 : goto stuffup;
1205 : break;
1206 :
1207 : case READ_COMMAND:
1208 : case WRITE_COMMAND:
1209 0 : rw = (struct scsi_rw *)xs->cmd;
1210 : blockno =
1211 0 : (uint64_t)(_3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff));
1212 0 : blockcnt = rw->length ? rw->length : 0x100;
1213 0 : if (mfi_scsi_io(sc, ccb, xs, blockno, blockcnt))
1214 : goto stuffup;
1215 : break;
1216 :
1217 : case READ_16:
1218 : case WRITE_16:
1219 0 : rw16 = (struct scsi_rw_16 *)xs->cmd;
1220 0 : blockno = _8btol(rw16->addr);
1221 0 : blockcnt = _4btol(rw16->length);
1222 0 : if (mfi_scsi_io(sc, ccb, xs, blockno, blockcnt))
1223 : goto stuffup;
1224 : break;
1225 :
1226 : case SYNCHRONIZE_CACHE:
1227 0 : mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
1228 0 : if (mfi_do_mgmt(sc, ccb, MR_DCMD_CTRL_CACHE_FLUSH,
1229 : MFI_DATA_NONE, 0, NULL, &mbox))
1230 : goto stuffup;
1231 :
1232 : goto complete;
1233 : /* NOTREACHED */
1234 :
1235 : default:
1236 0 : if (mfi_scsi_ld(sc, ccb, xs))
1237 : goto stuffup;
1238 : break;
1239 : }
1240 :
1241 : DNPRINTF(MFI_D_CMD, "%s: start io %d\n", DEVNAME(sc), target);
1242 :
1243 0 : if (xs->flags & SCSI_POLL)
1244 0 : mfi_poll(sc, ccb);
1245 : else
1246 0 : mfi_start(sc, ccb);
1247 :
1248 0 : KERNEL_LOCK();
1249 0 : return;
1250 :
1251 : stuffup:
1252 0 : xs->error = XS_DRIVER_STUFFUP;
1253 : complete:
1254 0 : KERNEL_LOCK();
1255 0 : scsi_done(xs);
1256 0 : }
1257 :
1258 : u_int
1259 0 : mfi_default_sgd_load(struct mfi_softc *sc, struct mfi_ccb *ccb)
1260 : {
1261 0 : struct mfi_frame_header *hdr = &ccb->ccb_frame->mfr_header;
1262 0 : union mfi_sgl *sgl = ccb->ccb_sgl;
1263 0 : bus_dma_segment_t *sgd = ccb->ccb_dmamap->dm_segs;
1264 : int i;
1265 :
1266 0 : hdr->mfh_flags |= sc->sc_sgl_flags;
1267 :
1268 0 : for (i = 0; i < ccb->ccb_dmamap->dm_nsegs; i++) {
1269 0 : if (sc->sc_64bit_dma) {
1270 0 : sgl->sg64[i].addr = htole64(sgd[i].ds_addr);
1271 0 : sgl->sg64[i].len = htole32(sgd[i].ds_len);
1272 : DNPRINTF(MFI_D_DMA, "%s: addr: %#x len: %#x\n",
1273 : DEVNAME(sc), sgl->sg64[i].addr, sgl->sg64[i].len);
1274 0 : } else {
1275 0 : sgl->sg32[i].addr = htole32(sgd[i].ds_addr);
1276 0 : sgl->sg32[i].len = htole32(sgd[i].ds_len);
1277 : DNPRINTF(MFI_D_DMA, "%s: addr: %#x len: %#x\n",
1278 : DEVNAME(sc), sgl->sg32[i].addr, sgl->sg32[i].len);
1279 : }
1280 : }
1281 :
1282 0 : return (ccb->ccb_dmamap->dm_nsegs *
1283 0 : (sc->sc_64bit_dma ? sizeof(sgl->sg64) : sizeof(sgl->sg32)));
1284 : }
1285 :
1286 : int
1287 0 : mfi_create_sgl(struct mfi_softc *sc, struct mfi_ccb *ccb, int flags)
1288 : {
1289 0 : struct mfi_frame_header *hdr = &ccb->ccb_frame->mfr_header;
1290 : int error;
1291 :
1292 : DNPRINTF(MFI_D_DMA, "%s: mfi_create_sgl %#x\n", DEVNAME(sc),
1293 : ccb->ccb_data);
1294 :
1295 0 : if (!ccb->ccb_data) {
1296 0 : hdr->mfh_sg_count = 0;
1297 0 : return (1);
1298 : }
1299 :
1300 0 : error = bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap,
1301 : ccb->ccb_data, ccb->ccb_len, NULL, flags);
1302 0 : if (error) {
1303 0 : if (error == EFBIG)
1304 0 : printf("more than %d dma segs\n",
1305 0 : sc->sc_max_sgl);
1306 : else
1307 0 : printf("error %d loading dma map\n", error);
1308 0 : return (1);
1309 : }
1310 :
1311 0 : ccb->ccb_frame_size += mfi_sgd_load(sc, ccb);
1312 :
1313 0 : if (ccb->ccb_direction == MFI_DATA_IN) {
1314 0 : hdr->mfh_flags |= MFI_FRAME_DIR_READ;
1315 0 : bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
1316 : ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
1317 0 : } else {
1318 0 : hdr->mfh_flags |= MFI_FRAME_DIR_WRITE;
1319 0 : bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
1320 : ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_PREWRITE);
1321 : }
1322 :
1323 0 : hdr->mfh_sg_count = ccb->ccb_dmamap->dm_nsegs;
1324 0 : ccb->ccb_extra_frames = (ccb->ccb_frame_size - 1) / MFI_FRAME_SIZE;
1325 :
1326 : DNPRINTF(MFI_D_DMA, "%s: sg_count: %d frame_size: %d frames_size: %d"
1327 : " dm_nsegs: %d extra_frames: %d\n",
1328 : DEVNAME(sc),
1329 : hdr->mfh_sg_count,
1330 : ccb->ccb_frame_size,
1331 : sc->sc_frames_size,
1332 : ccb->ccb_dmamap->dm_nsegs,
1333 : ccb->ccb_extra_frames);
1334 :
1335 0 : return (0);
1336 0 : }
1337 :
1338 : int
1339 0 : mfi_mgmt(struct mfi_softc *sc, uint32_t opc, uint32_t dir, uint32_t len,
1340 : void *buf, const union mfi_mbox *mbox)
1341 : {
1342 : struct mfi_ccb *ccb;
1343 : int rv;
1344 :
1345 0 : ccb = scsi_io_get(&sc->sc_iopool, 0);
1346 0 : mfi_scrub_ccb(ccb);
1347 0 : rv = mfi_do_mgmt(sc, ccb, opc, dir, len, buf, mbox);
1348 0 : scsi_io_put(&sc->sc_iopool, ccb);
1349 :
1350 0 : return (rv);
1351 : }
1352 :
1353 : int
1354 0 : mfi_do_mgmt(struct mfi_softc *sc, struct mfi_ccb *ccb, uint32_t opc,
1355 : uint32_t dir, uint32_t len, void *buf, const union mfi_mbox *mbox)
1356 : {
1357 : struct mfi_dcmd_frame *dcmd;
1358 : uint8_t *dma_buf = NULL;
1359 : int rv = EINVAL;
1360 :
1361 : DNPRINTF(MFI_D_MISC, "%s: mfi_do_mgmt %#x\n", DEVNAME(sc), opc);
1362 :
1363 0 : dma_buf = dma_alloc(len, cold ? PR_NOWAIT : PR_WAITOK);
1364 0 : if (dma_buf == NULL)
1365 : goto done;
1366 :
1367 0 : dcmd = &ccb->ccb_frame->mfr_dcmd;
1368 0 : memset(&dcmd->mdf_mbox, 0, sizeof(dcmd->mdf_mbox));
1369 0 : dcmd->mdf_header.mfh_cmd = MFI_CMD_DCMD;
1370 0 : dcmd->mdf_header.mfh_timeout = 0;
1371 :
1372 0 : dcmd->mdf_opcode = opc;
1373 0 : dcmd->mdf_header.mfh_data_len = 0;
1374 0 : ccb->ccb_direction = dir;
1375 :
1376 0 : ccb->ccb_frame_size = MFI_DCMD_FRAME_SIZE;
1377 :
1378 : /* handle special opcodes */
1379 0 : if (mbox != NULL)
1380 0 : memcpy(&dcmd->mdf_mbox, mbox, sizeof(dcmd->mdf_mbox));
1381 :
1382 0 : if (dir != MFI_DATA_NONE) {
1383 0 : if (dir == MFI_DATA_OUT)
1384 0 : memcpy(dma_buf, buf, len);
1385 0 : dcmd->mdf_header.mfh_data_len = len;
1386 0 : ccb->ccb_data = dma_buf;
1387 0 : ccb->ccb_len = len;
1388 0 : ccb->ccb_sgl = &dcmd->mdf_sgl;
1389 :
1390 0 : if (mfi_create_sgl(sc, ccb, cold ? BUS_DMA_NOWAIT :
1391 : BUS_DMA_WAITOK)) {
1392 : rv = EINVAL;
1393 0 : goto done;
1394 : }
1395 : }
1396 :
1397 0 : if (cold) {
1398 0 : ccb->ccb_done = mfi_empty_done;
1399 0 : mfi_poll(sc, ccb);
1400 0 : } else
1401 0 : mfi_exec(sc, ccb);
1402 :
1403 0 : if (dcmd->mdf_header.mfh_cmd_status != MFI_STAT_OK) {
1404 0 : if (dcmd->mdf_header.mfh_cmd_status == MFI_STAT_WRONG_STATE)
1405 0 : rv = ENXIO;
1406 : else
1407 : rv = EIO;
1408 : goto done;
1409 : }
1410 :
1411 0 : if (dir == MFI_DATA_IN)
1412 0 : memcpy(buf, dma_buf, len);
1413 :
1414 0 : rv = 0;
1415 : done:
1416 0 : if (dma_buf)
1417 0 : dma_free(dma_buf, len);
1418 :
1419 0 : return (rv);
1420 : }
1421 :
1422 : int
1423 0 : mfi_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag)
1424 : {
1425 0 : struct mfi_softc *sc = (struct mfi_softc *)link->adapter_softc;
1426 :
1427 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_scsi_ioctl\n", DEVNAME(sc));
1428 :
1429 0 : switch (cmd) {
1430 : case DIOCGCACHE:
1431 : case DIOCSCACHE:
1432 0 : return (mfi_ioctl_cache(link, cmd, (struct dk_cache *)addr));
1433 : break;
1434 :
1435 : default:
1436 0 : if (sc->sc_ioctl)
1437 0 : return (sc->sc_ioctl(link->adapter_softc, cmd, addr));
1438 : break;
1439 : }
1440 :
1441 0 : return (ENOTTY);
1442 0 : }
1443 :
1444 : int
1445 0 : mfi_ioctl_cache(struct scsi_link *link, u_long cmd, struct dk_cache *dc)
1446 : {
1447 0 : struct mfi_softc *sc = (struct mfi_softc *)link->adapter_softc;
1448 : int rv, wrenable, rdenable;
1449 0 : struct mfi_ld_prop ldp;
1450 0 : union mfi_mbox mbox;
1451 :
1452 0 : if (mfi_get_info(sc)) {
1453 : rv = EIO;
1454 0 : goto done;
1455 : }
1456 :
1457 0 : if (!sc->sc_ld[link->target].ld_present) {
1458 : rv = EIO;
1459 0 : goto done;
1460 : }
1461 :
1462 0 : memset(&mbox, 0, sizeof(mbox));
1463 0 : mbox.b[0] = link->target;
1464 0 : if ((rv = mfi_mgmt(sc, MR_DCMD_LD_GET_PROPERTIES, MFI_DATA_IN,
1465 0 : sizeof(ldp), &ldp, &mbox)) != 0)
1466 : goto done;
1467 :
1468 0 : if (sc->sc_info.mci_memory_size > 0) {
1469 0 : wrenable = ISSET(ldp.mlp_cur_cache_policy,
1470 : MR_LD_CACHE_ALLOW_WRITE_CACHE)? 1 : 0;
1471 0 : rdenable = ISSET(ldp.mlp_cur_cache_policy,
1472 : MR_LD_CACHE_ALLOW_READ_CACHE)? 1 : 0;
1473 0 : } else {
1474 0 : wrenable = ISSET(ldp.mlp_diskcache_policy,
1475 : MR_LD_DISK_CACHE_ENABLE)? 1 : 0;
1476 : rdenable = 0;
1477 : }
1478 :
1479 0 : if (cmd == DIOCGCACHE) {
1480 0 : dc->wrcache = wrenable;
1481 0 : dc->rdcache = rdenable;
1482 0 : goto done;
1483 : } /* else DIOCSCACHE */
1484 :
1485 0 : if (((dc->wrcache) ? 1 : 0) == wrenable &&
1486 0 : ((dc->rdcache) ? 1 : 0) == rdenable)
1487 : goto done;
1488 :
1489 0 : memset(&mbox, 0, sizeof(mbox));
1490 0 : mbox.b[0] = ldp.mlp_ld.mld_target;
1491 0 : mbox.b[1] = ldp.mlp_ld.mld_res;
1492 0 : mbox.s[1] = ldp.mlp_ld.mld_seq;
1493 :
1494 0 : if (sc->sc_info.mci_memory_size > 0) {
1495 0 : if (dc->rdcache)
1496 0 : SET(ldp.mlp_cur_cache_policy,
1497 : MR_LD_CACHE_ALLOW_READ_CACHE);
1498 : else
1499 0 : CLR(ldp.mlp_cur_cache_policy,
1500 : MR_LD_CACHE_ALLOW_READ_CACHE);
1501 0 : if (dc->wrcache)
1502 0 : SET(ldp.mlp_cur_cache_policy,
1503 : MR_LD_CACHE_ALLOW_WRITE_CACHE);
1504 : else
1505 0 : CLR(ldp.mlp_cur_cache_policy,
1506 : MR_LD_CACHE_ALLOW_WRITE_CACHE);
1507 : } else {
1508 0 : if (dc->rdcache) {
1509 : rv = EOPNOTSUPP;
1510 0 : goto done;
1511 : }
1512 0 : if (dc->wrcache)
1513 0 : ldp.mlp_diskcache_policy = MR_LD_DISK_CACHE_ENABLE;
1514 : else
1515 0 : ldp.mlp_diskcache_policy = MR_LD_DISK_CACHE_DISABLE;
1516 : }
1517 :
1518 0 : if ((rv = mfi_mgmt(sc, MR_DCMD_LD_SET_PROPERTIES, MFI_DATA_OUT,
1519 : sizeof(ldp), &ldp, &mbox)) != 0)
1520 0 : goto done;
1521 : done:
1522 0 : return (rv);
1523 0 : }
1524 :
1525 : #if NBIO > 0
1526 : int
1527 0 : mfi_ioctl(struct device *dev, u_long cmd, caddr_t addr)
1528 : {
1529 0 : struct mfi_softc *sc = (struct mfi_softc *)dev;
1530 : int error = 0;
1531 :
1532 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl ", DEVNAME(sc));
1533 :
1534 0 : rw_enter_write(&sc->sc_lock);
1535 :
1536 0 : switch (cmd) {
1537 : case BIOCINQ:
1538 : DNPRINTF(MFI_D_IOCTL, "inq\n");
1539 0 : error = mfi_ioctl_inq(sc, (struct bioc_inq *)addr);
1540 0 : break;
1541 :
1542 : case BIOCVOL:
1543 : DNPRINTF(MFI_D_IOCTL, "vol\n");
1544 0 : error = mfi_ioctl_vol(sc, (struct bioc_vol *)addr);
1545 0 : break;
1546 :
1547 : case BIOCDISK:
1548 : DNPRINTF(MFI_D_IOCTL, "disk\n");
1549 0 : error = mfi_ioctl_disk(sc, (struct bioc_disk *)addr);
1550 0 : break;
1551 :
1552 : case BIOCALARM:
1553 : DNPRINTF(MFI_D_IOCTL, "alarm\n");
1554 0 : error = mfi_ioctl_alarm(sc, (struct bioc_alarm *)addr);
1555 0 : break;
1556 :
1557 : case BIOCBLINK:
1558 : DNPRINTF(MFI_D_IOCTL, "blink\n");
1559 0 : error = mfi_ioctl_blink(sc, (struct bioc_blink *)addr);
1560 0 : break;
1561 :
1562 : case BIOCSETSTATE:
1563 : DNPRINTF(MFI_D_IOCTL, "setstate\n");
1564 0 : error = mfi_ioctl_setstate(sc, (struct bioc_setstate *)addr);
1565 0 : break;
1566 :
1567 : case BIOCPATROL:
1568 : DNPRINTF(MFI_D_IOCTL, "patrol\n");
1569 0 : error = mfi_ioctl_patrol(sc, (struct bioc_patrol *)addr);
1570 0 : break;
1571 :
1572 : default:
1573 : DNPRINTF(MFI_D_IOCTL, " invalid ioctl\n");
1574 : error = ENOTTY;
1575 0 : }
1576 :
1577 0 : rw_exit_write(&sc->sc_lock);
1578 :
1579 0 : return (error);
1580 : }
1581 :
1582 : int
1583 0 : mfi_bio_getitall(struct mfi_softc *sc)
1584 : {
1585 : int i, d, size, rv = EINVAL;
1586 0 : union mfi_mbox mbox;
1587 : struct mfi_conf *cfg = NULL;
1588 : struct mfi_ld_details *ld_det = NULL;
1589 :
1590 : /* get info */
1591 0 : if (mfi_get_info(sc)) {
1592 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_get_info failed\n",
1593 : DEVNAME(sc));
1594 : goto done;
1595 : }
1596 :
1597 : /* send single element command to retrieve size for full structure */
1598 0 : cfg = malloc(sizeof *cfg, M_DEVBUF, M_NOWAIT | M_ZERO);
1599 0 : if (cfg == NULL)
1600 : goto done;
1601 0 : if (mfi_mgmt(sc, MR_DCMD_CONF_GET, MFI_DATA_IN, sizeof *cfg, cfg,
1602 : NULL)) {
1603 0 : free(cfg, M_DEVBUF, sizeof *cfg);
1604 0 : goto done;
1605 : }
1606 :
1607 0 : size = cfg->mfc_size;
1608 0 : free(cfg, M_DEVBUF, sizeof *cfg);
1609 :
1610 : /* memory for read config */
1611 0 : cfg = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
1612 0 : if (cfg == NULL)
1613 : goto done;
1614 0 : if (mfi_mgmt(sc, MR_DCMD_CONF_GET, MFI_DATA_IN, size, cfg, NULL)) {
1615 0 : free(cfg, M_DEVBUF, size);
1616 0 : goto done;
1617 : }
1618 :
1619 : /* replace current pointer with new one */
1620 0 : if (sc->sc_cfg)
1621 0 : free(sc->sc_cfg, M_DEVBUF, 0);
1622 0 : sc->sc_cfg = cfg;
1623 :
1624 : /* get all ld info */
1625 0 : if (mfi_mgmt(sc, MR_DCMD_LD_GET_LIST, MFI_DATA_IN,
1626 0 : sizeof(sc->sc_ld_list), &sc->sc_ld_list, NULL))
1627 : goto done;
1628 :
1629 : /* get memory for all ld structures */
1630 0 : size = cfg->mfc_no_ld * sizeof(struct mfi_ld_details);
1631 0 : if (sc->sc_ld_sz != size) {
1632 0 : if (sc->sc_ld_details)
1633 0 : free(sc->sc_ld_details, M_DEVBUF, 0);
1634 :
1635 0 : ld_det = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
1636 0 : if (ld_det == NULL)
1637 : goto done;
1638 0 : sc->sc_ld_sz = size;
1639 0 : sc->sc_ld_details = ld_det;
1640 0 : }
1641 :
1642 : /* find used physical disks */
1643 : size = sizeof(struct mfi_ld_details);
1644 0 : for (i = 0, d = 0; i < cfg->mfc_no_ld; i++) {
1645 0 : memset(&mbox, 0, sizeof(mbox));
1646 0 : mbox.b[0] = sc->sc_ld_list.mll_list[i].mll_ld.mld_target;
1647 0 : if (mfi_mgmt(sc, MR_DCMD_LD_GET_INFO, MFI_DATA_IN, size,
1648 0 : &sc->sc_ld_details[i], &mbox))
1649 : goto done;
1650 :
1651 0 : d += sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_no_drv_per_span *
1652 0 : sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_span_depth;
1653 : }
1654 0 : sc->sc_no_pd = d;
1655 :
1656 0 : rv = 0;
1657 : done:
1658 0 : return (rv);
1659 0 : }
1660 :
1661 : int
1662 0 : mfi_ioctl_inq(struct mfi_softc *sc, struct bioc_inq *bi)
1663 : {
1664 : int rv = EINVAL;
1665 : struct mfi_conf *cfg = NULL;
1666 :
1667 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_inq\n", DEVNAME(sc));
1668 :
1669 0 : if (mfi_bio_getitall(sc)) {
1670 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_bio_getitall failed\n",
1671 : DEVNAME(sc));
1672 : goto done;
1673 : }
1674 :
1675 : /* count unused disks as volumes */
1676 0 : if (sc->sc_cfg == NULL)
1677 : goto done;
1678 : cfg = sc->sc_cfg;
1679 :
1680 0 : bi->bi_nodisk = sc->sc_info.mci_pd_disks_present;
1681 0 : bi->bi_novol = cfg->mfc_no_ld + cfg->mfc_no_hs;
1682 : #if notyet
1683 : bi->bi_novol = cfg->mfc_no_ld + cfg->mfc_no_hs +
1684 : (bi->bi_nodisk - sc->sc_no_pd);
1685 : #endif
1686 : /* tell bio who we are */
1687 0 : strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev));
1688 :
1689 0 : rv = 0;
1690 : done:
1691 0 : return (rv);
1692 : }
1693 :
1694 : int
1695 0 : mfi_ioctl_vol(struct mfi_softc *sc, struct bioc_vol *bv)
1696 : {
1697 : int i, per, rv = EINVAL;
1698 : struct scsi_link *link;
1699 : struct device *dev;
1700 :
1701 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_vol %#x\n",
1702 : DEVNAME(sc), bv->bv_volid);
1703 :
1704 : /* we really could skip and expect that inq took care of it */
1705 0 : if (mfi_bio_getitall(sc)) {
1706 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_bio_getitall failed\n",
1707 : DEVNAME(sc));
1708 : goto done;
1709 : }
1710 :
1711 0 : if (bv->bv_volid >= sc->sc_ld_list.mll_no_ld) {
1712 : /* go do hotspares & unused disks */
1713 0 : rv = mfi_bio_hs(sc, bv->bv_volid, MFI_MGMT_VD, bv);
1714 0 : goto done;
1715 : }
1716 :
1717 : i = bv->bv_volid;
1718 0 : link = scsi_get_link(sc->sc_scsibus, i, 0);
1719 0 : if (link != NULL && link->device_softc != NULL) {
1720 0 : dev = link->device_softc;
1721 0 : strlcpy(bv->bv_dev, dev->dv_xname, sizeof(bv->bv_dev));
1722 0 : }
1723 :
1724 0 : switch(sc->sc_ld_list.mll_list[i].mll_state) {
1725 : case MFI_LD_OFFLINE:
1726 0 : bv->bv_status = BIOC_SVOFFLINE;
1727 0 : break;
1728 :
1729 : case MFI_LD_PART_DEGRADED:
1730 : case MFI_LD_DEGRADED:
1731 0 : bv->bv_status = BIOC_SVDEGRADED;
1732 0 : break;
1733 :
1734 : case MFI_LD_ONLINE:
1735 0 : bv->bv_status = BIOC_SVONLINE;
1736 0 : break;
1737 :
1738 : default:
1739 0 : bv->bv_status = BIOC_SVINVALID;
1740 : DNPRINTF(MFI_D_IOCTL, "%s: invalid logical disk state %#x\n",
1741 : DEVNAME(sc),
1742 : sc->sc_ld_list.mll_list[i].mll_state);
1743 0 : }
1744 :
1745 : /* additional status can modify MFI status */
1746 0 : switch (sc->sc_ld_details[i].mld_progress.mlp_in_prog) {
1747 : case MFI_LD_PROG_CC:
1748 : case MFI_LD_PROG_BGI:
1749 0 : bv->bv_status = BIOC_SVSCRUB;
1750 0 : per = (int)sc->sc_ld_details[i].mld_progress.mlp_cc.mp_progress;
1751 0 : bv->bv_percent = (per * 100) / 0xffff;
1752 0 : bv->bv_seconds =
1753 0 : sc->sc_ld_details[i].mld_progress.mlp_cc.mp_elapsed_seconds;
1754 0 : break;
1755 :
1756 : case MFI_LD_PROG_FGI:
1757 : case MFI_LD_PROG_RECONSTRUCT:
1758 : /* nothing yet */
1759 : break;
1760 : }
1761 :
1762 0 : if (sc->sc_ld_details[i].mld_cfg.mlc_prop.mlp_cur_cache_policy & 0x01)
1763 0 : bv->bv_cache = BIOC_CVWRITEBACK;
1764 : else
1765 0 : bv->bv_cache = BIOC_CVWRITETHROUGH;
1766 :
1767 : /*
1768 : * The RAID levels are determined per the SNIA DDF spec, this is only
1769 : * a subset that is valid for the MFI controller.
1770 : */
1771 0 : bv->bv_level = sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_pri_raid;
1772 0 : if (sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_sec_raid ==
1773 : MFI_DDF_SRL_SPANNED)
1774 0 : bv->bv_level *= 10;
1775 :
1776 0 : bv->bv_nodisk = sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_no_drv_per_span *
1777 0 : sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_span_depth;
1778 :
1779 0 : bv->bv_size = sc->sc_ld_details[i].mld_size * 512; /* bytes per block */
1780 :
1781 0 : rv = 0;
1782 : done:
1783 0 : return (rv);
1784 : }
1785 :
1786 : int
1787 0 : mfi_ioctl_disk(struct mfi_softc *sc, struct bioc_disk *bd)
1788 : {
1789 : struct mfi_conf *cfg;
1790 : struct mfi_array *ar;
1791 : struct mfi_ld_cfg *ld;
1792 : struct mfi_pd_details *pd;
1793 : struct mfi_pd_progress *mfp;
1794 : struct mfi_progress *mp;
1795 : struct scsi_inquiry_data *inqbuf;
1796 0 : char vend[8+16+4+1], *vendp;
1797 : int rv = EINVAL;
1798 : int arr, vol, disk, span;
1799 0 : union mfi_mbox mbox;
1800 :
1801 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_disk %#x\n",
1802 : DEVNAME(sc), bd->bd_diskid);
1803 :
1804 : /* we really could skip and expect that inq took care of it */
1805 0 : if (mfi_bio_getitall(sc)) {
1806 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_bio_getitall failed\n",
1807 : DEVNAME(sc));
1808 0 : return (rv);
1809 : }
1810 0 : cfg = sc->sc_cfg;
1811 :
1812 0 : pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
1813 :
1814 0 : ar = cfg->mfc_array;
1815 0 : vol = bd->bd_volid;
1816 0 : if (vol >= cfg->mfc_no_ld) {
1817 : /* do hotspares */
1818 0 : rv = mfi_bio_hs(sc, bd->bd_volid, MFI_MGMT_SD, bd);
1819 0 : goto freeme;
1820 : }
1821 :
1822 : /* calculate offset to ld structure */
1823 0 : ld = (struct mfi_ld_cfg *)(
1824 0 : ((uint8_t *)cfg) + offsetof(struct mfi_conf, mfc_array) +
1825 0 : cfg->mfc_array_size * cfg->mfc_no_array);
1826 :
1827 : /* use span 0 only when raid group is not spanned */
1828 0 : if (ld[vol].mlc_parm.mpa_span_depth > 1)
1829 0 : span = bd->bd_diskid / ld[vol].mlc_parm.mpa_no_drv_per_span;
1830 : else
1831 : span = 0;
1832 0 : arr = ld[vol].mlc_span[span].mls_index;
1833 :
1834 : /* offset disk into pd list */
1835 0 : disk = bd->bd_diskid % ld[vol].mlc_parm.mpa_no_drv_per_span;
1836 0 : bd->bd_target = ar[arr].pd[disk].mar_enc_slot;
1837 :
1838 : /* get status */
1839 0 : switch (ar[arr].pd[disk].mar_pd_state){
1840 : case MFI_PD_UNCONFIG_GOOD:
1841 : case MFI_PD_FAILED:
1842 0 : bd->bd_status = BIOC_SDFAILED;
1843 0 : break;
1844 :
1845 : case MFI_PD_HOTSPARE: /* XXX dedicated hotspare part of array? */
1846 0 : bd->bd_status = BIOC_SDHOTSPARE;
1847 0 : break;
1848 :
1849 : case MFI_PD_OFFLINE:
1850 0 : bd->bd_status = BIOC_SDOFFLINE;
1851 0 : break;
1852 :
1853 : case MFI_PD_REBUILD:
1854 0 : bd->bd_status = BIOC_SDREBUILD;
1855 0 : break;
1856 :
1857 : case MFI_PD_ONLINE:
1858 0 : bd->bd_status = BIOC_SDONLINE;
1859 0 : break;
1860 :
1861 : case MFI_PD_UNCONFIG_BAD: /* XXX define new state in bio */
1862 : default:
1863 0 : bd->bd_status = BIOC_SDINVALID;
1864 0 : break;
1865 : }
1866 :
1867 : /* get the remaining fields */
1868 0 : memset(&mbox, 0, sizeof(mbox));
1869 0 : mbox.s[0] = ar[arr].pd[disk].mar_pd.mfp_id;
1870 0 : if (mfi_mgmt(sc, MR_DCMD_PD_GET_INFO, MFI_DATA_IN,
1871 : sizeof *pd, pd, &mbox)) {
1872 : /* disk is missing but succeed command */
1873 : rv = 0;
1874 0 : goto freeme;
1875 : }
1876 :
1877 0 : bd->bd_size = pd->mpd_size * 512; /* bytes per block */
1878 :
1879 : /* if pd->mpd_enc_idx is 0 then it is not in an enclosure */
1880 0 : bd->bd_channel = pd->mpd_enc_idx;
1881 :
1882 0 : inqbuf = (struct scsi_inquiry_data *)&pd->mpd_inq_data;
1883 0 : vendp = inqbuf->vendor;
1884 0 : memcpy(vend, vendp, sizeof vend - 1);
1885 0 : vend[sizeof vend - 1] = '\0';
1886 0 : strlcpy(bd->bd_vendor, vend, sizeof(bd->bd_vendor));
1887 :
1888 : /* XXX find a way to retrieve serial nr from drive */
1889 : /* XXX find a way to get bd_procdev */
1890 :
1891 0 : mfp = &pd->mpd_progress;
1892 0 : if (mfp->mfp_in_prog & MFI_PD_PROG_PR) {
1893 0 : mp = &mfp->mfp_patrol_read;
1894 0 : bd->bd_patrol.bdp_percent = (mp->mp_progress * 100) / 0xffff;
1895 0 : bd->bd_patrol.bdp_seconds = mp->mp_elapsed_seconds;
1896 0 : }
1897 :
1898 0 : rv = 0;
1899 : freeme:
1900 0 : free(pd, M_DEVBUF, sizeof *pd);
1901 :
1902 0 : return (rv);
1903 0 : }
1904 :
1905 : int
1906 0 : mfi_ioctl_alarm(struct mfi_softc *sc, struct bioc_alarm *ba)
1907 : {
1908 : uint32_t opc, dir = MFI_DATA_NONE;
1909 : int rv = 0;
1910 0 : int8_t ret;
1911 :
1912 0 : switch(ba->ba_opcode) {
1913 : case BIOC_SADISABLE:
1914 : opc = MR_DCMD_SPEAKER_DISABLE;
1915 0 : break;
1916 :
1917 : case BIOC_SAENABLE:
1918 : opc = MR_DCMD_SPEAKER_ENABLE;
1919 0 : break;
1920 :
1921 : case BIOC_SASILENCE:
1922 : opc = MR_DCMD_SPEAKER_SILENCE;
1923 0 : break;
1924 :
1925 : case BIOC_GASTATUS:
1926 : opc = MR_DCMD_SPEAKER_GET;
1927 : dir = MFI_DATA_IN;
1928 0 : break;
1929 :
1930 : case BIOC_SATEST:
1931 : opc = MR_DCMD_SPEAKER_TEST;
1932 0 : break;
1933 :
1934 : default:
1935 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_alarm biocalarm invalid "
1936 : "opcode %x\n", DEVNAME(sc), ba->ba_opcode);
1937 0 : return (EINVAL);
1938 : }
1939 :
1940 0 : if (mfi_mgmt(sc, opc, dir, sizeof(ret), &ret, NULL))
1941 0 : rv = EINVAL;
1942 : else
1943 0 : if (ba->ba_opcode == BIOC_GASTATUS)
1944 0 : ba->ba_status = ret;
1945 : else
1946 0 : ba->ba_status = 0;
1947 :
1948 0 : return (rv);
1949 0 : }
1950 :
1951 : int
1952 0 : mfi_ioctl_blink(struct mfi_softc *sc, struct bioc_blink *bb)
1953 : {
1954 : int i, found, rv = EINVAL;
1955 0 : union mfi_mbox mbox;
1956 : uint32_t cmd;
1957 : struct mfi_pd_list *pd;
1958 :
1959 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_blink %x\n", DEVNAME(sc),
1960 : bb->bb_status);
1961 :
1962 : /* channel 0 means not in an enclosure so can't be blinked */
1963 0 : if (bb->bb_channel == 0)
1964 0 : return (EINVAL);
1965 :
1966 0 : pd = malloc(sizeof(*pd), M_DEVBUF, M_WAITOK);
1967 :
1968 0 : if (mfi_mgmt(sc, MR_DCMD_PD_GET_LIST, MFI_DATA_IN,
1969 : sizeof(*pd), pd, NULL))
1970 : goto done;
1971 :
1972 0 : for (i = 0, found = 0; i < pd->mpl_no_pd; i++)
1973 0 : if (bb->bb_channel == pd->mpl_address[i].mpa_enc_index &&
1974 0 : bb->bb_target == pd->mpl_address[i].mpa_enc_slot) {
1975 : found = 1;
1976 0 : break;
1977 : }
1978 :
1979 0 : if (!found)
1980 : goto done;
1981 :
1982 0 : memset(&mbox, 0, sizeof(mbox));
1983 0 : mbox.s[0] = pd->mpl_address[i].mpa_pd_id;
1984 :
1985 0 : switch (bb->bb_status) {
1986 : case BIOC_SBUNBLINK:
1987 : cmd = MR_DCMD_PD_UNBLINK;
1988 0 : break;
1989 :
1990 : case BIOC_SBBLINK:
1991 : cmd = MR_DCMD_PD_BLINK;
1992 0 : break;
1993 :
1994 : case BIOC_SBALARM:
1995 : default:
1996 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_blink biocblink invalid "
1997 : "opcode %x\n", DEVNAME(sc), bb->bb_status);
1998 : goto done;
1999 : }
2000 :
2001 :
2002 0 : if (mfi_mgmt(sc, cmd, MFI_DATA_NONE, 0, NULL, &mbox))
2003 : goto done;
2004 :
2005 0 : rv = 0;
2006 : done:
2007 0 : free(pd, M_DEVBUF, sizeof *pd);
2008 0 : return (rv);
2009 0 : }
2010 :
2011 : int
2012 0 : mfi_ioctl_setstate(struct mfi_softc *sc, struct bioc_setstate *bs)
2013 : {
2014 : struct mfi_pd_list *pd;
2015 : struct mfi_pd_details *info;
2016 : int i, found, rv = EINVAL;
2017 0 : union mfi_mbox mbox;
2018 :
2019 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_setstate %x\n", DEVNAME(sc),
2020 : bs->bs_status);
2021 :
2022 0 : pd = malloc(sizeof(*pd), M_DEVBUF, M_WAITOK);
2023 0 : info = malloc(sizeof *info, M_DEVBUF, M_WAITOK);
2024 :
2025 0 : if (mfi_mgmt(sc, MR_DCMD_PD_GET_LIST, MFI_DATA_IN,
2026 : sizeof(*pd), pd, NULL))
2027 : goto done;
2028 :
2029 0 : for (i = 0, found = 0; i < pd->mpl_no_pd; i++)
2030 0 : if (bs->bs_channel == pd->mpl_address[i].mpa_enc_index &&
2031 0 : bs->bs_target == pd->mpl_address[i].mpa_enc_slot) {
2032 : found = 1;
2033 0 : break;
2034 : }
2035 :
2036 0 : if (!found)
2037 : goto done;
2038 :
2039 0 : memset(&mbox, 0, sizeof(mbox));
2040 0 : mbox.s[0] = pd->mpl_address[i].mpa_pd_id;
2041 :
2042 0 : if (mfi_mgmt(sc, MR_DCMD_PD_GET_INFO, MFI_DATA_IN,
2043 : sizeof *info, info, &mbox))
2044 : goto done;
2045 :
2046 0 : mbox.s[0] = pd->mpl_address[i].mpa_pd_id;
2047 0 : mbox.s[1] = info->mpd_pd.mfp_seq;
2048 :
2049 0 : switch (bs->bs_status) {
2050 : case BIOC_SSONLINE:
2051 0 : mbox.b[4] = MFI_PD_ONLINE;
2052 0 : break;
2053 :
2054 : case BIOC_SSOFFLINE:
2055 0 : mbox.b[4] = MFI_PD_OFFLINE;
2056 0 : break;
2057 :
2058 : case BIOC_SSHOTSPARE:
2059 0 : mbox.b[4] = MFI_PD_HOTSPARE;
2060 0 : break;
2061 :
2062 : case BIOC_SSREBUILD:
2063 0 : mbox.b[4] = MFI_PD_REBUILD;
2064 0 : break;
2065 :
2066 : default:
2067 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_setstate invalid "
2068 : "opcode %x\n", DEVNAME(sc), bs->bs_status);
2069 : goto done;
2070 : }
2071 :
2072 :
2073 0 : if ((rv = mfi_mgmt(sc, MR_DCMD_PD_SET_STATE, MFI_DATA_NONE, 0, NULL,
2074 : &mbox)))
2075 : goto done;
2076 :
2077 : rv = 0;
2078 : done:
2079 0 : free(pd, M_DEVBUF, sizeof *pd);
2080 0 : free(info, M_DEVBUF, sizeof *info);
2081 0 : return (rv);
2082 0 : }
2083 :
2084 : int
2085 0 : mfi_ioctl_patrol(struct mfi_softc *sc, struct bioc_patrol *bp)
2086 : {
2087 : uint32_t opc, dir = MFI_DATA_NONE;
2088 : int rv = 0;
2089 0 : struct mfi_pr_properties prop;
2090 0 : struct mfi_pr_status status;
2091 0 : uint32_t time, exec_freq;
2092 :
2093 0 : switch (bp->bp_opcode) {
2094 : case BIOC_SPSTOP:
2095 : case BIOC_SPSTART:
2096 0 : if (bp->bp_opcode == BIOC_SPSTART)
2097 0 : opc = MR_DCMD_PR_START;
2098 : else
2099 : opc = MR_DCMD_PR_STOP;
2100 : dir = MFI_DATA_IN;
2101 0 : if (mfi_mgmt(sc, opc, dir, 0, NULL, NULL))
2102 0 : return (EINVAL);
2103 : break;
2104 :
2105 : case BIOC_SPMANUAL:
2106 : case BIOC_SPDISABLE:
2107 : case BIOC_SPAUTO:
2108 : /* Get device's time. */
2109 : opc = MR_DCMD_TIME_SECS_GET;
2110 : dir = MFI_DATA_IN;
2111 0 : if (mfi_mgmt(sc, opc, dir, sizeof(time), &time, NULL))
2112 0 : return (EINVAL);
2113 :
2114 : opc = MR_DCMD_PR_GET_PROPERTIES;
2115 : dir = MFI_DATA_IN;
2116 0 : if (mfi_mgmt(sc, opc, dir, sizeof(prop), &prop, NULL))
2117 0 : return (EINVAL);
2118 :
2119 0 : switch (bp->bp_opcode) {
2120 : case BIOC_SPMANUAL:
2121 0 : prop.op_mode = MFI_PR_OPMODE_MANUAL;
2122 0 : break;
2123 : case BIOC_SPDISABLE:
2124 0 : prop.op_mode = MFI_PR_OPMODE_DISABLED;
2125 0 : break;
2126 : case BIOC_SPAUTO:
2127 0 : if (bp->bp_autoival != 0) {
2128 0 : if (bp->bp_autoival == -1)
2129 : /* continuously */
2130 0 : exec_freq = 0xffffffffU;
2131 0 : else if (bp->bp_autoival > 0)
2132 : exec_freq = bp->bp_autoival;
2133 : else
2134 0 : return (EINVAL);
2135 0 : prop.exec_freq = exec_freq;
2136 0 : }
2137 0 : if (bp->bp_autonext != 0) {
2138 0 : if (bp->bp_autonext < 0)
2139 0 : return (EINVAL);
2140 : else
2141 0 : prop.next_exec = time + bp->bp_autonext;
2142 0 : }
2143 0 : prop.op_mode = MFI_PR_OPMODE_AUTO;
2144 0 : break;
2145 : }
2146 :
2147 : opc = MR_DCMD_PR_SET_PROPERTIES;
2148 : dir = MFI_DATA_OUT;
2149 0 : if (mfi_mgmt(sc, opc, dir, sizeof(prop), &prop, NULL))
2150 0 : return (EINVAL);
2151 :
2152 : break;
2153 :
2154 : case BIOC_GPSTATUS:
2155 : opc = MR_DCMD_PR_GET_PROPERTIES;
2156 : dir = MFI_DATA_IN;
2157 0 : if (mfi_mgmt(sc, opc, dir, sizeof(prop), &prop, NULL))
2158 0 : return (EINVAL);
2159 :
2160 : opc = MR_DCMD_PR_GET_STATUS;
2161 : dir = MFI_DATA_IN;
2162 0 : if (mfi_mgmt(sc, opc, dir, sizeof(status), &status, NULL))
2163 0 : return (EINVAL);
2164 :
2165 : /* Get device's time. */
2166 : opc = MR_DCMD_TIME_SECS_GET;
2167 : dir = MFI_DATA_IN;
2168 0 : if (mfi_mgmt(sc, opc, dir, sizeof(time), &time, NULL))
2169 0 : return (EINVAL);
2170 :
2171 0 : switch (prop.op_mode) {
2172 : case MFI_PR_OPMODE_AUTO:
2173 0 : bp->bp_mode = BIOC_SPMAUTO;
2174 0 : bp->bp_autoival = prop.exec_freq;
2175 0 : bp->bp_autonext = prop.next_exec;
2176 0 : bp->bp_autonow = time;
2177 0 : break;
2178 : case MFI_PR_OPMODE_MANUAL:
2179 0 : bp->bp_mode = BIOC_SPMMANUAL;
2180 0 : break;
2181 : case MFI_PR_OPMODE_DISABLED:
2182 0 : bp->bp_mode = BIOC_SPMDISABLED;
2183 0 : break;
2184 : default:
2185 0 : printf("%s: unknown patrol mode %d\n",
2186 0 : DEVNAME(sc), prop.op_mode);
2187 0 : break;
2188 : }
2189 :
2190 0 : switch (status.state) {
2191 : case MFI_PR_STATE_STOPPED:
2192 0 : bp->bp_status = BIOC_SPSSTOPPED;
2193 0 : break;
2194 : case MFI_PR_STATE_READY:
2195 0 : bp->bp_status = BIOC_SPSREADY;
2196 0 : break;
2197 : case MFI_PR_STATE_ACTIVE:
2198 0 : bp->bp_status = BIOC_SPSACTIVE;
2199 0 : break;
2200 : case MFI_PR_STATE_ABORTED:
2201 0 : bp->bp_status = BIOC_SPSABORTED;
2202 0 : break;
2203 : default:
2204 0 : printf("%s: unknown patrol state %d\n",
2205 0 : DEVNAME(sc), status.state);
2206 0 : break;
2207 : }
2208 :
2209 : break;
2210 :
2211 : default:
2212 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_patrol biocpatrol invalid "
2213 : "opcode %x\n", DEVNAME(sc), bp->bp_opcode);
2214 0 : return (EINVAL);
2215 : }
2216 :
2217 0 : return (rv);
2218 0 : }
2219 :
2220 : int
2221 0 : mfi_bio_hs(struct mfi_softc *sc, int volid, int type, void *bio_hs)
2222 : {
2223 : struct mfi_conf *cfg;
2224 : struct mfi_hotspare *hs;
2225 : struct mfi_pd_details *pd;
2226 : struct bioc_disk *sdhs;
2227 : struct bioc_vol *vdhs;
2228 : struct scsi_inquiry_data *inqbuf;
2229 0 : char vend[8+16+4+1], *vendp;
2230 : int i, rv = EINVAL;
2231 : uint32_t size;
2232 0 : union mfi_mbox mbox;
2233 :
2234 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs %d\n", DEVNAME(sc), volid);
2235 :
2236 0 : if (!bio_hs)
2237 0 : return (EINVAL);
2238 :
2239 0 : pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
2240 :
2241 : /* send single element command to retrieve size for full structure */
2242 0 : cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK);
2243 0 : if (mfi_mgmt(sc, MR_DCMD_CONF_GET, MFI_DATA_IN, sizeof *cfg, cfg, NULL))
2244 : goto freeme;
2245 :
2246 0 : size = cfg->mfc_size;
2247 0 : free(cfg, M_DEVBUF, sizeof *cfg);
2248 :
2249 : /* memory for read config */
2250 0 : cfg = malloc(size, M_DEVBUF, M_WAITOK|M_ZERO);
2251 0 : if (mfi_mgmt(sc, MR_DCMD_CONF_GET, MFI_DATA_IN, size, cfg, NULL))
2252 : goto freeme;
2253 :
2254 : /* calculate offset to hs structure */
2255 0 : hs = (struct mfi_hotspare *)(
2256 0 : ((uint8_t *)cfg) + offsetof(struct mfi_conf, mfc_array) +
2257 0 : cfg->mfc_array_size * cfg->mfc_no_array +
2258 0 : cfg->mfc_ld_size * cfg->mfc_no_ld);
2259 :
2260 0 : if (volid < cfg->mfc_no_ld)
2261 : goto freeme; /* not a hotspare */
2262 :
2263 0 : if (volid > (cfg->mfc_no_ld + cfg->mfc_no_hs))
2264 : goto freeme; /* not a hotspare */
2265 :
2266 : /* offset into hotspare structure */
2267 0 : i = volid - cfg->mfc_no_ld;
2268 :
2269 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs i %d volid %d no_ld %d no_hs %d "
2270 : "hs %p cfg %p id %02x\n", DEVNAME(sc), i, volid, cfg->mfc_no_ld,
2271 : cfg->mfc_no_hs, hs, cfg, hs[i].mhs_pd.mfp_id);
2272 :
2273 : /* get pd fields */
2274 0 : memset(&mbox, 0, sizeof(mbox));
2275 0 : mbox.s[0] = hs[i].mhs_pd.mfp_id;
2276 0 : if (mfi_mgmt(sc, MR_DCMD_PD_GET_INFO, MFI_DATA_IN,
2277 : sizeof *pd, pd, &mbox)) {
2278 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs illegal PD\n",
2279 : DEVNAME(sc));
2280 : goto freeme;
2281 : }
2282 :
2283 0 : switch (type) {
2284 : case MFI_MGMT_VD:
2285 0 : vdhs = bio_hs;
2286 0 : vdhs->bv_status = BIOC_SVONLINE;
2287 0 : vdhs->bv_size = pd->mpd_size / 2 * 1024; /* XXX why? */
2288 0 : vdhs->bv_level = -1; /* hotspare */
2289 0 : vdhs->bv_nodisk = 1;
2290 0 : break;
2291 :
2292 : case MFI_MGMT_SD:
2293 0 : sdhs = bio_hs;
2294 0 : sdhs->bd_status = BIOC_SDHOTSPARE;
2295 0 : sdhs->bd_size = pd->mpd_size / 2 * 1024; /* XXX why? */
2296 0 : sdhs->bd_channel = pd->mpd_enc_idx;
2297 0 : sdhs->bd_target = pd->mpd_enc_slot;
2298 0 : inqbuf = (struct scsi_inquiry_data *)&pd->mpd_inq_data;
2299 0 : vendp = inqbuf->vendor;
2300 0 : memcpy(vend, vendp, sizeof vend - 1);
2301 0 : vend[sizeof vend - 1] = '\0';
2302 0 : strlcpy(sdhs->bd_vendor, vend, sizeof(sdhs->bd_vendor));
2303 0 : break;
2304 :
2305 : default:
2306 : goto freeme;
2307 : }
2308 :
2309 : DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs 6\n", DEVNAME(sc));
2310 0 : rv = 0;
2311 : freeme:
2312 0 : free(pd, M_DEVBUF, sizeof *pd);
2313 0 : free(cfg, M_DEVBUF, 0);
2314 :
2315 0 : return (rv);
2316 0 : }
2317 :
2318 : #ifndef SMALL_KERNEL
2319 :
2320 : static const char *mfi_bbu_indicators[] = {
2321 : "pack missing",
2322 : "voltage low",
2323 : "temp high",
2324 : "charge active",
2325 : "discharge active",
2326 : "learn cycle req'd",
2327 : "learn cycle active",
2328 : "learn cycle failed",
2329 : "learn cycle timeout",
2330 : "I2C errors",
2331 : "replace pack",
2332 : "low capacity",
2333 : "periodic learn req'd"
2334 : };
2335 :
2336 : #define MFI_BBU_SENSORS 4
2337 :
2338 : int
2339 0 : mfi_bbu(struct mfi_softc *sc)
2340 : {
2341 0 : struct mfi_bbu_status bbu;
2342 : u_int32_t status;
2343 : u_int32_t mask;
2344 : u_int32_t soh_bad;
2345 : int i;
2346 :
2347 0 : if (mfi_mgmt(sc, MR_DCMD_BBU_GET_STATUS, MFI_DATA_IN,
2348 0 : sizeof(bbu), &bbu, NULL) != 0) {
2349 0 : for (i = 0; i < MFI_BBU_SENSORS; i++) {
2350 0 : sc->sc_bbu[i].value = 0;
2351 0 : sc->sc_bbu[i].status = SENSOR_S_UNKNOWN;
2352 : }
2353 0 : for (i = 0; i < nitems(mfi_bbu_indicators); i++) {
2354 0 : sc->sc_bbu_status[i].value = 0;
2355 0 : sc->sc_bbu_status[i].status = SENSOR_S_UNKNOWN;
2356 : }
2357 0 : return (-1);
2358 : }
2359 :
2360 0 : switch (bbu.battery_type) {
2361 : case MFI_BBU_TYPE_IBBU:
2362 : mask = MFI_BBU_STATE_BAD_IBBU;
2363 : soh_bad = 0;
2364 0 : break;
2365 : case MFI_BBU_TYPE_BBU:
2366 : mask = MFI_BBU_STATE_BAD_BBU;
2367 0 : soh_bad = (bbu.detail.bbu.is_SOH_good == 0);
2368 0 : break;
2369 :
2370 : case MFI_BBU_TYPE_NONE:
2371 : default:
2372 0 : sc->sc_bbu[0].value = 0;
2373 0 : sc->sc_bbu[0].status = SENSOR_S_CRIT;
2374 0 : for (i = 1; i < MFI_BBU_SENSORS; i++) {
2375 0 : sc->sc_bbu[i].value = 0;
2376 0 : sc->sc_bbu[i].status = SENSOR_S_UNKNOWN;
2377 : }
2378 0 : for (i = 0; i < nitems(mfi_bbu_indicators); i++) {
2379 0 : sc->sc_bbu_status[i].value = 0;
2380 0 : sc->sc_bbu_status[i].status = SENSOR_S_UNKNOWN;
2381 : }
2382 0 : return (0);
2383 : }
2384 :
2385 0 : status = letoh32(bbu.fw_status);
2386 :
2387 0 : sc->sc_bbu[0].value = ((status & mask) || soh_bad) ? 0 : 1;
2388 0 : sc->sc_bbu[0].status = ((status & mask) || soh_bad) ? SENSOR_S_CRIT :
2389 : SENSOR_S_OK;
2390 :
2391 0 : sc->sc_bbu[1].value = letoh16(bbu.voltage) * 1000;
2392 0 : sc->sc_bbu[2].value = (int16_t)letoh16(bbu.current) * 1000;
2393 0 : sc->sc_bbu[3].value = letoh16(bbu.temperature) * 1000000 + 273150000;
2394 0 : for (i = 1; i < MFI_BBU_SENSORS; i++)
2395 0 : sc->sc_bbu[i].status = SENSOR_S_UNSPEC;
2396 :
2397 0 : for (i = 0; i < nitems(mfi_bbu_indicators); i++) {
2398 0 : sc->sc_bbu_status[i].value = (status & (1 << i)) ? 1 : 0;
2399 0 : sc->sc_bbu_status[i].status = SENSOR_S_UNSPEC;
2400 : }
2401 :
2402 0 : return (0);
2403 0 : }
2404 :
2405 : int
2406 0 : mfi_create_sensors(struct mfi_softc *sc)
2407 : {
2408 : struct device *dev;
2409 : struct scsi_link *link;
2410 : int i;
2411 :
2412 0 : strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
2413 : sizeof(sc->sc_sensordev.xname));
2414 :
2415 0 : if (ISSET(letoh32(sc->sc_info.mci_adapter_ops ), MFI_INFO_AOPS_BBU)) {
2416 0 : sc->sc_bbu = mallocarray(4, sizeof(*sc->sc_bbu),
2417 : M_DEVBUF, M_WAITOK | M_ZERO);
2418 :
2419 0 : sc->sc_bbu[0].type = SENSOR_INDICATOR;
2420 0 : sc->sc_bbu[0].status = SENSOR_S_UNKNOWN;
2421 0 : strlcpy(sc->sc_bbu[0].desc, "bbu ok",
2422 : sizeof(sc->sc_bbu[0].desc));
2423 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_bbu[0]);
2424 :
2425 0 : sc->sc_bbu[1].type = SENSOR_VOLTS_DC;
2426 0 : sc->sc_bbu[1].status = SENSOR_S_UNSPEC;
2427 0 : sc->sc_bbu[2].type = SENSOR_AMPS;
2428 0 : sc->sc_bbu[2].status = SENSOR_S_UNSPEC;
2429 0 : sc->sc_bbu[3].type = SENSOR_TEMP;
2430 0 : sc->sc_bbu[3].status = SENSOR_S_UNSPEC;
2431 0 : for (i = 1; i < MFI_BBU_SENSORS; i++) {
2432 0 : strlcpy(sc->sc_bbu[i].desc, "bbu",
2433 : sizeof(sc->sc_bbu[i].desc));
2434 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_bbu[i]);
2435 : }
2436 :
2437 0 : sc->sc_bbu_status = malloc(sizeof(*sc->sc_bbu_status) *
2438 : sizeof(mfi_bbu_indicators), M_DEVBUF, M_WAITOK | M_ZERO);
2439 :
2440 0 : for (i = 0; i < nitems(mfi_bbu_indicators); i++) {
2441 0 : sc->sc_bbu_status[i].type = SENSOR_INDICATOR;
2442 0 : sc->sc_bbu_status[i].status = SENSOR_S_UNSPEC;
2443 0 : strlcpy(sc->sc_bbu_status[i].desc,
2444 0 : mfi_bbu_indicators[i],
2445 : sizeof(sc->sc_bbu_status[i].desc));
2446 :
2447 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_bbu_status[i]);
2448 : }
2449 : }
2450 :
2451 0 : sc->sc_sensors = mallocarray(sc->sc_ld_cnt, sizeof(struct ksensor),
2452 : M_DEVBUF, M_NOWAIT | M_ZERO);
2453 0 : if (sc->sc_sensors == NULL)
2454 0 : return (1);
2455 :
2456 0 : for (i = 0; i < sc->sc_ld_cnt; i++) {
2457 0 : link = scsi_get_link(sc->sc_scsibus, i, 0);
2458 0 : if (link == NULL)
2459 : goto bad;
2460 :
2461 0 : dev = link->device_softc;
2462 :
2463 0 : sc->sc_sensors[i].type = SENSOR_DRIVE;
2464 0 : sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
2465 :
2466 0 : strlcpy(sc->sc_sensors[i].desc, dev->dv_xname,
2467 : sizeof(sc->sc_sensors[i].desc));
2468 :
2469 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
2470 : }
2471 :
2472 0 : if (sensor_task_register(sc, mfi_refresh_sensors, 10) == NULL)
2473 : goto bad;
2474 :
2475 0 : sensordev_install(&sc->sc_sensordev);
2476 :
2477 0 : return (0);
2478 :
2479 : bad:
2480 0 : free(sc->sc_sensors, M_DEVBUF,
2481 0 : sc->sc_ld_cnt * sizeof(struct ksensor));
2482 :
2483 0 : return (1);
2484 0 : }
2485 :
2486 : void
2487 0 : mfi_refresh_sensors(void *arg)
2488 : {
2489 0 : struct mfi_softc *sc = arg;
2490 : int i, rv;
2491 0 : struct bioc_vol bv;
2492 :
2493 0 : if (sc->sc_bbu != NULL && mfi_bbu(sc) != 0)
2494 0 : return;
2495 :
2496 0 : for (i = 0; i < sc->sc_ld_cnt; i++) {
2497 0 : bzero(&bv, sizeof(bv));
2498 0 : bv.bv_volid = i;
2499 :
2500 0 : rw_enter_write(&sc->sc_lock);
2501 0 : rv = mfi_ioctl_vol(sc, &bv);
2502 0 : rw_exit_write(&sc->sc_lock);
2503 :
2504 0 : if (rv != 0)
2505 0 : return;
2506 :
2507 0 : switch(bv.bv_status) {
2508 : case BIOC_SVOFFLINE:
2509 0 : sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL;
2510 0 : sc->sc_sensors[i].status = SENSOR_S_CRIT;
2511 0 : break;
2512 :
2513 : case BIOC_SVDEGRADED:
2514 0 : sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL;
2515 0 : sc->sc_sensors[i].status = SENSOR_S_WARN;
2516 0 : break;
2517 :
2518 : case BIOC_SVSCRUB:
2519 : case BIOC_SVONLINE:
2520 0 : sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE;
2521 0 : sc->sc_sensors[i].status = SENSOR_S_OK;
2522 0 : break;
2523 :
2524 : case BIOC_SVINVALID:
2525 : /* FALLTRHOUGH */
2526 : default:
2527 0 : sc->sc_sensors[i].value = 0; /* unknown */
2528 0 : sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
2529 0 : break;
2530 : }
2531 : }
2532 0 : }
2533 : #endif /* SMALL_KERNEL */
2534 : #endif /* NBIO > 0 */
2535 :
2536 : void
2537 0 : mfi_start(struct mfi_softc *sc, struct mfi_ccb *ccb)
2538 : {
2539 0 : bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_frames),
2540 : ccb->ccb_pframe_offset, sc->sc_frames_size,
2541 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2542 :
2543 0 : mfi_post(sc, ccb);
2544 0 : }
2545 :
2546 : void
2547 0 : mfi_done(struct mfi_softc *sc, struct mfi_ccb *ccb)
2548 : {
2549 0 : bus_dmamap_sync(sc->sc_dmat, MFIMEM_MAP(sc->sc_frames),
2550 : ccb->ccb_pframe_offset, sc->sc_frames_size,
2551 : BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2552 :
2553 0 : if (ccb->ccb_len > 0) {
2554 0 : bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap,
2555 : 0, ccb->ccb_dmamap->dm_mapsize,
2556 : (ccb->ccb_direction == MFI_DATA_IN) ?
2557 : BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
2558 :
2559 0 : bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
2560 0 : }
2561 :
2562 0 : ccb->ccb_done(sc, ccb);
2563 0 : }
2564 :
2565 : u_int32_t
2566 0 : mfi_xscale_fw_state(struct mfi_softc *sc)
2567 : {
2568 0 : return (mfi_read(sc, MFI_OMSG0));
2569 : }
2570 :
2571 : void
2572 0 : mfi_xscale_intr_ena(struct mfi_softc *sc)
2573 : {
2574 0 : mfi_write(sc, MFI_OMSK, MFI_ENABLE_INTR);
2575 0 : }
2576 :
2577 : int
2578 0 : mfi_xscale_intr(struct mfi_softc *sc)
2579 : {
2580 : u_int32_t status;
2581 :
2582 0 : status = mfi_read(sc, MFI_OSTS);
2583 0 : if (!ISSET(status, MFI_OSTS_INTR_VALID))
2584 0 : return (0);
2585 :
2586 : /* write status back to acknowledge interrupt */
2587 0 : mfi_write(sc, MFI_OSTS, status);
2588 :
2589 0 : return (1);
2590 0 : }
2591 :
2592 : void
2593 0 : mfi_xscale_post(struct mfi_softc *sc, struct mfi_ccb *ccb)
2594 : {
2595 0 : mfi_write(sc, MFI_IQP, (ccb->ccb_pframe >> 3) |
2596 0 : ccb->ccb_extra_frames);
2597 0 : }
2598 :
2599 : u_int32_t
2600 0 : mfi_ppc_fw_state(struct mfi_softc *sc)
2601 : {
2602 0 : return (mfi_read(sc, MFI_OSP));
2603 : }
2604 :
2605 : void
2606 0 : mfi_ppc_intr_ena(struct mfi_softc *sc)
2607 : {
2608 0 : mfi_write(sc, MFI_ODC, 0xffffffff);
2609 0 : mfi_write(sc, MFI_OMSK, ~0x80000004);
2610 0 : }
2611 :
2612 : int
2613 0 : mfi_ppc_intr(struct mfi_softc *sc)
2614 : {
2615 : u_int32_t status;
2616 :
2617 0 : status = mfi_read(sc, MFI_OSTS);
2618 0 : if (!ISSET(status, MFI_OSTS_PPC_INTR_VALID))
2619 0 : return (0);
2620 :
2621 : /* write status back to acknowledge interrupt */
2622 0 : mfi_write(sc, MFI_ODC, status);
2623 :
2624 0 : return (1);
2625 0 : }
2626 :
2627 : void
2628 0 : mfi_ppc_post(struct mfi_softc *sc, struct mfi_ccb *ccb)
2629 : {
2630 0 : mfi_write(sc, MFI_IQP, 0x1 | ccb->ccb_pframe |
2631 0 : (ccb->ccb_extra_frames << 1));
2632 0 : }
2633 :
2634 : u_int32_t
2635 0 : mfi_gen2_fw_state(struct mfi_softc *sc)
2636 : {
2637 0 : return (mfi_read(sc, MFI_OSP));
2638 : }
2639 :
2640 : void
2641 0 : mfi_gen2_intr_ena(struct mfi_softc *sc)
2642 : {
2643 0 : mfi_write(sc, MFI_ODC, 0xffffffff);
2644 0 : mfi_write(sc, MFI_OMSK, ~MFI_OSTS_GEN2_INTR_VALID);
2645 0 : }
2646 :
2647 : int
2648 0 : mfi_gen2_intr(struct mfi_softc *sc)
2649 : {
2650 : u_int32_t status;
2651 :
2652 0 : status = mfi_read(sc, MFI_OSTS);
2653 0 : if (!ISSET(status, MFI_OSTS_GEN2_INTR_VALID))
2654 0 : return (0);
2655 :
2656 : /* write status back to acknowledge interrupt */
2657 0 : mfi_write(sc, MFI_ODC, status);
2658 :
2659 0 : return (1);
2660 0 : }
2661 :
2662 : void
2663 0 : mfi_gen2_post(struct mfi_softc *sc, struct mfi_ccb *ccb)
2664 : {
2665 0 : mfi_write(sc, MFI_IQP, 0x1 | ccb->ccb_pframe |
2666 0 : (ccb->ccb_extra_frames << 1));
2667 0 : }
2668 :
2669 : u_int32_t
2670 0 : mfi_skinny_fw_state(struct mfi_softc *sc)
2671 : {
2672 0 : return (mfi_read(sc, MFI_OSP));
2673 : }
2674 :
2675 : void
2676 0 : mfi_skinny_intr_ena(struct mfi_softc *sc)
2677 : {
2678 0 : mfi_write(sc, MFI_OMSK, ~0x00000001);
2679 0 : }
2680 :
2681 : int
2682 0 : mfi_skinny_intr(struct mfi_softc *sc)
2683 : {
2684 : u_int32_t status;
2685 :
2686 0 : status = mfi_read(sc, MFI_OSTS);
2687 0 : if (!ISSET(status, MFI_OSTS_SKINNY_INTR_VALID))
2688 0 : return (0);
2689 :
2690 : /* write status back to acknowledge interrupt */
2691 0 : mfi_write(sc, MFI_OSTS, status);
2692 :
2693 0 : return (1);
2694 0 : }
2695 :
2696 : void
2697 0 : mfi_skinny_post(struct mfi_softc *sc, struct mfi_ccb *ccb)
2698 : {
2699 0 : mfi_write(sc, MFI_IQPL, 0x1 | ccb->ccb_pframe |
2700 0 : (ccb->ccb_extra_frames << 1));
2701 0 : mfi_write(sc, MFI_IQPH, 0x00000000);
2702 0 : }
2703 :
2704 : u_int
2705 0 : mfi_skinny_sgd_load(struct mfi_softc *sc, struct mfi_ccb *ccb)
2706 : {
2707 0 : struct mfi_frame_header *hdr = &ccb->ccb_frame->mfr_header;
2708 0 : union mfi_sgl *sgl = ccb->ccb_sgl;
2709 0 : bus_dma_segment_t *sgd = ccb->ccb_dmamap->dm_segs;
2710 : int i;
2711 :
2712 0 : switch (hdr->mfh_cmd) {
2713 : case MFI_CMD_LD_READ:
2714 : case MFI_CMD_LD_WRITE:
2715 : case MFI_CMD_PD_SCSI_IO:
2716 : /* Use MF_FRAME_IEEE for some IO commands on skinny adapters */
2717 0 : for (i = 0; i < ccb->ccb_dmamap->dm_nsegs; i++) {
2718 0 : sgl->sg_skinny[i].addr = htole64(sgd[i].ds_addr);
2719 0 : sgl->sg_skinny[i].len = htole32(sgd[i].ds_len);
2720 0 : sgl->sg_skinny[i].flag = 0;
2721 : }
2722 0 : hdr->mfh_flags |= MFI_FRAME_IEEE | MFI_FRAME_SGL64;
2723 :
2724 0 : return (ccb->ccb_dmamap->dm_nsegs * sizeof(sgl->sg_skinny));
2725 : default:
2726 0 : return (mfi_default_sgd_load(sc, ccb));
2727 : }
2728 0 : }
2729 :
2730 : int
2731 0 : mfi_pd_scsi_probe(struct scsi_link *link)
2732 : {
2733 0 : union mfi_mbox mbox;
2734 0 : struct mfi_softc *sc = link->adapter_softc;
2735 0 : struct mfi_pd_link *pl = sc->sc_pd->pd_links[link->target];
2736 :
2737 0 : if (link->lun > 0)
2738 0 : return (0);
2739 :
2740 0 : if (pl == NULL)
2741 0 : return (ENXIO);
2742 :
2743 0 : memset(&mbox, 0, sizeof(mbox));
2744 0 : mbox.s[0] = pl->pd_id;
2745 :
2746 0 : if (mfi_mgmt(sc, MR_DCMD_PD_GET_INFO, MFI_DATA_IN,
2747 0 : sizeof(pl->pd_info), &pl->pd_info, &mbox))
2748 0 : return (EIO);
2749 :
2750 0 : if (letoh16(pl->pd_info.mpd_fw_state) != MFI_PD_SYSTEM)
2751 0 : return (ENXIO);
2752 :
2753 0 : return (0);
2754 0 : }
2755 :
2756 : void
2757 0 : mfi_pd_scsi_cmd(struct scsi_xfer *xs)
2758 : {
2759 0 : struct scsi_link *link = xs->sc_link;
2760 0 : struct mfi_softc *sc = link->adapter_softc;
2761 0 : struct mfi_ccb *ccb = xs->io;
2762 0 : struct mfi_pass_frame *pf = &ccb->ccb_frame->mfr_pass;
2763 0 : struct mfi_pd_link *pl = sc->sc_pd->pd_links[link->target];
2764 :
2765 0 : KERNEL_UNLOCK();
2766 :
2767 0 : mfi_scrub_ccb(ccb);
2768 0 : xs->error = XS_NOERROR;
2769 :
2770 0 : pf->mpf_header.mfh_cmd = MFI_CMD_PD_SCSI_IO;
2771 0 : pf->mpf_header.mfh_target_id = pl->pd_id;
2772 0 : pf->mpf_header.mfh_lun_id = link->lun;
2773 0 : pf->mpf_header.mfh_cdb_len = xs->cmdlen;
2774 0 : pf->mpf_header.mfh_timeout = 0;
2775 0 : pf->mpf_header.mfh_data_len = htole32(xs->datalen); /* XXX */
2776 0 : pf->mpf_header.mfh_sense_len = MFI_SENSE_SIZE;
2777 0 : pf->mpf_sense_addr = htole64(ccb->ccb_psense);
2778 :
2779 0 : memset(pf->mpf_cdb, 0, sizeof(pf->mpf_cdb));
2780 0 : memcpy(pf->mpf_cdb, xs->cmd, xs->cmdlen);
2781 :
2782 0 : ccb->ccb_done = mfi_scsi_xs_done;
2783 0 : ccb->ccb_cookie = xs;
2784 0 : ccb->ccb_frame_size = MFI_PASS_FRAME_SIZE;
2785 0 : ccb->ccb_sgl = &pf->mpf_sgl;
2786 :
2787 0 : if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT))
2788 0 : ccb->ccb_direction = xs->flags & SCSI_DATA_IN ?
2789 : MFI_DATA_IN : MFI_DATA_OUT;
2790 : else
2791 0 : ccb->ccb_direction = MFI_DATA_NONE;
2792 :
2793 0 : if (xs->data) {
2794 0 : ccb->ccb_data = xs->data;
2795 0 : ccb->ccb_len = xs->datalen;
2796 :
2797 0 : if (mfi_create_sgl(sc, ccb, (xs->flags & SCSI_NOSLEEP) ?
2798 : BUS_DMA_NOWAIT : BUS_DMA_WAITOK))
2799 : goto stuffup;
2800 : }
2801 :
2802 0 : if (xs->flags & SCSI_POLL)
2803 0 : mfi_poll(sc, ccb);
2804 : else
2805 0 : mfi_start(sc, ccb);
2806 :
2807 0 : KERNEL_LOCK();
2808 0 : return;
2809 :
2810 : stuffup:
2811 0 : xs->error = XS_DRIVER_STUFFUP;
2812 0 : KERNEL_LOCK();
2813 0 : scsi_done(xs);
2814 0 : }
|