Annotation of sys/dev/ic/mfi.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: mfi.c,v 1.73 2007/06/24 05:34:35 dlg 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/ioctl.h>
24: #include <sys/device.h>
25: #include <sys/kernel.h>
26: #include <sys/malloc.h>
27: #include <sys/proc.h>
28: #include <sys/rwlock.h>
29:
30: #include <machine/bus.h>
31:
32: #include <scsi/scsi_all.h>
33: #include <scsi/scsi_disk.h>
34: #include <scsi/scsiconf.h>
35:
36: #include <dev/ic/mfireg.h>
37: #include <dev/ic/mfivar.h>
38:
39: #if NBIO > 0
40: #include <dev/biovar.h>
41: #include <sys/sensors.h>
42: #endif /* NBIO > 0 */
43:
44: #ifdef MFI_DEBUG
45: uint32_t mfi_debug = 0
46: /* | MFI_D_CMD */
47: /* | MFI_D_INTR */
48: /* | MFI_D_MISC */
49: /* | MFI_D_DMA */
50: | MFI_D_IOCTL
51: /* | MFI_D_RW */
52: /* | MFI_D_MEM */
53: /* | MFI_D_CCB */
54: ;
55: #endif
56:
57: struct cfdriver mfi_cd = {
58: NULL, "mfi", DV_DULL
59: };
60:
61: int mfi_scsi_cmd(struct scsi_xfer *);
62: int mfi_scsi_ioctl(struct scsi_link *, u_long, caddr_t, int, struct proc *);
63: void mfiminphys(struct buf *bp);
64:
65: struct scsi_adapter mfi_switch = {
66: mfi_scsi_cmd, mfiminphys, 0, 0, mfi_scsi_ioctl
67: };
68:
69: struct scsi_device mfi_dev = {
70: NULL, NULL, NULL, NULL
71: };
72:
73: struct mfi_ccb *mfi_get_ccb(struct mfi_softc *);
74: void mfi_put_ccb(struct mfi_ccb *);
75: int mfi_init_ccb(struct mfi_softc *);
76:
77: struct mfi_mem *mfi_allocmem(struct mfi_softc *, size_t);
78: void mfi_freemem(struct mfi_softc *, struct mfi_mem *);
79:
80: int mfi_transition_firmware(struct mfi_softc *);
81: int mfi_initialize_firmware(struct mfi_softc *);
82: int mfi_get_info(struct mfi_softc *);
83: uint32_t mfi_read(struct mfi_softc *, bus_size_t);
84: void mfi_write(struct mfi_softc *, bus_size_t, uint32_t);
85: int mfi_poll(struct mfi_ccb *);
86: int mfi_despatch_cmd(struct mfi_ccb *);
87: int mfi_create_sgl(struct mfi_ccb *, int);
88:
89: /* commands */
90: int mfi_scsi_ld(struct mfi_ccb *, struct scsi_xfer *);
91: int mfi_scsi_io(struct mfi_ccb *, struct scsi_xfer *, uint32_t,
92: uint32_t);
93: void mfi_scsi_xs_done(struct mfi_ccb *);
94: int mfi_mgmt(struct mfi_softc *, uint32_t, uint32_t, uint32_t,
95: void *, uint8_t *);
96: void mfi_mgmt_done(struct mfi_ccb *);
97:
98: #if NBIO > 0
99: int mfi_ioctl(struct device *, u_long, caddr_t);
100: int mfi_ioctl_inq(struct mfi_softc *, struct bioc_inq *);
101: int mfi_ioctl_vol(struct mfi_softc *, struct bioc_vol *);
102: int mfi_ioctl_disk(struct mfi_softc *, struct bioc_disk *);
103: int mfi_ioctl_alarm(struct mfi_softc *, struct bioc_alarm *);
104: int mfi_ioctl_blink(struct mfi_softc *sc, struct bioc_blink *);
105: int mfi_ioctl_setstate(struct mfi_softc *, struct bioc_setstate *);
106: int mfi_bio_hs(struct mfi_softc *, int, int, void *);
107: #ifndef SMALL_KERNEL
108: int mfi_create_sensors(struct mfi_softc *);
109: void mfi_refresh_sensors(void *);
110: #endif /* SMALL_KERNEL */
111: #endif /* NBIO > 0 */
112:
113: struct mfi_ccb *
114: mfi_get_ccb(struct mfi_softc *sc)
115: {
116: struct mfi_ccb *ccb;
117: int s;
118:
119: s = splbio();
120: ccb = TAILQ_FIRST(&sc->sc_ccb_freeq);
121: if (ccb) {
122: TAILQ_REMOVE(&sc->sc_ccb_freeq, ccb, ccb_link);
123: ccb->ccb_state = MFI_CCB_READY;
124: }
125: splx(s);
126:
127: DNPRINTF(MFI_D_CCB, "%s: mfi_get_ccb: %p\n", DEVNAME(sc), ccb);
128:
129: return (ccb);
130: }
131:
132: void
133: mfi_put_ccb(struct mfi_ccb *ccb)
134: {
135: struct mfi_softc *sc = ccb->ccb_sc;
136: int s;
137:
138: DNPRINTF(MFI_D_CCB, "%s: mfi_put_ccb: %p\n", DEVNAME(sc), ccb);
139:
140: s = splbio();
141: ccb->ccb_state = MFI_CCB_FREE;
142: ccb->ccb_xs = NULL;
143: ccb->ccb_flags = 0;
144: ccb->ccb_done = NULL;
145: ccb->ccb_direction = 0;
146: ccb->ccb_frame_size = 0;
147: ccb->ccb_extra_frames = 0;
148: ccb->ccb_sgl = NULL;
149: ccb->ccb_data = NULL;
150: ccb->ccb_len = 0;
151: TAILQ_INSERT_TAIL(&sc->sc_ccb_freeq, ccb, ccb_link);
152: splx(s);
153: }
154:
155: int
156: mfi_init_ccb(struct mfi_softc *sc)
157: {
158: struct mfi_ccb *ccb;
159: uint32_t i;
160: int error;
161:
162: DNPRINTF(MFI_D_CCB, "%s: mfi_init_ccb\n", DEVNAME(sc));
163:
164: sc->sc_ccb = malloc(sizeof(struct mfi_ccb) * sc->sc_max_cmds,
165: M_DEVBUF, M_WAITOK);
166: memset(sc->sc_ccb, 0, sizeof(struct mfi_ccb) * sc->sc_max_cmds);
167:
168: for (i = 0; i < sc->sc_max_cmds; i++) {
169: ccb = &sc->sc_ccb[i];
170:
171: ccb->ccb_sc = sc;
172:
173: /* select i'th frame */
174: ccb->ccb_frame = (union mfi_frame *)
175: (MFIMEM_KVA(sc->sc_frames) + sc->sc_frames_size * i);
176: ccb->ccb_pframe =
177: MFIMEM_DVA(sc->sc_frames) + sc->sc_frames_size * i;
178: ccb->ccb_frame->mfr_header.mfh_context = i;
179:
180: /* select i'th sense */
181: ccb->ccb_sense = (struct mfi_sense *)
182: (MFIMEM_KVA(sc->sc_sense) + MFI_SENSE_SIZE * i);
183: ccb->ccb_psense =
184: (MFIMEM_DVA(sc->sc_sense) + MFI_SENSE_SIZE * i);
185:
186: /* create a dma map for transfer */
187: error = bus_dmamap_create(sc->sc_dmat,
188: MAXPHYS, sc->sc_max_sgl, MAXPHYS, 0,
189: BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap);
190: if (error) {
191: printf("%s: cannot create ccb dmamap (%d)\n",
192: DEVNAME(sc), error);
193: goto destroy;
194: }
195:
196: DNPRINTF(MFI_D_CCB,
197: "ccb(%d): %p frame: %#x (%#x) sense: %#x (%#x) map: %#x\n",
198: ccb->ccb_frame->mfr_header.mfh_context, ccb,
199: ccb->ccb_frame, ccb->ccb_pframe,
200: ccb->ccb_sense, ccb->ccb_psense,
201: ccb->ccb_dmamap);
202:
203: /* add ccb to queue */
204: mfi_put_ccb(ccb);
205: }
206:
207: return (0);
208: destroy:
209: /* free dma maps and ccb memory */
210: while (i) {
211: ccb = &sc->sc_ccb[i];
212: bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
213: i--;
214: }
215:
216: free(sc->sc_ccb, M_DEVBUF);
217:
218: return (1);
219: }
220:
221: uint32_t
222: mfi_read(struct mfi_softc *sc, bus_size_t r)
223: {
224: uint32_t rv;
225:
226: bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
227: BUS_SPACE_BARRIER_READ);
228: rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, r);
229:
230: DNPRINTF(MFI_D_RW, "%s: mr 0x%x 0x08%x ", DEVNAME(sc), r, rv);
231: return (rv);
232: }
233:
234: void
235: mfi_write(struct mfi_softc *sc, bus_size_t r, uint32_t v)
236: {
237: DNPRINTF(MFI_D_RW, "%s: mw 0x%x 0x%08x", DEVNAME(sc), r, v);
238:
239: bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v);
240: bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
241: BUS_SPACE_BARRIER_WRITE);
242: }
243:
244: struct mfi_mem *
245: mfi_allocmem(struct mfi_softc *sc, size_t size)
246: {
247: struct mfi_mem *mm;
248: int nsegs;
249:
250: DNPRINTF(MFI_D_MEM, "%s: mfi_allocmem: %d\n", DEVNAME(sc),
251: size);
252:
253: mm = malloc(sizeof(struct mfi_mem), M_DEVBUF, M_NOWAIT);
254: if (mm == NULL)
255: return (NULL);
256:
257: memset(mm, 0, sizeof(struct mfi_mem));
258: mm->am_size = size;
259:
260: if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
261: BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &mm->am_map) != 0)
262: goto amfree;
263:
264: if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &mm->am_seg, 1,
265: &nsegs, BUS_DMA_NOWAIT) != 0)
266: goto destroy;
267:
268: if (bus_dmamem_map(sc->sc_dmat, &mm->am_seg, nsegs, size, &mm->am_kva,
269: BUS_DMA_NOWAIT) != 0)
270: goto free;
271:
272: if (bus_dmamap_load(sc->sc_dmat, mm->am_map, mm->am_kva, size, NULL,
273: BUS_DMA_NOWAIT) != 0)
274: goto unmap;
275:
276: DNPRINTF(MFI_D_MEM, " kva: %p dva: %p map: %p\n",
277: mm->am_kva, mm->am_map->dm_segs[0].ds_addr, mm->am_map);
278:
279: memset(mm->am_kva, 0, size);
280: return (mm);
281:
282: unmap:
283: bus_dmamem_unmap(sc->sc_dmat, mm->am_kva, size);
284: free:
285: bus_dmamem_free(sc->sc_dmat, &mm->am_seg, 1);
286: destroy:
287: bus_dmamap_destroy(sc->sc_dmat, mm->am_map);
288: amfree:
289: free(mm, M_DEVBUF);
290:
291: return (NULL);
292: }
293:
294: void
295: mfi_freemem(struct mfi_softc *sc, struct mfi_mem *mm)
296: {
297: DNPRINTF(MFI_D_MEM, "%s: mfi_freemem: %p\n", DEVNAME(sc), mm);
298:
299: bus_dmamap_unload(sc->sc_dmat, mm->am_map);
300: bus_dmamem_unmap(sc->sc_dmat, mm->am_kva, mm->am_size);
301: bus_dmamem_free(sc->sc_dmat, &mm->am_seg, 1);
302: bus_dmamap_destroy(sc->sc_dmat, mm->am_map);
303: free(mm, M_DEVBUF);
304: }
305:
306: int
307: mfi_transition_firmware(struct mfi_softc *sc)
308: {
309: int32_t fw_state, cur_state;
310: int max_wait, i;
311:
312: fw_state = mfi_read(sc, MFI_OMSG0) & MFI_STATE_MASK;
313:
314: DNPRINTF(MFI_D_CMD, "%s: mfi_transition_firmware: %#x\n", DEVNAME(sc),
315: fw_state);
316:
317: while (fw_state != MFI_STATE_READY) {
318: DNPRINTF(MFI_D_MISC,
319: "%s: waiting for firmware to become ready\n",
320: DEVNAME(sc));
321: cur_state = fw_state;
322: switch (fw_state) {
323: case MFI_STATE_FAULT:
324: printf("%s: firmware fault\n", DEVNAME(sc));
325: return (1);
326: case MFI_STATE_WAIT_HANDSHAKE:
327: mfi_write(sc, MFI_IDB, MFI_INIT_CLEAR_HANDSHAKE);
328: max_wait = 2;
329: break;
330: case MFI_STATE_OPERATIONAL:
331: mfi_write(sc, MFI_IDB, MFI_INIT_READY);
332: max_wait = 10;
333: break;
334: case MFI_STATE_UNDEFINED:
335: case MFI_STATE_BB_INIT:
336: max_wait = 2;
337: break;
338: case MFI_STATE_FW_INIT:
339: case MFI_STATE_DEVICE_SCAN:
340: case MFI_STATE_FLUSH_CACHE:
341: max_wait = 20;
342: break;
343: default:
344: printf("%s: unknown firmware state %d\n",
345: DEVNAME(sc), fw_state);
346: return (1);
347: }
348: for (i = 0; i < (max_wait * 10); i++) {
349: fw_state = mfi_read(sc, MFI_OMSG0) & MFI_STATE_MASK;
350: if (fw_state == cur_state)
351: DELAY(100000);
352: else
353: break;
354: }
355: if (fw_state == cur_state) {
356: printf("%s: firmware stuck in state %#x\n",
357: DEVNAME(sc), fw_state);
358: return (1);
359: }
360: }
361:
362: return (0);
363: }
364:
365: int
366: mfi_initialize_firmware(struct mfi_softc *sc)
367: {
368: struct mfi_ccb *ccb;
369: struct mfi_init_frame *init;
370: struct mfi_init_qinfo *qinfo;
371:
372: DNPRINTF(MFI_D_MISC, "%s: mfi_initialize_firmware\n", DEVNAME(sc));
373:
374: if ((ccb = mfi_get_ccb(sc)) == NULL)
375: return (1);
376:
377: init = &ccb->ccb_frame->mfr_init;
378: qinfo = (struct mfi_init_qinfo *)((uint8_t *)init + MFI_FRAME_SIZE);
379:
380: memset(qinfo, 0, sizeof *qinfo);
381: qinfo->miq_rq_entries = sc->sc_max_cmds + 1;
382: qinfo->miq_rq_addr_lo = htole32(MFIMEM_DVA(sc->sc_pcq) +
383: offsetof(struct mfi_prod_cons, mpc_reply_q));
384: qinfo->miq_pi_addr_lo = htole32(MFIMEM_DVA(sc->sc_pcq) +
385: offsetof(struct mfi_prod_cons, mpc_producer));
386: qinfo->miq_ci_addr_lo = htole32(MFIMEM_DVA(sc->sc_pcq) +
387: offsetof(struct mfi_prod_cons, mpc_consumer));
388:
389: init->mif_header.mfh_cmd = MFI_CMD_INIT;
390: init->mif_header.mfh_data_len = sizeof *qinfo;
391: init->mif_qinfo_new_addr_lo = htole32(ccb->ccb_pframe + MFI_FRAME_SIZE);
392:
393: DNPRINTF(MFI_D_MISC, "%s: entries: %#x rq: %#x pi: %#x ci: %#x\n",
394: DEVNAME(sc),
395: qinfo->miq_rq_entries, qinfo->miq_rq_addr_lo,
396: qinfo->miq_pi_addr_lo, qinfo->miq_ci_addr_lo);
397:
398: if (mfi_poll(ccb)) {
399: printf("%s: mfi_initialize_firmware failed\n", DEVNAME(sc));
400: return (1);
401: }
402:
403: mfi_put_ccb(ccb);
404:
405: return (0);
406: }
407:
408: int
409: mfi_get_info(struct mfi_softc *sc)
410: {
411: #ifdef MFI_DEBUG
412: int i;
413: #endif
414: DNPRINTF(MFI_D_MISC, "%s: mfi_get_info\n", DEVNAME(sc));
415:
416: if (mfi_mgmt(sc, MR_DCMD_CTRL_GET_INFO, MFI_DATA_IN,
417: sizeof(sc->sc_info), &sc->sc_info, NULL))
418: return (1);
419:
420: #ifdef MFI_DEBUG
421:
422: for (i = 0; i < sc->sc_info.mci_image_component_count; i++) {
423: printf("%s: active FW %s Version %s date %s time %s\n",
424: DEVNAME(sc),
425: sc->sc_info.mci_image_component[i].mic_name,
426: sc->sc_info.mci_image_component[i].mic_version,
427: sc->sc_info.mci_image_component[i].mic_build_date,
428: sc->sc_info.mci_image_component[i].mic_build_time);
429: }
430:
431: for (i = 0; i < sc->sc_info.mci_pending_image_component_count; i++) {
432: printf("%s: pending FW %s Version %s date %s time %s\n",
433: DEVNAME(sc),
434: sc->sc_info.mci_pending_image_component[i].mic_name,
435: sc->sc_info.mci_pending_image_component[i].mic_version,
436: sc->sc_info.mci_pending_image_component[i].mic_build_date,
437: sc->sc_info.mci_pending_image_component[i].mic_build_time);
438: }
439:
440: printf("%s: max_arms %d max_spans %d max_arrs %d max_lds %d name %s\n",
441: DEVNAME(sc),
442: sc->sc_info.mci_max_arms,
443: sc->sc_info.mci_max_spans,
444: sc->sc_info.mci_max_arrays,
445: sc->sc_info.mci_max_lds,
446: sc->sc_info.mci_product_name);
447:
448: printf("%s: serial %s present %#x fw time %d max_cmds %d max_sg %d\n",
449: DEVNAME(sc),
450: sc->sc_info.mci_serial_number,
451: sc->sc_info.mci_hw_present,
452: sc->sc_info.mci_current_fw_time,
453: sc->sc_info.mci_max_cmds,
454: sc->sc_info.mci_max_sg_elements);
455:
456: printf("%s: max_rq %d lds_pres %d lds_deg %d lds_off %d pd_pres %d\n",
457: DEVNAME(sc),
458: sc->sc_info.mci_max_request_size,
459: sc->sc_info.mci_lds_present,
460: sc->sc_info.mci_lds_degraded,
461: sc->sc_info.mci_lds_offline,
462: sc->sc_info.mci_pd_present);
463:
464: printf("%s: pd_dsk_prs %d pd_dsk_pred_fail %d pd_dsk_fail %d\n",
465: DEVNAME(sc),
466: sc->sc_info.mci_pd_disks_present,
467: sc->sc_info.mci_pd_disks_pred_failure,
468: sc->sc_info.mci_pd_disks_failed);
469:
470: printf("%s: nvram %d mem %d flash %d\n",
471: DEVNAME(sc),
472: sc->sc_info.mci_nvram_size,
473: sc->sc_info.mci_memory_size,
474: sc->sc_info.mci_flash_size);
475:
476: printf("%s: ram_cor %d ram_uncor %d clus_all %d clus_act %d\n",
477: DEVNAME(sc),
478: sc->sc_info.mci_ram_correctable_errors,
479: sc->sc_info.mci_ram_uncorrectable_errors,
480: sc->sc_info.mci_cluster_allowed,
481: sc->sc_info.mci_cluster_active);
482:
483: printf("%s: max_strps_io %d raid_lvl %#x adapt_ops %#x ld_ops %#x\n",
484: DEVNAME(sc),
485: sc->sc_info.mci_max_strips_per_io,
486: sc->sc_info.mci_raid_levels,
487: sc->sc_info.mci_adapter_ops,
488: sc->sc_info.mci_ld_ops);
489:
490: printf("%s: strp_sz_min %d strp_sz_max %d pd_ops %#x pd_mix %#x\n",
491: DEVNAME(sc),
492: sc->sc_info.mci_stripe_sz_ops.min,
493: sc->sc_info.mci_stripe_sz_ops.max,
494: sc->sc_info.mci_pd_ops,
495: sc->sc_info.mci_pd_mix_support);
496:
497: printf("%s: ecc_bucket %d pckg_prop %s\n",
498: DEVNAME(sc),
499: sc->sc_info.mci_ecc_bucket_count,
500: sc->sc_info.mci_package_version);
501:
502: printf("%s: sq_nm %d prd_fail_poll %d intr_thrtl %d intr_thrtl_to %d\n",
503: DEVNAME(sc),
504: sc->sc_info.mci_properties.mcp_seq_num,
505: sc->sc_info.mci_properties.mcp_pred_fail_poll_interval,
506: sc->sc_info.mci_properties.mcp_intr_throttle_cnt,
507: sc->sc_info.mci_properties.mcp_intr_throttle_timeout);
508:
509: printf("%s: rbld_rate %d patr_rd_rate %d bgi_rate %d cc_rate %d\n",
510: DEVNAME(sc),
511: sc->sc_info.mci_properties.mcp_rebuild_rate,
512: sc->sc_info.mci_properties.mcp_patrol_read_rate,
513: sc->sc_info.mci_properties.mcp_bgi_rate,
514: sc->sc_info.mci_properties.mcp_cc_rate);
515:
516: printf("%s: rc_rate %d ch_flsh %d spin_cnt %d spin_dly %d clus_en %d\n",
517: DEVNAME(sc),
518: sc->sc_info.mci_properties.mcp_recon_rate,
519: sc->sc_info.mci_properties.mcp_cache_flush_interval,
520: sc->sc_info.mci_properties.mcp_spinup_drv_cnt,
521: sc->sc_info.mci_properties.mcp_spinup_delay,
522: sc->sc_info.mci_properties.mcp_cluster_enable);
523:
524: printf("%s: coerc %d alarm %d dis_auto_rbld %d dis_bat_wrn %d ecc %d\n",
525: DEVNAME(sc),
526: sc->sc_info.mci_properties.mcp_coercion_mode,
527: sc->sc_info.mci_properties.mcp_alarm_enable,
528: sc->sc_info.mci_properties.mcp_disable_auto_rebuild,
529: sc->sc_info.mci_properties.mcp_disable_battery_warn,
530: sc->sc_info.mci_properties.mcp_ecc_bucket_size);
531:
532: printf("%s: ecc_leak %d rest_hs %d exp_encl_dev %d\n",
533: DEVNAME(sc),
534: sc->sc_info.mci_properties.mcp_ecc_bucket_leak_rate,
535: sc->sc_info.mci_properties.mcp_restore_hotspare_on_insertion,
536: sc->sc_info.mci_properties.mcp_expose_encl_devices);
537:
538: printf("%s: vendor %#x device %#x subvendor %#x subdevice %#x\n",
539: DEVNAME(sc),
540: sc->sc_info.mci_pci.mip_vendor,
541: sc->sc_info.mci_pci.mip_device,
542: sc->sc_info.mci_pci.mip_subvendor,
543: sc->sc_info.mci_pci.mip_subdevice);
544:
545: printf("%s: type %#x port_count %d port_addr ",
546: DEVNAME(sc),
547: sc->sc_info.mci_host.mih_type,
548: sc->sc_info.mci_host.mih_port_count);
549:
550: for (i = 0; i < 8; i++)
551: printf("%.0llx ", sc->sc_info.mci_host.mih_port_addr[i]);
552: printf("\n");
553:
554: printf("%s: type %.x port_count %d port_addr ",
555: DEVNAME(sc),
556: sc->sc_info.mci_device.mid_type,
557: sc->sc_info.mci_device.mid_port_count);
558:
559: for (i = 0; i < 8; i++)
560: printf("%.0llx ", sc->sc_info.mci_device.mid_port_addr[i]);
561: printf("\n");
562: #endif /* MFI_DEBUG */
563:
564: return (0);
565: }
566:
567: void
568: mfiminphys(struct buf *bp)
569: {
570: DNPRINTF(MFI_D_MISC, "mfiminphys: %d\n", bp->b_bcount);
571:
572: /* XXX currently using MFI_MAXFER = MAXPHYS */
573: if (bp->b_bcount > MFI_MAXFER)
574: bp->b_bcount = MFI_MAXFER;
575: minphys(bp);
576: }
577:
578: int
579: mfi_attach(struct mfi_softc *sc)
580: {
581: struct scsibus_attach_args saa;
582: uint32_t status, frames;
583: int i;
584:
585: DNPRINTF(MFI_D_MISC, "%s: mfi_attach\n", DEVNAME(sc));
586:
587: if (mfi_transition_firmware(sc))
588: return (1);
589:
590: TAILQ_INIT(&sc->sc_ccb_freeq);
591:
592: rw_init(&sc->sc_lock, "mfi_lock");
593:
594: status = mfi_read(sc, MFI_OMSG0);
595: sc->sc_max_cmds = status & MFI_STATE_MAXCMD_MASK;
596: sc->sc_max_sgl = (status & MFI_STATE_MAXSGL_MASK) >> 16;
597: DNPRINTF(MFI_D_MISC, "%s: max commands: %u, max sgl: %u\n",
598: DEVNAME(sc), sc->sc_max_cmds, sc->sc_max_sgl);
599:
600: /* consumer/producer and reply queue memory */
601: sc->sc_pcq = mfi_allocmem(sc, (sizeof(uint32_t) * sc->sc_max_cmds) +
602: sizeof(struct mfi_prod_cons));
603: if (sc->sc_pcq == NULL) {
604: printf("%s: unable to allocate reply queue memory\n",
605: DEVNAME(sc));
606: goto nopcq;
607: }
608:
609: /* frame memory */
610: /* we are not doing 64 bit IO so only calculate # of 32 bit frames */
611: frames = (sizeof(struct mfi_sg32) * sc->sc_max_sgl +
612: MFI_FRAME_SIZE - 1) / MFI_FRAME_SIZE + 1;
613: sc->sc_frames_size = frames * MFI_FRAME_SIZE;
614: sc->sc_frames = mfi_allocmem(sc, sc->sc_frames_size * sc->sc_max_cmds);
615: if (sc->sc_frames == NULL) {
616: printf("%s: unable to allocate frame memory\n", DEVNAME(sc));
617: goto noframe;
618: }
619: /* XXX hack, fix this */
620: if (MFIMEM_DVA(sc->sc_frames) & 0x3f) {
621: printf("%s: improper frame alignment (%#x) FIXME\n",
622: DEVNAME(sc), MFIMEM_DVA(sc->sc_frames));
623: goto noframe;
624: }
625:
626: /* sense memory */
627: sc->sc_sense = mfi_allocmem(sc, sc->sc_max_cmds * MFI_SENSE_SIZE);
628: if (sc->sc_sense == NULL) {
629: printf("%s: unable to allocate sense memory\n", DEVNAME(sc));
630: goto nosense;
631: }
632:
633: /* now that we have all memory bits go initialize ccbs */
634: if (mfi_init_ccb(sc)) {
635: printf("%s: could not init ccb list\n", DEVNAME(sc));
636: goto noinit;
637: }
638:
639: /* kickstart firmware with all addresses and pointers */
640: if (mfi_initialize_firmware(sc)) {
641: printf("%s: could not initialize firmware\n", DEVNAME(sc));
642: goto noinit;
643: }
644:
645: if (mfi_get_info(sc)) {
646: printf("%s: could not retrieve controller information\n",
647: DEVNAME(sc));
648: goto noinit;
649: }
650:
651: printf("%s: logical drives %d, version %s, %dMB RAM\n",
652: DEVNAME(sc),
653: sc->sc_info.mci_lds_present,
654: sc->sc_info.mci_package_version,
655: sc->sc_info.mci_memory_size);
656:
657: sc->sc_ld_cnt = sc->sc_info.mci_lds_present;
658: sc->sc_max_ld = sc->sc_ld_cnt;
659: for (i = 0; i < sc->sc_ld_cnt; i++)
660: sc->sc_ld[i].ld_present = 1;
661:
662: if (sc->sc_ld_cnt)
663: sc->sc_link.openings = sc->sc_max_cmds / sc->sc_ld_cnt;
664: else
665: sc->sc_link.openings = sc->sc_max_cmds;
666:
667: sc->sc_link.device = &mfi_dev;
668: sc->sc_link.adapter_softc = sc;
669: sc->sc_link.adapter = &mfi_switch;
670: sc->sc_link.adapter_target = MFI_MAX_LD;
671: sc->sc_link.adapter_buswidth = sc->sc_max_ld;
672:
673: bzero(&saa, sizeof(saa));
674: saa.saa_sc_link = &sc->sc_link;
675:
676: config_found(&sc->sc_dev, &saa, scsiprint);
677:
678: /* enable interrupts */
679: mfi_write(sc, MFI_OMSK, MFI_ENABLE_INTR);
680:
681: #if NBIO > 0
682: if (bio_register(&sc->sc_dev, mfi_ioctl) != 0)
683: panic("%s: controller registration failed", DEVNAME(sc));
684: else
685: sc->sc_ioctl = mfi_ioctl;
686:
687: #ifndef SMALL_KERNEL
688: if (mfi_create_sensors(sc) != 0)
689: printf("%s: unable to create sensors\n", DEVNAME(sc));
690: #endif
691: #endif /* NBIO > 0 */
692:
693: return (0);
694: noinit:
695: mfi_freemem(sc, sc->sc_sense);
696: nosense:
697: mfi_freemem(sc, sc->sc_frames);
698: noframe:
699: mfi_freemem(sc, sc->sc_pcq);
700: nopcq:
701: return (1);
702: }
703:
704: int
705: mfi_despatch_cmd(struct mfi_ccb *ccb)
706: {
707: DNPRINTF(MFI_D_CMD, "%s: mfi_despatch_cmd\n",
708: DEVNAME(ccb->ccb_sc));
709:
710: mfi_write(ccb->ccb_sc, MFI_IQP, (ccb->ccb_pframe >> 3) |
711: ccb->ccb_extra_frames);
712:
713: return(0);
714: }
715:
716: int
717: mfi_poll(struct mfi_ccb *ccb)
718: {
719: struct mfi_frame_header *hdr;
720: int to = 0;
721:
722: DNPRINTF(MFI_D_CMD, "%s: mfi_poll\n", DEVNAME(ccb->ccb_sc));
723:
724: hdr = &ccb->ccb_frame->mfr_header;
725: hdr->mfh_cmd_status = 0xff;
726: hdr->mfh_flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
727:
728: mfi_despatch_cmd(ccb);
729:
730: while (hdr->mfh_cmd_status == 0xff) {
731: delay(1000);
732: if (to++ > 5000) /* XXX 5 seconds busywait sucks */
733: break;
734: }
735: if (hdr->mfh_cmd_status == 0xff) {
736: printf("%s: timeout on ccb %d\n", DEVNAME(ccb->ccb_sc),
737: hdr->mfh_context);
738: ccb->ccb_flags |= MFI_CCB_F_ERR;
739: return (1);
740: }
741:
742: return (0);
743: }
744:
745: int
746: mfi_intr(void *arg)
747: {
748: struct mfi_softc *sc = arg;
749: struct mfi_prod_cons *pcq;
750: struct mfi_ccb *ccb;
751: uint32_t status, producer, consumer, ctx;
752: int claimed = 0;
753:
754: status = mfi_read(sc, MFI_OSTS);
755: if ((status & MFI_OSTS_INTR_VALID) == 0)
756: return (claimed);
757: /* write status back to acknowledge interrupt */
758: mfi_write(sc, MFI_OSTS, status);
759:
760: DNPRINTF(MFI_D_INTR, "%s: mfi_intr %#x %#x\n", DEVNAME(sc), sc, pcq);
761:
762: pcq = MFIMEM_KVA(sc->sc_pcq);
763: producer = pcq->mpc_producer;
764: consumer = pcq->mpc_consumer;
765:
766: while (consumer != producer) {
767: DNPRINTF(MFI_D_INTR, "%s: mfi_intr pi %#x ci %#x\n",
768: DEVNAME(sc), producer, consumer);
769:
770: ctx = pcq->mpc_reply_q[consumer];
771: pcq->mpc_reply_q[consumer] = MFI_INVALID_CTX;
772: if (ctx == MFI_INVALID_CTX)
773: printf("%s: invalid context, p: %d c: %d\n",
774: DEVNAME(sc), producer, consumer);
775: else {
776: /* XXX remove from queue and call scsi_done */
777: ccb = &sc->sc_ccb[ctx];
778: DNPRINTF(MFI_D_INTR, "%s: mfi_intr context %#x\n",
779: DEVNAME(sc), ctx);
780: ccb->ccb_done(ccb);
781:
782: claimed = 1;
783: }
784: consumer++;
785: if (consumer == (sc->sc_max_cmds + 1))
786: consumer = 0;
787: }
788:
789: pcq->mpc_consumer = consumer;
790:
791: return (claimed);
792: }
793:
794: int
795: mfi_scsi_io(struct mfi_ccb *ccb, struct scsi_xfer *xs, uint32_t blockno,
796: uint32_t blockcnt)
797: {
798: struct scsi_link *link = xs->sc_link;
799: struct mfi_io_frame *io;
800:
801: DNPRINTF(MFI_D_CMD, "%s: mfi_scsi_io: %d\n",
802: DEVNAME((struct mfi_softc *)link->adapter_softc), link->target);
803:
804: if (!xs->data)
805: return (1);
806:
807: io = &ccb->ccb_frame->mfr_io;
808: if (xs->flags & SCSI_DATA_IN) {
809: io->mif_header.mfh_cmd = MFI_CMD_LD_READ;
810: ccb->ccb_direction = MFI_DATA_IN;
811: } else {
812: io->mif_header.mfh_cmd = MFI_CMD_LD_WRITE;
813: ccb->ccb_direction = MFI_DATA_OUT;
814: }
815: io->mif_header.mfh_target_id = link->target;
816: io->mif_header.mfh_timeout = 0;
817: io->mif_header.mfh_flags = 0;
818: io->mif_header.mfh_sense_len = MFI_SENSE_SIZE;
819: io->mif_header.mfh_data_len= blockcnt;
820: io->mif_lba_hi = 0;
821: io->mif_lba_lo = blockno;
822: io->mif_sense_addr_lo = htole32(ccb->ccb_psense);
823: io->mif_sense_addr_hi = 0;
824:
825: ccb->ccb_done = mfi_scsi_xs_done;
826: ccb->ccb_xs = xs;
827: ccb->ccb_frame_size = MFI_IO_FRAME_SIZE;
828: ccb->ccb_sgl = &io->mif_sgl;
829: ccb->ccb_data = xs->data;
830: ccb->ccb_len = xs->datalen;
831:
832: if (mfi_create_sgl(ccb, (xs->flags & SCSI_NOSLEEP) ?
833: BUS_DMA_NOWAIT : BUS_DMA_WAITOK))
834: return (1);
835:
836: return (0);
837: }
838:
839: void
840: mfi_scsi_xs_done(struct mfi_ccb *ccb)
841: {
842: struct scsi_xfer *xs = ccb->ccb_xs;
843: struct mfi_softc *sc = ccb->ccb_sc;
844: struct mfi_frame_header *hdr = &ccb->ccb_frame->mfr_header;
845:
846: DNPRINTF(MFI_D_INTR, "%s: mfi_scsi_xs_done %#x %#x\n",
847: DEVNAME(sc), ccb, ccb->ccb_frame);
848:
849: if (xs->data != NULL) {
850: DNPRINTF(MFI_D_INTR, "%s: mfi_scsi_xs_done sync\n",
851: DEVNAME(sc));
852: bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
853: ccb->ccb_dmamap->dm_mapsize,
854: (xs->flags & SCSI_DATA_IN) ?
855: BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
856:
857: bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
858: }
859:
860: if (hdr->mfh_cmd_status != MFI_STAT_OK) {
861: xs->error = XS_DRIVER_STUFFUP;
862: DNPRINTF(MFI_D_INTR, "%s: mfi_scsi_xs_done stuffup %#x\n",
863: DEVNAME(sc), hdr->mfh_cmd_status);
864:
865: if (hdr->mfh_scsi_status != 0) {
866: DNPRINTF(MFI_D_INTR,
867: "%s: mfi_scsi_xs_done sense %#x %x %x\n",
868: DEVNAME(sc), hdr->mfh_scsi_status,
869: &xs->sense, ccb->ccb_sense);
870: memset(&xs->sense, 0, sizeof(xs->sense));
871: memcpy(&xs->sense, ccb->ccb_sense,
872: sizeof(struct scsi_sense_data));
873: xs->error = XS_SENSE;
874: }
875: }
876:
877: xs->resid = 0;
878: xs->flags |= ITSDONE;
879:
880: mfi_put_ccb(ccb);
881: scsi_done(xs);
882: }
883:
884: int
885: mfi_scsi_ld(struct mfi_ccb *ccb, struct scsi_xfer *xs)
886: {
887: struct scsi_link *link = xs->sc_link;
888: struct mfi_pass_frame *pf;
889:
890: DNPRINTF(MFI_D_CMD, "%s: mfi_scsi_ld: %d\n",
891: DEVNAME((struct mfi_softc *)link->adapter_softc), link->target);
892:
893: pf = &ccb->ccb_frame->mfr_pass;
894: pf->mpf_header.mfh_cmd = MFI_CMD_LD_SCSI_IO;
895: pf->mpf_header.mfh_target_id = link->target;
896: pf->mpf_header.mfh_lun_id = 0;
897: pf->mpf_header.mfh_cdb_len = xs->cmdlen;
898: pf->mpf_header.mfh_timeout = 0;
899: pf->mpf_header.mfh_data_len= xs->datalen; /* XXX */
900: pf->mpf_header.mfh_sense_len = MFI_SENSE_SIZE;
901:
902: pf->mpf_sense_addr_hi = 0;
903: pf->mpf_sense_addr_lo = htole32(ccb->ccb_psense);
904:
905: memset(pf->mpf_cdb, 0, 16);
906: memcpy(pf->mpf_cdb, &xs->cmdstore, xs->cmdlen);
907:
908: ccb->ccb_done = mfi_scsi_xs_done;
909: ccb->ccb_xs = xs;
910: ccb->ccb_frame_size = MFI_PASS_FRAME_SIZE;
911: ccb->ccb_sgl = &pf->mpf_sgl;
912:
913: if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT))
914: ccb->ccb_direction = xs->flags & SCSI_DATA_IN ?
915: MFI_DATA_IN : MFI_DATA_OUT;
916: else
917: ccb->ccb_direction = MFI_DATA_NONE;
918:
919: if (xs->data) {
920: ccb->ccb_data = xs->data;
921: ccb->ccb_len = xs->datalen;
922:
923: if (mfi_create_sgl(ccb, (xs->flags & SCSI_NOSLEEP) ?
924: BUS_DMA_NOWAIT : BUS_DMA_WAITOK))
925: return (1);
926: }
927:
928: return (0);
929: }
930:
931: int
932: mfi_scsi_cmd(struct scsi_xfer *xs)
933: {
934: struct scsi_link *link = xs->sc_link;
935: struct mfi_softc *sc = link->adapter_softc;
936: struct device *dev = link->device_softc;
937: struct mfi_ccb *ccb;
938: struct scsi_rw *rw;
939: struct scsi_rw_big *rwb;
940: uint32_t blockno, blockcnt;
941: uint8_t target = link->target;
942: uint8_t mbox[MFI_MBOX_SIZE];
943:
944: DNPRINTF(MFI_D_CMD, "%s: mfi_scsi_cmd opcode: %#x\n",
945: DEVNAME(sc), xs->cmd->opcode);
946:
947: if (target >= MFI_MAX_LD || !sc->sc_ld[target].ld_present ||
948: link->lun != 0) {
949: DNPRINTF(MFI_D_CMD, "%s: invalid target %d\n",
950: DEVNAME(sc), target);
951: goto stuffup;
952: }
953:
954: if ((ccb = mfi_get_ccb(sc)) == NULL) {
955: DNPRINTF(MFI_D_CMD, "%s: mfi_scsi_cmd no ccb\n", DEVNAME(sc));
956: return (TRY_AGAIN_LATER);
957: }
958:
959: xs->error = XS_NOERROR;
960:
961: switch (xs->cmd->opcode) {
962: /* IO path */
963: case READ_BIG:
964: case WRITE_BIG:
965: rwb = (struct scsi_rw_big *)xs->cmd;
966: blockno = _4btol(rwb->addr);
967: blockcnt = _2btol(rwb->length);
968: if (mfi_scsi_io(ccb, xs, blockno, blockcnt)) {
969: mfi_put_ccb(ccb);
970: goto stuffup;
971: }
972: break;
973:
974: case READ_COMMAND:
975: case WRITE_COMMAND:
976: rw = (struct scsi_rw *)xs->cmd;
977: blockno = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff);
978: blockcnt = rw->length ? rw->length : 0x100;
979: if (mfi_scsi_io(ccb, xs, blockno, blockcnt)) {
980: mfi_put_ccb(ccb);
981: goto stuffup;
982: }
983: break;
984:
985: case SYNCHRONIZE_CACHE:
986: mfi_put_ccb(ccb); /* we don't need this */
987:
988: mbox[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
989: if (mfi_mgmt(sc, MR_DCMD_CTRL_CACHE_FLUSH, MFI_DATA_NONE,
990: 0, NULL, mbox))
991: goto stuffup;
992:
993: return (COMPLETE);
994: /* NOTREACHED */
995:
996: /* hand it of to the firmware and let it deal with it */
997: case TEST_UNIT_READY:
998: /* save off sd? after autoconf */
999: if (!cold) /* XXX bogus */
1000: strlcpy(sc->sc_ld[target].ld_dev, dev->dv_xname,
1001: sizeof(sc->sc_ld[target].ld_dev));
1002: /* FALLTHROUGH */
1003:
1004: default:
1005: if (mfi_scsi_ld(ccb, xs)) {
1006: mfi_put_ccb(ccb);
1007: goto stuffup;
1008: }
1009: break;
1010: }
1011:
1012: DNPRINTF(MFI_D_CMD, "%s: start io %d\n", DEVNAME(sc), target);
1013:
1014: if (xs->flags & SCSI_POLL) {
1015: if (mfi_poll(ccb)) {
1016: /* XXX check for sense in ccb->ccb_sense? */
1017: printf("%s: mfi_scsi_cmd poll failed\n",
1018: DEVNAME(sc));
1019: mfi_put_ccb(ccb);
1020: bzero(&xs->sense, sizeof(xs->sense));
1021: xs->sense.error_code = SSD_ERRCODE_VALID | 0x70;
1022: xs->sense.flags = SKEY_ILLEGAL_REQUEST;
1023: xs->sense.add_sense_code = 0x20; /* invalid opcode */
1024: xs->error = XS_SENSE;
1025: xs->flags |= ITSDONE;
1026: scsi_done(xs);
1027: return (COMPLETE);
1028: }
1029: DNPRINTF(MFI_D_DMA, "%s: mfi_scsi_cmd poll complete %d\n",
1030: DEVNAME(sc), ccb->ccb_dmamap->dm_nsegs);
1031:
1032: mfi_put_ccb(ccb);
1033: return (COMPLETE);
1034: }
1035:
1036: mfi_despatch_cmd(ccb);
1037:
1038: DNPRINTF(MFI_D_DMA, "%s: mfi_scsi_cmd queued %d\n", DEVNAME(sc),
1039: ccb->ccb_dmamap->dm_nsegs);
1040:
1041: return (SUCCESSFULLY_QUEUED);
1042:
1043: stuffup:
1044: xs->error = XS_DRIVER_STUFFUP;
1045: xs->flags |= ITSDONE;
1046: scsi_done(xs);
1047: return (COMPLETE);
1048: }
1049:
1050: int
1051: mfi_create_sgl(struct mfi_ccb *ccb, int flags)
1052: {
1053: struct mfi_softc *sc = ccb->ccb_sc;
1054: struct mfi_frame_header *hdr;
1055: bus_dma_segment_t *sgd;
1056: union mfi_sgl *sgl;
1057: int error, i;
1058:
1059: DNPRINTF(MFI_D_DMA, "%s: mfi_create_sgl %#x\n", DEVNAME(sc),
1060: ccb->ccb_data);
1061:
1062: if (!ccb->ccb_data)
1063: return (1);
1064:
1065: error = bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap,
1066: ccb->ccb_data, ccb->ccb_len, NULL, flags);
1067: if (error) {
1068: if (error == EFBIG)
1069: printf("more than %d dma segs\n",
1070: sc->sc_max_sgl);
1071: else
1072: printf("error %d loading dma map\n", error);
1073: return (1);
1074: }
1075:
1076: hdr = &ccb->ccb_frame->mfr_header;
1077: sgl = ccb->ccb_sgl;
1078: sgd = ccb->ccb_dmamap->dm_segs;
1079: for (i = 0; i < ccb->ccb_dmamap->dm_nsegs; i++) {
1080: sgl->sg32[i].addr = htole32(sgd[i].ds_addr);
1081: sgl->sg32[i].len = htole32(sgd[i].ds_len);
1082: DNPRINTF(MFI_D_DMA, "%s: addr: %#x len: %#x\n",
1083: DEVNAME(sc), sgl->sg32[i].addr, sgl->sg32[i].len);
1084: }
1085:
1086: if (ccb->ccb_direction == MFI_DATA_IN) {
1087: hdr->mfh_flags |= MFI_FRAME_DIR_READ;
1088: bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
1089: ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
1090: } else {
1091: hdr->mfh_flags |= MFI_FRAME_DIR_WRITE;
1092: bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
1093: ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_PREWRITE);
1094: }
1095:
1096: hdr->mfh_sg_count = ccb->ccb_dmamap->dm_nsegs;
1097: /* for 64 bit io make the sizeof a variable to hold whatever sg size */
1098: ccb->ccb_frame_size += sizeof(struct mfi_sg32) *
1099: ccb->ccb_dmamap->dm_nsegs;
1100: ccb->ccb_extra_frames = (ccb->ccb_frame_size - 1) / MFI_FRAME_SIZE;
1101:
1102: DNPRINTF(MFI_D_DMA, "%s: sg_count: %d frame_size: %d frames_size: %d"
1103: " dm_nsegs: %d extra_frames: %d\n",
1104: DEVNAME(sc),
1105: hdr->mfh_sg_count,
1106: ccb->ccb_frame_size,
1107: sc->sc_frames_size,
1108: ccb->ccb_dmamap->dm_nsegs,
1109: ccb->ccb_extra_frames);
1110:
1111: return (0);
1112: }
1113:
1114: int
1115: mfi_mgmt(struct mfi_softc *sc, uint32_t opc, uint32_t dir, uint32_t len,
1116: void *buf, uint8_t *mbox)
1117: {
1118: struct mfi_ccb *ccb;
1119: struct mfi_dcmd_frame *dcmd;
1120: int rv = 1;
1121:
1122: DNPRINTF(MFI_D_MISC, "%s: mfi_mgmt %#x\n", DEVNAME(sc), opc);
1123:
1124: if ((ccb = mfi_get_ccb(sc)) == NULL)
1125: return (rv);
1126:
1127: dcmd = &ccb->ccb_frame->mfr_dcmd;
1128: memset(dcmd->mdf_mbox, 0, MFI_MBOX_SIZE);
1129: dcmd->mdf_header.mfh_cmd = MFI_CMD_DCMD;
1130: dcmd->mdf_header.mfh_timeout = 0;
1131:
1132: dcmd->mdf_opcode = opc;
1133: dcmd->mdf_header.mfh_data_len = 0;
1134: ccb->ccb_direction = dir;
1135: ccb->ccb_done = mfi_mgmt_done;
1136:
1137: ccb->ccb_frame_size = MFI_DCMD_FRAME_SIZE;
1138:
1139: /* handle special opcodes */
1140: if (mbox)
1141: memcpy(dcmd->mdf_mbox, mbox, MFI_MBOX_SIZE);
1142:
1143: if (dir != MFI_DATA_NONE) {
1144: dcmd->mdf_header.mfh_data_len = len;
1145: ccb->ccb_data = buf;
1146: ccb->ccb_len = len;
1147: ccb->ccb_sgl = &dcmd->mdf_sgl;
1148:
1149: if (mfi_create_sgl(ccb, BUS_DMA_WAITOK))
1150: goto done;
1151: }
1152:
1153: if (cold) {
1154: if (mfi_poll(ccb))
1155: goto done;
1156: } else {
1157: mfi_despatch_cmd(ccb);
1158:
1159: DNPRINTF(MFI_D_MISC, "%s: mfi_mgmt sleeping\n", DEVNAME(sc));
1160: while (ccb->ccb_state != MFI_CCB_DONE)
1161: tsleep(ccb, PRIBIO, "mfi_mgmt", 0);
1162:
1163: if (ccb->ccb_flags & MFI_CCB_F_ERR)
1164: goto done;
1165: }
1166:
1167: rv = 0;
1168:
1169: done:
1170: mfi_put_ccb(ccb);
1171: return (rv);
1172: }
1173:
1174: void
1175: mfi_mgmt_done(struct mfi_ccb *ccb)
1176: {
1177: struct mfi_softc *sc = ccb->ccb_sc;
1178: struct mfi_frame_header *hdr = &ccb->ccb_frame->mfr_header;
1179:
1180: DNPRINTF(MFI_D_INTR, "%s: mfi_mgmt_done %#x %#x\n",
1181: DEVNAME(sc), ccb, ccb->ccb_frame);
1182:
1183: if (ccb->ccb_data != NULL) {
1184: DNPRINTF(MFI_D_INTR, "%s: mfi_mgmt_done sync\n",
1185: DEVNAME(sc));
1186: bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
1187: ccb->ccb_dmamap->dm_mapsize,
1188: (ccb->ccb_direction & MFI_DATA_IN) ?
1189: BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
1190:
1191: bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
1192: }
1193:
1194: if (hdr->mfh_cmd_status != MFI_STAT_OK)
1195: ccb->ccb_flags |= MFI_CCB_F_ERR;
1196:
1197: ccb->ccb_state = MFI_CCB_DONE;
1198:
1199: wakeup(ccb);
1200: }
1201:
1202:
1203: int
1204: mfi_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag,
1205: struct proc *p)
1206: {
1207: struct mfi_softc *sc = (struct mfi_softc *)link->adapter_softc;
1208:
1209: DNPRINTF(MFI_D_IOCTL, "%s: mfi_scsi_ioctl\n", DEVNAME(sc));
1210:
1211: if (sc->sc_ioctl)
1212: return (sc->sc_ioctl(link->adapter_softc, cmd, addr));
1213: else
1214: return (ENOTTY);
1215: }
1216:
1217: #if NBIO > 0
1218: int
1219: mfi_ioctl(struct device *dev, u_long cmd, caddr_t addr)
1220: {
1221: struct mfi_softc *sc = (struct mfi_softc *)dev;
1222: int error = 0;
1223:
1224: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl ", DEVNAME(sc));
1225:
1226: rw_enter_write(&sc->sc_lock);
1227:
1228: switch (cmd) {
1229: case BIOCINQ:
1230: DNPRINTF(MFI_D_IOCTL, "inq\n");
1231: error = mfi_ioctl_inq(sc, (struct bioc_inq *)addr);
1232: break;
1233:
1234: case BIOCVOL:
1235: DNPRINTF(MFI_D_IOCTL, "vol\n");
1236: error = mfi_ioctl_vol(sc, (struct bioc_vol *)addr);
1237: break;
1238:
1239: case BIOCDISK:
1240: DNPRINTF(MFI_D_IOCTL, "disk\n");
1241: error = mfi_ioctl_disk(sc, (struct bioc_disk *)addr);
1242: break;
1243:
1244: case BIOCALARM:
1245: DNPRINTF(MFI_D_IOCTL, "alarm\n");
1246: error = mfi_ioctl_alarm(sc, (struct bioc_alarm *)addr);
1247: break;
1248:
1249: case BIOCBLINK:
1250: DNPRINTF(MFI_D_IOCTL, "blink\n");
1251: error = mfi_ioctl_blink(sc, (struct bioc_blink *)addr);
1252: break;
1253:
1254: case BIOCSETSTATE:
1255: DNPRINTF(MFI_D_IOCTL, "setstate\n");
1256: error = mfi_ioctl_setstate(sc, (struct bioc_setstate *)addr);
1257: break;
1258:
1259: default:
1260: DNPRINTF(MFI_D_IOCTL, " invalid ioctl\n");
1261: error = EINVAL;
1262: }
1263:
1264: rw_exit_write(&sc->sc_lock);
1265:
1266: return (error);
1267: }
1268:
1269: int
1270: mfi_ioctl_inq(struct mfi_softc *sc, struct bioc_inq *bi)
1271: {
1272: struct mfi_conf *cfg;
1273: int rv = EINVAL;
1274:
1275: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_inq\n", DEVNAME(sc));
1276:
1277: if (mfi_get_info(sc)) {
1278: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_inq failed\n",
1279: DEVNAME(sc));
1280: return (EIO);
1281: }
1282:
1283: /* get figures */
1284: cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK);
1285: if (mfi_mgmt(sc, MD_DCMD_CONF_GET, MFI_DATA_IN, sizeof *cfg, cfg, NULL))
1286: goto freeme;
1287:
1288: strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev));
1289: bi->bi_novol = cfg->mfc_no_ld + cfg->mfc_no_hs;
1290: bi->bi_nodisk = sc->sc_info.mci_pd_disks_present;
1291:
1292: rv = 0;
1293: freeme:
1294: free(cfg, M_DEVBUF);
1295: return (rv);
1296: }
1297:
1298: int
1299: mfi_ioctl_vol(struct mfi_softc *sc, struct bioc_vol *bv)
1300: {
1301: int i, per, rv = EINVAL;
1302: uint8_t mbox[MFI_MBOX_SIZE];
1303:
1304: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_vol %#x\n",
1305: DEVNAME(sc), bv->bv_volid);
1306:
1307: if (mfi_mgmt(sc, MR_DCMD_LD_GET_LIST, MFI_DATA_IN,
1308: sizeof(sc->sc_ld_list), &sc->sc_ld_list, NULL))
1309: goto done;
1310:
1311: i = bv->bv_volid;
1312: mbox[0] = sc->sc_ld_list.mll_list[i].mll_ld.mld_target;
1313: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_vol target %#x\n",
1314: DEVNAME(sc), mbox[0]);
1315:
1316: if (mfi_mgmt(sc, MR_DCMD_LD_GET_INFO, MFI_DATA_IN,
1317: sizeof(sc->sc_ld_details), &sc->sc_ld_details, mbox))
1318: goto done;
1319:
1320: if (bv->bv_volid >= sc->sc_ld_list.mll_no_ld) {
1321: /* go do hotspares */
1322: rv = mfi_bio_hs(sc, bv->bv_volid, MFI_MGMT_VD, bv);
1323: goto done;
1324: }
1325:
1326: strlcpy(bv->bv_dev, sc->sc_ld[i].ld_dev, sizeof(bv->bv_dev));
1327:
1328: switch(sc->sc_ld_list.mll_list[i].mll_state) {
1329: case MFI_LD_OFFLINE:
1330: bv->bv_status = BIOC_SVOFFLINE;
1331: break;
1332:
1333: case MFI_LD_PART_DEGRADED:
1334: case MFI_LD_DEGRADED:
1335: bv->bv_status = BIOC_SVDEGRADED;
1336: break;
1337:
1338: case MFI_LD_ONLINE:
1339: bv->bv_status = BIOC_SVONLINE;
1340: break;
1341:
1342: default:
1343: bv->bv_status = BIOC_SVINVALID;
1344: DNPRINTF(MFI_D_IOCTL, "%s: invalid logical disk state %#x\n",
1345: DEVNAME(sc),
1346: sc->sc_ld_list.mll_list[i].mll_state);
1347: }
1348:
1349: /* additional status can modify MFI status */
1350: switch (sc->sc_ld_details.mld_progress.mlp_in_prog) {
1351: case MFI_LD_PROG_CC:
1352: case MFI_LD_PROG_BGI:
1353: bv->bv_status = BIOC_SVSCRUB;
1354: per = (int)sc->sc_ld_details.mld_progress.mlp_cc.mp_progress;
1355: bv->bv_percent = (per * 100) / 0xffff;
1356: bv->bv_seconds =
1357: sc->sc_ld_details.mld_progress.mlp_cc.mp_elapsed_seconds;
1358: break;
1359:
1360: case MFI_LD_PROG_FGI:
1361: case MFI_LD_PROG_RECONSTRUCT:
1362: /* nothing yet */
1363: break;
1364: }
1365:
1366: /*
1367: * The RAID levels are determined per the SNIA DDF spec, this is only
1368: * a subset that is valid for the MFI contrller.
1369: */
1370: bv->bv_level = sc->sc_ld_details.mld_cfg.mlc_parm.mpa_pri_raid;
1371: if (sc->sc_ld_details.mld_cfg.mlc_parm.mpa_sec_raid ==
1372: MFI_DDF_SRL_SPANNED)
1373: bv->bv_level *= 10;
1374:
1375: bv->bv_nodisk = sc->sc_ld_details.mld_cfg.mlc_parm.mpa_no_drv_per_span *
1376: sc->sc_ld_details.mld_cfg.mlc_parm.mpa_span_depth;
1377:
1378: bv->bv_size = sc->sc_ld_details.mld_size * 512; /* bytes per block */
1379:
1380: rv = 0;
1381: done:
1382: return (rv);
1383: }
1384:
1385: int
1386: mfi_ioctl_disk(struct mfi_softc *sc, struct bioc_disk *bd)
1387: {
1388: struct mfi_conf *cfg;
1389: struct mfi_array *ar;
1390: struct mfi_ld_cfg *ld;
1391: struct mfi_pd_details *pd;
1392: struct scsi_inquiry_data *inqbuf;
1393: char vend[8+16+4+1];
1394: int i, rv = EINVAL;
1395: int arr, vol, disk;
1396: uint32_t size;
1397: uint8_t mbox[MFI_MBOX_SIZE];
1398:
1399: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_disk %#x\n",
1400: DEVNAME(sc), bd->bd_diskid);
1401:
1402: pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
1403:
1404: /* send single element command to retrieve size for full structure */
1405: cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK);
1406: if (mfi_mgmt(sc, MD_DCMD_CONF_GET, MFI_DATA_IN, sizeof *cfg, cfg, NULL))
1407: goto freeme;
1408:
1409: size = cfg->mfc_size;
1410: free(cfg, M_DEVBUF);
1411:
1412: /* memory for read config */
1413: cfg = malloc(size, M_DEVBUF, M_WAITOK);
1414: memset(cfg, 0, size);
1415: if (mfi_mgmt(sc, MD_DCMD_CONF_GET, MFI_DATA_IN, size, cfg, NULL))
1416: goto freeme;
1417:
1418: ar = cfg->mfc_array;
1419:
1420: /* calculate offset to ld structure */
1421: ld = (struct mfi_ld_cfg *)(
1422: ((uint8_t *)cfg) + offsetof(struct mfi_conf, mfc_array) +
1423: cfg->mfc_array_size * cfg->mfc_no_array);
1424:
1425: vol = bd->bd_volid;
1426:
1427: if (vol >= cfg->mfc_no_ld) {
1428: /* do hotspares */
1429: rv = mfi_bio_hs(sc, bd->bd_volid, MFI_MGMT_SD, bd);
1430: goto freeme;
1431: }
1432:
1433: /* find corresponding array for ld */
1434: for (i = 0, arr = 0; i < vol; i++)
1435: arr += ld[i].mlc_parm.mpa_span_depth;
1436:
1437: /* offset disk into pd list */
1438: disk = bd->bd_diskid % ld[vol].mlc_parm.mpa_no_drv_per_span;
1439:
1440: /* offset array index into the next spans */
1441: arr += bd->bd_diskid / ld[vol].mlc_parm.mpa_no_drv_per_span;
1442:
1443: bd->bd_target = ar[arr].pd[disk].mar_enc_slot;
1444: switch (ar[arr].pd[disk].mar_pd_state){
1445: case MFI_PD_UNCONFIG_GOOD:
1446: bd->bd_status = BIOC_SDUNUSED;
1447: break;
1448:
1449: case MFI_PD_HOTSPARE: /* XXX dedicated hotspare part of array? */
1450: bd->bd_status = BIOC_SDHOTSPARE;
1451: break;
1452:
1453: case MFI_PD_OFFLINE:
1454: bd->bd_status = BIOC_SDOFFLINE;
1455: break;
1456:
1457: case MFI_PD_FAILED:
1458: bd->bd_status = BIOC_SDFAILED;
1459: break;
1460:
1461: case MFI_PD_REBUILD:
1462: bd->bd_status = BIOC_SDREBUILD;
1463: break;
1464:
1465: case MFI_PD_ONLINE:
1466: bd->bd_status = BIOC_SDONLINE;
1467: break;
1468:
1469: case MFI_PD_UNCONFIG_BAD: /* XXX define new state in bio */
1470: default:
1471: bd->bd_status = BIOC_SDINVALID;
1472: break;
1473:
1474: }
1475:
1476: /* get the remaining fields */
1477: *((uint16_t *)&mbox) = ar[arr].pd[disk].mar_pd.mfp_id;
1478: if (mfi_mgmt(sc, MR_DCMD_PD_GET_INFO, MFI_DATA_IN,
1479: sizeof *pd, pd, mbox))
1480: goto freeme;
1481:
1482: bd->bd_size = pd->mpd_size * 512; /* bytes per block */
1483:
1484: /* if pd->mpd_enc_idx is 0 then it is not in an enclosure */
1485: bd->bd_channel = pd->mpd_enc_idx;
1486:
1487: inqbuf = (struct scsi_inquiry_data *)&pd->mpd_inq_data;
1488: memcpy(vend, inqbuf->vendor, sizeof vend - 1);
1489: vend[sizeof vend - 1] = '\0';
1490: strlcpy(bd->bd_vendor, vend, sizeof(bd->bd_vendor));
1491:
1492: /* XXX find a way to retrieve serial nr from drive */
1493: /* XXX find a way to get bd_procdev */
1494:
1495: rv = 0;
1496: freeme:
1497: free(pd, M_DEVBUF);
1498: free(cfg, M_DEVBUF);
1499:
1500: return (rv);
1501: }
1502:
1503: int
1504: mfi_ioctl_alarm(struct mfi_softc *sc, struct bioc_alarm *ba)
1505: {
1506: uint32_t opc, dir = MFI_DATA_NONE;
1507: int rv = 0;
1508: int8_t ret;
1509:
1510: switch(ba->ba_opcode) {
1511: case BIOC_SADISABLE:
1512: opc = MR_DCMD_SPEAKER_DISABLE;
1513: break;
1514:
1515: case BIOC_SAENABLE:
1516: opc = MR_DCMD_SPEAKER_ENABLE;
1517: break;
1518:
1519: case BIOC_SASILENCE:
1520: opc = MR_DCMD_SPEAKER_SILENCE;
1521: break;
1522:
1523: case BIOC_GASTATUS:
1524: opc = MR_DCMD_SPEAKER_GET;
1525: dir = MFI_DATA_IN;
1526: break;
1527:
1528: case BIOC_SATEST:
1529: opc = MR_DCMD_SPEAKER_TEST;
1530: break;
1531:
1532: default:
1533: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_alarm biocalarm invalid "
1534: "opcode %x\n", DEVNAME(sc), ba->ba_opcode);
1535: return (EINVAL);
1536: }
1537:
1538: if (mfi_mgmt(sc, opc, dir, sizeof(ret), &ret, NULL))
1539: rv = EINVAL;
1540: else
1541: if (ba->ba_opcode == BIOC_GASTATUS)
1542: ba->ba_status = ret;
1543: else
1544: ba->ba_status = 0;
1545:
1546: return (rv);
1547: }
1548:
1549: int
1550: mfi_ioctl_blink(struct mfi_softc *sc, struct bioc_blink *bb)
1551: {
1552: int i, found, rv = EINVAL;
1553: uint8_t mbox[MFI_MBOX_SIZE];
1554: uint32_t cmd;
1555: struct mfi_pd_list *pd;
1556:
1557: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_blink %x\n", DEVNAME(sc),
1558: bb->bb_status);
1559:
1560: /* channel 0 means not in an enclosure so can't be blinked */
1561: if (bb->bb_channel == 0)
1562: return (EINVAL);
1563:
1564: pd = malloc(MFI_PD_LIST_SIZE, M_DEVBUF, M_WAITOK);
1565:
1566: if (mfi_mgmt(sc, MR_DCMD_PD_GET_LIST, MFI_DATA_IN,
1567: MFI_PD_LIST_SIZE, pd, NULL))
1568: goto done;
1569:
1570: for (i = 0, found = 0; i < pd->mpl_no_pd; i++)
1571: if (bb->bb_channel == pd->mpl_address[i].mpa_enc_index &&
1572: bb->bb_target == pd->mpl_address[i].mpa_enc_slot) {
1573: found = 1;
1574: break;
1575: }
1576:
1577: if (!found)
1578: goto done;
1579:
1580: memset(mbox, 0, sizeof mbox);
1581:
1582: *((uint16_t *)&mbox) = pd->mpl_address[i].mpa_pd_id;
1583:
1584: switch (bb->bb_status) {
1585: case BIOC_SBUNBLINK:
1586: cmd = MR_DCMD_PD_UNBLINK;
1587: break;
1588:
1589: case BIOC_SBBLINK:
1590: cmd = MR_DCMD_PD_BLINK;
1591: break;
1592:
1593: case BIOC_SBALARM:
1594: default:
1595: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_blink biocblink invalid "
1596: "opcode %x\n", DEVNAME(sc), bb->bb_status);
1597: goto done;
1598: }
1599:
1600:
1601: if (mfi_mgmt(sc, cmd, MFI_DATA_NONE, 0, NULL, mbox))
1602: goto done;
1603:
1604: rv = 0;
1605: done:
1606: free(pd, M_DEVBUF);
1607: return (rv);
1608: }
1609:
1610: int
1611: mfi_ioctl_setstate(struct mfi_softc *sc, struct bioc_setstate *bs)
1612: {
1613: struct mfi_pd_list *pd;
1614: int i, found, rv = EINVAL;
1615: uint8_t mbox[MFI_MBOX_SIZE];
1616: uint32_t cmd;
1617:
1618: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_setstate %x\n", DEVNAME(sc),
1619: bs->bs_status);
1620:
1621: pd = malloc(MFI_PD_LIST_SIZE, M_DEVBUF, M_WAITOK);
1622:
1623: if (mfi_mgmt(sc, MR_DCMD_PD_GET_LIST, MFI_DATA_IN,
1624: MFI_PD_LIST_SIZE, pd, NULL))
1625: goto done;
1626:
1627: for (i = 0, found = 0; i < pd->mpl_no_pd; i++)
1628: if (bs->bs_channel == pd->mpl_address[i].mpa_enc_index &&
1629: bs->bs_target == pd->mpl_address[i].mpa_enc_slot) {
1630: found = 1;
1631: break;
1632: }
1633:
1634: if (!found)
1635: goto done;
1636:
1637: memset(mbox, 0, sizeof mbox);
1638:
1639: *((uint16_t *)&mbox) = pd->mpl_address[i].mpa_pd_id;
1640:
1641: switch (bs->bs_status) {
1642: case BIOC_SSONLINE:
1643: mbox[2] = MFI_PD_ONLINE;
1644: cmd = MD_DCMD_PD_SET_STATE;
1645: break;
1646:
1647: case BIOC_SSOFFLINE:
1648: mbox[2] = MFI_PD_OFFLINE;
1649: cmd = MD_DCMD_PD_SET_STATE;
1650: break;
1651:
1652: case BIOC_SSHOTSPARE:
1653: mbox[2] = MFI_PD_HOTSPARE;
1654: cmd = MD_DCMD_PD_SET_STATE;
1655: break;
1656: /*
1657: case BIOC_SSREBUILD:
1658: cmd = MD_DCMD_PD_REBUILD;
1659: break;
1660: */
1661: default:
1662: DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_setstate invalid "
1663: "opcode %x\n", DEVNAME(sc), bs->bs_status);
1664: goto done;
1665: }
1666:
1667:
1668: if (mfi_mgmt(sc, MD_DCMD_PD_SET_STATE, MFI_DATA_NONE, 0, NULL, mbox))
1669: goto done;
1670:
1671: rv = 0;
1672: done:
1673: free(pd, M_DEVBUF);
1674: return (rv);
1675: }
1676:
1677: int
1678: mfi_bio_hs(struct mfi_softc *sc, int volid, int type, void *bio_hs)
1679: {
1680: struct mfi_conf *cfg;
1681: struct mfi_hotspare *hs;
1682: struct mfi_pd_details *pd;
1683: struct bioc_disk *sdhs;
1684: struct bioc_vol *vdhs;
1685: struct scsi_inquiry_data *inqbuf;
1686: char vend[8+16+4+1];
1687: int i, rv = EINVAL;
1688: uint32_t size;
1689: uint8_t mbox[MFI_MBOX_SIZE];
1690:
1691: DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs %d\n", DEVNAME(sc), volid);
1692:
1693: if (!bio_hs)
1694: return (EINVAL);
1695:
1696: pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
1697:
1698: /* send single element command to retrieve size for full structure */
1699: cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK);
1700: if (mfi_mgmt(sc, MD_DCMD_CONF_GET, MFI_DATA_IN, sizeof *cfg, cfg, NULL))
1701: goto freeme;
1702:
1703: size = cfg->mfc_size;
1704: free(cfg, M_DEVBUF);
1705:
1706: /* memory for read config */
1707: cfg = malloc(size, M_DEVBUF, M_WAITOK);
1708: memset(cfg, 0, size);
1709: if (mfi_mgmt(sc, MD_DCMD_CONF_GET, MFI_DATA_IN, size, cfg, NULL))
1710: goto freeme;
1711:
1712: /* calculate offset to hs structure */
1713: hs = (struct mfi_hotspare *)(
1714: ((uint8_t *)cfg) + offsetof(struct mfi_conf, mfc_array) +
1715: cfg->mfc_array_size * cfg->mfc_no_array +
1716: cfg->mfc_ld_size * cfg->mfc_no_ld);
1717:
1718: if (volid < cfg->mfc_no_ld)
1719: goto freeme; /* not a hotspare */
1720:
1721: if (volid > (cfg->mfc_no_ld + cfg->mfc_no_hs))
1722: goto freeme; /* not a hotspare */
1723:
1724: /* offset into hotspare structure */
1725: i = volid - cfg->mfc_no_ld;
1726:
1727: DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs i %d volid %d no_ld %d no_hs %d "
1728: "hs %p cfg %p id %02x\n", DEVNAME(sc), i, volid, cfg->mfc_no_ld,
1729: cfg->mfc_no_hs, hs, cfg, hs[i].mhs_pd.mfp_id);
1730:
1731: /* get pd fields */
1732: memset(mbox, 0, sizeof mbox);
1733: *((uint16_t *)&mbox) = hs[i].mhs_pd.mfp_id;
1734: if (mfi_mgmt(sc, MR_DCMD_PD_GET_INFO, MFI_DATA_IN,
1735: sizeof *pd, pd, mbox)) {
1736: DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs illegal PD\n",
1737: DEVNAME(sc));
1738: goto freeme;
1739: }
1740:
1741: switch (type) {
1742: case MFI_MGMT_VD:
1743: vdhs = bio_hs;
1744: vdhs->bv_status = BIOC_SVONLINE;
1745: vdhs->bv_size = pd->mpd_size / 2; /* XXX why? / 2 */
1746: vdhs->bv_level = -1; /* hotspare */
1747: vdhs->bv_nodisk = 1;
1748: break;
1749:
1750: case MFI_MGMT_SD:
1751: sdhs = bio_hs;
1752: sdhs->bd_status = BIOC_SDHOTSPARE;
1753: sdhs->bd_size = pd->mpd_size / 2; /* XXX why? / 2 */
1754: sdhs->bd_channel = pd->mpd_enc_idx;
1755: sdhs->bd_target = pd->mpd_enc_slot;
1756: inqbuf = (struct scsi_inquiry_data *)&pd->mpd_inq_data;
1757: memcpy(vend, inqbuf->vendor, sizeof vend - 1);
1758: vend[sizeof vend - 1] = '\0';
1759: strlcpy(sdhs->bd_vendor, vend, sizeof(sdhs->bd_vendor));
1760: break;
1761:
1762: default:
1763: goto freeme;
1764: }
1765:
1766: DNPRINTF(MFI_D_IOCTL, "%s: mfi_vol_hs 6\n", DEVNAME(sc));
1767: rv = 0;
1768: freeme:
1769: free(pd, M_DEVBUF);
1770: free(cfg, M_DEVBUF);
1771:
1772: return (rv);
1773: }
1774:
1775: #ifndef SMALL_KERNEL
1776: int
1777: mfi_create_sensors(struct mfi_softc *sc)
1778: {
1779: struct device *dev;
1780: struct scsibus_softc *ssc;
1781: int i;
1782:
1783: TAILQ_FOREACH(dev, &alldevs, dv_list) {
1784: if (dev->dv_parent != &sc->sc_dev)
1785: continue;
1786:
1787: /* check if this is the scsibus for the logical disks */
1788: ssc = (struct scsibus_softc *)dev;
1789: if (ssc->adapter_link == &sc->sc_link)
1790: break;
1791: }
1792:
1793: if (ssc == NULL)
1794: return (1);
1795:
1796: sc->sc_sensors = malloc(sizeof(struct ksensor) * sc->sc_ld_cnt,
1797: M_DEVBUF, M_WAITOK);
1798: if (sc->sc_sensors == NULL)
1799: return (1);
1800: bzero(sc->sc_sensors, sizeof(struct ksensor) * sc->sc_ld_cnt);
1801:
1802: strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
1803: sizeof(sc->sc_sensordev.xname));
1804:
1805: for (i = 0; i < sc->sc_ld_cnt; i++) {
1806: if (ssc->sc_link[i][0] == NULL)
1807: goto bad;
1808:
1809: dev = ssc->sc_link[i][0]->device_softc;
1810:
1811: sc->sc_sensors[i].type = SENSOR_DRIVE;
1812: sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
1813:
1814: strlcpy(sc->sc_sensors[i].desc, dev->dv_xname,
1815: sizeof(sc->sc_sensors[i].desc));
1816:
1817: sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
1818: }
1819:
1820: if (sensor_task_register(sc, mfi_refresh_sensors, 10) == NULL)
1821: goto bad;
1822:
1823: sensordev_install(&sc->sc_sensordev);
1824:
1825: return (0);
1826:
1827: bad:
1828: free(sc->sc_sensors, M_DEVBUF);
1829:
1830: return (1);
1831: }
1832:
1833: void
1834: mfi_refresh_sensors(void *arg)
1835: {
1836: struct mfi_softc *sc = arg;
1837: int i;
1838: struct bioc_vol bv;
1839:
1840:
1841: for (i = 0; i < sc->sc_ld_cnt; i++) {
1842: bzero(&bv, sizeof(bv));
1843: bv.bv_volid = i;
1844: if (mfi_ioctl_vol(sc, &bv))
1845: return;
1846:
1847: switch(bv.bv_status) {
1848: case BIOC_SVOFFLINE:
1849: sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL;
1850: sc->sc_sensors[i].status = SENSOR_S_CRIT;
1851: break;
1852:
1853: case BIOC_SVDEGRADED:
1854: sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL;
1855: sc->sc_sensors[i].status = SENSOR_S_WARN;
1856: break;
1857:
1858: case BIOC_SVSCRUB:
1859: case BIOC_SVONLINE:
1860: sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE;
1861: sc->sc_sensors[i].status = SENSOR_S_OK;
1862: break;
1863:
1864: case BIOC_SVINVALID:
1865: /* FALLTRHOUGH */
1866: default:
1867: sc->sc_sensors[i].value = 0; /* unknown */
1868: sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
1869: }
1870:
1871: }
1872: }
1873: #endif /* SMALL_KERNEL */
1874: #endif /* NBIO > 0 */
CVSweb