mlx.c revision 1.69 1 /* $NetBSD: mlx.c,v 1.69 2021/04/24 23:36:55 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*-
33 * Copyright (c) 1999 Michael Smith
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 *
57 * from FreeBSD: mlx.c,v 1.14.2.3 2000/08/04 06:52:50 msmith Exp
58 */
59
60 /*
61 * Driver for the Mylex DAC960 family of RAID controllers.
62 *
63 * TODO:
64 *
65 * o Test and enable channel pause.
66 * o SCSI pass-through.
67 */
68
69 #include <sys/cdefs.h>
70 __KERNEL_RCSID(0, "$NetBSD: mlx.c,v 1.69 2021/04/24 23:36:55 thorpej Exp $");
71
72 #if defined(_KERNEL_OPT)
73 #include "ld.h"
74 #endif
75
76 #include <sys/param.h>
77 #include <sys/systm.h>
78 #include <sys/kernel.h>
79 #include <sys/device.h>
80 #include <sys/queue.h>
81 #include <sys/proc.h>
82 #include <sys/buf.h>
83 #include <sys/bufq.h>
84 #include <sys/endian.h>
85 #include <sys/malloc.h>
86 #include <sys/conf.h>
87 #include <sys/kthread.h>
88 #include <sys/disk.h>
89 #include <sys/kauth.h>
90 #include <sys/module.h>
91 #include <machine/vmparam.h>
92 #include <sys/bus.h>
93
94 #include <dev/ldvar.h>
95
96 #include <dev/ic/mlxreg.h>
97 #include <dev/ic/mlxio.h>
98 #include <dev/ic/mlxvar.h>
99
100 #include "ioconf.h"
101 #include "locators.h"
102
103 #define MLX_TIMEOUT 60
104
105 #ifdef DIAGNOSTIC
106 #define DPRINTF(x) printf x
107 #else
108 #define DPRINTF(x)
109 #endif
110
111 static void mlx_adjqparam(struct mlx_softc *, int, int);
112 static int mlx_ccb_submit(struct mlx_softc *, struct mlx_ccb *);
113 static int mlx_check(struct mlx_softc *, int);
114 static void mlx_describe(struct mlx_softc *);
115 static void *mlx_enquire(struct mlx_softc *, int, size_t,
116 void (*)(struct mlx_ccb *), int);
117 static int mlx_fw_message(struct mlx_softc *, int, int, int);
118 static void mlx_pause_action(struct mlx_softc *);
119 static void mlx_pause_done(struct mlx_ccb *);
120 static void mlx_periodic(struct mlx_softc *);
121 static void mlx_periodic_enquiry(struct mlx_ccb *);
122 static void mlx_periodic_eventlog_poll(struct mlx_softc *);
123 static void mlx_periodic_eventlog_respond(struct mlx_ccb *);
124 static void mlx_periodic_rebuild(struct mlx_ccb *);
125 static void mlx_periodic_thread(void *);
126 static int mlx_print(void *, const char *);
127 static int mlx_rebuild(struct mlx_softc *, int, int);
128 static void mlx_shutdown(void *);
129 static int mlx_user_command(struct mlx_softc *, struct mlx_usercommand *);
130
131 dev_type_open(mlxopen);
132 dev_type_close(mlxclose);
133 dev_type_ioctl(mlxioctl);
134
135 const struct cdevsw mlx_cdevsw = {
136 .d_open = mlxopen,
137 .d_close = mlxclose,
138 .d_read = noread,
139 .d_write = nowrite,
140 .d_ioctl = mlxioctl,
141 .d_stop = nostop,
142 .d_tty = notty,
143 .d_poll = nopoll,
144 .d_mmap = nommap,
145 .d_kqfilter = nokqfilter,
146 .d_discard = nodiscard,
147 .d_flag = D_OTHER
148 };
149
150 static struct lwp *mlx_periodic_lwp;
151 static void *mlx_sdh;
152
153 static struct {
154 int hwid;
155 const char *name;
156 } const mlx_cname[] = {
157 { 0x00, "960E/960M" },
158 { 0x01, "960P/PD" },
159 { 0x02, "960PL" },
160 { 0x10, "960PG" },
161 { 0x11, "960PJ" },
162 { 0x12, "960PR" },
163 { 0x13, "960PT" },
164 { 0x14, "960PTL0" },
165 { 0x15, "960PRL" },
166 { 0x16, "960PTL1" },
167 { 0x20, "1164PVX" },
168 };
169
170 static const char * const mlx_sense_msgs[] = {
171 "because write recovery failed",
172 "because of SCSI bus reset failure",
173 "because of double check condition",
174 "because it was removed",
175 "because of gross error on SCSI chip",
176 "because of bad tag returned from drive",
177 "because of timeout on SCSI command",
178 "because of reset SCSI command issued from system",
179 "because busy or parity error count exceeded limit",
180 "because of 'kill drive' command from system",
181 "because of selection timeout",
182 "due to SCSI phase sequence error",
183 "due to unknown status"
184 };
185
186 static const char * const mlx_status_msgs[] = {
187 "normal completion", /* 0 */
188 "irrecoverable data error", /* 1 */
189 "drive does not exist, or is offline", /* 2 */
190 "attempt to write beyond end of drive", /* 3 */
191 "bad data encountered", /* 4 */
192 "invalid log entry request", /* 5 */
193 "attempt to rebuild online drive", /* 6 */
194 "new disk failed during rebuild", /* 7 */
195 "invalid channel/target", /* 8 */
196 "rebuild/check already in progress", /* 9 */
197 "one or more disks are dead", /* 10 */
198 "invalid or non-redundant drive", /* 11 */
199 "channel is busy", /* 12 */
200 "channel is not stopped", /* 13 */
201 "rebuild successfully terminated", /* 14 */
202 "unsupported command", /* 15 */
203 "check condition received", /* 16 */
204 "device is busy", /* 17 */
205 "selection or command timeout", /* 18 */
206 "command terminated abnormally", /* 19 */
207 "controller wedged", /* 20 */
208 "software timeout", /* 21 */
209 "command busy (?)", /* 22 */
210 };
211
212 static struct {
213 u_char command;
214 u_char msg; /* Index into mlx_status_msgs[]. */
215 u_short status;
216 } const mlx_msgs[] = {
217 { MLX_CMD_READSG, 1, 0x0001 },
218 { MLX_CMD_READSG, 1, 0x0002 },
219 { MLX_CMD_READSG, 3, 0x0105 },
220 { MLX_CMD_READSG, 4, 0x010c },
221 { MLX_CMD_WRITESG, 1, 0x0001 },
222 { MLX_CMD_WRITESG, 1, 0x0002 },
223 { MLX_CMD_WRITESG, 3, 0x0105 },
224 { MLX_CMD_READSG_OLD, 1, 0x0001 },
225 { MLX_CMD_READSG_OLD, 1, 0x0002 },
226 { MLX_CMD_READSG_OLD, 3, 0x0105 },
227 { MLX_CMD_WRITESG_OLD, 1, 0x0001 },
228 { MLX_CMD_WRITESG_OLD, 1, 0x0002 },
229 { MLX_CMD_WRITESG_OLD, 3, 0x0105 },
230 { MLX_CMD_LOGOP, 5, 0x0105 },
231 { MLX_CMD_REBUILDASYNC, 6, 0x0002 },
232 { MLX_CMD_REBUILDASYNC, 7, 0x0004 },
233 { MLX_CMD_REBUILDASYNC, 8, 0x0105 },
234 { MLX_CMD_REBUILDASYNC, 9, 0x0106 },
235 { MLX_CMD_REBUILDASYNC, 14, 0x0107 },
236 { MLX_CMD_CHECKASYNC, 10, 0x0002 },
237 { MLX_CMD_CHECKASYNC, 11, 0x0105 },
238 { MLX_CMD_CHECKASYNC, 9, 0x0106 },
239 { MLX_CMD_STOPCHANNEL, 12, 0x0106 },
240 { MLX_CMD_STOPCHANNEL, 8, 0x0105 },
241 { MLX_CMD_STARTCHANNEL, 13, 0x0005 },
242 { MLX_CMD_STARTCHANNEL, 8, 0x0105 },
243 { MLX_CMD_DIRECT_CDB, 16, 0x0002 },
244 { MLX_CMD_DIRECT_CDB, 17, 0x0008 },
245 { MLX_CMD_DIRECT_CDB, 18, 0x000e },
246 { MLX_CMD_DIRECT_CDB, 19, 0x000f },
247 { MLX_CMD_DIRECT_CDB, 8, 0x0105 },
248
249 { 0, 20, MLX_STATUS_WEDGED },
250 { 0, 21, MLX_STATUS_LOST },
251 { 0, 22, MLX_STATUS_BUSY },
252
253 { 0, 14, 0x0104 },
254 };
255
256 /*
257 * Initialise the controller and our interface.
258 */
259 void
260 mlx_init(struct mlx_softc *mlx, const char *intrstr)
261 {
262 struct mlx_ccb *mc;
263 struct mlx_enquiry_old *meo;
264 struct mlx_enquiry2 *me2;
265 struct mlx_cinfo *ci;
266 int rv, fwminor, hscode, hserr, hsparam1, hsparam2, hsmsg;
267 int size, i, rseg;
268 const char *wantfwstr;
269 bus_dma_segment_t seg;
270
271 SIMPLEQ_INIT(&mlx->mlx_ccb_queue);
272 SLIST_INIT(&mlx->mlx_ccb_freelist);
273 TAILQ_INIT(&mlx->mlx_ccb_worklist);
274
275 if (intrstr != NULL)
276 printf("%s: interrupting at %s\n", device_xname(mlx->mlx_dv),
277 intrstr);
278
279 /*
280 * Allocate the scatter/gather lists.
281 */
282 size = MLX_SGL_SIZE * MLX_MAX_QUEUECNT;
283
284 if ((rv = bus_dmamem_alloc(mlx->mlx_dmat, size, PAGE_SIZE, 0, &seg, 1,
285 &rseg, BUS_DMA_NOWAIT)) != 0) {
286 aprint_error_dev(mlx->mlx_dv,
287 "unable to allocate sglists, rv = %d\n", rv);
288 return;
289 }
290
291 if ((rv = bus_dmamem_map(mlx->mlx_dmat, &seg, rseg, size,
292 (void **)&mlx->mlx_sgls,
293 BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
294 aprint_error_dev(mlx->mlx_dv,
295 "unable to map sglists, rv = %d\n", rv);
296 return;
297 }
298
299 if ((rv = bus_dmamap_create(mlx->mlx_dmat, size, 1, size, 0,
300 BUS_DMA_NOWAIT, &mlx->mlx_dmamap)) != 0) {
301 aprint_error_dev(mlx->mlx_dv,
302 "unable to create sglist DMA map, rv = %d\n", rv);
303 return;
304 }
305
306 if ((rv = bus_dmamap_load(mlx->mlx_dmat, mlx->mlx_dmamap,
307 mlx->mlx_sgls, size, NULL, BUS_DMA_NOWAIT)) != 0) {
308 aprint_error_dev(mlx->mlx_dv,
309 "unable to load sglist DMA map, rv = %d\n", rv);
310 return;
311 }
312
313 mlx->mlx_sgls_paddr = mlx->mlx_dmamap->dm_segs[0].ds_addr;
314 memset(mlx->mlx_sgls, 0, size);
315
316 /*
317 * Allocate and initialize the CCBs.
318 */
319 mc = malloc(sizeof(*mc) * MLX_MAX_QUEUECNT, M_DEVBUF, M_WAITOK);
320 mlx->mlx_ccbs = mc;
321
322 for (i = 0; i < MLX_MAX_QUEUECNT; i++, mc++) {
323 mc->mc_ident = i;
324 rv = bus_dmamap_create(mlx->mlx_dmat, MLX_MAX_XFER,
325 MLX_MAX_SEGS, MLX_MAX_XFER, 0,
326 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
327 &mc->mc_xfer_map);
328 if (rv != 0)
329 break;
330 mlx->mlx_nccbs++;
331 mlx_ccb_free(mlx, mc);
332 }
333 if (mlx->mlx_nccbs != MLX_MAX_QUEUECNT)
334 printf("%s: %d/%d CCBs usable\n", device_xname(mlx->mlx_dv),
335 mlx->mlx_nccbs, MLX_MAX_QUEUECNT);
336
337 /* Disable interrupts before we start talking to the controller */
338 (*mlx->mlx_intaction)(mlx, 0);
339
340 /* If we've got a reset routine, then reset the controller now. */
341 if (mlx->mlx_reset != NULL) {
342 printf("%s: resetting controller...\n",
343 device_xname(mlx->mlx_dv));
344 if ((*mlx->mlx_reset)(mlx) != 0) {
345 aprint_error_dev(mlx->mlx_dv, "reset failed\n");
346 return;
347 }
348 }
349
350 /*
351 * Wait for the controller to come ready, handshaking with the
352 * firmware if required. This is typically only necessary on
353 * platforms where the controller BIOS does not run.
354 */
355 hsmsg = 0;
356
357 for (;;) {
358 hscode = (*mlx->mlx_fw_handshake)(mlx, &hserr, &hsparam1,
359 &hsparam2);
360 if (hscode == 0) {
361 if (hsmsg != 0)
362 printf("%s: initialization complete\n",
363 device_xname(mlx->mlx_dv));
364 break;
365 }
366
367 /* Report first time around... */
368 if (hsmsg == 0) {
369 printf("%s: initializing (may take some time)...\n",
370 device_xname(mlx->mlx_dv));
371 hsmsg = 1;
372 }
373
374 /* Did we get a real message? */
375 if (hscode == 2) {
376 hscode = mlx_fw_message(mlx, hserr, hsparam1, hsparam2);
377
378 /* Fatal initialisation error? */
379 if (hscode != 0)
380 return;
381 }
382 }
383
384 /*
385 * Do quirk/feature related things.
386 */
387 ci = &mlx->mlx_ci;
388
389 if (ci->ci_iftype > 1) {
390 me2 = mlx_enquire(mlx, MLX_CMD_ENQUIRY2,
391 sizeof(struct mlx_enquiry2), NULL, 0);
392 if (me2 == NULL) {
393 aprint_error_dev(mlx->mlx_dv, "ENQUIRY2 failed\n");
394 return;
395 }
396
397 ci->ci_firmware_id[0] = me2->me_firmware_id[0];
398 ci->ci_firmware_id[1] = me2->me_firmware_id[1];
399 ci->ci_firmware_id[2] = me2->me_firmware_id[2];
400 ci->ci_firmware_id[3] = me2->me_firmware_id[3];
401 ci->ci_hardware_id = me2->me_hardware_id[0];
402 ci->ci_mem_size = le32toh(me2->me_mem_size);
403 ci->ci_max_sg = le16toh(me2->me_max_sg);
404 ci->ci_max_commands = le16toh(me2->me_max_commands);
405 ci->ci_nchan = me2->me_actual_channels;
406
407 free(me2, M_DEVBUF);
408 }
409
410 if (ci->ci_iftype <= 2) {
411 /*
412 * These controllers may not report the firmware version in
413 * the ENQUIRY2 response, or may not even support it.
414 */
415 meo = mlx_enquire(mlx, MLX_CMD_ENQUIRY_OLD,
416 sizeof(struct mlx_enquiry_old), NULL, 0);
417 if (meo == NULL) {
418 aprint_error_dev(mlx->mlx_dv, "ENQUIRY_OLD failed\n");
419 return;
420 }
421 ci->ci_firmware_id[0] = meo->me_fwmajor;
422 ci->ci_firmware_id[1] = meo->me_fwminor;
423 ci->ci_firmware_id[2] = 0;
424 ci->ci_firmware_id[3] = '0';
425
426 if (ci->ci_iftype == 1) {
427 ci->ci_hardware_id = 0; /* XXX */
428 ci->ci_mem_size = 0; /* XXX */
429 ci->ci_max_sg = 17; /* XXX */
430 ci->ci_max_commands = meo->me_max_commands;
431 }
432
433 free(meo, M_DEVBUF);
434 }
435
436 wantfwstr = NULL;
437 fwminor = ci->ci_firmware_id[1];
438
439 switch (ci->ci_firmware_id[0]) {
440 case 2:
441 if (ci->ci_iftype == 1) {
442 if (fwminor < 14)
443 wantfwstr = "2.14";
444 } else if (fwminor < 42)
445 wantfwstr = "2.42";
446 break;
447
448 case 3:
449 if (fwminor < 51)
450 wantfwstr = "3.51";
451 break;
452
453 case 4:
454 if (fwminor < 6)
455 wantfwstr = "4.06";
456 break;
457
458 case 5:
459 if (fwminor < 7)
460 wantfwstr = "5.07";
461 break;
462 }
463
464 /* Print a little information about the controller. */
465 mlx_describe(mlx);
466
467 if (wantfwstr != NULL) {
468 printf("%s: WARNING: this f/w revision is not recommended\n",
469 device_xname(mlx->mlx_dv));
470 printf("%s: WARNING: use revision %s or later\n",
471 device_xname(mlx->mlx_dv), wantfwstr);
472 }
473
474 /* We don't (yet) know where the event log is up to. */
475 mlx->mlx_currevent = -1;
476
477 /* No user-requested background operation is in progress. */
478 mlx->mlx_bg = 0;
479 mlx->mlx_rebuildstat.rs_code = MLX_REBUILDSTAT_IDLE;
480
481 /* Set maximum number of queued commands for `regular' operations. */
482 mlx->mlx_max_queuecnt =
483 uimin(ci->ci_max_commands, MLX_MAX_QUEUECNT) -
484 MLX_NCCBS_CONTROL;
485 #ifdef DIAGNOSTIC
486 if (mlx->mlx_max_queuecnt < MLX_NCCBS_CONTROL + MLX_MAX_DRIVES)
487 printf("%s: WARNING: few CCBs available\n",
488 device_xname(mlx->mlx_dv));
489 if (ci->ci_max_sg < MLX_MAX_SEGS) {
490 aprint_error_dev(mlx->mlx_dv,
491 "oops, not enough S/G segments\n");
492 return;
493 }
494 #endif
495
496 /* Attach child devices and enable interrupts. */
497 mlx_configure(mlx, 0);
498 (*mlx->mlx_intaction)(mlx, 1);
499 mlx->mlx_flags |= MLXF_INITOK;
500
501 if (mlx_sdh == NULL) {
502 /*
503 * Set our `shutdownhook' before we start any device
504 * activity.
505 */
506 mlx_sdh = shutdownhook_establish(mlx_shutdown, NULL);
507
508 /* Create a status monitoring thread. */
509 rv = kthread_create(PRI_NONE, 0, NULL, mlx_periodic_thread,
510 NULL, &mlx_periodic_lwp, "mlxtask");
511 if (rv != 0)
512 aprint_error_dev(mlx->mlx_dv,
513 "mlx_init: unable to create thread (%d)\n", rv);
514 }
515 }
516
517 /*
518 * Tell the world about the controller.
519 */
520 static void
521 mlx_describe(struct mlx_softc *mlx)
522 {
523 struct mlx_cinfo *ci;
524 static char tbuf[80];
525 const char *model;
526 int i;
527
528 model = NULL;
529 ci = &mlx->mlx_ci;
530
531 for (i = 0; i < sizeof(mlx_cname) / sizeof(mlx_cname[0]); i++)
532 if (ci->ci_hardware_id == mlx_cname[i].hwid) {
533 model = mlx_cname[i].name;
534 break;
535 }
536
537 if (model == NULL) {
538 snprintf(tbuf, sizeof(tbuf), " model 0x%x", ci->ci_hardware_id);
539 model = tbuf;
540 }
541
542 printf("%s: DAC%s, %d channel%s, firmware %d.%02d-%c-%02d",
543 device_xname(mlx->mlx_dv), model, ci->ci_nchan,
544 ci->ci_nchan > 1 ? "s" : "",
545 ci->ci_firmware_id[0], ci->ci_firmware_id[1],
546 ci->ci_firmware_id[3], ci->ci_firmware_id[2]);
547 if (ci->ci_mem_size != 0)
548 printf(", %dMB RAM", ci->ci_mem_size >> 20);
549 printf("\n");
550 }
551
552 /*
553 * Locate disk resources and attach children to them.
554 */
555 int
556 mlx_configure(struct mlx_softc *mlx, int waitok)
557 {
558 struct mlx_enquiry *me;
559 struct mlx_enquiry_old *meo;
560 struct mlx_enq_sys_drive *mes;
561 struct mlx_sysdrive *ms;
562 struct mlx_attach_args mlxa;
563 int i, nunits;
564 u_int size;
565 int locs[MLXCF_NLOCS];
566
567 mlx->mlx_flags |= MLXF_RESCANNING;
568
569 if (mlx->mlx_ci.ci_iftype <= 2) {
570 meo = mlx_enquire(mlx, MLX_CMD_ENQUIRY_OLD,
571 sizeof(struct mlx_enquiry_old), NULL, waitok);
572 if (meo == NULL) {
573 aprint_error_dev(mlx->mlx_dv, "ENQUIRY_OLD failed\n");
574 goto out;
575 }
576 mlx->mlx_numsysdrives = meo->me_num_sys_drvs;
577 free(meo, M_DEVBUF);
578 } else {
579 me = mlx_enquire(mlx, MLX_CMD_ENQUIRY,
580 sizeof(struct mlx_enquiry), NULL, waitok);
581 if (me == NULL) {
582 aprint_error_dev(mlx->mlx_dv, "ENQUIRY failed\n");
583 goto out;
584 }
585 mlx->mlx_numsysdrives = me->me_num_sys_drvs;
586 free(me, M_DEVBUF);
587 }
588
589 mes = mlx_enquire(mlx, MLX_CMD_ENQSYSDRIVE,
590 sizeof(*mes) * MLX_MAX_DRIVES, NULL, waitok);
591 if (mes == NULL) {
592 aprint_error_dev(mlx->mlx_dv, "error fetching drive status\n");
593 goto out;
594 }
595
596 /* Allow 1 queued command per unit while re-configuring. */
597 mlx_adjqparam(mlx, 1, 0);
598
599 ms = &mlx->mlx_sysdrive[0];
600 nunits = 0;
601 for (i = 0; i < MLX_MAX_DRIVES; i++, ms++) {
602 size = le32toh(mes[i].sd_size);
603 ms->ms_state = mes[i].sd_state;
604
605 /*
606 * If an existing device has changed in some way (e.g. no
607 * longer present) then detach it.
608 */
609 if (ms->ms_dv != NULL && (size != ms->ms_size ||
610 (mes[i].sd_raidlevel & 0xf) != ms->ms_raidlevel))
611 config_detach(ms->ms_dv, DETACH_FORCE);
612
613 ms->ms_size = size;
614 ms->ms_raidlevel = mes[i].sd_raidlevel & 0xf;
615 ms->ms_state = mes[i].sd_state;
616 ms->ms_dv = NULL;
617
618 if (i >= mlx->mlx_numsysdrives)
619 continue;
620 if (size == 0xffffffffU || size == 0)
621 continue;
622
623 /*
624 * Attach a new device.
625 */
626 mlxa.mlxa_unit = i;
627
628 locs[MLXCF_UNIT] = i;
629
630 ms->ms_dv = config_found(mlx->mlx_dv, &mlxa, mlx_print,
631 CFARG_SUBMATCH, config_stdsubmatch,
632 CFARG_LOCATORS, locs,
633 CFARG_EOL);
634 nunits += (ms->ms_dv != NULL);
635 }
636
637 free(mes, M_DEVBUF);
638
639 if (nunits != 0)
640 mlx_adjqparam(mlx, mlx->mlx_max_queuecnt / nunits,
641 mlx->mlx_max_queuecnt % nunits);
642 out:
643 mlx->mlx_flags &= ~MLXF_RESCANNING;
644
645 return 0;
646 }
647
648 /*
649 * Print autoconfiguration message for a sub-device.
650 */
651 static int
652 mlx_print(void *aux, const char *pnp)
653 {
654 struct mlx_attach_args *mlxa;
655
656 mlxa = (struct mlx_attach_args *)aux;
657
658 if (pnp != NULL)
659 aprint_normal("block device at %s", pnp);
660 aprint_normal(" unit %d", mlxa->mlxa_unit);
661 return (UNCONF);
662 }
663
664 /*
665 * Shut down all configured `mlx' devices.
666 */
667 static void
668 mlx_shutdown(void *cookie)
669 {
670 struct mlx_softc *mlx;
671 int i;
672
673 for (i = 0; i < mlx_cd.cd_ndevs; i++)
674 if ((mlx = device_lookup_private(&mlx_cd, i)) != NULL)
675 mlx_flush(mlx, 0);
676 }
677
678 /*
679 * Adjust queue parameters for all child devices.
680 */
681 static void
682 mlx_adjqparam(struct mlx_softc *mlx, int mpu, int slop)
683 {
684 #if NLD > 0
685 struct ld_softc *ld;
686 int i;
687
688 for (i = 0; i < ld_cd.cd_ndevs; i++) {
689 if ((ld = device_lookup_private(&ld_cd, i)) == NULL)
690 continue;
691 if (device_parent(ld->sc_dv) != mlx->mlx_dv)
692 continue;
693 ldadjqparam(ld, mpu + (slop-- > 0));
694 }
695 #endif
696 }
697
698 /*
699 * Accept an open operation on the control device.
700 */
701 int
702 mlxopen(dev_t dev, int flag, int mode, struct lwp *l)
703 {
704 struct mlx_softc *mlx;
705
706 if ((mlx = device_lookup_private(&mlx_cd, minor(dev))) == NULL)
707 return (ENXIO);
708 if ((mlx->mlx_flags & MLXF_INITOK) == 0)
709 return (ENXIO);
710 if ((mlx->mlx_flags & MLXF_OPEN) != 0)
711 return (EBUSY);
712
713 mlx->mlx_flags |= MLXF_OPEN;
714 return (0);
715 }
716
717 /*
718 * Accept the last close on the control device.
719 */
720 int
721 mlxclose(dev_t dev, int flag, int mode, struct lwp *l)
722 {
723 struct mlx_softc *mlx;
724
725 mlx = device_lookup_private(&mlx_cd, minor(dev));
726 mlx->mlx_flags &= ~MLXF_OPEN;
727 return (0);
728 }
729
730 /*
731 * Handle control operations.
732 */
733 int
734 mlxioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
735 {
736 struct mlx_softc *mlx;
737 struct mlx_rebuild_request *rb;
738 struct mlx_rebuild_status *rs;
739 struct mlx_pause *mp;
740 struct mlx_sysdrive *ms;
741 int i, rv, *arg, result;
742
743 mlx = device_lookup_private(&mlx_cd, minor(dev));
744
745 rb = (struct mlx_rebuild_request *)data;
746 rs = (struct mlx_rebuild_status *)data;
747 arg = (int *)data;
748 rv = 0;
749
750 switch (cmd) {
751 case MLX_RESCAN_DRIVES:
752 /*
753 * Scan the controller to see whether new drives have
754 * appeared, or old ones disappeared.
755 */
756 mlx_configure(mlx, 1);
757 return (0);
758
759 case MLX_PAUSE_CHANNEL:
760 /*
761 * Pause one or more SCSI channels for a period of time, to
762 * assist in the process of hot-swapping devices.
763 *
764 * Note that at least the 3.51 firmware on the DAC960PL
765 * doesn't seem to do this right.
766 */
767 if ((mlx->mlx_flags & MLXF_PAUSEWORKS) == 0)
768 return (EOPNOTSUPP);
769
770 mp = (struct mlx_pause *)data;
771
772 if ((mp->mp_which == MLX_PAUSE_CANCEL) &&
773 (mlx->mlx_pause.mp_when != 0)) {
774 /* Cancel a pending pause operation. */
775 mlx->mlx_pause.mp_which = 0;
776 break;
777 }
778
779 /* Fix for legal channels. */
780 mp->mp_which &= ((1 << mlx->mlx_ci.ci_nchan) -1);
781
782 /* Check time values. */
783 if (mp->mp_when < 0 || mp->mp_when > 3600 ||
784 mp->mp_howlong < 1 || mp->mp_howlong > (0xf * 30)) {
785 rv = EINVAL;
786 break;
787 }
788
789 /* Check for a pause currently running. */
790 if ((mlx->mlx_pause.mp_which != 0) &&
791 (mlx->mlx_pause.mp_when == 0)) {
792 rv = EBUSY;
793 break;
794 }
795
796 /* Looks ok, go with it. */
797 mlx->mlx_pause.mp_which = mp->mp_which;
798 mlx->mlx_pause.mp_when = time_second + mp->mp_when;
799 mlx->mlx_pause.mp_howlong =
800 mlx->mlx_pause.mp_when + mp->mp_howlong;
801
802 return (0);
803
804 case MLX_COMMAND:
805 rv = kauth_authorize_device_passthru(l->l_cred, dev,
806 KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL, data);
807 if (rv)
808 return (rv);
809
810 /*
811 * Accept a command passthrough-style.
812 */
813 return (mlx_user_command(mlx, (struct mlx_usercommand *)data));
814
815 case MLX_REBUILDASYNC:
816 /*
817 * Start a rebuild on a given SCSI disk
818 */
819 if (mlx->mlx_bg != 0) {
820 rb->rr_status = 0x0106;
821 rv = EBUSY;
822 break;
823 }
824
825 rb->rr_status = mlx_rebuild(mlx, rb->rr_channel, rb->rr_target);
826 switch (rb->rr_status) {
827 case 0:
828 rv = 0;
829 break;
830 case 0x10000:
831 rv = ENOMEM; /* Couldn't set up the command. */
832 break;
833 case 0x0002:
834 rv = EBUSY;
835 break;
836 case 0x0104:
837 rv = EIO;
838 break;
839 case 0x0105:
840 rv = ERANGE;
841 break;
842 case 0x0106:
843 rv = EBUSY;
844 break;
845 default:
846 rv = EINVAL;
847 break;
848 }
849
850 if (rv == 0)
851 mlx->mlx_bg = MLX_BG_REBUILD;
852
853 return (0);
854
855 case MLX_REBUILDSTAT:
856 /*
857 * Get the status of the current rebuild or consistency check.
858 */
859 *rs = mlx->mlx_rebuildstat;
860 return (0);
861
862 case MLX_GET_SYSDRIVE:
863 /*
864 * Return the system drive number matching the `ld' device
865 * unit in (arg), if it happens to belong to us.
866 */
867 for (i = 0; i < MLX_MAX_DRIVES; i++) {
868 ms = &mlx->mlx_sysdrive[i];
869 if (ms->ms_dv != NULL)
870 if (device_xname(ms->ms_dv)[2] == '0' + *arg) {
871 *arg = i;
872 return (0);
873 }
874 }
875 return (ENOENT);
876
877 case MLX_GET_CINFO:
878 /*
879 * Return controller info.
880 */
881 memcpy(arg, &mlx->mlx_ci, sizeof(mlx->mlx_ci));
882 return (0);
883 }
884
885 switch (cmd) {
886 case MLXD_DETACH:
887 case MLXD_STATUS:
888 case MLXD_CHECKASYNC:
889 if ((u_int)*arg >= MLX_MAX_DRIVES)
890 return (EINVAL);
891 ms = &mlx->mlx_sysdrive[*arg];
892 if (*arg > MLX_MAX_DRIVES || ms->ms_dv == NULL)
893 return (ENOENT);
894 break;
895
896 default:
897 return (ENOTTY);
898 }
899
900 switch (cmd) {
901 case MLXD_DETACH:
902 /*
903 * Disconnect from the specified drive; it may be about to go
904 * away.
905 */
906 return (config_detach(ms->ms_dv, 0));
907
908 case MLXD_STATUS:
909 /*
910 * Return the current status of this drive.
911 */
912 *arg = ms->ms_state;
913 return (0);
914
915 case MLXD_CHECKASYNC:
916 /*
917 * Start a background consistency check on this drive.
918 */
919 if (mlx->mlx_bg != 0) {
920 *arg = 0x0106;
921 return (EBUSY);
922 }
923
924 switch (result = mlx_check(mlx, *arg)) {
925 case 0:
926 rv = 0;
927 break;
928 case 0x10000:
929 rv = ENOMEM; /* Couldn't set up the command. */
930 break;
931 case 0x0002:
932 rv = EIO;
933 break;
934 case 0x0105:
935 rv = ERANGE;
936 break;
937 case 0x0106:
938 rv = EBUSY;
939 break;
940 default:
941 rv = EINVAL;
942 break;
943 }
944
945 if (rv == 0)
946 mlx->mlx_bg = MLX_BG_CHECK;
947 *arg = result;
948 return (rv);
949 }
950
951 return (ENOTTY); /* XXX shut up gcc */
952 }
953
954 static void
955 mlx_periodic_thread(void *cookie)
956 {
957 struct mlx_softc *mlx;
958 int i;
959
960 for (;;) {
961 for (i = 0; i < mlx_cd.cd_ndevs; i++)
962 if ((mlx = device_lookup_private(&mlx_cd, i)) != NULL)
963 if (mlx->mlx_ci.ci_iftype > 1)
964 mlx_periodic(mlx);
965
966 tsleep(mlx_periodic_thread, PWAIT, "mlxzzz", hz * 2);
967 }
968 }
969
970 static void
971 mlx_periodic(struct mlx_softc *mlx)
972 {
973 struct mlx_ccb *mc, *nmc;
974 int etype, s;
975
976 if ((mlx->mlx_pause.mp_which != 0) &&
977 (mlx->mlx_pause.mp_when > 0) &&
978 (time_second >= mlx->mlx_pause.mp_when)) {
979 /*
980 * Start bus pause.
981 */
982 mlx_pause_action(mlx);
983 mlx->mlx_pause.mp_when = 0;
984 } else if ((mlx->mlx_pause.mp_which != 0) &&
985 (mlx->mlx_pause.mp_when == 0)) {
986 /*
987 * Stop pause if required.
988 */
989 if (time_second >= mlx->mlx_pause.mp_howlong) {
990 mlx_pause_action(mlx);
991 mlx->mlx_pause.mp_which = 0;
992 }
993 } else if (time_second > (mlx->mlx_lastpoll + 10)) {
994 /*
995 * Run normal periodic activities...
996 */
997 mlx->mlx_lastpoll = time_second;
998
999 /*
1000 * Check controller status.
1001 */
1002 if ((mlx->mlx_flags & MLXF_PERIODIC_CTLR) == 0) {
1003 mlx->mlx_flags |= MLXF_PERIODIC_CTLR;
1004
1005 if (mlx->mlx_ci.ci_iftype <= 2)
1006 etype = MLX_CMD_ENQUIRY_OLD;
1007 else
1008 etype = MLX_CMD_ENQUIRY;
1009
1010 mlx_enquire(mlx, etype, uimax(sizeof(struct mlx_enquiry),
1011 sizeof(struct mlx_enquiry_old)),
1012 mlx_periodic_enquiry, 1);
1013 }
1014
1015 /*
1016 * Check system drive status.
1017 */
1018 if ((mlx->mlx_flags & MLXF_PERIODIC_DRIVE) == 0) {
1019 mlx->mlx_flags |= MLXF_PERIODIC_DRIVE;
1020 mlx_enquire(mlx, MLX_CMD_ENQSYSDRIVE,
1021 sizeof(struct mlx_enq_sys_drive) * MLX_MAX_DRIVES,
1022 mlx_periodic_enquiry, 1);
1023 }
1024 }
1025
1026 /*
1027 * Get drive rebuild/check status.
1028 */
1029 if ((mlx->mlx_flags & MLXF_PERIODIC_REBUILD) == 0) {
1030 mlx->mlx_flags |= MLXF_PERIODIC_REBUILD;
1031 mlx_enquire(mlx, MLX_CMD_REBUILDSTAT,
1032 sizeof(struct mlx_rebuild_stat), mlx_periodic_rebuild, 1);
1033 }
1034
1035 /*
1036 * Time-out busy CCBs.
1037 */
1038 s = splbio();
1039 for (mc = TAILQ_FIRST(&mlx->mlx_ccb_worklist); mc != NULL; mc = nmc) {
1040 nmc = TAILQ_NEXT(mc, mc_chain.tailq);
1041 if (mc->mc_expiry > time_second) {
1042 /*
1043 * The remaining CCBs will expire after this one, so
1044 * there's no point in going further.
1045 */
1046 break;
1047 }
1048 TAILQ_REMOVE(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
1049 mc->mc_status = MLX_STATUS_LOST;
1050 if (mc->mc_mx.mx_handler != NULL)
1051 (*mc->mc_mx.mx_handler)(mc);
1052 else if ((mc->mc_flags & MC_WAITING) != 0)
1053 wakeup(mc);
1054 }
1055 splx(s);
1056 }
1057
1058 /*
1059 * Handle the result of an ENQUIRY command instigated by periodic status
1060 * polling.
1061 */
1062 static void
1063 mlx_periodic_enquiry(struct mlx_ccb *mc)
1064 {
1065 struct mlx_softc *mlx;
1066 struct mlx_enquiry *me;
1067 struct mlx_enquiry_old *meo;
1068 struct mlx_enq_sys_drive *mes;
1069 struct mlx_sysdrive *dr;
1070 const char *statestr;
1071 int i, j;
1072 u_int lsn;
1073
1074 mlx = device_private(mc->mc_mx.mx_dv);
1075 mlx_ccb_unmap(mlx, mc);
1076
1077 /*
1078 * Command completed OK?
1079 */
1080 if (mc->mc_status != 0) {
1081 aprint_error_dev(mlx->mlx_dv, "periodic enquiry failed - %s\n",
1082 mlx_ccb_diagnose(mc));
1083 goto out;
1084 }
1085
1086 /*
1087 * Respond to command.
1088 */
1089 switch (mc->mc_mbox[0]) {
1090 case MLX_CMD_ENQUIRY_OLD:
1091 /*
1092 * This is currently a bit fruitless, as we don't know how
1093 * to extract the eventlog pointer yet.
1094 */
1095 me = (struct mlx_enquiry *)mc->mc_mx.mx_context;
1096 meo = (struct mlx_enquiry_old *)mc->mc_mx.mx_context;
1097
1098 /* Convert data in-place to new format */
1099 i = sizeof(me->me_dead) / sizeof(me->me_dead[0]);
1100 while (--i >= 0) {
1101 me->me_dead[i].dd_chan = meo->me_dead[i].dd_chan;
1102 me->me_dead[i].dd_targ = meo->me_dead[i].dd_targ;
1103 }
1104
1105 me->me_misc_flags = 0;
1106 me->me_rebuild_count = meo->me_rebuild_count;
1107 me->me_dead_count = meo->me_dead_count;
1108 me->me_critical_sd_count = meo->me_critical_sd_count;
1109 me->me_event_log_seq_num = 0;
1110 me->me_offline_sd_count = meo->me_offline_sd_count;
1111 me->me_max_commands = meo->me_max_commands;
1112 me->me_rebuild_flag = meo->me_rebuild_flag;
1113 me->me_fwmajor = meo->me_fwmajor;
1114 me->me_fwminor = meo->me_fwminor;
1115 me->me_status_flags = meo->me_status_flags;
1116 me->me_flash_age = meo->me_flash_age;
1117
1118 i = sizeof(me->me_drvsize) / sizeof(me->me_drvsize[0]);
1119 j = sizeof(meo->me_drvsize) / sizeof(meo->me_drvsize[0]);
1120
1121 while (--i >= 0) {
1122 if (i >= j)
1123 me->me_drvsize[i] = 0;
1124 else
1125 me->me_drvsize[i] = meo->me_drvsize[i];
1126 }
1127
1128 me->me_num_sys_drvs = meo->me_num_sys_drvs;
1129
1130 /* FALLTHROUGH */
1131
1132 case MLX_CMD_ENQUIRY:
1133 /*
1134 * Generic controller status update. We could do more with
1135 * this than just checking the event log.
1136 */
1137 me = (struct mlx_enquiry *)mc->mc_mx.mx_context;
1138 lsn = le16toh(me->me_event_log_seq_num);
1139
1140 if (mlx->mlx_currevent == -1) {
1141 /* Initialise our view of the event log. */
1142 mlx->mlx_currevent = lsn;
1143 mlx->mlx_lastevent = lsn;
1144 } else if (lsn != mlx->mlx_lastevent &&
1145 (mlx->mlx_flags & MLXF_EVENTLOG_BUSY) == 0) {
1146 /* Record where current events are up to */
1147 mlx->mlx_currevent = lsn;
1148
1149 /* Mark the event log as busy. */
1150 mlx->mlx_flags |= MLXF_EVENTLOG_BUSY;
1151
1152 /* Drain new eventlog entries. */
1153 mlx_periodic_eventlog_poll(mlx);
1154 }
1155 break;
1156
1157 case MLX_CMD_ENQSYSDRIVE:
1158 /*
1159 * Perform drive status comparison to see if something
1160 * has failed. Don't perform the comparison if we're
1161 * reconfiguring, since the system drive table will be
1162 * changing.
1163 */
1164 if ((mlx->mlx_flags & MLXF_RESCANNING) != 0)
1165 break;
1166
1167 mes = (struct mlx_enq_sys_drive *)mc->mc_mx.mx_context;
1168 dr = &mlx->mlx_sysdrive[0];
1169
1170 for (i = 0; i < mlx->mlx_numsysdrives; i++, dr++) {
1171 /* Has state been changed by controller? */
1172 if (dr->ms_state != mes[i].sd_state) {
1173 switch (mes[i].sd_state) {
1174 case MLX_SYSD_OFFLINE:
1175 statestr = "offline";
1176 break;
1177
1178 case MLX_SYSD_ONLINE:
1179 statestr = "online";
1180 break;
1181
1182 case MLX_SYSD_CRITICAL:
1183 statestr = "critical";
1184 break;
1185
1186 default:
1187 statestr = "unknown";
1188 break;
1189 }
1190
1191 printf("%s: unit %d %s\n",
1192 device_xname(mlx->mlx_dv), i, statestr);
1193
1194 /* Save new state. */
1195 dr->ms_state = mes[i].sd_state;
1196 }
1197 }
1198 break;
1199
1200 #ifdef DIAGNOSTIC
1201 default:
1202 printf("%s: mlx_periodic_enquiry: eh?\n",
1203 device_xname(mlx->mlx_dv));
1204 break;
1205 #endif
1206 }
1207
1208 out:
1209 if (mc->mc_mbox[0] == MLX_CMD_ENQSYSDRIVE)
1210 mlx->mlx_flags &= ~MLXF_PERIODIC_DRIVE;
1211 else
1212 mlx->mlx_flags &= ~MLXF_PERIODIC_CTLR;
1213
1214 free(mc->mc_mx.mx_context, M_DEVBUF);
1215 mlx_ccb_free(mlx, mc);
1216 }
1217
1218 /*
1219 * Instigate a poll for one event log message on (mlx). We only poll for
1220 * one message at a time, to keep our command usage down.
1221 */
1222 static void
1223 mlx_periodic_eventlog_poll(struct mlx_softc *mlx)
1224 {
1225 struct mlx_ccb *mc;
1226 void *result;
1227 int rv;
1228
1229 result = NULL;
1230
1231 if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
1232 goto out;
1233
1234 if ((result = malloc(1024, M_DEVBUF, M_WAITOK)) == NULL) {
1235 rv = ENOMEM;
1236 goto out;
1237 }
1238 if ((rv = mlx_ccb_map(mlx, mc, result, 1024, MC_XFER_IN)) != 0)
1239 goto out;
1240 if (mc->mc_nsgent != 1) {
1241 mlx_ccb_unmap(mlx, mc);
1242 printf("mlx_periodic_eventlog_poll: too many segs\n");
1243 goto out;
1244 }
1245
1246 /* Build the command to get one log entry. */
1247 mlx_make_type3(mc, MLX_CMD_LOGOP, MLX_LOGOP_GET, 1,
1248 mlx->mlx_lastevent, 0, 0, mc->mc_xfer_phys, 0);
1249
1250 mc->mc_mx.mx_handler = mlx_periodic_eventlog_respond;
1251 mc->mc_mx.mx_dv = mlx->mlx_dv;
1252 mc->mc_mx.mx_context = result;
1253
1254 /* Start the command. */
1255 mlx_ccb_enqueue(mlx, mc);
1256
1257 out:
1258 if (rv != 0) {
1259 if (mc != NULL)
1260 mlx_ccb_free(mlx, mc);
1261 if (result != NULL)
1262 free(result, M_DEVBUF);
1263 }
1264 }
1265
1266 /*
1267 * Handle the result of polling for a log message, generate diagnostic
1268 * output. If this wasn't the last message waiting for us, we'll go collect
1269 * another.
1270 */
1271 static void
1272 mlx_periodic_eventlog_respond(struct mlx_ccb *mc)
1273 {
1274 struct mlx_softc *mlx;
1275 struct mlx_eventlog_entry *el;
1276 const char *reason;
1277 u_int8_t sensekey, chan, targ;
1278
1279 mlx = device_private(mc->mc_mx.mx_dv);
1280 el = mc->mc_mx.mx_context;
1281 mlx_ccb_unmap(mlx, mc);
1282
1283 mlx->mlx_lastevent++;
1284
1285 if (mc->mc_status == 0) {
1286 switch (el->el_type) {
1287 case MLX_LOGMSG_SENSE: /* sense data */
1288 sensekey = el->el_sense & 0x0f;
1289 chan = (el->el_target >> 4) & 0x0f;
1290 targ = el->el_target & 0x0f;
1291
1292 /*
1293 * This is the only sort of message we understand at
1294 * the moment. The tests here are probably
1295 * incomplete.
1296 */
1297
1298 /*
1299 * Mylex vendor-specific message indicating a drive
1300 * was killed?
1301 */
1302 if (sensekey == 9 && el->el_asc == 0x80) {
1303 if (el->el_asq < sizeof(mlx_sense_msgs) /
1304 sizeof(mlx_sense_msgs[0]))
1305 reason = mlx_sense_msgs[el->el_asq];
1306 else
1307 reason = "for unknown reason";
1308
1309 printf("%s: physical drive %d:%d killed %s\n",
1310 device_xname(mlx->mlx_dv), chan, targ,
1311 reason);
1312 }
1313
1314 /*
1315 * SCSI drive was reset?
1316 */
1317 if (sensekey == 6 && el->el_asc == 0x29)
1318 printf("%s: physical drive %d:%d reset\n",
1319 device_xname(mlx->mlx_dv), chan, targ);
1320
1321 /*
1322 * SCSI drive error?
1323 */
1324 if (!(sensekey == 0 ||
1325 (sensekey == 2 &&
1326 el->el_asc == 0x04 &&
1327 (el->el_asq == 0x01 || el->el_asq == 0x02)))) {
1328 printf("%s: physical drive %d:%d error log: "
1329 "sense = %d asc = %x asq = %x\n",
1330 device_xname(mlx->mlx_dv), chan, targ,
1331 sensekey, el->el_asc, el->el_asq);
1332 printf("%s: info = %d:%d:%d:%d "
1333 " csi = %d:%d:%d:%d\n",
1334 device_xname(mlx->mlx_dv),
1335 el->el_information[0],
1336 el->el_information[1],
1337 el->el_information[2],
1338 el->el_information[3],
1339 el->el_csi[0], el->el_csi[1],
1340 el->el_csi[2], el->el_csi[3]);
1341 }
1342
1343 break;
1344
1345 default:
1346 aprint_error_dev(mlx->mlx_dv,
1347 "unknown log message type 0x%x\n", el->el_type);
1348 break;
1349 }
1350 } else {
1351 aprint_error_dev(mlx->mlx_dv,
1352 "error reading message log - %s\n", mlx_ccb_diagnose(mc));
1353
1354 /*
1355 * Give up on all the outstanding messages, as we may have
1356 * come unsynched.
1357 */
1358 mlx->mlx_lastevent = mlx->mlx_currevent;
1359 }
1360
1361 free(mc->mc_mx.mx_context, M_DEVBUF);
1362 mlx_ccb_free(mlx, mc);
1363
1364 /*
1365 * Is there another message to obtain?
1366 */
1367 if (mlx->mlx_lastevent != mlx->mlx_currevent)
1368 mlx_periodic_eventlog_poll(mlx);
1369 else
1370 mlx->mlx_flags &= ~MLXF_EVENTLOG_BUSY;
1371 }
1372
1373 /*
1374 * Handle check/rebuild operations in progress.
1375 */
1376 static void
1377 mlx_periodic_rebuild(struct mlx_ccb *mc)
1378 {
1379 struct mlx_softc *mlx;
1380 const char *opstr;
1381 struct mlx_rebuild_status *mr;
1382
1383 mlx = device_private(mc->mc_mx.mx_dv);
1384 mr = mc->mc_mx.mx_context;
1385 mlx_ccb_unmap(mlx, mc);
1386
1387 switch (mc->mc_status) {
1388 case 0:
1389 /*
1390 * Operation running, update stats.
1391 */
1392 mlx->mlx_rebuildstat = *mr;
1393
1394 /* Spontaneous rebuild/check? */
1395 if (mlx->mlx_bg == 0) {
1396 mlx->mlx_bg = MLX_BG_SPONTANEOUS;
1397 printf("%s: background check/rebuild started\n",
1398 device_xname(mlx->mlx_dv));
1399 }
1400 break;
1401
1402 case 0x0105:
1403 /*
1404 * Nothing running, finalise stats and report.
1405 */
1406 switch (mlx->mlx_bg) {
1407 case MLX_BG_CHECK:
1408 /* XXX Print drive? */
1409 opstr = "consistency check";
1410 break;
1411
1412 case MLX_BG_REBUILD:
1413 /* XXX Print channel:target? */
1414 opstr = "drive rebuild";
1415 break;
1416
1417 case MLX_BG_SPONTANEOUS:
1418 default:
1419 /*
1420 * If we have previously been non-idle, report the
1421 * transition
1422 */
1423 if (mlx->mlx_rebuildstat.rs_code !=
1424 MLX_REBUILDSTAT_IDLE)
1425 opstr = "background check/rebuild";
1426 else
1427 opstr = NULL;
1428 }
1429
1430 if (opstr != NULL)
1431 printf("%s: %s completed\n", device_xname(mlx->mlx_dv),
1432 opstr);
1433
1434 mlx->mlx_bg = 0;
1435 mlx->mlx_rebuildstat.rs_code = MLX_REBUILDSTAT_IDLE;
1436 break;
1437 }
1438
1439 free(mc->mc_mx.mx_context, M_DEVBUF);
1440 mlx_ccb_free(mlx, mc);
1441 mlx->mlx_flags &= ~MLXF_PERIODIC_REBUILD;
1442 }
1443
1444 /*
1445 * It's time to perform a channel pause action for (mlx), either start or
1446 * stop the pause.
1447 */
1448 static void
1449 mlx_pause_action(struct mlx_softc *mlx)
1450 {
1451 struct mlx_ccb *mc;
1452 int failsafe, i, cmd;
1453
1454 /* What are we doing here? */
1455 if (mlx->mlx_pause.mp_when == 0) {
1456 cmd = MLX_CMD_STARTCHANNEL;
1457 failsafe = 0;
1458 } else {
1459 cmd = MLX_CMD_STOPCHANNEL;
1460
1461 /*
1462 * Channels will always start again after the failsafe
1463 * period, which is specified in multiples of 30 seconds.
1464 * This constrains us to a maximum pause of 450 seconds.
1465 */
1466 failsafe = ((mlx->mlx_pause.mp_howlong - time_second) + 5) / 30;
1467
1468 if (failsafe > 0xf) {
1469 failsafe = 0xf;
1470 mlx->mlx_pause.mp_howlong =
1471 time_second + (0xf * 30) - 5;
1472 }
1473 }
1474
1475 /* Build commands for every channel requested. */
1476 for (i = 0; i < mlx->mlx_ci.ci_nchan; i++) {
1477 if ((1 << i) & mlx->mlx_pause.mp_which) {
1478 if (mlx_ccb_alloc(mlx, &mc, 1) != 0) {
1479 aprint_error_dev(mlx->mlx_dv,
1480 "%s failed for channel %d\n",
1481 cmd == MLX_CMD_STOPCHANNEL ?
1482 "pause" : "resume", i);
1483 continue;
1484 }
1485
1486 /* Build the command. */
1487 mlx_make_type2(mc, cmd, (failsafe << 4) | i, 0, 0,
1488 0, 0, 0, 0, 0);
1489 mc->mc_mx.mx_handler = mlx_pause_done;
1490 mc->mc_mx.mx_dv = mlx->mlx_dv;
1491
1492 mlx_ccb_enqueue(mlx, mc);
1493 }
1494 }
1495 }
1496
1497 static void
1498 mlx_pause_done(struct mlx_ccb *mc)
1499 {
1500 struct mlx_softc *mlx;
1501 int command, channel;
1502
1503 mlx = device_private(mc->mc_mx.mx_dv);
1504 command = mc->mc_mbox[0];
1505 channel = mc->mc_mbox[2] & 0xf;
1506
1507 if (mc->mc_status != 0)
1508 aprint_error_dev(mlx->mlx_dv, "%s command failed - %s\n",
1509 command == MLX_CMD_STOPCHANNEL ? "pause" : "resume",
1510 mlx_ccb_diagnose(mc));
1511 else if (command == MLX_CMD_STOPCHANNEL)
1512 printf("%s: channel %d pausing for %ld seconds\n",
1513 device_xname(mlx->mlx_dv), channel,
1514 (long)(mlx->mlx_pause.mp_howlong - time_second));
1515 else
1516 printf("%s: channel %d resuming\n", device_xname(mlx->mlx_dv),
1517 channel);
1518
1519 mlx_ccb_free(mlx, mc);
1520 }
1521
1522 /*
1523 * Perform an Enquiry command using a type-3 command buffer and a return a
1524 * single linear result buffer. If the completion function is specified, it
1525 * will be called with the completed command (and the result response will
1526 * not be valid until that point). Otherwise, the command will either be
1527 * busy-waited for (interrupts must be blocked), or slept for.
1528 */
1529 static void *
1530 mlx_enquire(struct mlx_softc *mlx, int command, size_t bufsize,
1531 void (*handler)(struct mlx_ccb *mc), int waitok)
1532 {
1533 struct mlx_ccb *mc;
1534 void *result;
1535 int rv, mapped;
1536
1537 result = NULL;
1538 mapped = 0;
1539
1540 if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
1541 goto out;
1542
1543 result = malloc(bufsize, M_DEVBUF, waitok ? M_WAITOK : M_NOWAIT);
1544 if (result == NULL) {
1545 printf("mlx_enquire: malloc() failed\n");
1546 goto out;
1547 }
1548 if ((rv = mlx_ccb_map(mlx, mc, result, bufsize, MC_XFER_IN)) != 0)
1549 goto out;
1550 mapped = 1;
1551 if (mc->mc_nsgent != 1) {
1552 printf("mlx_enquire: too many segs\n");
1553 goto out;
1554 }
1555
1556 /* Build an enquiry command. */
1557 mlx_make_type2(mc, command, 0, 0, 0, 0, 0, 0, mc->mc_xfer_phys, 0);
1558
1559 /* Do we want a completion callback? */
1560 if (handler != NULL) {
1561 mc->mc_mx.mx_context = result;
1562 mc->mc_mx.mx_dv = mlx->mlx_dv;
1563 mc->mc_mx.mx_handler = handler;
1564 mlx_ccb_enqueue(mlx, mc);
1565 } else {
1566 /* Run the command in either polled or wait mode. */
1567 if (waitok)
1568 rv = mlx_ccb_wait(mlx, mc);
1569 else
1570 rv = mlx_ccb_poll(mlx, mc, 5000);
1571 }
1572
1573 out:
1574 /* We got a command, but nobody else will free it. */
1575 if (handler == NULL && mc != NULL) {
1576 if (mapped)
1577 mlx_ccb_unmap(mlx, mc);
1578 mlx_ccb_free(mlx, mc);
1579 }
1580
1581 /* We got an error, and we allocated a result. */
1582 if (rv != 0 && result != NULL) {
1583 if (mc != NULL)
1584 mlx_ccb_free(mlx, mc);
1585 free(result, M_DEVBUF);
1586 result = NULL;
1587 }
1588
1589 return (result);
1590 }
1591
1592 /*
1593 * Perform a Flush command on the nominated controller.
1594 *
1595 * May be called with interrupts enabled or disabled; will not return until
1596 * the flush operation completes or fails.
1597 */
1598 int
1599 mlx_flush(struct mlx_softc *mlx, int async)
1600 {
1601 struct mlx_ccb *mc;
1602 int rv;
1603
1604 if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
1605 goto out;
1606
1607 /* Build a flush command and fire it off. */
1608 mlx_make_type2(mc, MLX_CMD_FLUSH, 0, 0, 0, 0, 0, 0, 0, 0);
1609
1610 if (async)
1611 rv = mlx_ccb_wait(mlx, mc);
1612 else
1613 rv = mlx_ccb_poll(mlx, mc, MLX_TIMEOUT * 1000);
1614 if (rv != 0)
1615 goto out;
1616
1617 /* Command completed OK? */
1618 if (mc->mc_status != 0) {
1619 aprint_error_dev(mlx->mlx_dv, "FLUSH failed - %s\n",
1620 mlx_ccb_diagnose(mc));
1621 rv = EIO;
1622 }
1623 out:
1624 if (mc != NULL)
1625 mlx_ccb_free(mlx, mc);
1626
1627 return (rv);
1628 }
1629
1630 /*
1631 * Start a background consistency check on (drive).
1632 */
1633 static int
1634 mlx_check(struct mlx_softc *mlx, int drive)
1635 {
1636 struct mlx_ccb *mc;
1637 int rv;
1638
1639 /* Get ourselves a command buffer. */
1640 rv = 0x10000;
1641
1642 if (mlx_ccb_alloc(mlx, &mc, 1) != 0)
1643 goto out;
1644
1645 /* Build a checkasync command, set the "fix it" flag. */
1646 mlx_make_type2(mc, MLX_CMD_CHECKASYNC, 0, 0, 0, 0, 0, drive | 0x80,
1647 0, 0);
1648
1649 /* Start the command and wait for it to be returned. */
1650 if (mlx_ccb_wait(mlx, mc) != 0)
1651 goto out;
1652
1653 /* Command completed OK? */
1654 if (mc->mc_status != 0)
1655 aprint_error_dev(mlx->mlx_dv, "CHECK ASYNC failed - %s\n",
1656 mlx_ccb_diagnose(mc));
1657 else
1658 printf("%s: consistency check started",
1659 device_xname(mlx->mlx_sysdrive[drive].ms_dv));
1660
1661 rv = mc->mc_status;
1662 out:
1663 if (mc != NULL)
1664 mlx_ccb_free(mlx, mc);
1665
1666 return (rv);
1667 }
1668
1669 /*
1670 * Start a background rebuild of the physical drive at (channel),(target).
1671 *
1672 * May be called with interrupts enabled or disabled; will return as soon as
1673 * the operation has started or been refused.
1674 */
1675 static int
1676 mlx_rebuild(struct mlx_softc *mlx, int channel, int target)
1677 {
1678 struct mlx_ccb *mc;
1679 int error;
1680
1681 error = 0x10000;
1682 if (mlx_ccb_alloc(mlx, &mc, 1) != 0)
1683 goto out;
1684
1685 /* Build a rebuildasync command, set the "fix it" flag. */
1686 mlx_make_type2(mc, MLX_CMD_REBUILDASYNC, channel, target, 0, 0, 0, 0,
1687 0, 0);
1688
1689 /* Start the command and wait for it to be returned. */
1690 if (mlx_ccb_wait(mlx, mc) != 0)
1691 goto out;
1692
1693 /* Command completed OK? */
1694 if (mc->mc_status != 0)
1695 aprint_normal_dev(mlx->mlx_dv, "REBUILD ASYNC failed - %s\n",
1696 mlx_ccb_diagnose(mc));
1697 else
1698 aprint_normal_dev(mlx->mlx_dv, "rebuild started for %d:%d\n",
1699 channel, target);
1700
1701 error = mc->mc_status;
1702
1703 out:
1704 if (mc != NULL)
1705 mlx_ccb_free(mlx, mc);
1706
1707 return (error);
1708 }
1709
1710 /*
1711 * Take a command from user-space and try to run it.
1712 *
1713 * XXX Note that this can't perform very much in the way of error checking,
1714 * XXX and as such, applications _must_ be considered trustworthy.
1715 *
1716 * XXX Commands using S/G for data are not supported.
1717 */
1718 static int
1719 mlx_user_command(struct mlx_softc *mlx, struct mlx_usercommand *mu)
1720 {
1721 struct mlx_ccb *mc;
1722 struct mlx_dcdb *dcdb;
1723 void *kbuf;
1724 int rv, mapped;
1725
1726 if ((mu->mu_bufdir & ~MU_XFER_MASK) != 0)
1727 return (EINVAL);
1728
1729 kbuf = NULL;
1730 dcdb = NULL;
1731 mapped = 0;
1732
1733 /* Get ourselves a command and copy in from user space. */
1734 if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0) {
1735 DPRINTF(("mlx_user_command: mlx_ccb_alloc = %d\n", rv));
1736 goto out;
1737 }
1738
1739 memcpy(mc->mc_mbox, mu->mu_command, sizeof(mc->mc_mbox));
1740
1741 /*
1742 * If we need a buffer for data transfer, allocate one and copy in
1743 * its initial contents.
1744 */
1745 if (mu->mu_datasize > 0) {
1746 if (mu->mu_datasize > MAXPHYS)
1747 return (EINVAL);
1748
1749 kbuf = malloc(mu->mu_datasize, M_DEVBUF, M_WAITOK);
1750 if (kbuf == NULL) {
1751 DPRINTF(("mlx_user_command: malloc = NULL\n"));
1752 rv = ENOMEM;
1753 goto out;
1754 }
1755
1756 if ((mu->mu_bufdir & MU_XFER_OUT) != 0) {
1757 rv = copyin(mu->mu_buf, kbuf, mu->mu_datasize);
1758 if (rv != 0) {
1759 DPRINTF(("mlx_user_command: copyin = %d\n",
1760 rv));
1761 goto out;
1762 }
1763 }
1764
1765 /* Map the buffer so the controller can see it. */
1766 rv = mlx_ccb_map(mlx, mc, kbuf, mu->mu_datasize, mu->mu_bufdir);
1767 if (rv != 0) {
1768 DPRINTF(("mlx_user_command: mlx_ccb_map = %d\n", rv));
1769 goto out;
1770 }
1771 if (mc->mc_nsgent > 1) {
1772 DPRINTF(("mlx_user_command: too many s/g entries\n"));
1773 rv = EFBIG;
1774 goto out;
1775 }
1776 mapped = 1;
1777 /*
1778 * If this is a passthrough SCSI command, the DCDB is packed at
1779 * the beginning of the data area. Fix up the DCDB to point to
1780 * the correct physical address and override any bufptr
1781 * supplied by the caller since we know what it's meant to be.
1782 */
1783 if (mc->mc_mbox[0] == MLX_CMD_DIRECT_CDB) {
1784 dcdb = (struct mlx_dcdb *)kbuf;
1785 dcdb->dcdb_physaddr = mc->mc_xfer_phys + sizeof(*dcdb);
1786 mu->mu_bufptr = 8;
1787 }
1788 }
1789
1790
1791 /*
1792 * If there's a data buffer, fix up the command's buffer pointer.
1793 */
1794 if (mu->mu_datasize > 0) {
1795 /* Range check the pointer to physical buffer address. */
1796 if (mu->mu_bufptr < 0 ||
1797 mu->mu_bufptr > sizeof(mu->mu_command) - 4) {
1798 DPRINTF(("mlx_user_command: bufptr botch\n"));
1799 rv = EINVAL;
1800 goto out;
1801 }
1802
1803 mc->mc_mbox[mu->mu_bufptr] = mc->mc_xfer_phys;
1804 mc->mc_mbox[mu->mu_bufptr+1] = mc->mc_xfer_phys >> 8;
1805 mc->mc_mbox[mu->mu_bufptr+2] = mc->mc_xfer_phys >> 16;
1806 mc->mc_mbox[mu->mu_bufptr+3] = mc->mc_xfer_phys >> 24;
1807 }
1808
1809 /* Submit the command and wait. */
1810 if ((rv = mlx_ccb_wait(mlx, mc)) != 0) {
1811 #ifdef DEBUG
1812 printf("mlx_user_command: mlx_ccb_wait = %d\n", rv);
1813 #endif
1814 }
1815
1816 out:
1817 if (mc != NULL) {
1818 /* Copy out status and data */
1819 mu->mu_status = mc->mc_status;
1820 if (mapped)
1821 mlx_ccb_unmap(mlx, mc);
1822 mlx_ccb_free(mlx, mc);
1823 }
1824
1825 if (kbuf != NULL) {
1826 if (mu->mu_datasize > 0 && (mu->mu_bufdir & MU_XFER_IN) != 0) {
1827 rv = copyout(kbuf, mu->mu_buf, mu->mu_datasize);
1828 #ifdef DIAGNOSTIC
1829 if (rv != 0)
1830 printf("mlx_user_command: copyout = %d\n", rv);
1831 #endif
1832 }
1833 }
1834 if (kbuf != NULL)
1835 free(kbuf, M_DEVBUF);
1836
1837 return (rv);
1838 }
1839
1840 /*
1841 * Allocate and initialise a CCB.
1842 */
1843 int
1844 mlx_ccb_alloc(struct mlx_softc *mlx, struct mlx_ccb **mcp, int control)
1845 {
1846 struct mlx_ccb *mc;
1847 int s;
1848
1849 s = splbio();
1850 mc = SLIST_FIRST(&mlx->mlx_ccb_freelist);
1851 if (control) {
1852 if (mlx->mlx_nccbs_ctrl >= MLX_NCCBS_CONTROL) {
1853 splx(s);
1854 *mcp = NULL;
1855 return (EAGAIN);
1856 }
1857 mc->mc_flags |= MC_CONTROL;
1858 mlx->mlx_nccbs_ctrl++;
1859 }
1860 SLIST_REMOVE_HEAD(&mlx->mlx_ccb_freelist, mc_chain.slist);
1861 splx(s);
1862
1863 *mcp = mc;
1864 return (0);
1865 }
1866
1867 /*
1868 * Free a CCB.
1869 */
1870 void
1871 mlx_ccb_free(struct mlx_softc *mlx, struct mlx_ccb *mc)
1872 {
1873 int s;
1874
1875 s = splbio();
1876 if ((mc->mc_flags & MC_CONTROL) != 0)
1877 mlx->mlx_nccbs_ctrl--;
1878 mc->mc_flags = 0;
1879 SLIST_INSERT_HEAD(&mlx->mlx_ccb_freelist, mc, mc_chain.slist);
1880 splx(s);
1881 }
1882
1883 /*
1884 * If a CCB is specified, enqueue it. Pull CCBs off the software queue in
1885 * the order that they were enqueued and try to submit their mailboxes to
1886 * the controller for execution.
1887 */
1888 void
1889 mlx_ccb_enqueue(struct mlx_softc *mlx, struct mlx_ccb *mc)
1890 {
1891 int s;
1892
1893 s = splbio();
1894
1895 if (mc != NULL)
1896 SIMPLEQ_INSERT_TAIL(&mlx->mlx_ccb_queue, mc, mc_chain.simpleq);
1897
1898 while ((mc = SIMPLEQ_FIRST(&mlx->mlx_ccb_queue)) != NULL) {
1899 if (mlx_ccb_submit(mlx, mc) != 0)
1900 break;
1901 SIMPLEQ_REMOVE_HEAD(&mlx->mlx_ccb_queue, mc_chain.simpleq);
1902 TAILQ_INSERT_TAIL(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
1903 }
1904
1905 splx(s);
1906 }
1907
1908 /*
1909 * Map the specified CCB's data buffer onto the bus, and fill the
1910 * scatter-gather list.
1911 */
1912 int
1913 mlx_ccb_map(struct mlx_softc *mlx, struct mlx_ccb *mc, void *data, int size,
1914 int dir)
1915 {
1916 struct mlx_sgentry *sge;
1917 int nsegs, i, rv, sgloff;
1918 bus_dmamap_t xfer;
1919
1920 xfer = mc->mc_xfer_map;
1921
1922 rv = bus_dmamap_load(mlx->mlx_dmat, xfer, data, size, NULL,
1923 BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
1924 ((dir & MC_XFER_IN) ? BUS_DMA_READ : BUS_DMA_WRITE));
1925 if (rv != 0)
1926 return (rv);
1927
1928 nsegs = xfer->dm_nsegs;
1929 mc->mc_xfer_size = size;
1930 mc->mc_flags |= dir;
1931 mc->mc_nsgent = nsegs;
1932 mc->mc_xfer_phys = xfer->dm_segs[0].ds_addr;
1933
1934 sgloff = MLX_SGL_SIZE * mc->mc_ident;
1935 sge = (struct mlx_sgentry *)((char *)mlx->mlx_sgls + sgloff);
1936
1937 for (i = 0; i < nsegs; i++, sge++) {
1938 sge->sge_addr = htole32(xfer->dm_segs[i].ds_addr);
1939 sge->sge_count = htole32(xfer->dm_segs[i].ds_len);
1940 }
1941
1942 if ((dir & MC_XFER_OUT) != 0)
1943 i = BUS_DMASYNC_PREWRITE;
1944 else
1945 i = 0;
1946 if ((dir & MC_XFER_IN) != 0)
1947 i |= BUS_DMASYNC_PREREAD;
1948
1949 bus_dmamap_sync(mlx->mlx_dmat, xfer, 0, mc->mc_xfer_size, i);
1950 bus_dmamap_sync(mlx->mlx_dmat, mlx->mlx_dmamap, sgloff,
1951 MLX_SGL_SIZE, BUS_DMASYNC_PREWRITE);
1952
1953 return (0);
1954 }
1955
1956 /*
1957 * Unmap the specified CCB's data buffer.
1958 */
1959 void
1960 mlx_ccb_unmap(struct mlx_softc *mlx, struct mlx_ccb *mc)
1961 {
1962 int i;
1963
1964 bus_dmamap_sync(mlx->mlx_dmat, mlx->mlx_dmamap,
1965 MLX_SGL_SIZE * mc->mc_ident, MLX_SGL_SIZE,
1966 BUS_DMASYNC_POSTWRITE);
1967
1968 if ((mc->mc_flags & MC_XFER_OUT) != 0)
1969 i = BUS_DMASYNC_POSTWRITE;
1970 else
1971 i = 0;
1972 if ((mc->mc_flags & MC_XFER_IN) != 0)
1973 i |= BUS_DMASYNC_POSTREAD;
1974
1975 bus_dmamap_sync(mlx->mlx_dmat, mc->mc_xfer_map, 0, mc->mc_xfer_size, i);
1976 bus_dmamap_unload(mlx->mlx_dmat, mc->mc_xfer_map);
1977 }
1978
1979 /*
1980 * Submit the CCB, and busy-wait for it to complete. Return non-zero on
1981 * timeout or submission error. Must be called with interrupts blocked.
1982 */
1983 int
1984 mlx_ccb_poll(struct mlx_softc *mlx, struct mlx_ccb *mc, int timo)
1985 {
1986 int rv;
1987
1988 mc->mc_mx.mx_handler = NULL;
1989
1990 if ((rv = mlx_ccb_submit(mlx, mc)) != 0)
1991 return (rv);
1992 TAILQ_INSERT_TAIL(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
1993
1994 for (timo *= 10; timo != 0; timo--) {
1995 mlx_intr(mlx);
1996 if (mc->mc_status != MLX_STATUS_BUSY)
1997 break;
1998 DELAY(100);
1999 }
2000
2001 if (timo != 0) {
2002 if (mc->mc_status != 0) {
2003 aprint_error_dev(mlx->mlx_dv, "command failed - %s\n",
2004 mlx_ccb_diagnose(mc));
2005 rv = EIO;
2006 } else
2007 rv = 0;
2008 } else {
2009 printf("%s: command timed out\n", device_xname(mlx->mlx_dv));
2010 rv = EIO;
2011 }
2012
2013 return (rv);
2014 }
2015
2016 /*
2017 * Enqueue the CCB, and sleep until it completes. Return non-zero on
2018 * timeout or error.
2019 */
2020 int
2021 mlx_ccb_wait(struct mlx_softc *mlx, struct mlx_ccb *mc)
2022 {
2023 int s;
2024
2025 mc->mc_flags |= MC_WAITING;
2026 mc->mc_mx.mx_handler = NULL;
2027
2028 s = splbio();
2029 mlx_ccb_enqueue(mlx, mc);
2030 tsleep(mc, PRIBIO, "mlxwccb", 0);
2031 splx(s);
2032
2033 if (mc->mc_status != 0) {
2034 aprint_error_dev(mlx->mlx_dv, "command failed - %s\n",
2035 mlx_ccb_diagnose(mc));
2036 return (EIO);
2037 }
2038
2039 return (0);
2040 }
2041
2042 /*
2043 * Try to submit a CCB's mailbox to the controller for execution. Return
2044 * non-zero on timeout or error. Must be called with interrupts blocked.
2045 */
2046 static int
2047 mlx_ccb_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
2048 {
2049 int i, s, r;
2050
2051 /* Save the ident so we can handle this command when complete. */
2052 mc->mc_mbox[1] = (u_int8_t)(mc->mc_ident + 1);
2053
2054 /* Mark the command as currently being processed. */
2055 mc->mc_status = MLX_STATUS_BUSY;
2056 mc->mc_expiry = time_second + MLX_TIMEOUT;
2057
2058 /* Spin waiting for the mailbox. */
2059 for (i = 100; i != 0; i--) {
2060 s = splbio();
2061 r = (*mlx->mlx_submit)(mlx, mc);
2062 splx(s);
2063 if (r != 0)
2064 break;
2065 DELAY(100);
2066 }
2067 if (i != 0)
2068 return (0);
2069
2070 DPRINTF(("mlx_ccb_submit: rejected; queueing\n"));
2071 mc->mc_status = MLX_STATUS_WEDGED;
2072 return (EIO);
2073 }
2074
2075 /*
2076 * Return a string that describes why a command has failed.
2077 */
2078 const char *
2079 mlx_ccb_diagnose(struct mlx_ccb *mc)
2080 {
2081 static char tbuf[80];
2082 int i;
2083
2084 for (i = 0; i < sizeof(mlx_msgs) / sizeof(mlx_msgs[0]); i++)
2085 if ((mc->mc_mbox[0] == mlx_msgs[i].command ||
2086 mlx_msgs[i].command == 0) &&
2087 mc->mc_status == mlx_msgs[i].status) {
2088 snprintf(tbuf, sizeof(tbuf), "%s (0x%x)",
2089 mlx_status_msgs[mlx_msgs[i].msg], mc->mc_status);
2090 return (tbuf);
2091 }
2092
2093 snprintf(tbuf, sizeof(tbuf), "unknown response 0x%x for command 0x%x",
2094 (int)mc->mc_status, (int)mc->mc_mbox[0]);
2095
2096 return (tbuf);
2097 }
2098
2099 /*
2100 * Poll the controller for completed commands. Returns non-zero if one or
2101 * more commands were completed. Must be called with interrupts blocked.
2102 */
2103 int
2104 mlx_intr(void *cookie)
2105 {
2106 struct mlx_softc *mlx;
2107 struct mlx_ccb *mc;
2108 int result;
2109 u_int ident, status;
2110
2111 mlx = cookie;
2112 result = 0;
2113
2114 while ((*mlx->mlx_findcomplete)(mlx, &ident, &status) != 0) {
2115 result = 1;
2116 ident--;
2117
2118 if (ident >= MLX_MAX_QUEUECNT) {
2119 aprint_error_dev(mlx->mlx_dv,
2120 "bad completion returned\n");
2121 continue;
2122 }
2123
2124 mc = mlx->mlx_ccbs + ident;
2125
2126 if (mc->mc_status != MLX_STATUS_BUSY) {
2127 aprint_error_dev(mlx->mlx_dv,
2128 "bad completion returned\n");
2129 continue;
2130 }
2131
2132 TAILQ_REMOVE(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
2133
2134 /* Record status and notify the initiator, if requested. */
2135 mc->mc_status = status;
2136 if (mc->mc_mx.mx_handler != NULL)
2137 (*mc->mc_mx.mx_handler)(mc);
2138 else if ((mc->mc_flags & MC_WAITING) != 0)
2139 wakeup(mc);
2140 }
2141
2142 /* If we've completed any commands, try posting some more. */
2143 if (result)
2144 mlx_ccb_enqueue(mlx, NULL);
2145
2146 return (result);
2147 }
2148
2149 /*
2150 * Emit a string describing the firmware handshake status code, and return a
2151 * flag indicating whether the code represents a fatal error.
2152 *
2153 * Error code interpretations are from the Linux driver, and don't directly
2154 * match the messages printed by Mylex's BIOS. This may change if
2155 * documentation on the codes is forthcoming.
2156 */
2157 static int
2158 mlx_fw_message(struct mlx_softc *mlx, int error, int param1, int param2)
2159 {
2160 const char *fmt;
2161
2162 switch (error) {
2163 case 0x00:
2164 fmt = "physical drive %d:%d not responding";
2165 break;
2166
2167 case 0x08:
2168 /*
2169 * We could be neater about this and give some indication
2170 * when we receive more of them.
2171 */
2172 if ((mlx->mlx_flags & MLXF_SPINUP_REPORTED) == 0) {
2173 printf("%s: spinning up drives...\n",
2174 device_xname(mlx->mlx_dv));
2175 mlx->mlx_flags |= MLXF_SPINUP_REPORTED;
2176 }
2177 return (0);
2178
2179 case 0x30:
2180 fmt = "configuration checksum error";
2181 break;
2182
2183 case 0x60:
2184 fmt = "mirror race recovery failed";
2185 break;
2186
2187 case 0x70:
2188 fmt = "mirror race recovery in progress";
2189 break;
2190
2191 case 0x90:
2192 fmt = "physical drive %d:%d COD mismatch";
2193 break;
2194
2195 case 0xa0:
2196 fmt = "logical drive installation aborted";
2197 break;
2198
2199 case 0xb0:
2200 fmt = "mirror race on a critical system drive";
2201 break;
2202
2203 case 0xd0:
2204 fmt = "new controller configuration found";
2205 break;
2206
2207 case 0xf0:
2208 aprint_error_dev(mlx->mlx_dv, "FATAL MEMORY PARITY ERROR\n");
2209 return (1);
2210
2211 default:
2212 aprint_error_dev(mlx->mlx_dv,
2213 "unknown firmware init error %02x:%02x:%02x\n",
2214 error, param1, param2);
2215 return (0);
2216 }
2217
2218 aprint_normal_dev(mlx->mlx_dv, fmt, param2, param1);
2219 aprint_normal("\n");
2220
2221 return (0);
2222 }
2223
2224 MODULE(MODULE_CLASS_DRIVER, mlx, NULL);
2225
2226 #ifdef _MODULE
2227 CFDRIVER_DECL(cac, DV_DISK, NULL);
2228 #endif
2229
2230 static int
2231 mlx_modcmd(modcmd_t cmd, void *opaque)
2232 {
2233 int error = 0;
2234
2235 #ifdef _MODULE
2236 switch (cmd) {
2237 case MODULE_CMD_INIT:
2238 error = config_cfdriver_attach(&mlx_cd);
2239 break;
2240 case MODULE_CMD_FINI:
2241 error = config_cfdriver_detach(&mlx_cd);
2242 break;
2243 default:
2244 error = ENOTTY;
2245 break;
2246 }
2247 #endif
2248 return error;
2249 }
2250