Line data Source code
1 : /* $OpenBSD: mfii.c,v 1.58 2018/08/14 05:22:21 jmatthew Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2012 David Gwynne <dlg@openbsd.org>
5 : *
6 : * Permission to use, copy, modify, and distribute this software for any
7 : * purpose with or without fee is hereby granted, provided that the above
8 : * copyright notice and this permission notice appear in all copies.
9 : *
10 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 : */
18 :
19 : #include "bio.h"
20 :
21 : #include <sys/param.h>
22 : #include <sys/systm.h>
23 : #include <sys/malloc.h>
24 : #include <sys/device.h>
25 : #include <sys/dkio.h>
26 : #include <sys/pool.h>
27 : #include <sys/task.h>
28 : #include <sys/atomic.h>
29 : #include <sys/sensors.h>
30 : #include <sys/rwlock.h>
31 :
32 : #include <dev/biovar.h>
33 : #include <dev/pci/pcidevs.h>
34 : #include <dev/pci/pcivar.h>
35 :
36 : #include <machine/bus.h>
37 :
38 : #include <scsi/scsi_all.h>
39 : #include <scsi/scsi_disk.h>
40 : #include <scsi/scsiconf.h>
41 :
42 : #include <dev/ic/mfireg.h>
43 : #include <dev/pci/mpiireg.h>
44 :
45 : #define MFII_BAR 0x14
46 : #define MFII_BAR_35 0x10
47 : #define MFII_PCI_MEMSIZE 0x2000 /* 8k */
48 :
49 : #define MFII_OSTS_INTR_VALID 0x00000009
50 : #define MFII_RPI 0x6c /* reply post host index */
51 : #define MFII_OSP2 0xb4 /* outbound scratch pad 2 */
52 : #define MFII_OSP3 0xb8 /* outbound scratch pad 3 */
53 :
54 : #define MFII_REQ_TYPE_SCSI MPII_REQ_DESCR_SCSI_IO
55 : #define MFII_REQ_TYPE_LDIO (0x7 << 1)
56 : #define MFII_REQ_TYPE_MFA (0x1 << 1)
57 : #define MFII_REQ_TYPE_NO_LOCK (0x2 << 1)
58 : #define MFII_REQ_TYPE_HI_PRI (0x6 << 1)
59 :
60 : #define MFII_REQ_MFA(_a) htole64((_a) | MFII_REQ_TYPE_MFA)
61 :
62 : #define MFII_FUNCTION_PASSTHRU_IO (0xf0)
63 : #define MFII_FUNCTION_LDIO_REQUEST (0xf1)
64 :
65 : #define MFII_MAX_CHAIN_UNIT 0x00400000
66 : #define MFII_MAX_CHAIN_MASK 0x000003E0
67 : #define MFII_MAX_CHAIN_SHIFT 5
68 :
69 : #define MFII_256K_IO 128
70 : #define MFII_1MB_IO (MFII_256K_IO * 4)
71 :
72 : #define MFII_CHAIN_FRAME_MIN 1024
73 :
74 : struct mfii_request_descr {
75 : u_int8_t flags;
76 : u_int8_t msix_index;
77 : u_int16_t smid;
78 :
79 : u_int16_t lmid;
80 : u_int16_t dev_handle;
81 : } __packed;
82 :
83 : #define MFII_RAID_CTX_IO_TYPE_SYSPD (0x1 << 4)
84 : #define MFII_RAID_CTX_TYPE_CUDA (0x2 << 4)
85 :
86 : struct mfii_raid_context {
87 : u_int8_t type_nseg;
88 : u_int8_t _reserved1;
89 : u_int16_t timeout_value;
90 :
91 : u_int16_t reg_lock_flags;
92 : #define MFII_RAID_CTX_RL_FLAGS_SEQNO_EN (0x08)
93 : #define MFII_RAID_CTX_RL_FLAGS_CPU0 (0x00)
94 : #define MFII_RAID_CTX_RL_FLAGS_CPU1 (0x10)
95 : #define MFII_RAID_CTX_RL_FLAGS_CUDA (0x80)
96 :
97 : #define MFII_RAID_CTX_ROUTING_FLAGS_SQN (1 << 4)
98 : #define MFII_RAID_CTX_ROUTING_FLAGS_CPU0 0
99 : u_int16_t virtual_disk_target_id;
100 :
101 : u_int64_t reg_lock_row_lba;
102 :
103 : u_int32_t reg_lock_length;
104 :
105 : u_int16_t next_lm_id;
106 : u_int8_t ex_status;
107 : u_int8_t status;
108 :
109 : u_int8_t raid_flags;
110 : u_int8_t num_sge;
111 : u_int16_t config_seq_num;
112 :
113 : u_int8_t span_arm;
114 : u_int8_t _reserved3[3];
115 : } __packed;
116 :
117 : struct mfii_sge {
118 : u_int64_t sg_addr;
119 : u_int32_t sg_len;
120 : u_int16_t _reserved;
121 : u_int8_t sg_next_chain_offset;
122 : u_int8_t sg_flags;
123 : } __packed;
124 :
125 : #define MFII_SGE_ADDR_MASK (0x03)
126 : #define MFII_SGE_ADDR_SYSTEM (0x00)
127 : #define MFII_SGE_ADDR_IOCDDR (0x01)
128 : #define MFII_SGE_ADDR_IOCPLB (0x02)
129 : #define MFII_SGE_ADDR_IOCPLBNTA (0x03)
130 : #define MFII_SGE_END_OF_LIST (0x40)
131 : #define MFII_SGE_CHAIN_ELEMENT (0x80)
132 :
133 : #define MFII_REQUEST_SIZE 256
134 :
135 : #define MR_DCMD_LD_MAP_GET_INFO 0x0300e101
136 :
137 : #define MFII_MAX_ROW 32
138 : #define MFII_MAX_ARRAY 128
139 :
140 : struct mfii_array_map {
141 : uint16_t mam_pd[MFII_MAX_ROW];
142 : } __packed;
143 :
144 : struct mfii_dev_handle {
145 : uint16_t mdh_cur_handle;
146 : uint8_t mdh_valid;
147 : uint8_t mdh_reserved;
148 : uint16_t mdh_handle[2];
149 : } __packed;
150 :
151 : struct mfii_ld_map {
152 : uint32_t mlm_total_size;
153 : uint32_t mlm_reserved1[5];
154 : uint32_t mlm_num_lds;
155 : uint32_t mlm_reserved2;
156 : uint8_t mlm_tgtid_to_ld[2 * MFI_MAX_LD];
157 : uint8_t mlm_pd_timeout;
158 : uint8_t mlm_reserved3[7];
159 : struct mfii_array_map mlm_am[MFII_MAX_ARRAY];
160 : struct mfii_dev_handle mlm_dev_handle[MFI_MAX_PD];
161 : } __packed;
162 :
163 : struct mfii_task_mgmt {
164 : union {
165 : uint8_t request[128];
166 : struct mpii_msg_scsi_task_request
167 : mpii_request;
168 : } __packed __aligned(8);
169 :
170 : union {
171 : uint8_t reply[128];
172 : uint32_t flags;
173 : #define MFII_TASK_MGMT_FLAGS_LD (1 << 0)
174 : #define MFII_TASK_MGMT_FLAGS_PD (1 << 1)
175 : struct mpii_msg_scsi_task_reply
176 : mpii_reply;
177 : } __packed __aligned(8);
178 : } __packed __aligned(8);
179 :
180 : struct mfii_dmamem {
181 : bus_dmamap_t mdm_map;
182 : bus_dma_segment_t mdm_seg;
183 : size_t mdm_size;
184 : caddr_t mdm_kva;
185 : };
186 : #define MFII_DMA_MAP(_mdm) ((_mdm)->mdm_map)
187 : #define MFII_DMA_LEN(_mdm) ((_mdm)->mdm_size)
188 : #define MFII_DMA_DVA(_mdm) ((u_int64_t)(_mdm)->mdm_map->dm_segs[0].ds_addr)
189 : #define MFII_DMA_KVA(_mdm) ((void *)(_mdm)->mdm_kva)
190 :
191 : struct mfii_softc;
192 :
193 : struct mfii_ccb {
194 : void *ccb_request;
195 : u_int64_t ccb_request_dva;
196 : bus_addr_t ccb_request_offset;
197 :
198 : void *ccb_mfi;
199 : u_int64_t ccb_mfi_dva;
200 : bus_addr_t ccb_mfi_offset;
201 :
202 : struct mfi_sense *ccb_sense;
203 : u_int64_t ccb_sense_dva;
204 : bus_addr_t ccb_sense_offset;
205 :
206 : struct mfii_sge *ccb_sgl;
207 : u_int64_t ccb_sgl_dva;
208 : bus_addr_t ccb_sgl_offset;
209 : u_int ccb_sgl_len;
210 :
211 : struct mfii_request_descr ccb_req;
212 :
213 : bus_dmamap_t ccb_dmamap;
214 :
215 : /* data for sgl */
216 : void *ccb_data;
217 : size_t ccb_len;
218 :
219 : int ccb_direction;
220 : #define MFII_DATA_NONE 0
221 : #define MFII_DATA_IN 1
222 : #define MFII_DATA_OUT 2
223 :
224 : void *ccb_cookie;
225 : void (*ccb_done)(struct mfii_softc *,
226 : struct mfii_ccb *);
227 :
228 : u_int32_t ccb_flags;
229 : #define MFI_CCB_F_ERR (1<<0)
230 : u_int ccb_smid;
231 : u_int ccb_refcnt;
232 : SIMPLEQ_ENTRY(mfii_ccb) ccb_link;
233 : };
234 : SIMPLEQ_HEAD(mfii_ccb_list, mfii_ccb);
235 :
236 : struct mfii_pd_softc {
237 : struct scsi_link pd_link;
238 : struct scsibus_softc *pd_scsibus;
239 : struct srp pd_dev_handles;
240 : uint8_t pd_timeout;
241 : };
242 :
243 : struct mfii_iop {
244 : int bar;
245 : int num_sge_loc;
246 : #define MFII_IOP_NUM_SGE_LOC_ORIG 0
247 : #define MFII_IOP_NUM_SGE_LOC_35 1
248 : u_int16_t ldio_ctx_reg_lock_flags;
249 : u_int8_t ldio_req_type;
250 : u_int8_t ldio_ctx_type_nseg;
251 : u_int8_t sge_flag_chain;
252 : u_int8_t sge_flag_eol;
253 : };
254 :
255 : struct mfii_softc {
256 : struct device sc_dev;
257 : const struct mfii_iop *sc_iop;
258 :
259 : pci_chipset_tag_t sc_pc;
260 : pcitag_t sc_tag;
261 :
262 : bus_space_tag_t sc_iot;
263 : bus_space_handle_t sc_ioh;
264 : bus_size_t sc_ios;
265 : bus_dma_tag_t sc_dmat;
266 :
267 : void *sc_ih;
268 :
269 : struct mutex sc_ccb_mtx;
270 : struct mutex sc_post_mtx;
271 :
272 : u_int sc_max_fw_cmds;
273 : u_int sc_max_cmds;
274 : u_int sc_max_sgl;
275 :
276 : u_int sc_reply_postq_depth;
277 : u_int sc_reply_postq_index;
278 : struct mutex sc_reply_postq_mtx;
279 : struct mfii_dmamem *sc_reply_postq;
280 :
281 : struct mfii_dmamem *sc_requests;
282 : struct mfii_dmamem *sc_mfi;
283 : struct mfii_dmamem *sc_sense;
284 : struct mfii_dmamem *sc_sgl;
285 :
286 : struct mfii_ccb *sc_ccb;
287 : struct mfii_ccb_list sc_ccb_freeq;
288 :
289 : struct mfii_ccb *sc_aen_ccb;
290 : struct task sc_aen_task;
291 :
292 : struct mutex sc_abort_mtx;
293 : struct mfii_ccb_list sc_abort_list;
294 : struct task sc_abort_task;
295 :
296 : struct scsi_link sc_link;
297 : struct scsibus_softc *sc_scsibus;
298 : struct mfii_pd_softc *sc_pd;
299 : struct scsi_iopool sc_iopool;
300 :
301 : /* save some useful information for logical drives that is missing
302 : * in sc_ld_list
303 : */
304 : struct {
305 : char ld_dev[16]; /* device name sd? */
306 : } sc_ld[MFI_MAX_LD];
307 : int sc_target_lds[MFI_MAX_LD];
308 :
309 : /* scsi ioctl from sd device */
310 : int (*sc_ioctl)(struct device *, u_long, caddr_t);
311 :
312 : /* bio */
313 : struct mfi_conf *sc_cfg;
314 : struct mfi_ctrl_info sc_info;
315 : struct mfi_ld_list sc_ld_list;
316 : struct mfi_ld_details *sc_ld_details; /* array to all logical disks */
317 : int sc_no_pd; /* used physical disks */
318 : int sc_ld_sz; /* sizeof sc_ld_details */
319 :
320 : /* mgmt lock */
321 : struct rwlock sc_lock;
322 :
323 : /* sensors */
324 : struct ksensordev sc_sensordev;
325 : struct ksensor *sc_bbu;
326 : struct ksensor *sc_bbu_status;
327 : struct ksensor *sc_sensors;
328 : };
329 :
330 : #ifdef MFII_DEBUG
331 : #define DPRINTF(x...) do { if (mfii_debug) printf(x); } while(0)
332 : #define DNPRINTF(n,x...) do { if (mfii_debug & n) printf(x); } while(0)
333 : #define MFII_D_CMD 0x0001
334 : #define MFII_D_INTR 0x0002
335 : #define MFII_D_MISC 0x0004
336 : #define MFII_D_DMA 0x0008
337 : #define MFII_D_IOCTL 0x0010
338 : #define MFII_D_RW 0x0020
339 : #define MFII_D_MEM 0x0040
340 : #define MFII_D_CCB 0x0080
341 : uint32_t mfii_debug = 0
342 : /* | MFII_D_CMD */
343 : /* | MFII_D_INTR */
344 : | MFII_D_MISC
345 : /* | MFII_D_DMA */
346 : /* | MFII_D_IOCTL */
347 : /* | MFII_D_RW */
348 : /* | MFII_D_MEM */
349 : /* | MFII_D_CCB */
350 : ;
351 : #else
352 : #define DPRINTF(x...)
353 : #define DNPRINTF(n,x...)
354 : #endif
355 :
356 : int mfii_match(struct device *, void *, void *);
357 : void mfii_attach(struct device *, struct device *, void *);
358 : int mfii_detach(struct device *, int);
359 :
360 : struct cfattach mfii_ca = {
361 : sizeof(struct mfii_softc),
362 : mfii_match,
363 : mfii_attach,
364 : mfii_detach
365 : };
366 :
367 : struct cfdriver mfii_cd = {
368 : NULL,
369 : "mfii",
370 : DV_DULL
371 : };
372 :
373 : void mfii_scsi_cmd(struct scsi_xfer *);
374 : void mfii_scsi_cmd_done(struct mfii_softc *, struct mfii_ccb *);
375 : int mfii_scsi_ioctl(struct scsi_link *, u_long, caddr_t, int);
376 : int mfii_ioctl_cache(struct scsi_link *, u_long, struct dk_cache *);
377 :
378 : struct scsi_adapter mfii_switch = {
379 : mfii_scsi_cmd,
380 : scsi_minphys,
381 : NULL, /* probe */
382 : NULL, /* unprobe */
383 : mfii_scsi_ioctl
384 : };
385 :
386 : void mfii_pd_scsi_cmd(struct scsi_xfer *);
387 : int mfii_pd_scsi_probe(struct scsi_link *);
388 :
389 : struct scsi_adapter mfii_pd_switch = {
390 : mfii_pd_scsi_cmd,
391 : scsi_minphys,
392 : mfii_pd_scsi_probe
393 : };
394 :
395 : #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
396 :
397 : u_int32_t mfii_read(struct mfii_softc *, bus_size_t);
398 : void mfii_write(struct mfii_softc *, bus_size_t, u_int32_t);
399 :
400 : struct mfii_dmamem * mfii_dmamem_alloc(struct mfii_softc *, size_t);
401 : void mfii_dmamem_free(struct mfii_softc *,
402 : struct mfii_dmamem *);
403 :
404 : void * mfii_get_ccb(void *);
405 : void mfii_put_ccb(void *, void *);
406 : int mfii_init_ccb(struct mfii_softc *);
407 : void mfii_scrub_ccb(struct mfii_ccb *);
408 :
409 : int mfii_transition_firmware(struct mfii_softc *);
410 : int mfii_initialise_firmware(struct mfii_softc *);
411 : int mfii_get_info(struct mfii_softc *);
412 : int mfii_syspd(struct mfii_softc *);
413 :
414 : void mfii_start(struct mfii_softc *, struct mfii_ccb *);
415 : void mfii_done(struct mfii_softc *, struct mfii_ccb *);
416 : int mfii_poll(struct mfii_softc *, struct mfii_ccb *);
417 : void mfii_poll_done(struct mfii_softc *, struct mfii_ccb *);
418 : int mfii_exec(struct mfii_softc *, struct mfii_ccb *);
419 : void mfii_exec_done(struct mfii_softc *, struct mfii_ccb *);
420 : int mfii_my_intr(struct mfii_softc *);
421 : int mfii_intr(void *);
422 : void mfii_postq(struct mfii_softc *);
423 :
424 : int mfii_load_ccb(struct mfii_softc *, struct mfii_ccb *,
425 : void *, int);
426 : int mfii_load_mfa(struct mfii_softc *, struct mfii_ccb *,
427 : void *, int);
428 :
429 : int mfii_mfa_poll(struct mfii_softc *, struct mfii_ccb *);
430 :
431 : int mfii_mgmt(struct mfii_softc *, uint32_t,
432 : const union mfi_mbox *, void *, size_t, int);
433 : int mfii_do_mgmt(struct mfii_softc *, struct mfii_ccb *,
434 : uint32_t, const union mfi_mbox *, void *, size_t,
435 : int);
436 : void mfii_empty_done(struct mfii_softc *, struct mfii_ccb *);
437 :
438 : int mfii_scsi_cmd_io(struct mfii_softc *,
439 : struct scsi_xfer *);
440 : int mfii_scsi_cmd_cdb(struct mfii_softc *,
441 : struct scsi_xfer *);
442 : int mfii_pd_scsi_cmd_cdb(struct mfii_softc *,
443 : struct scsi_xfer *);
444 : void mfii_scsi_cmd_tmo(void *);
445 :
446 : int mfii_dev_handles_update(struct mfii_softc *sc);
447 : void mfii_dev_handles_dtor(void *, void *);
448 :
449 : void mfii_abort_task(void *);
450 : void mfii_abort(struct mfii_softc *, struct mfii_ccb *,
451 : uint16_t, uint16_t, uint8_t, uint32_t);
452 : void mfii_scsi_cmd_abort_done(struct mfii_softc *,
453 : struct mfii_ccb *);
454 :
455 : int mfii_aen_register(struct mfii_softc *);
456 : void mfii_aen_start(struct mfii_softc *, struct mfii_ccb *,
457 : struct mfii_dmamem *, uint32_t);
458 : void mfii_aen_done(struct mfii_softc *, struct mfii_ccb *);
459 : void mfii_aen(void *);
460 : void mfii_aen_unregister(struct mfii_softc *);
461 :
462 : void mfii_aen_pd_insert(struct mfii_softc *,
463 : const struct mfi_evtarg_pd_address *);
464 : void mfii_aen_pd_remove(struct mfii_softc *,
465 : const struct mfi_evtarg_pd_address *);
466 : void mfii_aen_pd_state_change(struct mfii_softc *,
467 : const struct mfi_evtarg_pd_state *);
468 : void mfii_aen_ld_update(struct mfii_softc *);
469 :
470 : #if NBIO > 0
471 : int mfii_ioctl(struct device *, u_long, caddr_t);
472 : int mfii_bio_getitall(struct mfii_softc *);
473 : int mfii_ioctl_inq(struct mfii_softc *, struct bioc_inq *);
474 : int mfii_ioctl_vol(struct mfii_softc *, struct bioc_vol *);
475 : int mfii_ioctl_disk(struct mfii_softc *, struct bioc_disk *);
476 : int mfii_ioctl_alarm(struct mfii_softc *, struct bioc_alarm *);
477 : int mfii_ioctl_blink(struct mfii_softc *sc, struct bioc_blink *);
478 : int mfii_ioctl_setstate(struct mfii_softc *,
479 : struct bioc_setstate *);
480 : int mfii_ioctl_patrol(struct mfii_softc *sc, struct bioc_patrol *);
481 : int mfii_bio_hs(struct mfii_softc *, int, int, void *);
482 :
483 : #ifndef SMALL_KERNEL
484 : static const char *mfi_bbu_indicators[] = {
485 : "pack missing",
486 : "voltage low",
487 : "temp high",
488 : "charge active",
489 : "discharge active",
490 : "learn cycle req'd",
491 : "learn cycle active",
492 : "learn cycle failed",
493 : "learn cycle timeout",
494 : "I2C errors",
495 : "replace pack",
496 : "low capacity",
497 : "periodic learn req'd"
498 : };
499 :
500 : void mfii_init_ld_sensor(struct mfii_softc *, int);
501 : void mfii_refresh_ld_sensor(struct mfii_softc *, int);
502 : int mfii_create_sensors(struct mfii_softc *);
503 : void mfii_refresh_sensors(void *);
504 : void mfii_bbu(struct mfii_softc *);
505 : #endif /* SMALL_KERNEL */
506 : #endif /* NBIO > 0 */
507 :
508 : /*
509 : * mfii boards support asynchronous (and non-polled) completion of
510 : * dcmds by proxying them through a passthru mpii command that points
511 : * at a dcmd frame. since the passthru command is submitted like
512 : * the scsi commands using an SMID in the request descriptor,
513 : * ccb_request memory * must contain the passthru command because
514 : * that is what the SMID refers to. this means ccb_request cannot
515 : * contain the dcmd. rather than allocating separate dma memory to
516 : * hold the dcmd, we reuse the sense memory buffer for it.
517 : */
518 :
519 : void mfii_dcmd_start(struct mfii_softc *,
520 : struct mfii_ccb *);
521 :
522 : static inline void
523 0 : mfii_dcmd_scrub(struct mfii_ccb *ccb)
524 : {
525 0 : memset(ccb->ccb_sense, 0, sizeof(*ccb->ccb_sense));
526 0 : }
527 :
528 : static inline struct mfi_dcmd_frame *
529 0 : mfii_dcmd_frame(struct mfii_ccb *ccb)
530 : {
531 : CTASSERT(sizeof(struct mfi_dcmd_frame) <= sizeof(*ccb->ccb_sense));
532 0 : return ((struct mfi_dcmd_frame *)ccb->ccb_sense);
533 : }
534 :
535 : static inline void
536 0 : mfii_dcmd_sync(struct mfii_softc *sc, struct mfii_ccb *ccb, int flags)
537 : {
538 0 : bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_sense),
539 : ccb->ccb_sense_offset, sizeof(*ccb->ccb_sense), flags);
540 0 : }
541 :
542 : #define mfii_fw_state(_sc) mfii_read((_sc), MFI_OSP)
543 :
544 : const struct mfii_iop mfii_iop_thunderbolt = {
545 : MFII_BAR,
546 : MFII_IOP_NUM_SGE_LOC_ORIG,
547 : 0,
548 : MFII_REQ_TYPE_LDIO,
549 : 0,
550 : MFII_SGE_CHAIN_ELEMENT | MFII_SGE_ADDR_IOCPLBNTA,
551 : 0
552 : };
553 :
554 : /*
555 : * a lot of these values depend on us not implementing fastpath yet.
556 : */
557 : const struct mfii_iop mfii_iop_25 = {
558 : MFII_BAR,
559 : MFII_IOP_NUM_SGE_LOC_ORIG,
560 : MFII_RAID_CTX_RL_FLAGS_CPU0, /* | MFII_RAID_CTX_RL_FLAGS_SEQNO_EN */
561 : MFII_REQ_TYPE_NO_LOCK,
562 : MFII_RAID_CTX_TYPE_CUDA | 0x1,
563 : MFII_SGE_CHAIN_ELEMENT,
564 : MFII_SGE_END_OF_LIST
565 : };
566 :
567 : const struct mfii_iop mfii_iop_35 = {
568 : MFII_BAR_35,
569 : MFII_IOP_NUM_SGE_LOC_35,
570 : MFII_RAID_CTX_ROUTING_FLAGS_CPU0, /* | MFII_RAID_CTX_ROUTING_FLAGS_SQN */
571 : MFII_REQ_TYPE_NO_LOCK,
572 : MFII_RAID_CTX_TYPE_CUDA | 0x1,
573 : MFII_SGE_CHAIN_ELEMENT,
574 : MFII_SGE_END_OF_LIST
575 : };
576 :
577 : struct mfii_device {
578 : pcireg_t mpd_vendor;
579 : pcireg_t mpd_product;
580 : const struct mfii_iop *mpd_iop;
581 : };
582 :
583 : const struct mfii_device mfii_devices[] = {
584 : { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_MEGARAID_2208,
585 : &mfii_iop_thunderbolt },
586 : { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_MEGARAID_3008,
587 : &mfii_iop_25 },
588 : { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_MEGARAID_3108,
589 : &mfii_iop_25 },
590 : { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_MEGARAID_3404,
591 : &mfii_iop_35 },
592 : { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_MEGARAID_3504,
593 : &mfii_iop_35 },
594 : { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_MEGARAID_3408,
595 : &mfii_iop_35 },
596 : { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_MEGARAID_3508,
597 : &mfii_iop_35 },
598 : { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_MEGARAID_3416,
599 : &mfii_iop_35 },
600 : { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_MEGARAID_3516,
601 : &mfii_iop_35 }
602 : };
603 :
604 : const struct mfii_iop *mfii_find_iop(struct pci_attach_args *);
605 :
606 : const struct mfii_iop *
607 0 : mfii_find_iop(struct pci_attach_args *pa)
608 : {
609 : const struct mfii_device *mpd;
610 : int i;
611 :
612 0 : for (i = 0; i < nitems(mfii_devices); i++) {
613 0 : mpd = &mfii_devices[i];
614 :
615 0 : if (mpd->mpd_vendor == PCI_VENDOR(pa->pa_id) &&
616 0 : mpd->mpd_product == PCI_PRODUCT(pa->pa_id))
617 0 : return (mpd->mpd_iop);
618 : }
619 :
620 0 : return (NULL);
621 0 : }
622 :
623 : int
624 0 : mfii_match(struct device *parent, void *match, void *aux)
625 : {
626 0 : return ((mfii_find_iop(aux) != NULL) ? 1 : 0);
627 : }
628 :
629 : void
630 0 : mfii_attach(struct device *parent, struct device *self, void *aux)
631 : {
632 0 : struct mfii_softc *sc = (struct mfii_softc *)self;
633 0 : struct pci_attach_args *pa = aux;
634 : pcireg_t memtype;
635 0 : pci_intr_handle_t ih;
636 0 : struct scsibus_attach_args saa;
637 : u_int32_t status, scpad2, scpad3;
638 : int chain_frame_sz, nsge_in_io, nsge_in_chain, i;
639 :
640 : /* init sc */
641 0 : sc->sc_iop = mfii_find_iop(aux);
642 0 : sc->sc_dmat = pa->pa_dmat;
643 0 : SIMPLEQ_INIT(&sc->sc_ccb_freeq);
644 0 : mtx_init(&sc->sc_ccb_mtx, IPL_BIO);
645 0 : mtx_init(&sc->sc_post_mtx, IPL_BIO);
646 0 : mtx_init(&sc->sc_reply_postq_mtx, IPL_BIO);
647 0 : scsi_iopool_init(&sc->sc_iopool, sc, mfii_get_ccb, mfii_put_ccb);
648 :
649 0 : rw_init(&sc->sc_lock, "mfii_lock");
650 :
651 0 : sc->sc_aen_ccb = NULL;
652 0 : task_set(&sc->sc_aen_task, mfii_aen, sc);
653 :
654 0 : mtx_init(&sc->sc_abort_mtx, IPL_BIO);
655 0 : SIMPLEQ_INIT(&sc->sc_abort_list);
656 0 : task_set(&sc->sc_abort_task, mfii_abort_task, sc);
657 :
658 : /* wire up the bus shizz */
659 0 : memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, sc->sc_iop->bar);
660 0 : if (pci_mapreg_map(pa, sc->sc_iop->bar, memtype, 0,
661 0 : &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_ios, MFII_PCI_MEMSIZE)) {
662 0 : printf(": unable to map registers\n");
663 0 : return;
664 : }
665 :
666 : /* disable interrupts */
667 0 : mfii_write(sc, MFI_OMSK, 0xffffffff);
668 :
669 0 : if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
670 0 : printf(": unable to map interrupt\n");
671 0 : goto pci_unmap;
672 : }
673 0 : printf(": %s\n", pci_intr_string(pa->pa_pc, ih));
674 :
675 : /* lets get started */
676 0 : if (mfii_transition_firmware(sc))
677 : goto pci_unmap;
678 :
679 : /* determine max_cmds (refer to the Linux megaraid_sas driver) */
680 0 : scpad3 = mfii_read(sc, MFII_OSP3);
681 0 : status = mfii_fw_state(sc);
682 0 : sc->sc_max_fw_cmds = scpad3 & MFI_STATE_MAXCMD_MASK;
683 0 : if (sc->sc_max_fw_cmds == 0)
684 0 : sc->sc_max_fw_cmds = status & MFI_STATE_MAXCMD_MASK;
685 : /*
686 : * reduce max_cmds by 1 to ensure that the reply queue depth does not
687 : * exceed FW supplied max_fw_cmds.
688 : */
689 0 : sc->sc_max_cmds = min(sc->sc_max_fw_cmds, 1024) - 1;
690 :
691 : /* determine max_sgl (refer to the Linux megaraid_sas driver) */
692 0 : scpad2 = mfii_read(sc, MFII_OSP2);
693 : chain_frame_sz =
694 0 : ((scpad2 & MFII_MAX_CHAIN_MASK) >> MFII_MAX_CHAIN_SHIFT) *
695 0 : ((scpad2 & MFII_MAX_CHAIN_UNIT) ? MFII_1MB_IO : MFII_256K_IO);
696 0 : if (chain_frame_sz < MFII_CHAIN_FRAME_MIN)
697 : chain_frame_sz = MFII_CHAIN_FRAME_MIN;
698 :
699 : nsge_in_io = (MFII_REQUEST_SIZE -
700 : sizeof(struct mpii_msg_scsi_io) -
701 : sizeof(struct mfii_raid_context)) / sizeof(struct mfii_sge);
702 0 : nsge_in_chain = chain_frame_sz / sizeof(struct mfii_sge);
703 :
704 : /* round down to nearest power of two */
705 0 : sc->sc_max_sgl = 1;
706 0 : while ((sc->sc_max_sgl << 1) <= (nsge_in_io + nsge_in_chain))
707 0 : sc->sc_max_sgl <<= 1;
708 :
709 : DNPRINTF(MFII_D_MISC, "%s: OSP 0x%08x, OSP2 0x%08x, OSP3 0x%08x\n",
710 : DEVNAME(sc), status, scpad2, scpad3);
711 : DNPRINTF(MFII_D_MISC, "%s: max_fw_cmds %d, max_cmds %d\n",
712 : DEVNAME(sc), sc->sc_max_fw_cmds, sc->sc_max_cmds);
713 : DNPRINTF(MFII_D_MISC, "%s: nsge_in_io %d, nsge_in_chain %d, "
714 : "max_sgl %d\n", DEVNAME(sc), nsge_in_io, nsge_in_chain,
715 : sc->sc_max_sgl);
716 :
717 : /* sense memory */
718 : CTASSERT(sizeof(struct mfi_sense) == MFI_SENSE_SIZE);
719 0 : sc->sc_sense = mfii_dmamem_alloc(sc, sc->sc_max_cmds * MFI_SENSE_SIZE);
720 0 : if (sc->sc_sense == NULL) {
721 0 : printf("%s: unable to allocate sense memory\n", DEVNAME(sc));
722 0 : goto pci_unmap;
723 : }
724 :
725 : /* reply post queue */
726 0 : sc->sc_reply_postq_depth = roundup(sc->sc_max_fw_cmds, 16);
727 :
728 0 : sc->sc_reply_postq = mfii_dmamem_alloc(sc,
729 0 : sc->sc_reply_postq_depth * sizeof(struct mpii_reply_descr));
730 0 : if (sc->sc_reply_postq == NULL)
731 : goto free_sense;
732 :
733 0 : memset(MFII_DMA_KVA(sc->sc_reply_postq), 0xff,
734 : MFII_DMA_LEN(sc->sc_reply_postq));
735 :
736 : /* MPII request frame array */
737 0 : sc->sc_requests = mfii_dmamem_alloc(sc,
738 0 : MFII_REQUEST_SIZE * (sc->sc_max_cmds + 1));
739 0 : if (sc->sc_requests == NULL)
740 : goto free_reply_postq;
741 :
742 : /* MFI command frame array */
743 0 : sc->sc_mfi = mfii_dmamem_alloc(sc, sc->sc_max_cmds * MFI_FRAME_SIZE);
744 0 : if (sc->sc_mfi == NULL)
745 : goto free_requests;
746 :
747 : /* MPII SGL array */
748 0 : sc->sc_sgl = mfii_dmamem_alloc(sc, sc->sc_max_cmds *
749 0 : sizeof(struct mfii_sge) * sc->sc_max_sgl);
750 0 : if (sc->sc_sgl == NULL)
751 : goto free_mfi;
752 :
753 0 : if (mfii_init_ccb(sc) != 0) {
754 0 : printf("%s: could not init ccb list\n", DEVNAME(sc));
755 0 : goto free_sgl;
756 : }
757 :
758 : /* kickstart firmware with all addresses and pointers */
759 0 : if (mfii_initialise_firmware(sc) != 0) {
760 0 : printf("%s: could not initialize firmware\n", DEVNAME(sc));
761 0 : goto free_sgl;
762 : }
763 :
764 0 : if (mfii_get_info(sc) != 0) {
765 0 : printf("%s: could not retrieve controller information\n",
766 : DEVNAME(sc));
767 0 : goto free_sgl;
768 : }
769 :
770 0 : printf("%s: \"%s\", firmware %s", DEVNAME(sc),
771 0 : sc->sc_info.mci_product_name, sc->sc_info.mci_package_version);
772 0 : if (letoh16(sc->sc_info.mci_memory_size) > 0)
773 0 : printf(", %uMB cache", letoh16(sc->sc_info.mci_memory_size));
774 0 : printf("\n");
775 :
776 0 : sc->sc_ih = pci_intr_establish(sc->sc_pc, ih, IPL_BIO,
777 : mfii_intr, sc, DEVNAME(sc));
778 0 : if (sc->sc_ih == NULL)
779 : goto free_sgl;
780 :
781 0 : sc->sc_link.openings = sc->sc_max_cmds;
782 0 : sc->sc_link.adapter_softc = sc;
783 0 : sc->sc_link.adapter = &mfii_switch;
784 0 : sc->sc_link.adapter_target = sc->sc_info.mci_max_lds;
785 0 : sc->sc_link.adapter_buswidth = sc->sc_info.mci_max_lds;
786 0 : sc->sc_link.pool = &sc->sc_iopool;
787 :
788 0 : memset(&saa, 0, sizeof(saa));
789 0 : saa.saa_sc_link = &sc->sc_link;
790 :
791 0 : sc->sc_scsibus = (struct scsibus_softc *)
792 0 : config_found(&sc->sc_dev, &saa, scsiprint);
793 :
794 0 : mfii_syspd(sc);
795 :
796 0 : if (mfii_aen_register(sc) != 0) {
797 : /* error printed by mfii_aen_register */
798 : goto intr_disestablish;
799 : }
800 :
801 0 : if (mfii_mgmt(sc, MR_DCMD_LD_GET_LIST, NULL, &sc->sc_ld_list,
802 0 : sizeof(sc->sc_ld_list), SCSI_DATA_IN) != 0) {
803 0 : printf("%s: getting list of logical disks failed\n", DEVNAME(sc));
804 0 : goto intr_disestablish;
805 : }
806 0 : memset(sc->sc_target_lds, -1, sizeof(sc->sc_target_lds));
807 0 : for (i = 0; i < sc->sc_ld_list.mll_no_ld; i++) {
808 0 : int target = sc->sc_ld_list.mll_list[i].mll_ld.mld_target;
809 0 : sc->sc_target_lds[target] = i;
810 : }
811 :
812 : /* enable interrupts */
813 0 : mfii_write(sc, MFI_OSTS, 0xffffffff);
814 0 : mfii_write(sc, MFI_OMSK, ~MFII_OSTS_INTR_VALID);
815 :
816 : #if NBIO > 0
817 0 : if (bio_register(&sc->sc_dev, mfii_ioctl) != 0)
818 0 : panic("%s: controller registration failed", DEVNAME(sc));
819 : else
820 0 : sc->sc_ioctl = mfii_ioctl;
821 :
822 : #ifndef SMALL_KERNEL
823 0 : if (mfii_create_sensors(sc) != 0)
824 0 : printf("%s: unable to create sensors\n", DEVNAME(sc));
825 : #endif
826 : #endif /* NBIO > 0 */
827 :
828 0 : return;
829 : intr_disestablish:
830 0 : pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
831 : free_sgl:
832 0 : mfii_dmamem_free(sc, sc->sc_sgl);
833 : free_mfi:
834 0 : mfii_dmamem_free(sc, sc->sc_mfi);
835 : free_requests:
836 0 : mfii_dmamem_free(sc, sc->sc_requests);
837 : free_reply_postq:
838 0 : mfii_dmamem_free(sc, sc->sc_reply_postq);
839 : free_sense:
840 0 : mfii_dmamem_free(sc, sc->sc_sense);
841 : pci_unmap:
842 0 : bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
843 0 : }
844 :
845 : struct srp_gc mfii_dev_handles_gc =
846 : SRP_GC_INITIALIZER(mfii_dev_handles_dtor, NULL);
847 :
848 : static inline uint16_t
849 0 : mfii_dev_handle(struct mfii_softc *sc, uint16_t target)
850 : {
851 0 : struct srp_ref sr;
852 : uint16_t *map, handle;
853 :
854 0 : map = srp_enter(&sr, &sc->sc_pd->pd_dev_handles);
855 0 : handle = map[target];
856 0 : srp_leave(&sr);
857 :
858 0 : return (handle);
859 0 : }
860 :
861 : int
862 0 : mfii_dev_handles_update(struct mfii_softc *sc)
863 : {
864 : struct mfii_ld_map *lm;
865 : uint16_t *dev_handles = NULL;
866 : int i;
867 : int rv = 0;
868 :
869 0 : lm = malloc(sizeof(*lm), M_TEMP, M_WAITOK|M_ZERO);
870 :
871 0 : rv = mfii_mgmt(sc, MR_DCMD_LD_MAP_GET_INFO, NULL, lm, sizeof(*lm),
872 : SCSI_DATA_IN|SCSI_NOSLEEP);
873 :
874 0 : if (rv != 0) {
875 : rv = EIO;
876 0 : goto free_lm;
877 : }
878 :
879 0 : dev_handles = mallocarray(MFI_MAX_PD, sizeof(*dev_handles),
880 : M_DEVBUF, M_WAITOK);
881 :
882 0 : for (i = 0; i < MFI_MAX_PD; i++)
883 0 : dev_handles[i] = lm->mlm_dev_handle[i].mdh_cur_handle;
884 :
885 : /* commit the updated info */
886 0 : sc->sc_pd->pd_timeout = lm->mlm_pd_timeout;
887 0 : srp_update_locked(&mfii_dev_handles_gc,
888 0 : &sc->sc_pd->pd_dev_handles, dev_handles);
889 :
890 : free_lm:
891 0 : free(lm, M_TEMP, sizeof(*lm));
892 :
893 0 : return (rv);
894 : }
895 :
896 : void
897 0 : mfii_dev_handles_dtor(void *null, void *v)
898 : {
899 0 : uint16_t *dev_handles = v;
900 :
901 0 : free(dev_handles, M_DEVBUF, sizeof(*dev_handles) * MFI_MAX_PD);
902 0 : }
903 :
904 : int
905 0 : mfii_syspd(struct mfii_softc *sc)
906 : {
907 0 : struct scsibus_attach_args saa;
908 : struct scsi_link *link;
909 :
910 0 : sc->sc_pd = malloc(sizeof(*sc->sc_pd), M_DEVBUF, M_WAITOK|M_ZERO);
911 0 : if (sc->sc_pd == NULL)
912 0 : return (1);
913 :
914 0 : srp_init(&sc->sc_pd->pd_dev_handles);
915 0 : if (mfii_dev_handles_update(sc) != 0)
916 : goto free_pdsc;
917 :
918 0 : link = &sc->sc_pd->pd_link;
919 0 : link->adapter = &mfii_pd_switch;
920 0 : link->adapter_softc = sc;
921 0 : link->adapter_buswidth = MFI_MAX_PD;
922 0 : link->adapter_target = -1;
923 0 : link->openings = sc->sc_max_cmds - 1;
924 0 : link->pool = &sc->sc_iopool;
925 :
926 0 : memset(&saa, 0, sizeof(saa));
927 0 : saa.saa_sc_link = link;
928 :
929 0 : sc->sc_pd->pd_scsibus = (struct scsibus_softc *)
930 0 : config_found(&sc->sc_dev, &saa, scsiprint);
931 :
932 0 : return (0);
933 :
934 : free_pdsc:
935 0 : free(sc->sc_pd, M_DEVBUF, sizeof(*sc->sc_pd));
936 0 : return (1);
937 0 : }
938 :
939 : int
940 0 : mfii_detach(struct device *self, int flags)
941 : {
942 0 : struct mfii_softc *sc = (struct mfii_softc *)self;
943 :
944 0 : if (sc->sc_ih == NULL)
945 0 : return (0);
946 :
947 : #ifndef SMALL_KERNEL
948 0 : if (sc->sc_sensors) {
949 0 : sensordev_deinstall(&sc->sc_sensordev);
950 0 : free(sc->sc_sensors, M_DEVBUF,
951 : MFI_MAX_LD * sizeof(struct ksensor));
952 0 : }
953 :
954 0 : if (sc->sc_bbu) {
955 0 : free(sc->sc_bbu, M_DEVBUF, 4 * sizeof(*sc->sc_bbu));
956 0 : }
957 :
958 0 : if (sc->sc_bbu_status) {
959 0 : free(sc->sc_bbu_status, M_DEVBUF,
960 : sizeof(*sc->sc_bbu_status) * sizeof(mfi_bbu_indicators));
961 0 : }
962 : #endif /* SMALL_KERNEL */
963 :
964 0 : mfii_aen_unregister(sc);
965 0 : pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
966 0 : mfii_dmamem_free(sc, sc->sc_sgl);
967 0 : mfii_dmamem_free(sc, sc->sc_mfi);
968 0 : mfii_dmamem_free(sc, sc->sc_requests);
969 0 : mfii_dmamem_free(sc, sc->sc_reply_postq);
970 0 : mfii_dmamem_free(sc, sc->sc_sense);
971 0 : bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
972 :
973 0 : return (0);
974 0 : }
975 :
976 : u_int32_t
977 0 : mfii_read(struct mfii_softc *sc, bus_size_t r)
978 : {
979 0 : bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
980 : BUS_SPACE_BARRIER_READ);
981 0 : return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, r));
982 : }
983 :
984 : void
985 0 : mfii_write(struct mfii_softc *sc, bus_size_t r, u_int32_t v)
986 : {
987 0 : bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v);
988 0 : bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
989 : BUS_SPACE_BARRIER_WRITE);
990 0 : }
991 :
992 : struct mfii_dmamem *
993 0 : mfii_dmamem_alloc(struct mfii_softc *sc, size_t size)
994 : {
995 : struct mfii_dmamem *m;
996 0 : int nsegs;
997 :
998 0 : m = malloc(sizeof(*m), M_DEVBUF, M_NOWAIT | M_ZERO);
999 0 : if (m == NULL)
1000 0 : return (NULL);
1001 :
1002 0 : m->mdm_size = size;
1003 :
1004 0 : if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
1005 0 : BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &m->mdm_map) != 0)
1006 : goto mdmfree;
1007 :
1008 0 : if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &m->mdm_seg, 1,
1009 0 : &nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO) != 0)
1010 : goto destroy;
1011 :
1012 0 : if (bus_dmamem_map(sc->sc_dmat, &m->mdm_seg, nsegs, size, &m->mdm_kva,
1013 0 : BUS_DMA_NOWAIT) != 0)
1014 : goto free;
1015 :
1016 0 : if (bus_dmamap_load(sc->sc_dmat, m->mdm_map, m->mdm_kva, size, NULL,
1017 0 : BUS_DMA_NOWAIT) != 0)
1018 : goto unmap;
1019 :
1020 0 : return (m);
1021 :
1022 : unmap:
1023 0 : bus_dmamem_unmap(sc->sc_dmat, m->mdm_kva, m->mdm_size);
1024 : free:
1025 0 : bus_dmamem_free(sc->sc_dmat, &m->mdm_seg, 1);
1026 : destroy:
1027 0 : bus_dmamap_destroy(sc->sc_dmat, m->mdm_map);
1028 : mdmfree:
1029 0 : free(m, M_DEVBUF, sizeof *m);
1030 :
1031 0 : return (NULL);
1032 0 : }
1033 :
1034 : void
1035 0 : mfii_dmamem_free(struct mfii_softc *sc, struct mfii_dmamem *m)
1036 : {
1037 0 : bus_dmamap_unload(sc->sc_dmat, m->mdm_map);
1038 0 : bus_dmamem_unmap(sc->sc_dmat, m->mdm_kva, m->mdm_size);
1039 0 : bus_dmamem_free(sc->sc_dmat, &m->mdm_seg, 1);
1040 0 : bus_dmamap_destroy(sc->sc_dmat, m->mdm_map);
1041 0 : free(m, M_DEVBUF, sizeof *m);
1042 0 : }
1043 :
1044 : void
1045 0 : mfii_dcmd_start(struct mfii_softc *sc, struct mfii_ccb *ccb)
1046 : {
1047 0 : struct mpii_msg_scsi_io *io = ccb->ccb_request;
1048 0 : struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
1049 0 : struct mfii_sge *sge = (struct mfii_sge *)(ctx + 1);
1050 :
1051 0 : io->function = MFII_FUNCTION_PASSTHRU_IO;
1052 0 : io->sgl_offset0 = (uint32_t *)sge - (uint32_t *)io;
1053 0 : io->chain_offset = io->sgl_offset0 / 4;
1054 :
1055 0 : htolem64(&sge->sg_addr, ccb->ccb_sense_dva);
1056 0 : htolem32(&sge->sg_len, sizeof(*ccb->ccb_sense));
1057 0 : sge->sg_flags = MFII_SGE_CHAIN_ELEMENT | MFII_SGE_ADDR_IOCPLBNTA;
1058 :
1059 0 : ccb->ccb_req.flags = MFII_REQ_TYPE_SCSI;
1060 0 : ccb->ccb_req.smid = letoh16(ccb->ccb_smid);
1061 :
1062 0 : mfii_start(sc, ccb);
1063 0 : }
1064 :
1065 : int
1066 0 : mfii_aen_register(struct mfii_softc *sc)
1067 : {
1068 0 : struct mfi_evt_log_info mel;
1069 : struct mfii_ccb *ccb;
1070 : struct mfii_dmamem *mdm;
1071 : int rv;
1072 :
1073 0 : ccb = scsi_io_get(&sc->sc_iopool, SCSI_NOSLEEP);
1074 0 : if (ccb == NULL) {
1075 0 : printf("%s: unable to allocate ccb for aen\n", DEVNAME(sc));
1076 0 : return (ENOMEM);
1077 : }
1078 :
1079 0 : memset(&mel, 0, sizeof(mel));
1080 0 : mfii_scrub_ccb(ccb);
1081 :
1082 0 : rv = mfii_do_mgmt(sc, ccb, MR_DCMD_CTRL_EVENT_GET_INFO, NULL,
1083 : &mel, sizeof(mel), SCSI_DATA_IN|SCSI_NOSLEEP);
1084 0 : if (rv != 0) {
1085 0 : scsi_io_put(&sc->sc_iopool, ccb);
1086 0 : printf("%s: unable to get event info\n", DEVNAME(sc));
1087 0 : return (EIO);
1088 : }
1089 :
1090 0 : mdm = mfii_dmamem_alloc(sc, sizeof(struct mfi_evt_detail));
1091 0 : if (mdm == NULL) {
1092 0 : scsi_io_put(&sc->sc_iopool, ccb);
1093 0 : printf("%s: unable to allocate event data\n", DEVNAME(sc));
1094 0 : return (ENOMEM);
1095 : }
1096 :
1097 : /* replay all the events from boot */
1098 0 : mfii_aen_start(sc, ccb, mdm, lemtoh32(&mel.mel_boot_seq_num));
1099 :
1100 0 : return (0);
1101 0 : }
1102 :
1103 : void
1104 0 : mfii_aen_start(struct mfii_softc *sc, struct mfii_ccb *ccb,
1105 : struct mfii_dmamem *mdm, uint32_t seq)
1106 : {
1107 0 : struct mfi_dcmd_frame *dcmd = mfii_dcmd_frame(ccb);
1108 0 : struct mfi_frame_header *hdr = &dcmd->mdf_header;
1109 0 : union mfi_sgl *sgl = &dcmd->mdf_sgl;
1110 : union mfi_evt_class_locale mec;
1111 :
1112 0 : mfii_scrub_ccb(ccb);
1113 0 : mfii_dcmd_scrub(ccb);
1114 0 : memset(MFII_DMA_KVA(mdm), 0, MFII_DMA_LEN(mdm));
1115 :
1116 0 : ccb->ccb_cookie = mdm;
1117 0 : ccb->ccb_done = mfii_aen_done;
1118 0 : sc->sc_aen_ccb = ccb;
1119 :
1120 : mec.mec_members.class = MFI_EVT_CLASS_DEBUG;
1121 : mec.mec_members.reserved = 0;
1122 : mec.mec_members.locale = htole16(MFI_EVT_LOCALE_ALL);
1123 :
1124 0 : hdr->mfh_cmd = MFI_CMD_DCMD;
1125 0 : hdr->mfh_sg_count = 1;
1126 0 : hdr->mfh_flags = htole16(MFI_FRAME_DIR_READ | MFI_FRAME_SGL64);
1127 0 : htolem32(&hdr->mfh_data_len, MFII_DMA_LEN(mdm));
1128 0 : dcmd->mdf_opcode = htole32(MR_DCMD_CTRL_EVENT_WAIT);
1129 0 : htolem32(&dcmd->mdf_mbox.w[0], seq);
1130 0 : htolem32(&dcmd->mdf_mbox.w[1], mec.mec_word);
1131 0 : htolem64(&sgl->sg64[0].addr, MFII_DMA_DVA(mdm));
1132 0 : htolem32(&sgl->sg64[0].len, MFII_DMA_LEN(mdm));
1133 :
1134 0 : bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(mdm),
1135 : 0, MFII_DMA_LEN(mdm), BUS_DMASYNC_PREREAD);
1136 :
1137 0 : mfii_dcmd_sync(sc, ccb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
1138 0 : mfii_dcmd_start(sc, ccb);
1139 0 : }
1140 :
1141 : void
1142 0 : mfii_aen_done(struct mfii_softc *sc, struct mfii_ccb *ccb)
1143 : {
1144 0 : KASSERT(sc->sc_aen_ccb == ccb);
1145 :
1146 : /* defer to a thread with KERNEL_LOCK so we can run autoconf */
1147 0 : task_add(systq, &sc->sc_aen_task);
1148 0 : }
1149 :
1150 : void
1151 0 : mfii_aen(void *arg)
1152 : {
1153 0 : struct mfii_softc *sc = arg;
1154 0 : struct mfii_ccb *ccb = sc->sc_aen_ccb;
1155 0 : struct mfii_dmamem *mdm = ccb->ccb_cookie;
1156 0 : const struct mfi_evt_detail *med = MFII_DMA_KVA(mdm);
1157 :
1158 0 : mfii_dcmd_sync(sc, ccb,
1159 : BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
1160 0 : bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(mdm),
1161 : 0, MFII_DMA_LEN(mdm), BUS_DMASYNC_POSTREAD);
1162 :
1163 : #if 0
1164 : printf("%s: %u %08x %02x %s\n", DEVNAME(sc),
1165 : lemtoh32(&med->med_seq_num), lemtoh32(&med->med_code),
1166 : med->med_arg_type, med->med_description);
1167 : #endif
1168 :
1169 0 : switch (lemtoh32(&med->med_code)) {
1170 : case MFI_EVT_PD_INSERTED_EXT:
1171 0 : if (med->med_arg_type != MFI_EVT_ARGS_PD_ADDRESS)
1172 : break;
1173 :
1174 0 : mfii_aen_pd_insert(sc, &med->args.pd_address);
1175 0 : break;
1176 : case MFI_EVT_PD_REMOVED_EXT:
1177 0 : if (med->med_arg_type != MFI_EVT_ARGS_PD_ADDRESS)
1178 : break;
1179 :
1180 0 : mfii_aen_pd_remove(sc, &med->args.pd_address);
1181 0 : break;
1182 :
1183 : case MFI_EVT_PD_STATE_CHANGE:
1184 0 : if (med->med_arg_type != MFI_EVT_ARGS_PD_STATE)
1185 : break;
1186 :
1187 0 : mfii_aen_pd_state_change(sc, &med->args.pd_state);
1188 0 : break;
1189 :
1190 : case MFI_EVT_LD_CREATED:
1191 : case MFI_EVT_LD_DELETED:
1192 0 : mfii_aen_ld_update(sc);
1193 0 : break;
1194 :
1195 : default:
1196 : break;
1197 : }
1198 :
1199 0 : mfii_aen_start(sc, ccb, mdm, lemtoh32(&med->med_seq_num) + 1);
1200 0 : }
1201 :
1202 : void
1203 0 : mfii_aen_pd_insert(struct mfii_softc *sc,
1204 : const struct mfi_evtarg_pd_address *pd)
1205 : {
1206 : #if 0
1207 : printf("%s: pd inserted ext\n", DEVNAME(sc));
1208 : printf("%s: device_id %04x encl_id: %04x type %x\n", DEVNAME(sc),
1209 : lemtoh16(&pd->device_id), lemtoh16(&pd->encl_id),
1210 : pd->scsi_dev_type);
1211 : printf("%s: connected %02x addrs %016llx %016llx\n", DEVNAME(sc),
1212 : pd->connected.port_bitmap, lemtoh64(&pd->sas_addr[0]),
1213 : lemtoh64(&pd->sas_addr[1]));
1214 : #endif
1215 :
1216 0 : if (mfii_dev_handles_update(sc) != 0) /* refresh map */
1217 : return;
1218 :
1219 0 : scsi_probe_target(sc->sc_pd->pd_scsibus, lemtoh16(&pd->device_id));
1220 0 : }
1221 :
1222 : void
1223 0 : mfii_aen_pd_remove(struct mfii_softc *sc,
1224 : const struct mfi_evtarg_pd_address *pd)
1225 : {
1226 : #if 0
1227 : printf("%s: pd removed ext\n", DEVNAME(sc));
1228 : printf("%s: device_id %04x encl_id: %04x type %u\n", DEVNAME(sc),
1229 : lemtoh16(&pd->device_id), lemtoh16(&pd->encl_id),
1230 : pd->scsi_dev_type);
1231 : printf("%s: connected %02x addrs %016llx %016llx\n", DEVNAME(sc),
1232 : pd->connected.port_bitmap, lemtoh64(&pd->sas_addr[0]),
1233 : lemtoh64(&pd->sas_addr[1]));
1234 : #endif
1235 0 : uint16_t target = lemtoh16(&pd->device_id);
1236 :
1237 0 : scsi_activate(sc->sc_pd->pd_scsibus, target, -1, DVACT_DEACTIVATE);
1238 :
1239 : /* the firmware will abort outstanding commands for us */
1240 :
1241 0 : scsi_detach_target(sc->sc_pd->pd_scsibus, target, DETACH_FORCE);
1242 0 : }
1243 :
1244 : void
1245 0 : mfii_aen_pd_state_change(struct mfii_softc *sc,
1246 : const struct mfi_evtarg_pd_state *state)
1247 : {
1248 0 : uint16_t target = lemtoh16(&state->pd.mep_device_id);
1249 :
1250 0 : if (state->prev_state == htole32(MFI_PD_SYSTEM) &&
1251 0 : state->new_state != htole32(MFI_PD_SYSTEM)) {
1252 : /* it's been pulled or configured for raid */
1253 :
1254 0 : scsi_activate(sc->sc_pd->pd_scsibus, target, -1,
1255 : DVACT_DEACTIVATE);
1256 : /* outstanding commands will simply complete or get aborted */
1257 0 : scsi_detach_target(sc->sc_pd->pd_scsibus, target,
1258 : DETACH_FORCE);
1259 :
1260 0 : } else if (state->prev_state == htole32(MFI_PD_UNCONFIG_GOOD) &&
1261 0 : state->new_state == htole32(MFI_PD_SYSTEM)) {
1262 : /* the firmware is handing the disk over */
1263 :
1264 0 : scsi_probe_target(sc->sc_pd->pd_scsibus, target);
1265 0 : }
1266 0 : }
1267 :
1268 : void
1269 0 : mfii_aen_ld_update(struct mfii_softc *sc)
1270 : {
1271 : int i, state, target, old, nld;
1272 0 : int newlds[MFI_MAX_LD];
1273 :
1274 0 : if (mfii_mgmt(sc, MR_DCMD_LD_GET_LIST, NULL, &sc->sc_ld_list,
1275 0 : sizeof(sc->sc_ld_list), SCSI_DATA_IN) != 0) {
1276 : DNPRINTF(MFII_D_MISC, "%s: getting list of logical disks failed\n",
1277 : DEVNAME(sc));
1278 0 : return;
1279 : }
1280 :
1281 0 : memset(newlds, -1, sizeof(newlds));
1282 :
1283 0 : for (i = 0; i < sc->sc_ld_list.mll_no_ld; i++) {
1284 0 : state = sc->sc_ld_list.mll_list[i].mll_state;
1285 0 : target = sc->sc_ld_list.mll_list[i].mll_ld.mld_target;
1286 : DNPRINTF(MFII_D_MISC, "%s: target %d: state %d\n",
1287 : DEVNAME(sc), target, state);
1288 0 : newlds[target] = i;
1289 : }
1290 :
1291 0 : for (i = 0; i < MFI_MAX_LD; i++) {
1292 0 : old = sc->sc_target_lds[i];
1293 0 : nld = newlds[i];
1294 :
1295 0 : if (old == -1 && nld != -1) {
1296 : DNPRINTF(MFII_D_MISC, "%s: attaching target %d\n",
1297 : DEVNAME(sc), i);
1298 :
1299 0 : scsi_probe_target(sc->sc_scsibus, i);
1300 :
1301 : #ifndef SMALL_KERNEL
1302 0 : mfii_init_ld_sensor(sc, nld);
1303 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
1304 : #endif
1305 0 : } else if (nld == -1 && old != -1) {
1306 : DNPRINTF(MFII_D_MISC, "%s: detaching target %d\n",
1307 : DEVNAME(sc), i);
1308 :
1309 0 : scsi_activate(sc->sc_scsibus, i, -1,
1310 : DVACT_DEACTIVATE);
1311 0 : scsi_detach_target(sc->sc_scsibus, i,
1312 : DETACH_FORCE);
1313 : #ifndef SMALL_KERNEL
1314 0 : sensor_detach(&sc->sc_sensordev, &sc->sc_sensors[i]);
1315 : #endif
1316 0 : }
1317 : }
1318 :
1319 0 : memcpy(sc->sc_target_lds, newlds, sizeof(sc->sc_target_lds));
1320 0 : }
1321 :
1322 : void
1323 0 : mfii_aen_unregister(struct mfii_softc *sc)
1324 : {
1325 : /* XXX */
1326 0 : }
1327 :
1328 : int
1329 0 : mfii_transition_firmware(struct mfii_softc *sc)
1330 : {
1331 : int32_t fw_state, cur_state;
1332 : int max_wait, i;
1333 :
1334 0 : fw_state = mfii_fw_state(sc) & MFI_STATE_MASK;
1335 :
1336 0 : while (fw_state != MFI_STATE_READY) {
1337 : cur_state = fw_state;
1338 0 : switch (fw_state) {
1339 : case MFI_STATE_FAULT:
1340 0 : printf("%s: firmware fault\n", DEVNAME(sc));
1341 0 : return (1);
1342 : case MFI_STATE_WAIT_HANDSHAKE:
1343 0 : mfii_write(sc, MFI_SKINNY_IDB,
1344 : MFI_INIT_CLEAR_HANDSHAKE);
1345 : max_wait = 2;
1346 0 : break;
1347 : case MFI_STATE_OPERATIONAL:
1348 0 : mfii_write(sc, MFI_SKINNY_IDB, MFI_INIT_READY);
1349 : max_wait = 10;
1350 0 : break;
1351 : case MFI_STATE_UNDEFINED:
1352 : case MFI_STATE_BB_INIT:
1353 : max_wait = 2;
1354 0 : break;
1355 : case MFI_STATE_FW_INIT:
1356 : case MFI_STATE_DEVICE_SCAN:
1357 : case MFI_STATE_FLUSH_CACHE:
1358 : max_wait = 20;
1359 0 : break;
1360 : default:
1361 0 : printf("%s: unknown firmware state %d\n",
1362 0 : DEVNAME(sc), fw_state);
1363 0 : return (1);
1364 : }
1365 0 : for (i = 0; i < (max_wait * 10); i++) {
1366 0 : fw_state = mfii_fw_state(sc) & MFI_STATE_MASK;
1367 0 : if (fw_state == cur_state)
1368 0 : DELAY(100000);
1369 : else
1370 : break;
1371 : }
1372 0 : if (fw_state == cur_state) {
1373 0 : printf("%s: firmware stuck in state %#x\n",
1374 0 : DEVNAME(sc), fw_state);
1375 0 : return (1);
1376 : }
1377 : }
1378 :
1379 0 : return (0);
1380 0 : }
1381 :
1382 : int
1383 0 : mfii_get_info(struct mfii_softc *sc)
1384 : {
1385 : int i, rv;
1386 :
1387 0 : rv = mfii_mgmt(sc, MR_DCMD_CTRL_GET_INFO, NULL, &sc->sc_info,
1388 : sizeof(sc->sc_info), SCSI_DATA_IN|SCSI_NOSLEEP);
1389 :
1390 0 : if (rv != 0)
1391 0 : return (rv);
1392 :
1393 0 : for (i = 0; i < sc->sc_info.mci_image_component_count; i++) {
1394 : DPRINTF("%s: active FW %s Version %s date %s time %s\n",
1395 : DEVNAME(sc),
1396 : sc->sc_info.mci_image_component[i].mic_name,
1397 : sc->sc_info.mci_image_component[i].mic_version,
1398 : sc->sc_info.mci_image_component[i].mic_build_date,
1399 : sc->sc_info.mci_image_component[i].mic_build_time);
1400 : }
1401 :
1402 0 : for (i = 0; i < sc->sc_info.mci_pending_image_component_count; i++) {
1403 : DPRINTF("%s: pending FW %s Version %s date %s time %s\n",
1404 : DEVNAME(sc),
1405 : sc->sc_info.mci_pending_image_component[i].mic_name,
1406 : sc->sc_info.mci_pending_image_component[i].mic_version,
1407 : sc->sc_info.mci_pending_image_component[i].mic_build_date,
1408 : sc->sc_info.mci_pending_image_component[i].mic_build_time);
1409 : }
1410 :
1411 : DPRINTF("%s: max_arms %d max_spans %d max_arrs %d max_lds %d name %s\n",
1412 : DEVNAME(sc),
1413 : sc->sc_info.mci_max_arms,
1414 : sc->sc_info.mci_max_spans,
1415 : sc->sc_info.mci_max_arrays,
1416 : sc->sc_info.mci_max_lds,
1417 : sc->sc_info.mci_product_name);
1418 :
1419 : DPRINTF("%s: serial %s present %#x fw time %d max_cmds %d max_sg %d\n",
1420 : DEVNAME(sc),
1421 : sc->sc_info.mci_serial_number,
1422 : sc->sc_info.mci_hw_present,
1423 : sc->sc_info.mci_current_fw_time,
1424 : sc->sc_info.mci_max_cmds,
1425 : sc->sc_info.mci_max_sg_elements);
1426 :
1427 : DPRINTF("%s: max_rq %d lds_pres %d lds_deg %d lds_off %d pd_pres %d\n",
1428 : DEVNAME(sc),
1429 : sc->sc_info.mci_max_request_size,
1430 : sc->sc_info.mci_lds_present,
1431 : sc->sc_info.mci_lds_degraded,
1432 : sc->sc_info.mci_lds_offline,
1433 : sc->sc_info.mci_pd_present);
1434 :
1435 : DPRINTF("%s: pd_dsk_prs %d pd_dsk_pred_fail %d pd_dsk_fail %d\n",
1436 : DEVNAME(sc),
1437 : sc->sc_info.mci_pd_disks_present,
1438 : sc->sc_info.mci_pd_disks_pred_failure,
1439 : sc->sc_info.mci_pd_disks_failed);
1440 :
1441 : DPRINTF("%s: nvram %d mem %d flash %d\n",
1442 : DEVNAME(sc),
1443 : sc->sc_info.mci_nvram_size,
1444 : sc->sc_info.mci_memory_size,
1445 : sc->sc_info.mci_flash_size);
1446 :
1447 : DPRINTF("%s: ram_cor %d ram_uncor %d clus_all %d clus_act %d\n",
1448 : DEVNAME(sc),
1449 : sc->sc_info.mci_ram_correctable_errors,
1450 : sc->sc_info.mci_ram_uncorrectable_errors,
1451 : sc->sc_info.mci_cluster_allowed,
1452 : sc->sc_info.mci_cluster_active);
1453 :
1454 : DPRINTF("%s: max_strps_io %d raid_lvl %#x adapt_ops %#x ld_ops %#x\n",
1455 : DEVNAME(sc),
1456 : sc->sc_info.mci_max_strips_per_io,
1457 : sc->sc_info.mci_raid_levels,
1458 : sc->sc_info.mci_adapter_ops,
1459 : sc->sc_info.mci_ld_ops);
1460 :
1461 : DPRINTF("%s: strp_sz_min %d strp_sz_max %d pd_ops %#x pd_mix %#x\n",
1462 : DEVNAME(sc),
1463 : sc->sc_info.mci_stripe_sz_ops.min,
1464 : sc->sc_info.mci_stripe_sz_ops.max,
1465 : sc->sc_info.mci_pd_ops,
1466 : sc->sc_info.mci_pd_mix_support);
1467 :
1468 : DPRINTF("%s: ecc_bucket %d pckg_prop %s\n",
1469 : DEVNAME(sc),
1470 : sc->sc_info.mci_ecc_bucket_count,
1471 : sc->sc_info.mci_package_version);
1472 :
1473 : DPRINTF("%s: sq_nm %d prd_fail_poll %d intr_thrtl %d intr_thrtl_to %d\n",
1474 : DEVNAME(sc),
1475 : sc->sc_info.mci_properties.mcp_seq_num,
1476 : sc->sc_info.mci_properties.mcp_pred_fail_poll_interval,
1477 : sc->sc_info.mci_properties.mcp_intr_throttle_cnt,
1478 : sc->sc_info.mci_properties.mcp_intr_throttle_timeout);
1479 :
1480 : DPRINTF("%s: rbld_rate %d patr_rd_rate %d bgi_rate %d cc_rate %d\n",
1481 : DEVNAME(sc),
1482 : sc->sc_info.mci_properties.mcp_rebuild_rate,
1483 : sc->sc_info.mci_properties.mcp_patrol_read_rate,
1484 : sc->sc_info.mci_properties.mcp_bgi_rate,
1485 : sc->sc_info.mci_properties.mcp_cc_rate);
1486 :
1487 : DPRINTF("%s: rc_rate %d ch_flsh %d spin_cnt %d spin_dly %d clus_en %d\n",
1488 : DEVNAME(sc),
1489 : sc->sc_info.mci_properties.mcp_recon_rate,
1490 : sc->sc_info.mci_properties.mcp_cache_flush_interval,
1491 : sc->sc_info.mci_properties.mcp_spinup_drv_cnt,
1492 : sc->sc_info.mci_properties.mcp_spinup_delay,
1493 : sc->sc_info.mci_properties.mcp_cluster_enable);
1494 :
1495 : DPRINTF("%s: coerc %d alarm %d dis_auto_rbld %d dis_bat_wrn %d ecc %d\n",
1496 : DEVNAME(sc),
1497 : sc->sc_info.mci_properties.mcp_coercion_mode,
1498 : sc->sc_info.mci_properties.mcp_alarm_enable,
1499 : sc->sc_info.mci_properties.mcp_disable_auto_rebuild,
1500 : sc->sc_info.mci_properties.mcp_disable_battery_warn,
1501 : sc->sc_info.mci_properties.mcp_ecc_bucket_size);
1502 :
1503 : DPRINTF("%s: ecc_leak %d rest_hs %d exp_encl_dev %d\n",
1504 : DEVNAME(sc),
1505 : sc->sc_info.mci_properties.mcp_ecc_bucket_leak_rate,
1506 : sc->sc_info.mci_properties.mcp_restore_hotspare_on_insertion,
1507 : sc->sc_info.mci_properties.mcp_expose_encl_devices);
1508 :
1509 : DPRINTF("%s: vendor %#x device %#x subvendor %#x subdevice %#x\n",
1510 : DEVNAME(sc),
1511 : sc->sc_info.mci_pci.mip_vendor,
1512 : sc->sc_info.mci_pci.mip_device,
1513 : sc->sc_info.mci_pci.mip_subvendor,
1514 : sc->sc_info.mci_pci.mip_subdevice);
1515 :
1516 : DPRINTF("%s: type %#x port_count %d port_addr ",
1517 : DEVNAME(sc),
1518 : sc->sc_info.mci_host.mih_type,
1519 : sc->sc_info.mci_host.mih_port_count);
1520 :
1521 0 : for (i = 0; i < 8; i++)
1522 : DPRINTF("%.0llx ", sc->sc_info.mci_host.mih_port_addr[i]);
1523 : DPRINTF("\n");
1524 :
1525 : DPRINTF("%s: type %.x port_count %d port_addr ",
1526 : DEVNAME(sc),
1527 : sc->sc_info.mci_device.mid_type,
1528 : sc->sc_info.mci_device.mid_port_count);
1529 :
1530 0 : for (i = 0; i < 8; i++)
1531 : DPRINTF("%.0llx ", sc->sc_info.mci_device.mid_port_addr[i]);
1532 : DPRINTF("\n");
1533 :
1534 0 : return (0);
1535 0 : }
1536 :
1537 : int
1538 0 : mfii_mfa_poll(struct mfii_softc *sc, struct mfii_ccb *ccb)
1539 : {
1540 0 : struct mfi_frame_header *hdr = ccb->ccb_request;
1541 : u_int64_t r;
1542 : int to = 0, rv = 0;
1543 :
1544 : #ifdef DIAGNOSTIC
1545 0 : if (ccb->ccb_cookie != NULL || ccb->ccb_done != NULL)
1546 0 : panic("mfii_mfa_poll called with cookie or done set");
1547 : #endif
1548 :
1549 0 : hdr->mfh_context = ccb->ccb_smid;
1550 0 : hdr->mfh_cmd_status = MFI_STAT_INVALID_STATUS;
1551 0 : hdr->mfh_flags |= htole16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE);
1552 :
1553 0 : r = MFII_REQ_MFA(ccb->ccb_request_dva);
1554 0 : memcpy(&ccb->ccb_req, &r, sizeof(ccb->ccb_req));
1555 :
1556 0 : mfii_start(sc, ccb);
1557 :
1558 0 : for (;;) {
1559 0 : bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_requests),
1560 : ccb->ccb_request_offset, MFII_REQUEST_SIZE,
1561 : BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1562 :
1563 0 : if (hdr->mfh_cmd_status != MFI_STAT_INVALID_STATUS)
1564 : break;
1565 :
1566 0 : if (to++ > 5000) { /* XXX 5 seconds busywait sucks */
1567 0 : printf("%s: timeout on ccb %d\n", DEVNAME(sc),
1568 0 : ccb->ccb_smid);
1569 0 : ccb->ccb_flags |= MFI_CCB_F_ERR;
1570 : rv = 1;
1571 0 : break;
1572 : }
1573 :
1574 0 : bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_requests),
1575 : ccb->ccb_request_offset, MFII_REQUEST_SIZE,
1576 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1577 :
1578 0 : delay(1000);
1579 : }
1580 :
1581 0 : if (ccb->ccb_len > 0) {
1582 0 : bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap,
1583 : 0, ccb->ccb_dmamap->dm_mapsize,
1584 : (ccb->ccb_direction == MFII_DATA_IN) ?
1585 : BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
1586 :
1587 0 : bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
1588 0 : }
1589 :
1590 0 : return (rv);
1591 : }
1592 :
1593 : int
1594 0 : mfii_poll(struct mfii_softc *sc, struct mfii_ccb *ccb)
1595 : {
1596 : void (*done)(struct mfii_softc *, struct mfii_ccb *);
1597 : void *cookie;
1598 0 : int rv = 1;
1599 :
1600 0 : done = ccb->ccb_done;
1601 0 : cookie = ccb->ccb_cookie;
1602 :
1603 0 : ccb->ccb_done = mfii_poll_done;
1604 0 : ccb->ccb_cookie = &rv;
1605 :
1606 0 : mfii_start(sc, ccb);
1607 :
1608 0 : do {
1609 0 : delay(10);
1610 0 : mfii_postq(sc);
1611 0 : } while (rv == 1);
1612 :
1613 0 : ccb->ccb_cookie = cookie;
1614 0 : done(sc, ccb);
1615 :
1616 0 : return (0);
1617 0 : }
1618 :
1619 : void
1620 0 : mfii_poll_done(struct mfii_softc *sc, struct mfii_ccb *ccb)
1621 : {
1622 0 : int *rv = ccb->ccb_cookie;
1623 :
1624 0 : *rv = 0;
1625 0 : }
1626 :
1627 : int
1628 0 : mfii_exec(struct mfii_softc *sc, struct mfii_ccb *ccb)
1629 : {
1630 0 : struct mutex m = MUTEX_INITIALIZER(IPL_BIO);
1631 :
1632 : #ifdef DIAGNOSTIC
1633 0 : if (ccb->ccb_cookie != NULL || ccb->ccb_done != NULL)
1634 0 : panic("mfii_exec called with cookie or done set");
1635 : #endif
1636 :
1637 0 : ccb->ccb_cookie = &m;
1638 0 : ccb->ccb_done = mfii_exec_done;
1639 :
1640 0 : mfii_start(sc, ccb);
1641 :
1642 0 : mtx_enter(&m);
1643 0 : while (ccb->ccb_cookie != NULL)
1644 0 : msleep(ccb, &m, PRIBIO, "mfiiexec", 0);
1645 0 : mtx_leave(&m);
1646 :
1647 0 : return (0);
1648 0 : }
1649 :
1650 : void
1651 0 : mfii_exec_done(struct mfii_softc *sc, struct mfii_ccb *ccb)
1652 : {
1653 0 : struct mutex *m = ccb->ccb_cookie;
1654 :
1655 0 : mtx_enter(m);
1656 0 : ccb->ccb_cookie = NULL;
1657 0 : wakeup_one(ccb);
1658 0 : mtx_leave(m);
1659 0 : }
1660 :
1661 : int
1662 0 : mfii_mgmt(struct mfii_softc *sc, uint32_t opc, const union mfi_mbox *mbox,
1663 : void *buf, size_t len, int flags)
1664 : {
1665 : struct mfii_ccb *ccb;
1666 : int rv;
1667 :
1668 0 : ccb = scsi_io_get(&sc->sc_iopool, flags);
1669 0 : if (ccb == NULL)
1670 0 : return (ENOMEM);
1671 :
1672 0 : mfii_scrub_ccb(ccb);
1673 0 : rv = mfii_do_mgmt(sc, ccb, opc, mbox, buf, len, flags);
1674 0 : scsi_io_put(&sc->sc_iopool, ccb);
1675 :
1676 0 : return (rv);
1677 0 : }
1678 :
1679 : int
1680 0 : mfii_do_mgmt(struct mfii_softc *sc, struct mfii_ccb *ccb, uint32_t opc,
1681 : const union mfi_mbox *mbox, void *buf, size_t len, int flags)
1682 : {
1683 0 : struct mpii_msg_scsi_io *io = ccb->ccb_request;
1684 0 : struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
1685 0 : struct mfii_sge *sge = (struct mfii_sge *)(ctx + 1);
1686 0 : struct mfi_dcmd_frame *dcmd = ccb->ccb_mfi;
1687 0 : struct mfi_frame_header *hdr = &dcmd->mdf_header;
1688 : u_int8_t *dma_buf;
1689 : int rv = EIO;
1690 :
1691 0 : if (cold)
1692 0 : flags |= SCSI_NOSLEEP;
1693 :
1694 0 : dma_buf = dma_alloc(len, PR_WAITOK);
1695 0 : if (dma_buf == NULL)
1696 0 : return (ENOMEM);
1697 :
1698 0 : ccb->ccb_data = dma_buf;
1699 0 : ccb->ccb_len = len;
1700 0 : switch (flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
1701 : case SCSI_DATA_IN:
1702 0 : ccb->ccb_direction = MFII_DATA_IN;
1703 0 : hdr->mfh_flags = htole16(MFI_FRAME_DIR_READ);
1704 0 : break;
1705 : case SCSI_DATA_OUT:
1706 0 : ccb->ccb_direction = MFII_DATA_OUT;
1707 0 : hdr->mfh_flags = htole16(MFI_FRAME_DIR_WRITE);
1708 0 : memcpy(dma_buf, buf, len);
1709 0 : break;
1710 : case 0:
1711 0 : ccb->ccb_direction = MFII_DATA_NONE;
1712 0 : hdr->mfh_flags = htole16(MFI_FRAME_DIR_NONE);
1713 0 : break;
1714 : }
1715 :
1716 0 : if (mfii_load_mfa(sc, ccb, &dcmd->mdf_sgl,
1717 0 : ISSET(flags, SCSI_NOSLEEP)) != 0) {
1718 : rv = ENOMEM;
1719 0 : goto done;
1720 : }
1721 :
1722 0 : hdr->mfh_cmd = MFI_CMD_DCMD;
1723 0 : hdr->mfh_context = ccb->ccb_smid;
1724 0 : hdr->mfh_data_len = htole32(len);
1725 0 : hdr->mfh_sg_count = ccb->ccb_dmamap->dm_nsegs;
1726 :
1727 0 : dcmd->mdf_opcode = opc;
1728 : /* handle special opcodes */
1729 0 : if (mbox != NULL)
1730 0 : memcpy(&dcmd->mdf_mbox, mbox, sizeof(dcmd->mdf_mbox));
1731 :
1732 0 : io->function = MFII_FUNCTION_PASSTHRU_IO;
1733 0 : io->sgl_offset0 = ((u_int8_t *)sge - (u_int8_t *)io) / 4;
1734 0 : io->chain_offset = ((u_int8_t *)sge - (u_int8_t *)io) / 16;
1735 :
1736 0 : htolem64(&sge->sg_addr, ccb->ccb_mfi_dva);
1737 0 : htolem32(&sge->sg_len, MFI_FRAME_SIZE);
1738 0 : sge->sg_flags = MFII_SGE_CHAIN_ELEMENT | MFII_SGE_ADDR_IOCPLBNTA;
1739 :
1740 0 : ccb->ccb_req.flags = MFII_REQ_TYPE_SCSI;
1741 0 : ccb->ccb_req.smid = letoh16(ccb->ccb_smid);
1742 :
1743 0 : if (ISSET(flags, SCSI_NOSLEEP)) {
1744 0 : ccb->ccb_done = mfii_empty_done;
1745 0 : mfii_poll(sc, ccb);
1746 0 : } else
1747 0 : mfii_exec(sc, ccb);
1748 :
1749 0 : if (hdr->mfh_cmd_status == MFI_STAT_OK) {
1750 : rv = 0;
1751 :
1752 0 : if (ccb->ccb_direction == MFII_DATA_IN)
1753 0 : memcpy(buf, dma_buf, len);
1754 : }
1755 :
1756 : done:
1757 0 : dma_free(dma_buf, len);
1758 :
1759 0 : return (rv);
1760 0 : }
1761 :
1762 : void
1763 0 : mfii_empty_done(struct mfii_softc *sc, struct mfii_ccb *ccb)
1764 : {
1765 0 : return;
1766 : }
1767 :
1768 : int
1769 0 : mfii_load_mfa(struct mfii_softc *sc, struct mfii_ccb *ccb,
1770 : void *sglp, int nosleep)
1771 : {
1772 0 : union mfi_sgl *sgl = sglp;
1773 0 : bus_dmamap_t dmap = ccb->ccb_dmamap;
1774 : int error;
1775 : int i;
1776 :
1777 0 : if (ccb->ccb_len == 0)
1778 0 : return (0);
1779 :
1780 0 : error = bus_dmamap_load(sc->sc_dmat, dmap,
1781 : ccb->ccb_data, ccb->ccb_len, NULL,
1782 : nosleep ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
1783 0 : if (error) {
1784 0 : printf("%s: error %d loading dmamap\n", DEVNAME(sc), error);
1785 0 : return (1);
1786 : }
1787 :
1788 0 : for (i = 0; i < dmap->dm_nsegs; i++) {
1789 0 : sgl->sg32[i].addr = htole32(dmap->dm_segs[i].ds_addr);
1790 0 : sgl->sg32[i].len = htole32(dmap->dm_segs[i].ds_len);
1791 : }
1792 :
1793 0 : bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
1794 : ccb->ccb_direction == MFII_DATA_OUT ?
1795 : BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD);
1796 :
1797 0 : return (0);
1798 0 : }
1799 :
1800 : void
1801 0 : mfii_start(struct mfii_softc *sc, struct mfii_ccb *ccb)
1802 : {
1803 0 : u_long *r = (u_long *)&ccb->ccb_req;
1804 :
1805 0 : bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_requests),
1806 : ccb->ccb_request_offset, MFII_REQUEST_SIZE,
1807 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1808 :
1809 : #if defined(__LP64__)
1810 0 : bus_space_write_raw_8(sc->sc_iot, sc->sc_ioh, MFI_IQPL, *r);
1811 : #else
1812 : mtx_enter(&sc->sc_post_mtx);
1813 : bus_space_write_raw_4(sc->sc_iot, sc->sc_ioh, MFI_IQPL, r[0]);
1814 : bus_space_barrier(sc->sc_iot, sc->sc_ioh,
1815 : MFI_IQPL, 8, BUS_SPACE_BARRIER_WRITE);
1816 :
1817 : bus_space_write_raw_4(sc->sc_iot, sc->sc_ioh, MFI_IQPH, r[1]);
1818 : bus_space_barrier(sc->sc_iot, sc->sc_ioh,
1819 : MFI_IQPH, 8, BUS_SPACE_BARRIER_WRITE);
1820 : mtx_leave(&sc->sc_post_mtx);
1821 : #endif
1822 0 : }
1823 :
1824 : void
1825 0 : mfii_done(struct mfii_softc *sc, struct mfii_ccb *ccb)
1826 : {
1827 0 : bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_requests),
1828 : ccb->ccb_request_offset, MFII_REQUEST_SIZE,
1829 : BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1830 :
1831 0 : if (ccb->ccb_sgl_len > 0) {
1832 0 : bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_sgl),
1833 : ccb->ccb_sgl_offset, ccb->ccb_sgl_len,
1834 : BUS_DMASYNC_POSTWRITE);
1835 0 : }
1836 :
1837 0 : if (ccb->ccb_len > 0) {
1838 0 : bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap,
1839 : 0, ccb->ccb_dmamap->dm_mapsize,
1840 : (ccb->ccb_direction == MFII_DATA_IN) ?
1841 : BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
1842 :
1843 0 : bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
1844 0 : }
1845 :
1846 0 : ccb->ccb_done(sc, ccb);
1847 0 : }
1848 :
1849 : int
1850 0 : mfii_initialise_firmware(struct mfii_softc *sc)
1851 : {
1852 : struct mpii_msg_iocinit_request *iiq;
1853 : struct mfii_dmamem *m;
1854 : struct mfii_ccb *ccb;
1855 : struct mfi_init_frame *init;
1856 : int rv;
1857 :
1858 0 : m = mfii_dmamem_alloc(sc, sizeof(*iiq));
1859 0 : if (m == NULL)
1860 0 : return (1);
1861 :
1862 0 : iiq = MFII_DMA_KVA(m);
1863 0 : memset(iiq, 0, sizeof(*iiq));
1864 :
1865 0 : iiq->function = MPII_FUNCTION_IOC_INIT;
1866 0 : iiq->whoinit = MPII_WHOINIT_HOST_DRIVER;
1867 :
1868 0 : iiq->msg_version_maj = 0x02;
1869 0 : iiq->msg_version_min = 0x00;
1870 0 : iiq->hdr_version_unit = 0x10;
1871 0 : iiq->hdr_version_dev = 0x0;
1872 :
1873 0 : iiq->system_request_frame_size = htole16(MFII_REQUEST_SIZE / 4);
1874 :
1875 0 : iiq->reply_descriptor_post_queue_depth =
1876 0 : htole16(sc->sc_reply_postq_depth);
1877 0 : iiq->reply_free_queue_depth = htole16(0);
1878 :
1879 0 : htolem32(&iiq->sense_buffer_address_high,
1880 : MFII_DMA_DVA(sc->sc_sense) >> 32);
1881 :
1882 0 : htolem32(&iiq->reply_descriptor_post_queue_address_lo,
1883 : MFII_DMA_DVA(sc->sc_reply_postq));
1884 0 : htolem32(&iiq->reply_descriptor_post_queue_address_hi,
1885 : MFII_DMA_DVA(sc->sc_reply_postq) >> 32);
1886 :
1887 0 : htolem32(&iiq->system_request_frame_base_address_lo,
1888 : MFII_DMA_DVA(sc->sc_requests));
1889 0 : htolem32(&iiq->system_request_frame_base_address_hi,
1890 : MFII_DMA_DVA(sc->sc_requests) >> 32);
1891 :
1892 0 : iiq->timestamp = htole64(time_uptime);
1893 :
1894 0 : ccb = scsi_io_get(&sc->sc_iopool, SCSI_NOSLEEP);
1895 0 : if (ccb == NULL) {
1896 : /* shouldn't ever run out of ccbs during attach */
1897 0 : return (1);
1898 : }
1899 0 : mfii_scrub_ccb(ccb);
1900 0 : init = ccb->ccb_request;
1901 :
1902 0 : init->mif_header.mfh_cmd = MFI_CMD_INIT;
1903 0 : init->mif_header.mfh_data_len = htole32(sizeof(*iiq));
1904 0 : init->mif_qinfo_new_addr = htole64(MFII_DMA_DVA(m));
1905 :
1906 0 : bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_reply_postq),
1907 : 0, MFII_DMA_LEN(sc->sc_reply_postq),
1908 : BUS_DMASYNC_PREREAD);
1909 :
1910 0 : bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(m),
1911 : 0, sizeof(*iiq), BUS_DMASYNC_PREREAD);
1912 :
1913 0 : rv = mfii_mfa_poll(sc, ccb);
1914 :
1915 0 : bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(m),
1916 : 0, sizeof(*iiq), BUS_DMASYNC_POSTREAD);
1917 :
1918 0 : scsi_io_put(&sc->sc_iopool, ccb);
1919 0 : mfii_dmamem_free(sc, m);
1920 :
1921 0 : return (rv);
1922 0 : }
1923 :
1924 : int
1925 0 : mfii_my_intr(struct mfii_softc *sc)
1926 : {
1927 : u_int32_t status;
1928 :
1929 0 : status = mfii_read(sc, MFI_OSTS);
1930 0 : if (ISSET(status, 0x1)) {
1931 0 : mfii_write(sc, MFI_OSTS, status);
1932 0 : return (1);
1933 : }
1934 :
1935 0 : return (ISSET(status, MFII_OSTS_INTR_VALID) ? 1 : 0);
1936 0 : }
1937 :
1938 : int
1939 0 : mfii_intr(void *arg)
1940 : {
1941 0 : struct mfii_softc *sc = arg;
1942 :
1943 0 : if (!mfii_my_intr(sc))
1944 0 : return (0);
1945 :
1946 0 : mfii_postq(sc);
1947 :
1948 0 : return (1);
1949 0 : }
1950 :
1951 : void
1952 0 : mfii_postq(struct mfii_softc *sc)
1953 : {
1954 0 : struct mfii_ccb_list ccbs = SIMPLEQ_HEAD_INITIALIZER(ccbs);
1955 0 : struct mpii_reply_descr *postq = MFII_DMA_KVA(sc->sc_reply_postq);
1956 : struct mpii_reply_descr *rdp;
1957 : struct mfii_ccb *ccb;
1958 : int rpi = 0;
1959 :
1960 0 : mtx_enter(&sc->sc_reply_postq_mtx);
1961 :
1962 0 : bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_reply_postq),
1963 : 0, MFII_DMA_LEN(sc->sc_reply_postq),
1964 : BUS_DMASYNC_POSTREAD);
1965 :
1966 0 : for (;;) {
1967 0 : rdp = &postq[sc->sc_reply_postq_index];
1968 0 : if ((rdp->reply_flags & MPII_REPLY_DESCR_TYPE_MASK) ==
1969 : MPII_REPLY_DESCR_UNUSED)
1970 : break;
1971 0 : if (rdp->data == 0xffffffff) {
1972 : /*
1973 : * ioc is still writing to the reply post queue
1974 : * race condition - bail!
1975 : */
1976 : break;
1977 : }
1978 :
1979 0 : ccb = &sc->sc_ccb[letoh16(rdp->smid) - 1];
1980 0 : SIMPLEQ_INSERT_TAIL(&ccbs, ccb, ccb_link);
1981 0 : memset(rdp, 0xff, sizeof(*rdp));
1982 :
1983 0 : sc->sc_reply_postq_index++;
1984 0 : sc->sc_reply_postq_index %= sc->sc_reply_postq_depth;
1985 : rpi = 1;
1986 : }
1987 :
1988 0 : bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_reply_postq),
1989 : 0, MFII_DMA_LEN(sc->sc_reply_postq),
1990 : BUS_DMASYNC_PREREAD);
1991 :
1992 0 : if (rpi)
1993 0 : mfii_write(sc, MFII_RPI, sc->sc_reply_postq_index);
1994 :
1995 0 : mtx_leave(&sc->sc_reply_postq_mtx);
1996 :
1997 0 : while ((ccb = SIMPLEQ_FIRST(&ccbs)) != NULL) {
1998 0 : SIMPLEQ_REMOVE_HEAD(&ccbs, ccb_link);
1999 0 : mfii_done(sc, ccb);
2000 : }
2001 0 : }
2002 :
2003 : void
2004 0 : mfii_scsi_cmd(struct scsi_xfer *xs)
2005 : {
2006 0 : struct scsi_link *link = xs->sc_link;
2007 0 : struct mfii_softc *sc = link->adapter_softc;
2008 0 : struct mfii_ccb *ccb = xs->io;
2009 :
2010 0 : mfii_scrub_ccb(ccb);
2011 0 : ccb->ccb_cookie = xs;
2012 0 : ccb->ccb_done = mfii_scsi_cmd_done;
2013 0 : ccb->ccb_data = xs->data;
2014 0 : ccb->ccb_len = xs->datalen;
2015 :
2016 0 : timeout_set(&xs->stimeout, mfii_scsi_cmd_tmo, xs);
2017 :
2018 0 : switch (xs->cmd->opcode) {
2019 : case READ_COMMAND:
2020 : case READ_BIG:
2021 : case READ_12:
2022 : case READ_16:
2023 : case WRITE_COMMAND:
2024 : case WRITE_BIG:
2025 : case WRITE_12:
2026 : case WRITE_16:
2027 0 : if (mfii_scsi_cmd_io(sc, xs) != 0)
2028 : goto stuffup;
2029 :
2030 : break;
2031 :
2032 : default:
2033 0 : if (mfii_scsi_cmd_cdb(sc, xs) != 0)
2034 : goto stuffup;
2035 : break;
2036 : }
2037 :
2038 0 : xs->error = XS_NOERROR;
2039 0 : xs->resid = 0;
2040 :
2041 0 : if (ISSET(xs->flags, SCSI_POLL)) {
2042 0 : if (mfii_poll(sc, ccb) != 0)
2043 : goto stuffup;
2044 0 : return;
2045 : }
2046 :
2047 0 : ccb->ccb_refcnt = 2; /* one for the chip, one for the timeout */
2048 0 : timeout_add_msec(&xs->stimeout, xs->timeout);
2049 0 : mfii_start(sc, ccb);
2050 :
2051 0 : return;
2052 :
2053 : stuffup:
2054 0 : xs->error = XS_DRIVER_STUFFUP;
2055 0 : scsi_done(xs);
2056 0 : }
2057 :
2058 : void
2059 0 : mfii_scsi_cmd_done(struct mfii_softc *sc, struct mfii_ccb *ccb)
2060 : {
2061 0 : struct scsi_xfer *xs = ccb->ccb_cookie;
2062 0 : struct mpii_msg_scsi_io *io = ccb->ccb_request;
2063 0 : struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
2064 : u_int refs = 1;
2065 :
2066 0 : if (timeout_del(&xs->stimeout))
2067 0 : refs = 2;
2068 :
2069 0 : switch (ctx->status) {
2070 : case MFI_STAT_OK:
2071 : break;
2072 :
2073 : case MFI_STAT_SCSI_DONE_WITH_ERROR:
2074 0 : xs->error = XS_SENSE;
2075 0 : memset(&xs->sense, 0, sizeof(xs->sense));
2076 0 : memcpy(&xs->sense, ccb->ccb_sense, sizeof(xs->sense));
2077 0 : break;
2078 :
2079 : case MFI_STAT_LD_OFFLINE:
2080 : case MFI_STAT_DEVICE_NOT_FOUND:
2081 0 : xs->error = XS_SELTIMEOUT;
2082 0 : break;
2083 :
2084 : default:
2085 0 : xs->error = XS_DRIVER_STUFFUP;
2086 0 : break;
2087 : }
2088 :
2089 0 : if (atomic_sub_int_nv(&ccb->ccb_refcnt, refs) == 0)
2090 0 : scsi_done(xs);
2091 0 : }
2092 :
2093 : int
2094 0 : mfii_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag)
2095 : {
2096 0 : struct mfii_softc *sc = (struct mfii_softc *)link->adapter_softc;
2097 :
2098 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_scsi_ioctl\n", DEVNAME(sc));
2099 :
2100 0 : switch (cmd) {
2101 : case DIOCGCACHE:
2102 : case DIOCSCACHE:
2103 0 : return (mfii_ioctl_cache(link, cmd, (struct dk_cache *)addr));
2104 : break;
2105 :
2106 : default:
2107 0 : if (sc->sc_ioctl)
2108 0 : return (sc->sc_ioctl(link->adapter_softc, cmd, addr));
2109 : break;
2110 : }
2111 :
2112 0 : return (ENOTTY);
2113 0 : }
2114 :
2115 : int
2116 0 : mfii_ioctl_cache(struct scsi_link *link, u_long cmd, struct dk_cache *dc)
2117 : {
2118 0 : struct mfii_softc *sc = (struct mfii_softc *)link->adapter_softc;
2119 : int rv, wrenable, rdenable;
2120 0 : struct mfi_ld_prop ldp;
2121 0 : union mfi_mbox mbox;
2122 :
2123 0 : if (mfii_get_info(sc)) {
2124 : rv = EIO;
2125 0 : goto done;
2126 : }
2127 :
2128 0 : if (sc->sc_target_lds[link->target] == -1) {
2129 : rv = EIO;
2130 0 : goto done;
2131 : }
2132 :
2133 0 : memset(&mbox, 0, sizeof(mbox));
2134 0 : mbox.b[0] = link->target;
2135 0 : rv = mfii_mgmt(sc, MR_DCMD_LD_GET_PROPERTIES, &mbox, &ldp, sizeof(ldp),
2136 : SCSI_DATA_IN);
2137 0 : if (rv != 0)
2138 : goto done;
2139 :
2140 0 : if (sc->sc_info.mci_memory_size > 0) {
2141 0 : wrenable = ISSET(ldp.mlp_cur_cache_policy,
2142 : MR_LD_CACHE_ALLOW_WRITE_CACHE)? 1 : 0;
2143 0 : rdenable = ISSET(ldp.mlp_cur_cache_policy,
2144 : MR_LD_CACHE_ALLOW_READ_CACHE)? 1 : 0;
2145 0 : } else {
2146 0 : wrenable = ISSET(ldp.mlp_diskcache_policy,
2147 : MR_LD_DISK_CACHE_ENABLE)? 1 : 0;
2148 : rdenable = 0;
2149 : }
2150 :
2151 0 : if (cmd == DIOCGCACHE) {
2152 0 : dc->wrcache = wrenable;
2153 0 : dc->rdcache = rdenable;
2154 0 : goto done;
2155 : } /* else DIOCSCACHE */
2156 :
2157 0 : if (((dc->wrcache) ? 1 : 0) == wrenable &&
2158 0 : ((dc->rdcache) ? 1 : 0) == rdenable)
2159 : goto done;
2160 :
2161 0 : memset(&mbox, 0, sizeof(mbox));
2162 0 : mbox.b[0] = ldp.mlp_ld.mld_target;
2163 0 : mbox.b[1] = ldp.mlp_ld.mld_res;
2164 0 : mbox.s[1] = ldp.mlp_ld.mld_seq;
2165 :
2166 0 : if (sc->sc_info.mci_memory_size > 0) {
2167 0 : if (dc->rdcache)
2168 0 : SET(ldp.mlp_cur_cache_policy,
2169 : MR_LD_CACHE_ALLOW_READ_CACHE);
2170 : else
2171 0 : CLR(ldp.mlp_cur_cache_policy,
2172 : MR_LD_CACHE_ALLOW_READ_CACHE);
2173 0 : if (dc->wrcache)
2174 0 : SET(ldp.mlp_cur_cache_policy,
2175 : MR_LD_CACHE_ALLOW_WRITE_CACHE);
2176 : else
2177 0 : CLR(ldp.mlp_cur_cache_policy,
2178 : MR_LD_CACHE_ALLOW_WRITE_CACHE);
2179 : } else {
2180 0 : if (dc->rdcache) {
2181 : rv = EOPNOTSUPP;
2182 0 : goto done;
2183 : }
2184 0 : if (dc->wrcache)
2185 0 : ldp.mlp_diskcache_policy = MR_LD_DISK_CACHE_ENABLE;
2186 : else
2187 0 : ldp.mlp_diskcache_policy = MR_LD_DISK_CACHE_DISABLE;
2188 : }
2189 :
2190 0 : rv = mfii_mgmt(sc, MR_DCMD_LD_SET_PROPERTIES, &mbox, &ldp, sizeof(ldp),
2191 : SCSI_DATA_OUT);
2192 : done:
2193 0 : return (rv);
2194 0 : }
2195 :
2196 : int
2197 0 : mfii_scsi_cmd_io(struct mfii_softc *sc, struct scsi_xfer *xs)
2198 : {
2199 0 : struct scsi_link *link = xs->sc_link;
2200 0 : struct mfii_ccb *ccb = xs->io;
2201 0 : struct mpii_msg_scsi_io *io = ccb->ccb_request;
2202 0 : struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
2203 : int segs;
2204 :
2205 0 : io->dev_handle = htole16(link->target);
2206 0 : io->function = MFII_FUNCTION_LDIO_REQUEST;
2207 0 : io->sense_buffer_low_address = htole32(ccb->ccb_sense_dva);
2208 0 : io->sgl_flags = htole16(0x02); /* XXX */
2209 0 : io->sense_buffer_length = sizeof(xs->sense);
2210 0 : io->sgl_offset0 = (sizeof(*io) + sizeof(*ctx)) / 4;
2211 0 : io->data_length = htole32(xs->datalen);
2212 0 : io->io_flags = htole16(xs->cmdlen);
2213 0 : switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
2214 : case SCSI_DATA_IN:
2215 0 : ccb->ccb_direction = MFII_DATA_IN;
2216 0 : io->direction = MPII_SCSIIO_DIR_READ;
2217 0 : break;
2218 : case SCSI_DATA_OUT:
2219 0 : ccb->ccb_direction = MFII_DATA_OUT;
2220 0 : io->direction = MPII_SCSIIO_DIR_WRITE;
2221 0 : break;
2222 : default:
2223 0 : ccb->ccb_direction = MFII_DATA_NONE;
2224 0 : io->direction = MPII_SCSIIO_DIR_NONE;
2225 0 : break;
2226 : }
2227 0 : memcpy(io->cdb, xs->cmd, xs->cmdlen);
2228 :
2229 0 : ctx->type_nseg = sc->sc_iop->ldio_ctx_type_nseg;
2230 0 : ctx->timeout_value = htole16(0x14); /* XXX */
2231 0 : ctx->reg_lock_flags = htole16(sc->sc_iop->ldio_ctx_reg_lock_flags);
2232 0 : ctx->virtual_disk_target_id = htole16(link->target);
2233 :
2234 0 : if (mfii_load_ccb(sc, ccb, ctx + 1,
2235 0 : ISSET(xs->flags, SCSI_NOSLEEP)) != 0)
2236 0 : return (1);
2237 :
2238 0 : segs = (ccb->ccb_len == 0) ? 0 : ccb->ccb_dmamap->dm_nsegs;
2239 0 : switch (sc->sc_iop->num_sge_loc) {
2240 : case MFII_IOP_NUM_SGE_LOC_ORIG:
2241 0 : ctx->num_sge = segs;
2242 0 : break;
2243 : case MFII_IOP_NUM_SGE_LOC_35:
2244 : /* 12 bit field, but we're only using the lower 8 */
2245 0 : ctx->span_arm = segs;
2246 0 : break;
2247 : }
2248 :
2249 0 : ccb->ccb_req.flags = sc->sc_iop->ldio_req_type;
2250 0 : ccb->ccb_req.smid = letoh16(ccb->ccb_smid);
2251 :
2252 0 : return (0);
2253 0 : }
2254 :
2255 : int
2256 0 : mfii_scsi_cmd_cdb(struct mfii_softc *sc, struct scsi_xfer *xs)
2257 : {
2258 0 : struct scsi_link *link = xs->sc_link;
2259 0 : struct mfii_ccb *ccb = xs->io;
2260 0 : struct mpii_msg_scsi_io *io = ccb->ccb_request;
2261 0 : struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
2262 :
2263 0 : io->dev_handle = htole16(link->target);
2264 0 : io->function = MFII_FUNCTION_LDIO_REQUEST;
2265 0 : io->sense_buffer_low_address = htole32(ccb->ccb_sense_dva);
2266 0 : io->sgl_flags = htole16(0x02); /* XXX */
2267 0 : io->sense_buffer_length = sizeof(xs->sense);
2268 0 : io->sgl_offset0 = (sizeof(*io) + sizeof(*ctx)) / 4;
2269 0 : io->data_length = htole32(xs->datalen);
2270 0 : io->io_flags = htole16(xs->cmdlen);
2271 0 : io->lun[0] = htobe16(link->lun);
2272 0 : switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
2273 : case SCSI_DATA_IN:
2274 0 : ccb->ccb_direction = MFII_DATA_IN;
2275 0 : io->direction = MPII_SCSIIO_DIR_READ;
2276 0 : break;
2277 : case SCSI_DATA_OUT:
2278 0 : ccb->ccb_direction = MFII_DATA_OUT;
2279 0 : io->direction = MPII_SCSIIO_DIR_WRITE;
2280 0 : break;
2281 : default:
2282 0 : ccb->ccb_direction = MFII_DATA_NONE;
2283 0 : io->direction = MPII_SCSIIO_DIR_NONE;
2284 0 : break;
2285 : }
2286 0 : memcpy(io->cdb, xs->cmd, xs->cmdlen);
2287 :
2288 0 : ctx->virtual_disk_target_id = htole16(link->target);
2289 :
2290 0 : if (mfii_load_ccb(sc, ccb, ctx + 1,
2291 0 : ISSET(xs->flags, SCSI_NOSLEEP)) != 0)
2292 0 : return (1);
2293 :
2294 0 : ctx->num_sge = (ccb->ccb_len == 0) ? 0 : ccb->ccb_dmamap->dm_nsegs;
2295 :
2296 0 : ccb->ccb_req.flags = MFII_REQ_TYPE_SCSI;
2297 0 : ccb->ccb_req.smid = letoh16(ccb->ccb_smid);
2298 :
2299 0 : return (0);
2300 0 : }
2301 :
2302 : void
2303 0 : mfii_pd_scsi_cmd(struct scsi_xfer *xs)
2304 : {
2305 0 : struct scsi_link *link = xs->sc_link;
2306 0 : struct mfii_softc *sc = link->adapter_softc;
2307 0 : struct mfii_ccb *ccb = xs->io;
2308 :
2309 0 : mfii_scrub_ccb(ccb);
2310 0 : ccb->ccb_cookie = xs;
2311 0 : ccb->ccb_done = mfii_scsi_cmd_done;
2312 0 : ccb->ccb_data = xs->data;
2313 0 : ccb->ccb_len = xs->datalen;
2314 :
2315 0 : timeout_set(&xs->stimeout, mfii_scsi_cmd_tmo, xs);
2316 :
2317 0 : xs->error = mfii_pd_scsi_cmd_cdb(sc, xs);
2318 0 : if (xs->error != XS_NOERROR)
2319 : goto done;
2320 :
2321 0 : xs->resid = 0;
2322 :
2323 0 : if (ISSET(xs->flags, SCSI_POLL)) {
2324 0 : if (mfii_poll(sc, ccb) != 0)
2325 : goto stuffup;
2326 0 : return;
2327 : }
2328 :
2329 0 : ccb->ccb_refcnt = 2; /* one for the chip, one for the timeout */
2330 0 : timeout_add_msec(&xs->stimeout, xs->timeout);
2331 0 : mfii_start(sc, ccb);
2332 :
2333 0 : return;
2334 :
2335 : stuffup:
2336 0 : xs->error = XS_DRIVER_STUFFUP;
2337 : done:
2338 0 : scsi_done(xs);
2339 0 : }
2340 :
2341 : int
2342 0 : mfii_pd_scsi_probe(struct scsi_link *link)
2343 : {
2344 0 : struct mfii_softc *sc = link->adapter_softc;
2345 0 : struct mfi_pd_details mpd;
2346 0 : union mfi_mbox mbox;
2347 : int rv;
2348 :
2349 0 : if (link->lun > 0)
2350 0 : return (0);
2351 :
2352 0 : memset(&mbox, 0, sizeof(mbox));
2353 0 : mbox.s[0] = htole16(link->target);
2354 :
2355 0 : rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, &mpd, sizeof(mpd),
2356 : SCSI_DATA_IN|SCSI_NOSLEEP);
2357 0 : if (rv != 0)
2358 0 : return (EIO);
2359 :
2360 0 : if (mpd.mpd_fw_state != htole16(MFI_PD_SYSTEM))
2361 0 : return (ENXIO);
2362 :
2363 0 : return (0);
2364 0 : }
2365 :
2366 : int
2367 0 : mfii_pd_scsi_cmd_cdb(struct mfii_softc *sc, struct scsi_xfer *xs)
2368 : {
2369 0 : struct scsi_link *link = xs->sc_link;
2370 0 : struct mfii_ccb *ccb = xs->io;
2371 0 : struct mpii_msg_scsi_io *io = ccb->ccb_request;
2372 0 : struct mfii_raid_context *ctx = (struct mfii_raid_context *)(io + 1);
2373 : uint16_t dev_handle;
2374 :
2375 0 : dev_handle = mfii_dev_handle(sc, link->target);
2376 0 : if (dev_handle == htole16(0xffff))
2377 0 : return (XS_SELTIMEOUT);
2378 :
2379 0 : io->dev_handle = dev_handle;
2380 0 : io->function = 0;
2381 0 : io->sense_buffer_low_address = htole32(ccb->ccb_sense_dva);
2382 0 : io->sgl_flags = htole16(0x02); /* XXX */
2383 0 : io->sense_buffer_length = sizeof(xs->sense);
2384 0 : io->sgl_offset0 = (sizeof(*io) + sizeof(*ctx)) / 4;
2385 0 : io->data_length = htole32(xs->datalen);
2386 0 : io->io_flags = htole16(xs->cmdlen);
2387 0 : io->lun[0] = htobe16(link->lun);
2388 0 : switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
2389 : case SCSI_DATA_IN:
2390 0 : ccb->ccb_direction = MFII_DATA_IN;
2391 0 : io->direction = MPII_SCSIIO_DIR_READ;
2392 0 : break;
2393 : case SCSI_DATA_OUT:
2394 0 : ccb->ccb_direction = MFII_DATA_OUT;
2395 0 : io->direction = MPII_SCSIIO_DIR_WRITE;
2396 0 : break;
2397 : default:
2398 0 : ccb->ccb_direction = MFII_DATA_NONE;
2399 0 : io->direction = MPII_SCSIIO_DIR_NONE;
2400 0 : break;
2401 : }
2402 0 : memcpy(io->cdb, xs->cmd, xs->cmdlen);
2403 :
2404 0 : ctx->virtual_disk_target_id = htole16(link->target);
2405 0 : ctx->raid_flags = MFII_RAID_CTX_IO_TYPE_SYSPD;
2406 0 : ctx->timeout_value = sc->sc_pd->pd_timeout;
2407 :
2408 0 : if (mfii_load_ccb(sc, ccb, ctx + 1,
2409 0 : ISSET(xs->flags, SCSI_NOSLEEP)) != 0)
2410 0 : return (XS_DRIVER_STUFFUP);
2411 :
2412 0 : ctx->num_sge = (ccb->ccb_len == 0) ? 0 : ccb->ccb_dmamap->dm_nsegs;
2413 :
2414 0 : ccb->ccb_req.flags = MFII_REQ_TYPE_HI_PRI;
2415 0 : ccb->ccb_req.smid = letoh16(ccb->ccb_smid);
2416 0 : ccb->ccb_req.dev_handle = dev_handle;
2417 :
2418 0 : return (XS_NOERROR);
2419 0 : }
2420 :
2421 : int
2422 0 : mfii_load_ccb(struct mfii_softc *sc, struct mfii_ccb *ccb, void *sglp,
2423 : int nosleep)
2424 : {
2425 0 : struct mpii_msg_request *req = ccb->ccb_request;
2426 0 : struct mfii_sge *sge = NULL, *nsge = sglp;
2427 : struct mfii_sge *ce = NULL;
2428 0 : bus_dmamap_t dmap = ccb->ccb_dmamap;
2429 : u_int space;
2430 : int i;
2431 :
2432 : int error;
2433 :
2434 0 : if (ccb->ccb_len == 0)
2435 0 : return (0);
2436 :
2437 0 : error = bus_dmamap_load(sc->sc_dmat, dmap,
2438 : ccb->ccb_data, ccb->ccb_len, NULL,
2439 : nosleep ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
2440 0 : if (error) {
2441 0 : printf("%s: error %d loading dmamap\n", DEVNAME(sc), error);
2442 0 : return (1);
2443 : }
2444 :
2445 0 : space = (MFII_REQUEST_SIZE - ((u_int8_t *)nsge - (u_int8_t *)req)) /
2446 : sizeof(*nsge);
2447 0 : if (dmap->dm_nsegs > space) {
2448 0 : space--;
2449 :
2450 0 : ccb->ccb_sgl_len = (dmap->dm_nsegs - space) * sizeof(*nsge);
2451 0 : memset(ccb->ccb_sgl, 0, ccb->ccb_sgl_len);
2452 :
2453 0 : ce = nsge + space;
2454 0 : ce->sg_addr = htole64(ccb->ccb_sgl_dva);
2455 0 : ce->sg_len = htole32(ccb->ccb_sgl_len);
2456 0 : ce->sg_flags = sc->sc_iop->sge_flag_chain;
2457 :
2458 0 : req->chain_offset = ((u_int8_t *)ce - (u_int8_t *)req) / 16;
2459 0 : }
2460 :
2461 0 : for (i = 0; i < dmap->dm_nsegs; i++) {
2462 0 : if (nsge == ce)
2463 0 : nsge = ccb->ccb_sgl;
2464 :
2465 : sge = nsge;
2466 :
2467 0 : sge->sg_addr = htole64(dmap->dm_segs[i].ds_addr);
2468 0 : sge->sg_len = htole32(dmap->dm_segs[i].ds_len);
2469 0 : sge->sg_flags = MFII_SGE_ADDR_SYSTEM;
2470 :
2471 0 : nsge = sge + 1;
2472 : }
2473 0 : sge->sg_flags |= sc->sc_iop->sge_flag_eol;
2474 :
2475 0 : bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
2476 : ccb->ccb_direction == MFII_DATA_OUT ?
2477 : BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD);
2478 :
2479 0 : if (ccb->ccb_sgl_len > 0) {
2480 0 : bus_dmamap_sync(sc->sc_dmat, MFII_DMA_MAP(sc->sc_sgl),
2481 : ccb->ccb_sgl_offset, ccb->ccb_sgl_len,
2482 : BUS_DMASYNC_PREWRITE);
2483 0 : }
2484 :
2485 0 : return (0);
2486 0 : }
2487 :
2488 : void
2489 0 : mfii_scsi_cmd_tmo(void *xsp)
2490 : {
2491 0 : struct scsi_xfer *xs = xsp;
2492 0 : struct scsi_link *link = xs->sc_link;
2493 0 : struct mfii_softc *sc = link->adapter_softc;
2494 0 : struct mfii_ccb *ccb = xs->io;
2495 :
2496 0 : mtx_enter(&sc->sc_abort_mtx);
2497 0 : SIMPLEQ_INSERT_TAIL(&sc->sc_abort_list, ccb, ccb_link);
2498 0 : mtx_leave(&sc->sc_abort_mtx);
2499 :
2500 0 : task_add(systqmp, &sc->sc_abort_task);
2501 0 : }
2502 :
2503 : void
2504 0 : mfii_abort_task(void *scp)
2505 : {
2506 0 : struct mfii_softc *sc = scp;
2507 : struct mfii_ccb *list;
2508 :
2509 0 : mtx_enter(&sc->sc_abort_mtx);
2510 0 : list = SIMPLEQ_FIRST(&sc->sc_abort_list);
2511 0 : SIMPLEQ_INIT(&sc->sc_abort_list);
2512 0 : mtx_leave(&sc->sc_abort_mtx);
2513 :
2514 0 : while (list != NULL) {
2515 : struct mfii_ccb *ccb = list;
2516 0 : struct scsi_xfer *xs = ccb->ccb_cookie;
2517 0 : struct scsi_link *link = xs->sc_link;
2518 :
2519 : uint16_t dev_handle;
2520 : struct mfii_ccb *accb;
2521 :
2522 0 : list = SIMPLEQ_NEXT(ccb, ccb_link);
2523 :
2524 0 : dev_handle = mfii_dev_handle(sc, link->target);
2525 0 : if (dev_handle == htole16(0xffff)) {
2526 : /* device is gone */
2527 0 : if (atomic_dec_int_nv(&ccb->ccb_refcnt) == 0)
2528 0 : scsi_done(xs);
2529 0 : continue;
2530 : }
2531 :
2532 0 : accb = scsi_io_get(&sc->sc_iopool, 0);
2533 0 : mfii_scrub_ccb(accb);
2534 0 : mfii_abort(sc, accb, dev_handle, ccb->ccb_smid,
2535 : MPII_SCSI_TASK_ABORT_TASK,
2536 : htole32(MFII_TASK_MGMT_FLAGS_PD));
2537 :
2538 0 : accb->ccb_cookie = ccb;
2539 0 : accb->ccb_done = mfii_scsi_cmd_abort_done;
2540 :
2541 0 : mfii_start(sc, accb);
2542 0 : }
2543 0 : }
2544 :
2545 : void
2546 0 : mfii_abort(struct mfii_softc *sc, struct mfii_ccb *accb, uint16_t dev_handle,
2547 : uint16_t smid, uint8_t type, uint32_t flags)
2548 : {
2549 : struct mfii_task_mgmt *msg;
2550 : struct mpii_msg_scsi_task_request *req;
2551 :
2552 0 : msg = accb->ccb_request;
2553 0 : req = &msg->mpii_request;
2554 0 : req->dev_handle = dev_handle;
2555 0 : req->function = MPII_FUNCTION_SCSI_TASK_MGMT;
2556 0 : req->task_type = type;
2557 0 : htolem16(&req->task_mid, smid);
2558 0 : msg->flags = flags;
2559 :
2560 0 : accb->ccb_req.flags = MFII_REQ_TYPE_HI_PRI;
2561 0 : accb->ccb_req.smid = letoh16(accb->ccb_smid);
2562 0 : }
2563 :
2564 : void
2565 0 : mfii_scsi_cmd_abort_done(struct mfii_softc *sc, struct mfii_ccb *accb)
2566 : {
2567 0 : struct mfii_ccb *ccb = accb->ccb_cookie;
2568 0 : struct scsi_xfer *xs = ccb->ccb_cookie;
2569 :
2570 : /* XXX check accb completion? */
2571 :
2572 0 : scsi_io_put(&sc->sc_iopool, accb);
2573 :
2574 0 : if (atomic_dec_int_nv(&ccb->ccb_refcnt) == 0)
2575 0 : scsi_done(xs);
2576 0 : }
2577 :
2578 : void *
2579 0 : mfii_get_ccb(void *cookie)
2580 : {
2581 0 : struct mfii_softc *sc = cookie;
2582 : struct mfii_ccb *ccb;
2583 :
2584 0 : mtx_enter(&sc->sc_ccb_mtx);
2585 0 : ccb = SIMPLEQ_FIRST(&sc->sc_ccb_freeq);
2586 0 : if (ccb != NULL)
2587 0 : SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_freeq, ccb_link);
2588 0 : mtx_leave(&sc->sc_ccb_mtx);
2589 :
2590 0 : return (ccb);
2591 : }
2592 :
2593 : void
2594 0 : mfii_scrub_ccb(struct mfii_ccb *ccb)
2595 : {
2596 0 : ccb->ccb_cookie = NULL;
2597 0 : ccb->ccb_done = NULL;
2598 0 : ccb->ccb_flags = 0;
2599 0 : ccb->ccb_data = NULL;
2600 0 : ccb->ccb_direction = 0;
2601 0 : ccb->ccb_len = 0;
2602 0 : ccb->ccb_sgl_len = 0;
2603 0 : ccb->ccb_refcnt = 1;
2604 :
2605 0 : memset(&ccb->ccb_req, 0, sizeof(ccb->ccb_req));
2606 0 : memset(ccb->ccb_request, 0, MFII_REQUEST_SIZE);
2607 0 : memset(ccb->ccb_mfi, 0, MFI_FRAME_SIZE);
2608 0 : }
2609 :
2610 : void
2611 0 : mfii_put_ccb(void *cookie, void *io)
2612 : {
2613 0 : struct mfii_softc *sc = cookie;
2614 0 : struct mfii_ccb *ccb = io;
2615 :
2616 0 : mtx_enter(&sc->sc_ccb_mtx);
2617 0 : SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_freeq, ccb, ccb_link);
2618 0 : mtx_leave(&sc->sc_ccb_mtx);
2619 0 : }
2620 :
2621 : int
2622 0 : mfii_init_ccb(struct mfii_softc *sc)
2623 : {
2624 : struct mfii_ccb *ccb;
2625 0 : u_int8_t *request = MFII_DMA_KVA(sc->sc_requests);
2626 0 : u_int8_t *mfi = MFII_DMA_KVA(sc->sc_mfi);
2627 0 : u_int8_t *sense = MFII_DMA_KVA(sc->sc_sense);
2628 0 : u_int8_t *sgl = MFII_DMA_KVA(sc->sc_sgl);
2629 : u_int i;
2630 : int error;
2631 :
2632 0 : sc->sc_ccb = mallocarray(sc->sc_max_cmds, sizeof(struct mfii_ccb),
2633 : M_DEVBUF, M_WAITOK|M_ZERO);
2634 :
2635 0 : for (i = 0; i < sc->sc_max_cmds; i++) {
2636 0 : ccb = &sc->sc_ccb[i];
2637 :
2638 : /* create a dma map for transfer */
2639 0 : error = bus_dmamap_create(sc->sc_dmat,
2640 : MAXPHYS, sc->sc_max_sgl, MAXPHYS, 0,
2641 : BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap);
2642 0 : if (error) {
2643 0 : printf("%s: cannot create ccb dmamap (%d)\n",
2644 0 : DEVNAME(sc), error);
2645 : goto destroy;
2646 : }
2647 :
2648 : /* select i + 1'th request. 0 is reserved for events */
2649 0 : ccb->ccb_smid = i + 1;
2650 0 : ccb->ccb_request_offset = MFII_REQUEST_SIZE * (i + 1);
2651 0 : ccb->ccb_request = request + ccb->ccb_request_offset;
2652 0 : ccb->ccb_request_dva = MFII_DMA_DVA(sc->sc_requests) +
2653 0 : ccb->ccb_request_offset;
2654 :
2655 : /* select i'th MFI command frame */
2656 0 : ccb->ccb_mfi_offset = MFI_FRAME_SIZE * i;
2657 0 : ccb->ccb_mfi = mfi + ccb->ccb_mfi_offset;
2658 0 : ccb->ccb_mfi_dva = MFII_DMA_DVA(sc->sc_mfi) +
2659 0 : ccb->ccb_mfi_offset;
2660 :
2661 : /* select i'th sense */
2662 0 : ccb->ccb_sense_offset = MFI_SENSE_SIZE * i;
2663 0 : ccb->ccb_sense = (struct mfi_sense *)(sense +
2664 : ccb->ccb_sense_offset);
2665 0 : ccb->ccb_sense_dva = MFII_DMA_DVA(sc->sc_sense) +
2666 0 : ccb->ccb_sense_offset;
2667 :
2668 : /* select i'th sgl */
2669 0 : ccb->ccb_sgl_offset = sizeof(struct mfii_sge) *
2670 0 : sc->sc_max_sgl * i;
2671 0 : ccb->ccb_sgl = (struct mfii_sge *)(sgl + ccb->ccb_sgl_offset);
2672 0 : ccb->ccb_sgl_dva = MFII_DMA_DVA(sc->sc_sgl) +
2673 0 : ccb->ccb_sgl_offset;
2674 :
2675 : /* add ccb to queue */
2676 0 : mfii_put_ccb(sc, ccb);
2677 : }
2678 :
2679 0 : return (0);
2680 :
2681 : destroy:
2682 : /* free dma maps and ccb memory */
2683 0 : while ((ccb = mfii_get_ccb(sc)) != NULL)
2684 0 : bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
2685 :
2686 0 : free(sc->sc_ccb, M_DEVBUF, 0);
2687 :
2688 0 : return (1);
2689 0 : }
2690 :
2691 : #if NBIO > 0
2692 : int
2693 0 : mfii_ioctl(struct device *dev, u_long cmd, caddr_t addr)
2694 : {
2695 0 : struct mfii_softc *sc = (struct mfii_softc *)dev;
2696 : int error = 0;
2697 :
2698 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl ", DEVNAME(sc));
2699 :
2700 0 : rw_enter_write(&sc->sc_lock);
2701 :
2702 0 : switch (cmd) {
2703 : case BIOCINQ:
2704 : DNPRINTF(MFII_D_IOCTL, "inq\n");
2705 0 : error = mfii_ioctl_inq(sc, (struct bioc_inq *)addr);
2706 0 : break;
2707 :
2708 : case BIOCVOL:
2709 : DNPRINTF(MFII_D_IOCTL, "vol\n");
2710 0 : error = mfii_ioctl_vol(sc, (struct bioc_vol *)addr);
2711 0 : break;
2712 :
2713 : case BIOCDISK:
2714 : DNPRINTF(MFII_D_IOCTL, "disk\n");
2715 0 : error = mfii_ioctl_disk(sc, (struct bioc_disk *)addr);
2716 0 : break;
2717 :
2718 : case BIOCALARM:
2719 : DNPRINTF(MFII_D_IOCTL, "alarm\n");
2720 0 : error = mfii_ioctl_alarm(sc, (struct bioc_alarm *)addr);
2721 0 : break;
2722 :
2723 : case BIOCBLINK:
2724 : DNPRINTF(MFII_D_IOCTL, "blink\n");
2725 0 : error = mfii_ioctl_blink(sc, (struct bioc_blink *)addr);
2726 0 : break;
2727 :
2728 : case BIOCSETSTATE:
2729 : DNPRINTF(MFII_D_IOCTL, "setstate\n");
2730 0 : error = mfii_ioctl_setstate(sc, (struct bioc_setstate *)addr);
2731 0 : break;
2732 :
2733 : case BIOCPATROL:
2734 : DNPRINTF(MFII_D_IOCTL, "patrol\n");
2735 0 : error = mfii_ioctl_patrol(sc, (struct bioc_patrol *)addr);
2736 0 : break;
2737 :
2738 : default:
2739 : DNPRINTF(MFII_D_IOCTL, " invalid ioctl\n");
2740 : error = ENOTTY;
2741 0 : }
2742 :
2743 0 : rw_exit_write(&sc->sc_lock);
2744 :
2745 0 : return (error);
2746 : }
2747 :
2748 : int
2749 0 : mfii_bio_getitall(struct mfii_softc *sc)
2750 : {
2751 : int i, d, rv = EINVAL;
2752 : size_t size;
2753 0 : union mfi_mbox mbox;
2754 : struct mfi_conf *cfg = NULL;
2755 : struct mfi_ld_details *ld_det = NULL;
2756 :
2757 : /* get info */
2758 0 : if (mfii_get_info(sc)) {
2759 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_get_info failed\n",
2760 : DEVNAME(sc));
2761 : goto done;
2762 : }
2763 :
2764 : /* send single element command to retrieve size for full structure */
2765 0 : cfg = malloc(sizeof *cfg, M_DEVBUF, M_NOWAIT | M_ZERO);
2766 0 : if (cfg == NULL)
2767 : goto done;
2768 0 : if (mfii_mgmt(sc, MR_DCMD_CONF_GET, NULL, cfg, sizeof(*cfg),
2769 : SCSI_DATA_IN)) {
2770 0 : free(cfg, M_DEVBUF, sizeof *cfg);
2771 0 : goto done;
2772 : }
2773 :
2774 0 : size = cfg->mfc_size;
2775 0 : free(cfg, M_DEVBUF, sizeof *cfg);
2776 :
2777 : /* memory for read config */
2778 0 : cfg = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
2779 0 : if (cfg == NULL)
2780 : goto done;
2781 0 : if (mfii_mgmt(sc, MR_DCMD_CONF_GET, NULL, cfg, size, SCSI_DATA_IN)) {
2782 0 : free(cfg, M_DEVBUF, size);
2783 0 : goto done;
2784 : }
2785 :
2786 : /* replace current pointer with new one */
2787 0 : if (sc->sc_cfg)
2788 0 : free(sc->sc_cfg, M_DEVBUF, 0);
2789 0 : sc->sc_cfg = cfg;
2790 :
2791 : /* get all ld info */
2792 0 : if (mfii_mgmt(sc, MR_DCMD_LD_GET_LIST, NULL, &sc->sc_ld_list,
2793 : sizeof(sc->sc_ld_list), SCSI_DATA_IN))
2794 : goto done;
2795 :
2796 : /* get memory for all ld structures */
2797 0 : size = cfg->mfc_no_ld * sizeof(struct mfi_ld_details);
2798 0 : if (sc->sc_ld_sz != size) {
2799 0 : if (sc->sc_ld_details)
2800 0 : free(sc->sc_ld_details, M_DEVBUF, 0);
2801 :
2802 0 : ld_det = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
2803 0 : if (ld_det == NULL)
2804 : goto done;
2805 0 : sc->sc_ld_sz = size;
2806 0 : sc->sc_ld_details = ld_det;
2807 0 : }
2808 :
2809 : /* find used physical disks */
2810 : size = sizeof(struct mfi_ld_details);
2811 0 : for (i = 0, d = 0; i < cfg->mfc_no_ld; i++) {
2812 0 : memset(&mbox, 0, sizeof(mbox));
2813 0 : mbox.b[0] = sc->sc_ld_list.mll_list[i].mll_ld.mld_target;
2814 0 : if (mfii_mgmt(sc, MR_DCMD_LD_GET_INFO, &mbox, &sc->sc_ld_details[i], size,
2815 : SCSI_DATA_IN))
2816 : goto done;
2817 :
2818 0 : d += sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_no_drv_per_span *
2819 0 : sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_span_depth;
2820 : }
2821 0 : sc->sc_no_pd = d;
2822 :
2823 0 : rv = 0;
2824 : done:
2825 0 : return (rv);
2826 0 : }
2827 :
2828 : int
2829 0 : mfii_ioctl_inq(struct mfii_softc *sc, struct bioc_inq *bi)
2830 : {
2831 : int rv = EINVAL;
2832 : struct mfi_conf *cfg = NULL;
2833 :
2834 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_inq\n", DEVNAME(sc));
2835 :
2836 0 : if (mfii_bio_getitall(sc)) {
2837 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_bio_getitall failed\n",
2838 : DEVNAME(sc));
2839 : goto done;
2840 : }
2841 :
2842 : /* count unused disks as volumes */
2843 0 : if (sc->sc_cfg == NULL)
2844 : goto done;
2845 : cfg = sc->sc_cfg;
2846 :
2847 0 : bi->bi_nodisk = sc->sc_info.mci_pd_disks_present;
2848 0 : bi->bi_novol = cfg->mfc_no_ld + cfg->mfc_no_hs;
2849 : #if notyet
2850 : bi->bi_novol = cfg->mfc_no_ld + cfg->mfc_no_hs +
2851 : (bi->bi_nodisk - sc->sc_no_pd);
2852 : #endif
2853 : /* tell bio who we are */
2854 0 : strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev));
2855 :
2856 0 : rv = 0;
2857 : done:
2858 0 : return (rv);
2859 : }
2860 :
2861 : int
2862 0 : mfii_ioctl_vol(struct mfii_softc *sc, struct bioc_vol *bv)
2863 : {
2864 : int i, per, target, rv = EINVAL;
2865 : struct scsi_link *link;
2866 : struct device *dev;
2867 :
2868 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_vol %#x\n",
2869 : DEVNAME(sc), bv->bv_volid);
2870 :
2871 : /* we really could skip and expect that inq took care of it */
2872 0 : if (mfii_bio_getitall(sc)) {
2873 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_bio_getitall failed\n",
2874 : DEVNAME(sc));
2875 : goto done;
2876 : }
2877 :
2878 0 : if (bv->bv_volid >= sc->sc_ld_list.mll_no_ld) {
2879 : /* go do hotspares & unused disks */
2880 0 : rv = mfii_bio_hs(sc, bv->bv_volid, MFI_MGMT_VD, bv);
2881 0 : goto done;
2882 : }
2883 :
2884 : i = bv->bv_volid;
2885 0 : target = sc->sc_ld_list.mll_list[i].mll_ld.mld_target;
2886 0 : link = scsi_get_link(sc->sc_scsibus, target, 0);
2887 0 : if (link == NULL) {
2888 0 : strlcpy(bv->bv_dev, "cache", sizeof(bv->bv_dev));
2889 0 : } else {
2890 0 : dev = link->device_softc;
2891 0 : if (dev == NULL)
2892 : goto done;
2893 :
2894 0 : strlcpy(bv->bv_dev, dev->dv_xname, sizeof(bv->bv_dev));
2895 : }
2896 :
2897 0 : switch(sc->sc_ld_list.mll_list[i].mll_state) {
2898 : case MFI_LD_OFFLINE:
2899 0 : bv->bv_status = BIOC_SVOFFLINE;
2900 0 : break;
2901 :
2902 : case MFI_LD_PART_DEGRADED:
2903 : case MFI_LD_DEGRADED:
2904 0 : bv->bv_status = BIOC_SVDEGRADED;
2905 0 : break;
2906 :
2907 : case MFI_LD_ONLINE:
2908 0 : bv->bv_status = BIOC_SVONLINE;
2909 0 : break;
2910 :
2911 : default:
2912 0 : bv->bv_status = BIOC_SVINVALID;
2913 : DNPRINTF(MFII_D_IOCTL, "%s: invalid logical disk state %#x\n",
2914 : DEVNAME(sc),
2915 : sc->sc_ld_list.mll_list[i].mll_state);
2916 0 : }
2917 :
2918 : /* additional status can modify MFI status */
2919 0 : switch (sc->sc_ld_details[i].mld_progress.mlp_in_prog) {
2920 : case MFI_LD_PROG_CC:
2921 : case MFI_LD_PROG_BGI:
2922 0 : bv->bv_status = BIOC_SVSCRUB;
2923 0 : per = (int)sc->sc_ld_details[i].mld_progress.mlp_cc.mp_progress;
2924 0 : bv->bv_percent = (per * 100) / 0xffff;
2925 0 : bv->bv_seconds =
2926 0 : sc->sc_ld_details[i].mld_progress.mlp_cc.mp_elapsed_seconds;
2927 0 : break;
2928 :
2929 : case MFI_LD_PROG_FGI:
2930 : case MFI_LD_PROG_RECONSTRUCT:
2931 : /* nothing yet */
2932 : break;
2933 : }
2934 :
2935 0 : if (sc->sc_ld_details[i].mld_cfg.mlc_prop.mlp_cur_cache_policy & 0x01)
2936 0 : bv->bv_cache = BIOC_CVWRITEBACK;
2937 : else
2938 0 : bv->bv_cache = BIOC_CVWRITETHROUGH;
2939 :
2940 : /*
2941 : * The RAID levels are determined per the SNIA DDF spec, this is only
2942 : * a subset that is valid for the MFI controller.
2943 : */
2944 0 : bv->bv_level = sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_pri_raid;
2945 0 : if (sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_span_depth > 1)
2946 0 : bv->bv_level *= 10;
2947 :
2948 0 : bv->bv_nodisk = sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_no_drv_per_span *
2949 0 : sc->sc_ld_details[i].mld_cfg.mlc_parm.mpa_span_depth;
2950 :
2951 0 : bv->bv_size = sc->sc_ld_details[i].mld_size * 512; /* bytes per block */
2952 :
2953 0 : rv = 0;
2954 : done:
2955 0 : return (rv);
2956 : }
2957 :
2958 : int
2959 0 : mfii_ioctl_disk(struct mfii_softc *sc, struct bioc_disk *bd)
2960 : {
2961 : struct mfi_conf *cfg;
2962 : struct mfi_array *ar;
2963 : struct mfi_ld_cfg *ld;
2964 : struct mfi_pd_details *pd;
2965 : struct mfi_pd_list *pl;
2966 : struct mfi_pd_progress *mfp;
2967 : struct mfi_progress *mp;
2968 : struct scsi_inquiry_data *inqbuf;
2969 0 : char vend[8+16+4+1], *vendp;
2970 : int i, rv = EINVAL;
2971 : int arr, vol, disk, span;
2972 0 : union mfi_mbox mbox;
2973 :
2974 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_disk %#x\n",
2975 : DEVNAME(sc), bd->bd_diskid);
2976 :
2977 : /* we really could skip and expect that inq took care of it */
2978 0 : if (mfii_bio_getitall(sc)) {
2979 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_bio_getitall failed\n",
2980 : DEVNAME(sc));
2981 0 : return (rv);
2982 : }
2983 0 : cfg = sc->sc_cfg;
2984 :
2985 0 : pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
2986 0 : pl = malloc(sizeof *pl, M_DEVBUF, M_WAITOK);
2987 :
2988 0 : ar = cfg->mfc_array;
2989 0 : vol = bd->bd_volid;
2990 0 : if (vol >= cfg->mfc_no_ld) {
2991 : /* do hotspares */
2992 0 : rv = mfii_bio_hs(sc, bd->bd_volid, MFI_MGMT_SD, bd);
2993 0 : goto freeme;
2994 : }
2995 :
2996 : /* calculate offset to ld structure */
2997 0 : ld = (struct mfi_ld_cfg *)(
2998 0 : ((uint8_t *)cfg) + offsetof(struct mfi_conf, mfc_array) +
2999 0 : cfg->mfc_array_size * cfg->mfc_no_array);
3000 :
3001 : /* use span 0 only when raid group is not spanned */
3002 0 : if (ld[vol].mlc_parm.mpa_span_depth > 1)
3003 0 : span = bd->bd_diskid / ld[vol].mlc_parm.mpa_no_drv_per_span;
3004 : else
3005 : span = 0;
3006 0 : arr = ld[vol].mlc_span[span].mls_index;
3007 :
3008 : /* offset disk into pd list */
3009 0 : disk = bd->bd_diskid % ld[vol].mlc_parm.mpa_no_drv_per_span;
3010 :
3011 0 : if (ar[arr].pd[disk].mar_pd.mfp_id == 0xffffU) {
3012 : /* disk is missing but succeed command */
3013 0 : bd->bd_status = BIOC_SDFAILED;
3014 : rv = 0;
3015 :
3016 : /* try to find an unused disk for the target to rebuild */
3017 0 : if (mfii_mgmt(sc, MR_DCMD_PD_GET_LIST, NULL, pl, sizeof(*pl),
3018 : SCSI_DATA_IN))
3019 : goto freeme;
3020 :
3021 0 : for (i = 0; i < pl->mpl_no_pd; i++) {
3022 0 : if (pl->mpl_address[i].mpa_scsi_type != 0)
3023 : continue;
3024 :
3025 0 : memset(&mbox, 0, sizeof(mbox));
3026 0 : mbox.s[0] = pl->mpl_address[i].mpa_pd_id;
3027 0 : if (mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
3028 : SCSI_DATA_IN))
3029 : continue;
3030 :
3031 0 : if (pd->mpd_fw_state == MFI_PD_UNCONFIG_GOOD ||
3032 0 : pd->mpd_fw_state == MFI_PD_UNCONFIG_BAD)
3033 : break;
3034 : }
3035 :
3036 0 : if (i == pl->mpl_no_pd)
3037 : goto freeme;
3038 : } else {
3039 0 : memset(&mbox, 0, sizeof(mbox));
3040 0 : mbox.s[0] = ar[arr].pd[disk].mar_pd.mfp_id;
3041 0 : if (mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
3042 : SCSI_DATA_IN)) {
3043 0 : bd->bd_status = BIOC_SDINVALID;
3044 0 : goto freeme;
3045 : }
3046 : }
3047 :
3048 : /* get the remaining fields */
3049 0 : bd->bd_channel = pd->mpd_enc_idx;
3050 0 : bd->bd_target = pd->mpd_enc_slot;
3051 :
3052 : /* get status */
3053 0 : switch (pd->mpd_fw_state){
3054 : case MFI_PD_UNCONFIG_GOOD:
3055 : case MFI_PD_UNCONFIG_BAD:
3056 0 : bd->bd_status = BIOC_SDUNUSED;
3057 0 : break;
3058 :
3059 : case MFI_PD_HOTSPARE: /* XXX dedicated hotspare part of array? */
3060 0 : bd->bd_status = BIOC_SDHOTSPARE;
3061 0 : break;
3062 :
3063 : case MFI_PD_OFFLINE:
3064 0 : bd->bd_status = BIOC_SDOFFLINE;
3065 0 : break;
3066 :
3067 : case MFI_PD_FAILED:
3068 0 : bd->bd_status = BIOC_SDFAILED;
3069 0 : break;
3070 :
3071 : case MFI_PD_REBUILD:
3072 0 : bd->bd_status = BIOC_SDREBUILD;
3073 0 : break;
3074 :
3075 : case MFI_PD_ONLINE:
3076 0 : bd->bd_status = BIOC_SDONLINE;
3077 0 : break;
3078 :
3079 : case MFI_PD_COPYBACK:
3080 : case MFI_PD_SYSTEM:
3081 : default:
3082 0 : bd->bd_status = BIOC_SDINVALID;
3083 0 : break;
3084 : }
3085 :
3086 0 : bd->bd_size = pd->mpd_size * 512; /* bytes per block */
3087 :
3088 0 : inqbuf = (struct scsi_inquiry_data *)&pd->mpd_inq_data;
3089 0 : vendp = inqbuf->vendor;
3090 0 : memcpy(vend, vendp, sizeof vend - 1);
3091 0 : vend[sizeof vend - 1] = '\0';
3092 0 : strlcpy(bd->bd_vendor, vend, sizeof(bd->bd_vendor));
3093 :
3094 : /* XXX find a way to retrieve serial nr from drive */
3095 : /* XXX find a way to get bd_procdev */
3096 :
3097 0 : mfp = &pd->mpd_progress;
3098 0 : if (mfp->mfp_in_prog & MFI_PD_PROG_PR) {
3099 0 : mp = &mfp->mfp_patrol_read;
3100 0 : bd->bd_patrol.bdp_percent = (mp->mp_progress * 100) / 0xffff;
3101 0 : bd->bd_patrol.bdp_seconds = mp->mp_elapsed_seconds;
3102 0 : }
3103 :
3104 0 : rv = 0;
3105 : freeme:
3106 0 : free(pd, M_DEVBUF, sizeof *pd);
3107 0 : free(pl, M_DEVBUF, sizeof *pl);
3108 :
3109 0 : return (rv);
3110 0 : }
3111 :
3112 : int
3113 0 : mfii_ioctl_alarm(struct mfii_softc *sc, struct bioc_alarm *ba)
3114 : {
3115 : uint32_t opc, flags = 0;
3116 : int rv = 0;
3117 0 : int8_t ret;
3118 :
3119 0 : switch(ba->ba_opcode) {
3120 : case BIOC_SADISABLE:
3121 : opc = MR_DCMD_SPEAKER_DISABLE;
3122 0 : break;
3123 :
3124 : case BIOC_SAENABLE:
3125 : opc = MR_DCMD_SPEAKER_ENABLE;
3126 0 : break;
3127 :
3128 : case BIOC_SASILENCE:
3129 : opc = MR_DCMD_SPEAKER_SILENCE;
3130 0 : break;
3131 :
3132 : case BIOC_GASTATUS:
3133 : opc = MR_DCMD_SPEAKER_GET;
3134 : flags = SCSI_DATA_IN;
3135 0 : break;
3136 :
3137 : case BIOC_SATEST:
3138 : opc = MR_DCMD_SPEAKER_TEST;
3139 0 : break;
3140 :
3141 : default:
3142 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_alarm biocalarm invalid "
3143 : "opcode %x\n", DEVNAME(sc), ba->ba_opcode);
3144 0 : return (EINVAL);
3145 : }
3146 :
3147 0 : if (mfii_mgmt(sc, opc, NULL, &ret, sizeof(ret), flags))
3148 0 : rv = EINVAL;
3149 : else
3150 0 : if (ba->ba_opcode == BIOC_GASTATUS)
3151 0 : ba->ba_status = ret;
3152 : else
3153 0 : ba->ba_status = 0;
3154 :
3155 0 : return (rv);
3156 0 : }
3157 :
3158 : int
3159 0 : mfii_ioctl_blink(struct mfii_softc *sc, struct bioc_blink *bb)
3160 : {
3161 : int i, found, rv = EINVAL;
3162 0 : union mfi_mbox mbox;
3163 : uint32_t cmd;
3164 : struct mfi_pd_list *pd;
3165 :
3166 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_blink %x\n", DEVNAME(sc),
3167 : bb->bb_status);
3168 :
3169 : /* channel 0 means not in an enclosure so can't be blinked */
3170 0 : if (bb->bb_channel == 0)
3171 0 : return (EINVAL);
3172 :
3173 0 : pd = malloc(sizeof(*pd), M_DEVBUF, M_WAITOK);
3174 :
3175 0 : if (mfii_mgmt(sc, MR_DCMD_PD_GET_LIST, NULL, pd, sizeof(*pd), SCSI_DATA_IN))
3176 : goto done;
3177 :
3178 0 : for (i = 0, found = 0; i < pd->mpl_no_pd; i++)
3179 0 : if (bb->bb_channel == pd->mpl_address[i].mpa_enc_index &&
3180 0 : bb->bb_target == pd->mpl_address[i].mpa_enc_slot) {
3181 : found = 1;
3182 0 : break;
3183 : }
3184 :
3185 0 : if (!found)
3186 : goto done;
3187 :
3188 0 : memset(&mbox, 0, sizeof(mbox));
3189 0 : mbox.s[0] = pd->mpl_address[i].mpa_pd_id;
3190 :
3191 0 : switch (bb->bb_status) {
3192 : case BIOC_SBUNBLINK:
3193 : cmd = MR_DCMD_PD_UNBLINK;
3194 0 : break;
3195 :
3196 : case BIOC_SBBLINK:
3197 : cmd = MR_DCMD_PD_BLINK;
3198 0 : break;
3199 :
3200 : case BIOC_SBALARM:
3201 : default:
3202 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_blink biocblink invalid "
3203 : "opcode %x\n", DEVNAME(sc), bb->bb_status);
3204 : goto done;
3205 : }
3206 :
3207 :
3208 0 : if (mfii_mgmt(sc, cmd, &mbox, NULL, 0, 0))
3209 : goto done;
3210 :
3211 0 : rv = 0;
3212 : done:
3213 0 : free(pd, M_DEVBUF, sizeof *pd);
3214 0 : return (rv);
3215 0 : }
3216 :
3217 : static int
3218 0 : mfii_makegood(struct mfii_softc *sc, uint16_t pd_id)
3219 : {
3220 : struct mfii_foreign_scan_info *fsi;
3221 : struct mfi_pd_details *pd;
3222 0 : union mfi_mbox mbox;
3223 : int rv;
3224 :
3225 0 : fsi = malloc(sizeof *fsi, M_DEVBUF, M_WAITOK);
3226 0 : pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
3227 :
3228 0 : memset(&mbox, 0, sizeof mbox);
3229 0 : mbox.s[0] = pd_id;
3230 0 : rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd), SCSI_DATA_IN);
3231 0 : if (rv != 0)
3232 : goto done;
3233 :
3234 0 : if (pd->mpd_fw_state == MFI_PD_UNCONFIG_BAD) {
3235 0 : mbox.s[0] = pd_id;
3236 0 : mbox.s[1] = pd->mpd_pd.mfp_seq;
3237 0 : mbox.b[4] = MFI_PD_UNCONFIG_GOOD;
3238 0 : rv = mfii_mgmt(sc, MR_DCMD_PD_SET_STATE, &mbox, NULL, 0, 0);
3239 0 : if (rv != 0)
3240 : goto done;
3241 : }
3242 :
3243 0 : memset(&mbox, 0, sizeof mbox);
3244 0 : mbox.s[0] = pd_id;
3245 0 : rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd), SCSI_DATA_IN);
3246 0 : if (rv != 0)
3247 : goto done;
3248 :
3249 0 : if (pd->mpd_ddf_state & MFI_DDF_FOREIGN) {
3250 0 : rv = mfii_mgmt(sc, MR_DCMD_CFG_FOREIGN_SCAN, NULL, fsi, sizeof(*fsi),
3251 : SCSI_DATA_IN);
3252 0 : if (rv != 0)
3253 : goto done;
3254 :
3255 0 : if (fsi->count > 0) {
3256 0 : rv = mfii_mgmt(sc, MR_DCMD_CFG_FOREIGN_CLEAR, NULL, NULL, 0, 0);
3257 0 : if (rv != 0)
3258 : goto done;
3259 : }
3260 : }
3261 :
3262 0 : memset(&mbox, 0, sizeof mbox);
3263 0 : mbox.s[0] = pd_id;
3264 0 : rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd), SCSI_DATA_IN);
3265 0 : if (rv != 0)
3266 : goto done;
3267 :
3268 0 : if (pd->mpd_fw_state != MFI_PD_UNCONFIG_GOOD ||
3269 0 : pd->mpd_ddf_state & MFI_DDF_FOREIGN)
3270 0 : rv = ENXIO;
3271 :
3272 : done:
3273 0 : free(fsi, M_DEVBUF, sizeof *fsi);
3274 0 : free(pd, M_DEVBUF, sizeof *pd);
3275 :
3276 0 : return (rv);
3277 0 : }
3278 :
3279 : static int
3280 0 : mfii_makespare(struct mfii_softc *sc, uint16_t pd_id)
3281 : {
3282 : struct mfi_hotspare *hs;
3283 : struct mfi_pd_details *pd;
3284 0 : union mfi_mbox mbox;
3285 : size_t size;
3286 : int rv = EINVAL;
3287 :
3288 : /* we really could skip and expect that inq took care of it */
3289 0 : if (mfii_bio_getitall(sc)) {
3290 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_bio_getitall failed\n",
3291 : DEVNAME(sc));
3292 0 : return (rv);
3293 : }
3294 0 : size = sizeof *hs + sizeof(uint16_t) * sc->sc_cfg->mfc_no_array;
3295 :
3296 0 : hs = malloc(size, M_DEVBUF, M_WAITOK);
3297 0 : pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
3298 :
3299 0 : memset(&mbox, 0, sizeof mbox);
3300 0 : mbox.s[0] = pd_id;
3301 0 : rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
3302 : SCSI_DATA_IN);
3303 0 : if (rv != 0)
3304 : goto done;
3305 :
3306 0 : memset(hs, 0, size);
3307 0 : hs->mhs_pd.mfp_id = pd->mpd_pd.mfp_id;
3308 0 : hs->mhs_pd.mfp_seq = pd->mpd_pd.mfp_seq;
3309 0 : rv = mfii_mgmt(sc, MR_DCMD_CFG_MAKE_SPARE, NULL, hs, size, SCSI_DATA_OUT);
3310 :
3311 : done:
3312 0 : free(hs, M_DEVBUF, size);
3313 0 : free(pd, M_DEVBUF, sizeof *pd);
3314 :
3315 0 : return (rv);
3316 0 : }
3317 :
3318 : int
3319 0 : mfii_ioctl_setstate(struct mfii_softc *sc, struct bioc_setstate *bs)
3320 : {
3321 : struct mfi_pd_details *pd;
3322 : struct mfi_pd_list *pl;
3323 : int i, found, rv = EINVAL;
3324 0 : union mfi_mbox mbox;
3325 :
3326 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_setstate %x\n", DEVNAME(sc),
3327 : bs->bs_status);
3328 :
3329 0 : pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
3330 0 : pl = malloc(sizeof *pl, M_DEVBUF, M_WAITOK);
3331 :
3332 0 : if (mfii_mgmt(sc, MR_DCMD_PD_GET_LIST, NULL, pl, sizeof(*pl), SCSI_DATA_IN))
3333 : goto done;
3334 :
3335 0 : for (i = 0, found = 0; i < pl->mpl_no_pd; i++)
3336 0 : if (bs->bs_channel == pl->mpl_address[i].mpa_enc_index &&
3337 0 : bs->bs_target == pl->mpl_address[i].mpa_enc_slot) {
3338 : found = 1;
3339 0 : break;
3340 : }
3341 :
3342 0 : if (!found)
3343 : goto done;
3344 :
3345 0 : memset(&mbox, 0, sizeof(mbox));
3346 0 : mbox.s[0] = pl->mpl_address[i].mpa_pd_id;
3347 :
3348 0 : if (mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd), SCSI_DATA_IN))
3349 : goto done;
3350 :
3351 0 : mbox.s[0] = pl->mpl_address[i].mpa_pd_id;
3352 0 : mbox.s[1] = pd->mpd_pd.mfp_seq;
3353 :
3354 0 : switch (bs->bs_status) {
3355 : case BIOC_SSONLINE:
3356 0 : mbox.b[4] = MFI_PD_ONLINE;
3357 0 : break;
3358 :
3359 : case BIOC_SSOFFLINE:
3360 0 : mbox.b[4] = MFI_PD_OFFLINE;
3361 0 : break;
3362 :
3363 : case BIOC_SSHOTSPARE:
3364 0 : mbox.b[4] = MFI_PD_HOTSPARE;
3365 0 : break;
3366 :
3367 : case BIOC_SSREBUILD:
3368 0 : if (pd->mpd_fw_state != MFI_PD_OFFLINE) {
3369 0 : if ((rv = mfii_makegood(sc,
3370 0 : pl->mpl_address[i].mpa_pd_id)))
3371 : goto done;
3372 :
3373 0 : if ((rv = mfii_makespare(sc,
3374 0 : pl->mpl_address[i].mpa_pd_id)))
3375 : goto done;
3376 :
3377 0 : memset(&mbox, 0, sizeof(mbox));
3378 0 : mbox.s[0] = pl->mpl_address[i].mpa_pd_id;
3379 0 : rv = mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
3380 : SCSI_DATA_IN);
3381 0 : if (rv != 0)
3382 : goto done;
3383 :
3384 : /* rebuilding might be started by mfii_makespare() */
3385 0 : if (pd->mpd_fw_state == MFI_PD_REBUILD) {
3386 : rv = 0;
3387 0 : goto done;
3388 : }
3389 :
3390 0 : mbox.s[0] = pl->mpl_address[i].mpa_pd_id;
3391 0 : mbox.s[1] = pd->mpd_pd.mfp_seq;
3392 0 : }
3393 0 : mbox.b[4] = MFI_PD_REBUILD;
3394 0 : break;
3395 :
3396 : default:
3397 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_setstate invalid "
3398 : "opcode %x\n", DEVNAME(sc), bs->bs_status);
3399 : goto done;
3400 : }
3401 :
3402 :
3403 0 : rv = mfii_mgmt(sc, MR_DCMD_PD_SET_STATE, &mbox, NULL, 0, 0);
3404 : done:
3405 0 : free(pd, M_DEVBUF, sizeof *pd);
3406 0 : free(pl, M_DEVBUF, sizeof *pl);
3407 0 : return (rv);
3408 0 : }
3409 :
3410 : int
3411 0 : mfii_ioctl_patrol(struct mfii_softc *sc, struct bioc_patrol *bp)
3412 : {
3413 : uint32_t opc;
3414 : int rv = 0;
3415 0 : struct mfi_pr_properties prop;
3416 0 : struct mfi_pr_status status;
3417 0 : uint32_t time, exec_freq;
3418 :
3419 0 : switch (bp->bp_opcode) {
3420 : case BIOC_SPSTOP:
3421 : case BIOC_SPSTART:
3422 0 : if (bp->bp_opcode == BIOC_SPSTART)
3423 0 : opc = MR_DCMD_PR_START;
3424 : else
3425 : opc = MR_DCMD_PR_STOP;
3426 0 : if (mfii_mgmt(sc, opc, NULL, NULL, 0, SCSI_DATA_IN))
3427 0 : return (EINVAL);
3428 : break;
3429 :
3430 : case BIOC_SPMANUAL:
3431 : case BIOC_SPDISABLE:
3432 : case BIOC_SPAUTO:
3433 : /* Get device's time. */
3434 : opc = MR_DCMD_TIME_SECS_GET;
3435 0 : if (mfii_mgmt(sc, opc, NULL, &time, sizeof(time), SCSI_DATA_IN))
3436 0 : return (EINVAL);
3437 :
3438 : opc = MR_DCMD_PR_GET_PROPERTIES;
3439 0 : if (mfii_mgmt(sc, opc, NULL, &prop, sizeof(prop), SCSI_DATA_IN))
3440 0 : return (EINVAL);
3441 :
3442 0 : switch (bp->bp_opcode) {
3443 : case BIOC_SPMANUAL:
3444 0 : prop.op_mode = MFI_PR_OPMODE_MANUAL;
3445 0 : break;
3446 : case BIOC_SPDISABLE:
3447 0 : prop.op_mode = MFI_PR_OPMODE_DISABLED;
3448 0 : break;
3449 : case BIOC_SPAUTO:
3450 0 : if (bp->bp_autoival != 0) {
3451 0 : if (bp->bp_autoival == -1)
3452 : /* continuously */
3453 0 : exec_freq = 0xffffffffU;
3454 0 : else if (bp->bp_autoival > 0)
3455 : exec_freq = bp->bp_autoival;
3456 : else
3457 0 : return (EINVAL);
3458 0 : prop.exec_freq = exec_freq;
3459 0 : }
3460 0 : if (bp->bp_autonext != 0) {
3461 0 : if (bp->bp_autonext < 0)
3462 0 : return (EINVAL);
3463 : else
3464 0 : prop.next_exec = time + bp->bp_autonext;
3465 0 : }
3466 0 : prop.op_mode = MFI_PR_OPMODE_AUTO;
3467 0 : break;
3468 : }
3469 :
3470 : opc = MR_DCMD_PR_SET_PROPERTIES;
3471 0 : if (mfii_mgmt(sc, opc, NULL, &prop, sizeof(prop), SCSI_DATA_OUT))
3472 0 : return (EINVAL);
3473 :
3474 : break;
3475 :
3476 : case BIOC_GPSTATUS:
3477 : opc = MR_DCMD_PR_GET_PROPERTIES;
3478 0 : if (mfii_mgmt(sc, opc, NULL, &prop, sizeof(prop), SCSI_DATA_IN))
3479 0 : return (EINVAL);
3480 :
3481 : opc = MR_DCMD_PR_GET_STATUS;
3482 0 : if (mfii_mgmt(sc, opc, NULL, &status, sizeof(status), SCSI_DATA_IN))
3483 0 : return (EINVAL);
3484 :
3485 : /* Get device's time. */
3486 : opc = MR_DCMD_TIME_SECS_GET;
3487 0 : if (mfii_mgmt(sc, opc, NULL, &time, sizeof(time), SCSI_DATA_IN))
3488 0 : return (EINVAL);
3489 :
3490 0 : switch (prop.op_mode) {
3491 : case MFI_PR_OPMODE_AUTO:
3492 0 : bp->bp_mode = BIOC_SPMAUTO;
3493 0 : bp->bp_autoival = prop.exec_freq;
3494 0 : bp->bp_autonext = prop.next_exec;
3495 0 : bp->bp_autonow = time;
3496 0 : break;
3497 : case MFI_PR_OPMODE_MANUAL:
3498 0 : bp->bp_mode = BIOC_SPMMANUAL;
3499 0 : break;
3500 : case MFI_PR_OPMODE_DISABLED:
3501 0 : bp->bp_mode = BIOC_SPMDISABLED;
3502 0 : break;
3503 : default:
3504 0 : printf("%s: unknown patrol mode %d\n",
3505 0 : DEVNAME(sc), prop.op_mode);
3506 0 : break;
3507 : }
3508 :
3509 0 : switch (status.state) {
3510 : case MFI_PR_STATE_STOPPED:
3511 0 : bp->bp_status = BIOC_SPSSTOPPED;
3512 0 : break;
3513 : case MFI_PR_STATE_READY:
3514 0 : bp->bp_status = BIOC_SPSREADY;
3515 0 : break;
3516 : case MFI_PR_STATE_ACTIVE:
3517 0 : bp->bp_status = BIOC_SPSACTIVE;
3518 0 : break;
3519 : case MFI_PR_STATE_ABORTED:
3520 0 : bp->bp_status = BIOC_SPSABORTED;
3521 0 : break;
3522 : default:
3523 0 : printf("%s: unknown patrol state %d\n",
3524 0 : DEVNAME(sc), status.state);
3525 0 : break;
3526 : }
3527 :
3528 : break;
3529 :
3530 : default:
3531 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_ioctl_patrol biocpatrol invalid "
3532 : "opcode %x\n", DEVNAME(sc), bp->bp_opcode);
3533 0 : return (EINVAL);
3534 : }
3535 :
3536 0 : return (rv);
3537 0 : }
3538 :
3539 : int
3540 0 : mfii_bio_hs(struct mfii_softc *sc, int volid, int type, void *bio_hs)
3541 : {
3542 : struct mfi_conf *cfg;
3543 : struct mfi_hotspare *hs;
3544 : struct mfi_pd_details *pd;
3545 : struct bioc_disk *sdhs;
3546 : struct bioc_vol *vdhs;
3547 : struct scsi_inquiry_data *inqbuf;
3548 0 : char vend[8+16+4+1], *vendp;
3549 : int i, rv = EINVAL;
3550 : uint32_t size;
3551 0 : union mfi_mbox mbox;
3552 :
3553 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_vol_hs %d\n", DEVNAME(sc), volid);
3554 :
3555 0 : if (!bio_hs)
3556 0 : return (EINVAL);
3557 :
3558 0 : pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
3559 :
3560 : /* send single element command to retrieve size for full structure */
3561 0 : cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK);
3562 0 : if (mfii_mgmt(sc, MR_DCMD_CONF_GET, NULL, cfg, sizeof(*cfg), SCSI_DATA_IN))
3563 : goto freeme;
3564 :
3565 0 : size = cfg->mfc_size;
3566 0 : free(cfg, M_DEVBUF, sizeof *cfg);
3567 :
3568 : /* memory for read config */
3569 0 : cfg = malloc(size, M_DEVBUF, M_WAITOK|M_ZERO);
3570 0 : if (mfii_mgmt(sc, MR_DCMD_CONF_GET, NULL, cfg, size, SCSI_DATA_IN))
3571 : goto freeme;
3572 :
3573 : /* calculate offset to hs structure */
3574 0 : hs = (struct mfi_hotspare *)(
3575 0 : ((uint8_t *)cfg) + offsetof(struct mfi_conf, mfc_array) +
3576 0 : cfg->mfc_array_size * cfg->mfc_no_array +
3577 0 : cfg->mfc_ld_size * cfg->mfc_no_ld);
3578 :
3579 0 : if (volid < cfg->mfc_no_ld)
3580 : goto freeme; /* not a hotspare */
3581 :
3582 0 : if (volid > (cfg->mfc_no_ld + cfg->mfc_no_hs))
3583 : goto freeme; /* not a hotspare */
3584 :
3585 : /* offset into hotspare structure */
3586 0 : i = volid - cfg->mfc_no_ld;
3587 :
3588 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_vol_hs i %d volid %d no_ld %d no_hs %d "
3589 : "hs %p cfg %p id %02x\n", DEVNAME(sc), i, volid, cfg->mfc_no_ld,
3590 : cfg->mfc_no_hs, hs, cfg, hs[i].mhs_pd.mfp_id);
3591 :
3592 : /* get pd fields */
3593 0 : memset(&mbox, 0, sizeof(mbox));
3594 0 : mbox.s[0] = hs[i].mhs_pd.mfp_id;
3595 0 : if (mfii_mgmt(sc, MR_DCMD_PD_GET_INFO, &mbox, pd, sizeof(*pd),
3596 : SCSI_DATA_IN)) {
3597 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_vol_hs illegal PD\n",
3598 : DEVNAME(sc));
3599 : goto freeme;
3600 : }
3601 :
3602 0 : switch (type) {
3603 : case MFI_MGMT_VD:
3604 0 : vdhs = bio_hs;
3605 0 : vdhs->bv_status = BIOC_SVONLINE;
3606 0 : vdhs->bv_size = pd->mpd_size / 2 * 1024; /* XXX why? */
3607 0 : vdhs->bv_level = -1; /* hotspare */
3608 0 : vdhs->bv_nodisk = 1;
3609 0 : break;
3610 :
3611 : case MFI_MGMT_SD:
3612 0 : sdhs = bio_hs;
3613 0 : sdhs->bd_status = BIOC_SDHOTSPARE;
3614 0 : sdhs->bd_size = pd->mpd_size / 2 * 1024; /* XXX why? */
3615 0 : sdhs->bd_channel = pd->mpd_enc_idx;
3616 0 : sdhs->bd_target = pd->mpd_enc_slot;
3617 0 : inqbuf = (struct scsi_inquiry_data *)&pd->mpd_inq_data;
3618 0 : vendp = inqbuf->vendor;
3619 0 : memcpy(vend, vendp, sizeof vend - 1);
3620 0 : vend[sizeof vend - 1] = '\0';
3621 0 : strlcpy(sdhs->bd_vendor, vend, sizeof(sdhs->bd_vendor));
3622 0 : break;
3623 :
3624 : default:
3625 : goto freeme;
3626 : }
3627 :
3628 : DNPRINTF(MFII_D_IOCTL, "%s: mfii_vol_hs 6\n", DEVNAME(sc));
3629 0 : rv = 0;
3630 : freeme:
3631 0 : free(pd, M_DEVBUF, sizeof *pd);
3632 0 : free(cfg, M_DEVBUF, 0);
3633 :
3634 0 : return (rv);
3635 0 : }
3636 :
3637 : #ifndef SMALL_KERNEL
3638 :
3639 : #define MFI_BBU_SENSORS 4
3640 :
3641 : void
3642 0 : mfii_bbu(struct mfii_softc *sc)
3643 : {
3644 0 : struct mfi_bbu_status bbu;
3645 : u_int32_t status;
3646 : u_int32_t mask;
3647 : u_int32_t soh_bad;
3648 : int i;
3649 :
3650 0 : if (mfii_mgmt(sc, MR_DCMD_BBU_GET_STATUS, NULL, &bbu,
3651 0 : sizeof(bbu), SCSI_DATA_IN) != 0) {
3652 0 : for (i = 0; i < MFI_BBU_SENSORS; i++) {
3653 0 : sc->sc_bbu[i].value = 0;
3654 0 : sc->sc_bbu[i].status = SENSOR_S_UNKNOWN;
3655 : }
3656 0 : for (i = 0; i < nitems(mfi_bbu_indicators); i++) {
3657 0 : sc->sc_bbu_status[i].value = 0;
3658 0 : sc->sc_bbu_status[i].status = SENSOR_S_UNKNOWN;
3659 : }
3660 0 : return;
3661 : }
3662 :
3663 0 : switch (bbu.battery_type) {
3664 : case MFI_BBU_TYPE_IBBU:
3665 : mask = MFI_BBU_STATE_BAD_IBBU;
3666 : soh_bad = 0;
3667 0 : break;
3668 : case MFI_BBU_TYPE_BBU:
3669 : mask = MFI_BBU_STATE_BAD_BBU;
3670 0 : soh_bad = (bbu.detail.bbu.is_SOH_good == 0);
3671 0 : break;
3672 :
3673 : case MFI_BBU_TYPE_NONE:
3674 : default:
3675 0 : sc->sc_bbu[0].value = 0;
3676 0 : sc->sc_bbu[0].status = SENSOR_S_CRIT;
3677 0 : for (i = 1; i < MFI_BBU_SENSORS; i++) {
3678 0 : sc->sc_bbu[i].value = 0;
3679 0 : sc->sc_bbu[i].status = SENSOR_S_UNKNOWN;
3680 : }
3681 0 : for (i = 0; i < nitems(mfi_bbu_indicators); i++) {
3682 0 : sc->sc_bbu_status[i].value = 0;
3683 0 : sc->sc_bbu_status[i].status = SENSOR_S_UNKNOWN;
3684 : }
3685 0 : return;
3686 : }
3687 :
3688 0 : status = letoh32(bbu.fw_status);
3689 :
3690 0 : sc->sc_bbu[0].value = ((status & mask) || soh_bad) ? 0 : 1;
3691 0 : sc->sc_bbu[0].status = ((status & mask) || soh_bad) ? SENSOR_S_CRIT :
3692 : SENSOR_S_OK;
3693 :
3694 0 : sc->sc_bbu[1].value = letoh16(bbu.voltage) * 1000;
3695 0 : sc->sc_bbu[2].value = (int16_t)letoh16(bbu.current) * 1000;
3696 0 : sc->sc_bbu[3].value = letoh16(bbu.temperature) * 1000000 + 273150000;
3697 0 : for (i = 1; i < MFI_BBU_SENSORS; i++)
3698 0 : sc->sc_bbu[i].status = SENSOR_S_UNSPEC;
3699 :
3700 0 : for (i = 0; i < nitems(mfi_bbu_indicators); i++) {
3701 0 : sc->sc_bbu_status[i].value = (status & (1 << i)) ? 1 : 0;
3702 0 : sc->sc_bbu_status[i].status = SENSOR_S_UNSPEC;
3703 : }
3704 0 : }
3705 :
3706 : void
3707 0 : mfii_refresh_ld_sensor(struct mfii_softc *sc, int ld)
3708 : {
3709 : struct ksensor *sensor;
3710 : int target;
3711 :
3712 0 : target = sc->sc_ld_list.mll_list[ld].mll_ld.mld_target;
3713 0 : sensor = &sc->sc_sensors[target];
3714 :
3715 0 : switch(sc->sc_ld_list.mll_list[ld].mll_state) {
3716 : case MFI_LD_OFFLINE:
3717 0 : sensor->value = SENSOR_DRIVE_FAIL;
3718 0 : sensor->status = SENSOR_S_CRIT;
3719 0 : break;
3720 :
3721 : case MFI_LD_PART_DEGRADED:
3722 : case MFI_LD_DEGRADED:
3723 0 : sensor->value = SENSOR_DRIVE_PFAIL;
3724 0 : sensor->status = SENSOR_S_WARN;
3725 0 : break;
3726 :
3727 : case MFI_LD_ONLINE:
3728 0 : sensor->value = SENSOR_DRIVE_ONLINE;
3729 0 : sensor->status = SENSOR_S_OK;
3730 0 : break;
3731 :
3732 : default:
3733 0 : sensor->value = 0; /* unknown */
3734 0 : sensor->status = SENSOR_S_UNKNOWN;
3735 0 : break;
3736 : }
3737 0 : }
3738 :
3739 : void
3740 0 : mfii_init_ld_sensor(struct mfii_softc *sc, int ld)
3741 : {
3742 : struct device *dev;
3743 : struct scsi_link *link;
3744 : struct ksensor *sensor;
3745 : int target;
3746 :
3747 0 : target = sc->sc_ld_list.mll_list[ld].mll_ld.mld_target;
3748 0 : sensor = &sc->sc_sensors[target];
3749 :
3750 0 : link = scsi_get_link(sc->sc_scsibus, target, 0);
3751 0 : if (link == NULL) {
3752 0 : strlcpy(sensor->desc, "cache", sizeof(sensor->desc));
3753 0 : } else {
3754 0 : dev = link->device_softc;
3755 0 : if (dev != NULL)
3756 0 : strlcpy(sensor->desc, dev->dv_xname,
3757 : sizeof(sensor->desc));
3758 : }
3759 0 : sensor->type = SENSOR_DRIVE;
3760 0 : mfii_refresh_ld_sensor(sc, ld);
3761 0 : }
3762 :
3763 : int
3764 0 : mfii_create_sensors(struct mfii_softc *sc)
3765 : {
3766 : int i, target;
3767 :
3768 0 : strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
3769 : sizeof(sc->sc_sensordev.xname));
3770 :
3771 0 : if (ISSET(letoh32(sc->sc_info.mci_hw_present), MFI_INFO_HW_BBU)) {
3772 0 : sc->sc_bbu = mallocarray(4, sizeof(*sc->sc_bbu),
3773 : M_DEVBUF, M_WAITOK | M_ZERO);
3774 :
3775 0 : sc->sc_bbu[0].type = SENSOR_INDICATOR;
3776 0 : sc->sc_bbu[0].status = SENSOR_S_UNKNOWN;
3777 0 : strlcpy(sc->sc_bbu[0].desc, "bbu ok",
3778 : sizeof(sc->sc_bbu[0].desc));
3779 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_bbu[0]);
3780 :
3781 0 : sc->sc_bbu[1].type = SENSOR_VOLTS_DC;
3782 0 : sc->sc_bbu[1].status = SENSOR_S_UNSPEC;
3783 0 : sc->sc_bbu[2].type = SENSOR_AMPS;
3784 0 : sc->sc_bbu[2].status = SENSOR_S_UNSPEC;
3785 0 : sc->sc_bbu[3].type = SENSOR_TEMP;
3786 0 : sc->sc_bbu[3].status = SENSOR_S_UNSPEC;
3787 0 : for (i = 1; i < MFI_BBU_SENSORS; i++) {
3788 0 : strlcpy(sc->sc_bbu[i].desc, "bbu",
3789 : sizeof(sc->sc_bbu[i].desc));
3790 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_bbu[i]);
3791 : }
3792 :
3793 0 : sc->sc_bbu_status = malloc(sizeof(*sc->sc_bbu_status) *
3794 : sizeof(mfi_bbu_indicators), M_DEVBUF, M_WAITOK | M_ZERO);
3795 :
3796 0 : for (i = 0; i < nitems(mfi_bbu_indicators); i++) {
3797 0 : sc->sc_bbu_status[i].type = SENSOR_INDICATOR;
3798 0 : sc->sc_bbu_status[i].status = SENSOR_S_UNSPEC;
3799 0 : strlcpy(sc->sc_bbu_status[i].desc,
3800 0 : mfi_bbu_indicators[i],
3801 : sizeof(sc->sc_bbu_status[i].desc));
3802 :
3803 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_bbu_status[i]);
3804 : }
3805 : }
3806 :
3807 0 : sc->sc_sensors = mallocarray(MFI_MAX_LD, sizeof(struct ksensor),
3808 : M_DEVBUF, M_NOWAIT | M_ZERO);
3809 0 : if (sc->sc_sensors == NULL)
3810 0 : return (1);
3811 :
3812 0 : for (i = 0; i < sc->sc_ld_list.mll_no_ld; i++) {
3813 0 : mfii_init_ld_sensor(sc, i);
3814 0 : target = sc->sc_ld_list.mll_list[i].mll_ld.mld_target;
3815 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[target]);
3816 : }
3817 :
3818 0 : if (sensor_task_register(sc, mfii_refresh_sensors, 10) == NULL)
3819 : goto bad;
3820 :
3821 0 : sensordev_install(&sc->sc_sensordev);
3822 :
3823 0 : return (0);
3824 :
3825 : bad:
3826 0 : free(sc->sc_sensors, M_DEVBUF,
3827 : MFI_MAX_LD * sizeof(struct ksensor));
3828 :
3829 0 : return (1);
3830 0 : }
3831 :
3832 : void
3833 0 : mfii_refresh_sensors(void *arg)
3834 : {
3835 0 : struct mfii_softc *sc = arg;
3836 : int i;
3837 :
3838 0 : rw_enter_write(&sc->sc_lock);
3839 0 : if (sc->sc_bbu != NULL)
3840 0 : mfii_bbu(sc);
3841 :
3842 0 : mfii_bio_getitall(sc);
3843 0 : rw_exit_write(&sc->sc_lock);
3844 :
3845 0 : for (i = 0; i < sc->sc_ld_list.mll_no_ld; i++)
3846 0 : mfii_refresh_ld_sensor(sc, i);
3847 0 : }
3848 : #endif /* SMALL_KERNEL */
3849 : #endif /* NBIO > 0 */
|