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