1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2019 Nexenta Systems, Inc.
14 */
15
16 /*
17 * Driver attach/detach routines are found here.
18 */
19
20 /* ---- Private header files ---- */
21 #include <smartpqi.h>
22
23 void *pqi_state;
24
25 /* ---- Autoconfigure forward declarations ---- */
26 static int smartpqi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
27 static int smartpqi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
28 static int smartpqi_power(dev_info_t *dip, int component, int level);
29 static int smartpqi_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
30 void **results);
31
32 /* ---- cb_ops forward declarations ---- */
33 static int smartpqi_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
34 cred_t *credp, int *rval);
35
36 static struct cb_ops smartpqi_cb_ops = {
37 scsi_hba_open, /* open */
38 scsi_hba_close, /* close */
39 nodev, /* strategy */
40 nodev, /* print */
41 nodev, /* dump */
42 nodev, /* read */
43 nodev, /* write */
44 smartpqi_ioctl, /* ioctl */
45 nodev, /* devmap */
46 nodev, /* mmap */
47 nodev, /* segmap */
48 nochpoll, /* chpoll */
49 ddi_prop_op, /* cb_prop_op */
50 NULL, /* streamtab */
51 D_MP, /* cb_flag */
52 CB_REV, /* rev */
53 nodev, /* aread */
54 nodev /* awrite */
55 };
56
57 static struct dev_ops smartpqi_ops = {
58 DEVO_REV, /* dev_rev */
59 0, /* refcnt */
60 smartpqi_getinfo, /* info */
61 nulldev, /* identify */
62 nulldev, /* probe */
63 smartpqi_attach, /* attach */
64 smartpqi_detach, /* detach */
65 nodev, /* reset */
66 &smartpqi_cb_ops, /* driver operations */
67 NULL, /* bus operations */
68 smartpqi_power, /* power management */
69 ddi_quiesce_not_needed, /* quience */
70 };
71
72 static struct modldrv modldrv = {
73 &mod_driverops,
74 SMARTPQI_MOD_STRING,
75 &smartpqi_ops,
76 };
77
78 static struct modlinkage modlinkage = {
79 MODREV_1, &modldrv, NULL
80 };
81
82 int pqi_do_scan = 0;
83 int pqi_do_ctrl = 0;
84 int pqi_offline_target = 0;
85 int pqi_do_offline = 0;
86
87 /*
88 * This is used for data I/O DMA memory allocation. (full 64-bit DMA
89 * physical addresses are supported.)
90 */
91 ddi_dma_attr_t smartpqi_dma_attrs = {
92 DMA_ATTR_V0, /* attribute layout version */
93 0x0ull, /* address low - should be 0 (longlong) */
94 0xffffffffffffffffull, /* address high - 64-bit max */
95 0x00666600ull, /* count max - max DMA object size */
96 4096, /* allocation alignment requirements */
97 0x78, /* burstsizes - binary encoded values */
98 1, /* minxfer - gran. of DMA engine */
99 0x00666600ull, /* maxxfer - gran. of DMA engine */
100 0x00666600ull, /* max segment size (DMA boundary) */
101 PQI_MAX_SCATTER_GATHER, /* scatter/gather list length */
102 512, /* granularity - device transfer size */
103 0 /* flags, set to 0 */
104 };
105
106 ddi_device_acc_attr_t smartpqi_dev_attr = {
107 DDI_DEVICE_ATTR_V1,
108 DDI_STRUCTURE_LE_ACC,
109 DDI_STRICTORDER_ACC,
110 DDI_DEFAULT_ACC
111 };
112
113 int
114 _init(void)
115 {
116 int status;
117
118 if ((status = ddi_soft_state_init(&pqi_state,
119 sizeof (struct pqi_state), SMARTPQI_INITIAL_SOFT_SPACE)) !=
120 0) {
121 return (status);
122 }
123
124 if ((status = scsi_hba_init(&modlinkage)) != 0) {
125 ddi_soft_state_fini(&pqi_state);
126 return (status);
127 }
128
129 if ((status = mod_install(&modlinkage)) != 0) {
130 ddi_soft_state_fini(&pqi_state);
131 scsi_hba_fini(&modlinkage);
132 }
133
134 return (status);
135 }
136
137 int
138 _fini(void)
139 {
140 int ret;
141
142 if ((ret = mod_remove(&modlinkage)) == 0) {
143 scsi_hba_fini(&modlinkage);
144 ddi_soft_state_fini(&pqi_state);
145 }
146 return (ret);
147 }
148
149 /*
150 * The loadable-module _info(9E) entry point
151 */
152 int
153 _info(struct modinfo *modinfop)
154 {
155 /* CONSTCOND */
156 ASSERT(NO_COMPETING_THREADS);
157
158 return (mod_info(&modlinkage, modinfop));
159 }
160
161 /*ARGSUSED*/
162 static int smartpqi_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
163 void **result)
164 {
165 int rc = DDI_FAILURE;
166 pqi_state_t s;
167
168 switch (cmd) {
169 case DDI_INFO_DEVT2DEVINFO:
170 if ((s = ddi_get_soft_state(pqi_state, 0)) == NULL)
171 break;
172 *result = s->s_dip;
173 break;
174
175 case DDI_INFO_DEVT2INSTANCE:
176 *result = 0;
177 rc = DDI_SUCCESS;
178 break;
179
180 default:
181 break;
182 }
183 return (rc);
184 }
185
186 static int
187 smartpqi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
188 {
189 int instance;
190 pqi_state_t s = NULL;
191 int mem_bar = IO_SPACE;
192 mem_len_pair_t m;
193
194 switch (cmd) {
195 case DDI_ATTACH:
196 break;
197
198 case DDI_RESUME:
199 default:
200 return (DDI_FAILURE);
201 }
202
203 instance = ddi_get_instance(dip);
204
205 /* ---- allocate softc structure ---- */
206 if (ddi_soft_state_zalloc(pqi_state, instance) != DDI_SUCCESS)
207 return (DDI_FAILURE);
208
209 if ((s = ddi_get_soft_state(pqi_state, instance)) == NULL)
210 goto fail;
211
212 scsi_size_clean(dip);
213
214 s->s_dip = dip;
215 s->s_instance = instance;
216 s->s_intr_ready = 0;
217 s->s_offline = 0;
218 list_create(&s->s_devnodes, sizeof (struct pqi_device),
219 offsetof(struct pqi_device, pd_list));
220 list_create(&s->s_mem_check, sizeof (struct mem_check),
221 offsetof(struct mem_check, m_node));
222
223 /* ---- Initialize mutex used in interrupt handler ---- */
224 mutex_init(&s->s_mutex, NULL, MUTEX_DRIVER,
225 DDI_INTR_PRI(s->s_intr_pri));
226 mutex_init(&s->s_mem_mutex, NULL, MUTEX_DRIVER, NULL);
227 mutex_init(&s->s_io_mutex, NULL, MUTEX_DRIVER, NULL);
228 mutex_init(&s->s_intr_mutex, NULL, MUTEX_DRIVER, NULL);
229 cv_init(&s->s_quiescedvar, NULL, CV_DRIVER, NULL);
230 cv_init(&s->s_io_condvar, NULL, CV_DRIVER, NULL);
231 sema_init(&s->s_sync_rqst, 1, NULL, SEMA_DRIVER, NULL);
232
233 m = pqi_alloc_mem_len(256);
234 (void) snprintf(m.mem, m.len, "smartpqi_cache%d", instance);
235 s->s_cmd_cache = kmem_cache_create(m.mem, sizeof (struct pqi_cmd), 0,
236 pqi_cache_constructor, pqi_cache_destructor, NULL, s, NULL, 0);
237
238 (void) snprintf(m.mem, m.len, "pqi_events_taskq%d", instance);
239 s->s_events_taskq = ddi_taskq_create(s->s_dip, m.mem, 1,
240 TASKQ_DEFAULTPRI, 0);
241 (void) snprintf(m.mem, m.len, "pqi_complete_taskq%d", instance);
242 s->s_complete_taskq = ddi_taskq_create(s->s_dip, m.mem, 4,
243 TASKQ_DEFAULTPRI, 0);
244 pqi_free_mem_len(&m);
245
246 s->s_debug_level = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
247 DDI_PROP_DONTPASS, "debug", 0);
248 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
249 "enable-mpxio", 0) != 0) {
250 s->s_enable_mpxio = 1;
251 }
252 if (smartpqi_register_intrs(s) == FALSE) {
253 dev_err(s->s_dip, CE_WARN, "unable to register interrupts");
254 goto fail;
255 }
256
257 s->s_msg_dma_attr = smartpqi_dma_attrs;
258 s->s_reg_acc_attr = smartpqi_dev_attr;
259
260 if (ddi_regs_map_setup(dip, mem_bar, (caddr_t *)&s->s_reg, 0,
261 /* sizeof (pqi_ctrl_regs_t) */ 0x8000, &s->s_reg_acc_attr,
262 &s->s_datap) != DDI_SUCCESS) {
263 dev_err(s->s_dip, CE_WARN, "map setup failed");
264 goto fail;
265 }
266
267 if (pqi_check_firmware(s) == B_FALSE) {
268 dev_err(s->s_dip, CE_WARN, "firmware issue");
269 goto fail;
270 }
271 if (pqi_prep_full(s) == B_FALSE) {
272 goto fail;
273 }
274 if (smartpqi_register_hba(s) == FALSE) {
275 dev_err(s->s_dip, CE_WARN, "unable to register SCSI interface");
276 goto fail;
277 }
278 ddi_report_dev(s->s_dip);
279 s->s_mem_timeo = timeout(pqi_mem_check, s, drv_usectohz(5 * MICROSEC));
280
281 return (DDI_SUCCESS);
282
283 fail:
284 (void) smartpqi_detach(s->s_dip, 0);
285 return (DDI_FAILURE);
286 }
287
288 /*ARGSUSED*/
289 static int
290 smartpqi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
291 {
292 int instance;
293 pqi_state_t s;
294 pqi_device_t devp;
295
296 instance = ddi_get_instance(dip);
297 if ((s = ddi_get_soft_state(pqi_state, instance)) != NULL) {
298 if (s->s_rescan != NULL) {
299 (void) untimeout(s->s_rescan);
300 s->s_rescan = NULL;
301 }
302
303 if (s->s_watchdog != 0) {
304 (void) untimeout(s->s_watchdog);
305 s->s_watchdog = 0;
306 }
307
308 if (s->s_error_dma != NULL) {
309 pqi_free_single(s, s->s_error_dma);
310 s->s_error_dma = NULL;
311 }
312 if (s->s_adminq_dma != NULL) {
313 pqi_free_single(s, s->s_adminq_dma);
314 s->s_adminq_dma = NULL;
315 }
316 if (s->s_queue_dma != NULL) {
317 pqi_free_single(s, s->s_queue_dma);
318 s->s_queue_dma = NULL;
319 }
320
321 /* ---- Safe to always call ---- */
322 pqi_free_io_resource(s);
323
324 if (s->s_cmd_cache != NULL) {
325 kmem_cache_destroy(s->s_cmd_cache);
326 s->s_cmd_cache = NULL;
327 }
328
329 if (s->s_events_taskq != NULL) {
330 ddi_taskq_destroy(s->s_events_taskq);
331 s->s_events_taskq = NULL;
332 }
333 if (s->s_complete_taskq != NULL) {
334 ddi_taskq_destroy(s->s_complete_taskq);
335 s->s_complete_taskq = NULL;
336 }
337
338 while ((devp = list_head(&s->s_devnodes)) != NULL) {
339 /* ---- Better not be any active commands ---- */
340 ASSERT(list_is_empty(&devp->pd_cmd_list));
341
342 ddi_devid_free_guid(devp->pd_guid);
343 if (devp->pd_pip != NULL)
344 (void) mdi_pi_free(devp->pd_pip, 0);
345 if (devp->pd_pip_offlined)
346 (void) mdi_pi_free(devp->pd_pip_offlined, 0);
347 list_destroy(&devp->pd_cmd_list);
348 mutex_destroy(&devp->pd_mutex);
349 list_remove(&s->s_devnodes, devp);
350 PQI_FREE(devp, sizeof (*devp));
351 }
352 list_destroy(&s->s_devnodes);
353 mutex_destroy(&s->s_mutex);
354 mutex_destroy(&s->s_io_mutex);
355 mutex_destroy(&s->s_intr_mutex);
356
357 cv_destroy(&s->s_quiescedvar);
358 smartpqi_unregister_hba(s);
359 smartpqi_unregister_intrs(s);
360
361 if (s->s_mem_timeo != 0) {
362 mutex_enter(&s->s_mem_mutex);
363 (void) untimeout(s->s_mem_timeo);
364 s->s_mem_timeo = 0;
365 mutex_exit(&s->s_mem_mutex);
366 mutex_destroy(&s->s_mem_mutex);
367 }
368
369 if (s->s_time_of_day != 0) {
370 (void) untimeout(s->s_time_of_day);
371 s->s_time_of_day = 0;
372 }
373
374 ddi_soft_state_free(pqi_state, instance);
375 ddi_prop_remove_all(dip);
376 }
377
378 return (DDI_SUCCESS);
379 }
380
381 /*ARGSUSED*/
382 static int
383 smartpqi_power(dev_info_t *dip, int component, int level)
384 {
385 return (DDI_SUCCESS);
386 }
387
388 /*ARGSUSED*/
389 static int
390 smartpqi_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp,
391 int *rval)
392 {
393 return (0);
394 }