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