No empty .Rs/.Re
[netbsd-mini2440.git] / sys / dev / ic / mlx.c
blob92cd23da8187ea78fc2ac2a6440c15675f8dbd24
1 /* $NetBSD: mlx.c,v 1.57 2008/09/09 12:45:40 tron Exp $ */
3 /*-
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran.
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.
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.
32 /*-
33 * Copyright (c) 1999 Michael Smith
34 * All rights reserved.
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.
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.
57 * from FreeBSD: mlx.c,v 1.14.2.3 2000/08/04 06:52:50 msmith Exp
61 * Driver for the Mylex DAC960 family of RAID controllers.
63 * TODO:
65 * o Test and enable channel pause.
66 * o SCSI pass-through.
69 #include <sys/cdefs.h>
70 __KERNEL_RCSID(0, "$NetBSD: mlx.c,v 1.57 2008/09/09 12:45:40 tron Exp $");
72 #include "ld.h"
74 #include <sys/param.h>
75 #include <sys/systm.h>
76 #include <sys/kernel.h>
77 #include <sys/device.h>
78 #include <sys/queue.h>
79 #include <sys/proc.h>
80 #include <sys/buf.h>
81 #include <sys/bufq.h>
82 #include <sys/endian.h>
83 #include <sys/malloc.h>
84 #include <sys/conf.h>
85 #include <sys/kthread.h>
86 #include <sys/disk.h>
87 #include <sys/kauth.h>
89 #include <machine/vmparam.h>
90 #include <sys/bus.h>
92 #include <uvm/uvm_extern.h>
94 #include <dev/ldvar.h>
96 #include <dev/ic/mlxreg.h>
97 #include <dev/ic/mlxio.h>
98 #include <dev/ic/mlxvar.h>
100 #include "locators.h"
102 #define MLX_TIMEOUT 60
104 #ifdef DIAGNOSTIC
105 #define DPRINTF(x) printf x
106 #else
107 #define DPRINTF(x)
108 #endif
110 static void mlx_adjqparam(struct mlx_softc *, int, int);
111 static int mlx_ccb_submit(struct mlx_softc *, struct mlx_ccb *);
112 static int mlx_check(struct mlx_softc *, int);
113 static void mlx_configure(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 *);
131 dev_type_open(mlxopen);
132 dev_type_close(mlxclose);
133 dev_type_ioctl(mlxioctl);
135 const struct cdevsw mlx_cdevsw = {
136 mlxopen, mlxclose, noread, nowrite, mlxioctl,
137 nostop, notty, nopoll, nommap, nokqfilter, D_OTHER,
140 extern struct cfdriver mlx_cd;
141 static struct lwp *mlx_periodic_lwp;
142 static void *mlx_sdh;
144 static struct {
145 int hwid;
146 const char *name;
147 } const mlx_cname[] = {
148 { 0x00, "960E/960M" },
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" },
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"
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 */
203 static struct {
204 u_char command;
205 u_char msg; /* Index into mlx_status_msgs[]. */
206 u_short status;
207 } 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 },
240 { 0, 20, MLX_STATUS_WEDGED },
241 { 0, 21, MLX_STATUS_LOST },
242 { 0, 22, MLX_STATUS_BUSY },
244 { 0, 14, 0x0104 },
248 * Initialise the controller and our interface.
250 void
251 mlx_init(struct mlx_softc *mlx, const char *intrstr)
253 struct mlx_ccb *mc;
254 struct mlx_enquiry_old *meo;
255 struct mlx_enquiry2 *me2;
256 struct mlx_cinfo *ci;
257 int rv, fwminor, hscode, hserr, hsparam1, hsparam2, hsmsg;
258 int size, i, rseg;
259 const char *wantfwstr;
260 bus_dma_segment_t seg;
262 SIMPLEQ_INIT(&mlx->mlx_ccb_queue);
263 SLIST_INIT(&mlx->mlx_ccb_freelist);
264 TAILQ_INIT(&mlx->mlx_ccb_worklist);
266 if (intrstr != NULL)
267 printf("%s: interrupting at %s\n", device_xname(&mlx->mlx_dv),
268 intrstr);
271 * Allocate the scatter/gather lists.
273 size = MLX_SGL_SIZE * MLX_MAX_QUEUECNT;
275 if ((rv = bus_dmamem_alloc(mlx->mlx_dmat, size, PAGE_SIZE, 0, &seg, 1,
276 &rseg, BUS_DMA_NOWAIT)) != 0) {
277 aprint_error_dev(&mlx->mlx_dv, "unable to allocate sglists, rv = %d\n", rv);
278 return;
281 if ((rv = bus_dmamem_map(mlx->mlx_dmat, &seg, rseg, size,
282 (void **)&mlx->mlx_sgls,
283 BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
284 aprint_error_dev(&mlx->mlx_dv, "unable to map sglists, rv = %d\n", rv);
285 return;
288 if ((rv = bus_dmamap_create(mlx->mlx_dmat, size, 1, size, 0,
289 BUS_DMA_NOWAIT, &mlx->mlx_dmamap)) != 0) {
290 aprint_error_dev(&mlx->mlx_dv, "unable to create sglist DMA map, rv = %d\n", rv);
291 return;
294 if ((rv = bus_dmamap_load(mlx->mlx_dmat, mlx->mlx_dmamap,
295 mlx->mlx_sgls, size, NULL, BUS_DMA_NOWAIT)) != 0) {
296 aprint_error_dev(&mlx->mlx_dv, "unable to load sglist DMA map, rv = %d\n", rv);
297 return;
300 mlx->mlx_sgls_paddr = mlx->mlx_dmamap->dm_segs[0].ds_addr;
301 memset(mlx->mlx_sgls, 0, size);
304 * Allocate and initialize the CCBs.
306 mc = malloc(sizeof(*mc) * MLX_MAX_QUEUECNT, M_DEVBUF, M_NOWAIT);
307 mlx->mlx_ccbs = mc;
309 for (i = 0; i < MLX_MAX_QUEUECNT; i++, mc++) {
310 mc->mc_ident = i;
311 rv = bus_dmamap_create(mlx->mlx_dmat, MLX_MAX_XFER,
312 MLX_MAX_SEGS, MLX_MAX_XFER, 0,
313 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
314 &mc->mc_xfer_map);
315 if (rv != 0)
316 break;
317 mlx->mlx_nccbs++;
318 mlx_ccb_free(mlx, mc);
320 if (mlx->mlx_nccbs != MLX_MAX_QUEUECNT)
321 printf("%s: %d/%d CCBs usable\n", device_xname(&mlx->mlx_dv),
322 mlx->mlx_nccbs, MLX_MAX_QUEUECNT);
324 /* Disable interrupts before we start talking to the controller */
325 (*mlx->mlx_intaction)(mlx, 0);
327 /* If we've got a reset routine, then reset the controller now. */
328 if (mlx->mlx_reset != NULL) {
329 printf("%s: resetting controller...\n", device_xname(&mlx->mlx_dv));
330 if ((*mlx->mlx_reset)(mlx) != 0) {
331 aprint_error_dev(&mlx->mlx_dv, "reset failed\n");
332 return;
337 * Wait for the controller to come ready, handshaking with the
338 * firmware if required. This is typically only necessary on
339 * platforms where the controller BIOS does not run.
341 hsmsg = 0;
343 for (;;) {
344 hscode = (*mlx->mlx_fw_handshake)(mlx, &hserr, &hsparam1,
345 &hsparam2);
346 if (hscode == 0) {
347 if (hsmsg != 0)
348 printf("%s: initialization complete\n",
349 device_xname(&mlx->mlx_dv));
350 break;
353 /* Report first time around... */
354 if (hsmsg == 0) {
355 printf("%s: initializing (may take some time)...\n",
356 device_xname(&mlx->mlx_dv));
357 hsmsg = 1;
360 /* Did we get a real message? */
361 if (hscode == 2) {
362 hscode = mlx_fw_message(mlx, hserr, hsparam1, hsparam2);
364 /* Fatal initialisation error? */
365 if (hscode != 0)
366 return;
371 * Do quirk/feature related things.
373 ci = &mlx->mlx_ci;
375 if (ci->ci_iftype > 1) {
376 me2 = mlx_enquire(mlx, MLX_CMD_ENQUIRY2,
377 sizeof(struct mlx_enquiry2), NULL, 0);
378 if (me2 == NULL) {
379 aprint_error_dev(&mlx->mlx_dv, "ENQUIRY2 failed\n");
380 return;
383 ci->ci_firmware_id[0] = me2->me_firmware_id[0];
384 ci->ci_firmware_id[1] = me2->me_firmware_id[1];
385 ci->ci_firmware_id[2] = me2->me_firmware_id[2];
386 ci->ci_firmware_id[3] = me2->me_firmware_id[3];
387 ci->ci_hardware_id = me2->me_hardware_id[0];
388 ci->ci_mem_size = le32toh(me2->me_mem_size);
389 ci->ci_max_sg = le16toh(me2->me_max_sg);
390 ci->ci_max_commands = le16toh(me2->me_max_commands);
391 ci->ci_nchan = me2->me_actual_channels;
393 free(me2, M_DEVBUF);
396 if (ci->ci_iftype <= 2) {
398 * These controllers may not report the firmware version in
399 * the ENQUIRY2 response, or may not even support it.
401 meo = mlx_enquire(mlx, MLX_CMD_ENQUIRY_OLD,
402 sizeof(struct mlx_enquiry_old), NULL, 0);
403 if (meo == NULL) {
404 aprint_error_dev(&mlx->mlx_dv, "ENQUIRY_OLD failed\n");
405 return;
407 ci->ci_firmware_id[0] = meo->me_fwmajor;
408 ci->ci_firmware_id[1] = meo->me_fwminor;
409 ci->ci_firmware_id[2] = 0;
410 ci->ci_firmware_id[3] = '0';
412 if (ci->ci_iftype == 1) {
413 ci->ci_hardware_id = 0; /* XXX */
414 ci->ci_mem_size = 0; /* XXX */
415 ci->ci_max_sg = 17; /* XXX */
416 ci->ci_max_commands = meo->me_max_commands;
419 free(meo, M_DEVBUF);
422 wantfwstr = NULL;
423 fwminor = ci->ci_firmware_id[1];
425 switch (ci->ci_firmware_id[0]) {
426 case 2:
427 if (ci->ci_iftype == 1) {
428 if (fwminor < 14)
429 wantfwstr = "2.14";
430 } else if (fwminor < 42)
431 wantfwstr = "2.42";
432 break;
434 case 3:
435 if (fwminor < 51)
436 wantfwstr = "3.51";
437 break;
439 case 4:
440 if (fwminor < 6)
441 wantfwstr = "4.06";
442 break;
444 case 5:
445 if (fwminor < 7)
446 wantfwstr = "5.07";
447 break;
450 /* Print a little information about the controller. */
451 mlx_describe(mlx);
453 if (wantfwstr != NULL) {
454 printf("%s: WARNING: this f/w revision is not recommended\n",
455 device_xname(&mlx->mlx_dv));
456 printf("%s: WARNING: use revision %s or later\n",
457 device_xname(&mlx->mlx_dv), wantfwstr);
460 /* We don't (yet) know where the event log is up to. */
461 mlx->mlx_currevent = -1;
463 /* No user-requested background operation is in progress. */
464 mlx->mlx_bg = 0;
465 mlx->mlx_rebuildstat.rs_code = MLX_REBUILDSTAT_IDLE;
467 /* Set maximum number of queued commands for `regular' operations. */
468 mlx->mlx_max_queuecnt =
469 min(ci->ci_max_commands, MLX_MAX_QUEUECNT) -
470 MLX_NCCBS_CONTROL;
471 #ifdef DIAGNOSTIC
472 if (mlx->mlx_max_queuecnt < MLX_NCCBS_CONTROL + MLX_MAX_DRIVES)
473 printf("%s: WARNING: few CCBs available\n",
474 device_xname(&mlx->mlx_dv));
475 if (ci->ci_max_sg < MLX_MAX_SEGS) {
476 aprint_error_dev(&mlx->mlx_dv, "oops, not enough S/G segments\n");
477 return;
479 #endif
481 /* Attach child devices and enable interrupts. */
482 mlx_configure(mlx, 0);
483 (*mlx->mlx_intaction)(mlx, 1);
484 mlx->mlx_flags |= MLXF_INITOK;
486 if (mlx_sdh == NULL) {
488 * Set our `shutdownhook' before we start any device
489 * activity.
491 mlx_sdh = shutdownhook_establish(mlx_shutdown, NULL);
493 /* Create a status monitoring thread. */
494 rv = kthread_create(PRI_NONE, 0, NULL, mlx_periodic_thread,
495 NULL, &mlx_periodic_lwp, "mlxtask");
496 if (rv != 0)
497 printf("mlx_init: unable to create thread (%d)\n", rv);
502 * Tell the world about the controller.
504 static void
505 mlx_describe(struct mlx_softc *mlx)
507 struct mlx_cinfo *ci;
508 static char tbuf[80];
509 const char *model;
510 int i;
512 model = NULL;
513 ci = &mlx->mlx_ci;
515 for (i = 0; i < sizeof(mlx_cname) / sizeof(mlx_cname[0]); i++)
516 if (ci->ci_hardware_id == mlx_cname[i].hwid) {
517 model = mlx_cname[i].name;
518 break;
521 if (model == NULL) {
522 snprintf(tbuf, sizeof(tbuf), " model 0x%x", ci->ci_hardware_id);
523 model = tbuf;
526 printf("%s: DAC%s, %d channel%s, firmware %d.%02d-%c-%02d",
527 device_xname(&mlx->mlx_dv), model, ci->ci_nchan,
528 ci->ci_nchan > 1 ? "s" : "",
529 ci->ci_firmware_id[0], ci->ci_firmware_id[1],
530 ci->ci_firmware_id[3], ci->ci_firmware_id[2]);
531 if (ci->ci_mem_size != 0)
532 printf(", %dMB RAM", ci->ci_mem_size >> 20);
533 printf("\n");
537 * Locate disk resources and attach children to them.
539 static void
540 mlx_configure(struct mlx_softc *mlx, int waitok)
542 struct mlx_enquiry *me;
543 struct mlx_enquiry_old *meo;
544 struct mlx_enq_sys_drive *mes;
545 struct mlx_sysdrive *ms;
546 struct mlx_attach_args mlxa;
547 int i, nunits;
548 u_int size;
549 int locs[MLXCF_NLOCS];
551 mlx->mlx_flags |= MLXF_RESCANNING;
553 if (mlx->mlx_ci.ci_iftype <= 2) {
554 meo = mlx_enquire(mlx, MLX_CMD_ENQUIRY_OLD,
555 sizeof(struct mlx_enquiry_old), NULL, waitok);
556 if (meo == NULL) {
557 aprint_error_dev(&mlx->mlx_dv, "ENQUIRY_OLD failed\n");
558 goto out;
560 mlx->mlx_numsysdrives = meo->me_num_sys_drvs;
561 free(meo, M_DEVBUF);
562 } else {
563 me = mlx_enquire(mlx, MLX_CMD_ENQUIRY,
564 sizeof(struct mlx_enquiry), NULL, waitok);
565 if (me == NULL) {
566 aprint_error_dev(&mlx->mlx_dv, "ENQUIRY failed\n");
567 goto out;
569 mlx->mlx_numsysdrives = me->me_num_sys_drvs;
570 free(me, M_DEVBUF);
573 mes = mlx_enquire(mlx, MLX_CMD_ENQSYSDRIVE,
574 sizeof(*mes) * MLX_MAX_DRIVES, NULL, waitok);
575 if (mes == NULL) {
576 aprint_error_dev(&mlx->mlx_dv, "error fetching drive status\n");
577 goto out;
580 /* Allow 1 queued command per unit while re-configuring. */
581 mlx_adjqparam(mlx, 1, 0);
583 ms = &mlx->mlx_sysdrive[0];
584 nunits = 0;
585 for (i = 0; i < MLX_MAX_DRIVES; i++, ms++) {
586 size = le32toh(mes[i].sd_size);
587 ms->ms_state = mes[i].sd_state;
590 * If an existing device has changed in some way (e.g. no
591 * longer present) then detach it.
593 if (ms->ms_dv != NULL && (size != ms->ms_size ||
594 (mes[i].sd_raidlevel & 0xf) != ms->ms_raidlevel))
595 config_detach(ms->ms_dv, DETACH_FORCE);
597 ms->ms_size = size;
598 ms->ms_raidlevel = mes[i].sd_raidlevel & 0xf;
599 ms->ms_state = mes[i].sd_state;
600 ms->ms_dv = NULL;
602 if (i >= mlx->mlx_numsysdrives)
603 continue;
604 if (size == 0xffffffffU || size == 0)
605 continue;
608 * Attach a new device.
610 mlxa.mlxa_unit = i;
612 locs[MLXCF_UNIT] = i;
614 ms->ms_dv = config_found_sm_loc(&mlx->mlx_dv, "mlx", locs,
615 &mlxa, mlx_print, config_stdsubmatch);
616 nunits += (ms->ms_dv != NULL);
619 free(mes, M_DEVBUF);
621 if (nunits != 0)
622 mlx_adjqparam(mlx, mlx->mlx_max_queuecnt / nunits,
623 mlx->mlx_max_queuecnt % nunits);
624 out:
625 mlx->mlx_flags &= ~MLXF_RESCANNING;
629 * Print autoconfiguration message for a sub-device.
631 static int
632 mlx_print(void *aux, const char *pnp)
634 struct mlx_attach_args *mlxa;
636 mlxa = (struct mlx_attach_args *)aux;
638 if (pnp != NULL)
639 aprint_normal("block device at %s", pnp);
640 aprint_normal(" unit %d", mlxa->mlxa_unit);
641 return (UNCONF);
645 * Shut down all configured `mlx' devices.
647 static void
648 mlx_shutdown(void *cookie)
650 struct mlx_softc *mlx;
651 int i;
653 for (i = 0; i < mlx_cd.cd_ndevs; i++)
654 if ((mlx = device_lookup_private(&mlx_cd, i)) != NULL)
655 mlx_flush(mlx, 0);
659 * Adjust queue parameters for all child devices.
661 static void
662 mlx_adjqparam(struct mlx_softc *mlx, int mpu, int slop)
664 #if NLD > 0
665 extern struct cfdriver ld_cd;
666 struct ld_softc *ld;
667 int i;
669 for (i = 0; i < ld_cd.cd_ndevs; i++) {
670 if ((ld = device_lookup_private(&ld_cd, i)) == NULL)
671 continue;
672 if (device_parent(ld->sc_dv) != &mlx->mlx_dv)
673 continue;
674 ldadjqparam(ld, mpu + (slop-- > 0));
676 #endif
680 * Accept an open operation on the control device.
683 mlxopen(dev_t dev, int flag, int mode, struct lwp *l)
685 struct mlx_softc *mlx;
687 if ((mlx = device_lookup_private(&mlx_cd, minor(dev))) == NULL)
688 return (ENXIO);
689 if ((mlx->mlx_flags & MLXF_INITOK) == 0)
690 return (ENXIO);
691 if ((mlx->mlx_flags & MLXF_OPEN) != 0)
692 return (EBUSY);
694 mlx->mlx_flags |= MLXF_OPEN;
695 return (0);
699 * Accept the last close on the control device.
702 mlxclose(dev_t dev, int flag, int mode,
703 struct lwp *l)
705 struct mlx_softc *mlx;
707 mlx = device_lookup_private(&mlx_cd, minor(dev));
708 mlx->mlx_flags &= ~MLXF_OPEN;
709 return (0);
713 * Handle control operations.
716 mlxioctl(dev_t dev, u_long cmd, void *data, int flag,
717 struct lwp *l)
719 struct mlx_softc *mlx;
720 struct mlx_rebuild_request *rb;
721 struct mlx_rebuild_status *rs;
722 struct mlx_pause *mp;
723 struct mlx_sysdrive *ms;
724 int i, rv, *arg, result;
726 mlx = device_lookup_private(&mlx_cd, minor(dev));
728 rb = (struct mlx_rebuild_request *)data;
729 rs = (struct mlx_rebuild_status *)data;
730 arg = (int *)data;
731 rv = 0;
733 switch (cmd) {
734 case MLX_RESCAN_DRIVES:
736 * Scan the controller to see whether new drives have
737 * appeared, or old ones disappeared.
739 mlx_configure(mlx, 1);
740 return (0);
742 case MLX_PAUSE_CHANNEL:
744 * Pause one or more SCSI channels for a period of time, to
745 * assist in the process of hot-swapping devices.
747 * Note that at least the 3.51 firmware on the DAC960PL
748 * doesn't seem to do this right.
750 if ((mlx->mlx_flags & MLXF_PAUSEWORKS) == 0)
751 return (EOPNOTSUPP);
753 mp = (struct mlx_pause *)data;
755 if ((mp->mp_which == MLX_PAUSE_CANCEL) &&
756 (mlx->mlx_pause.mp_when != 0)) {
757 /* Cancel a pending pause operation. */
758 mlx->mlx_pause.mp_which = 0;
759 break;
762 /* Fix for legal channels. */
763 mp->mp_which &= ((1 << mlx->mlx_ci.ci_nchan) -1);
765 /* Check time values. */
766 if (mp->mp_when < 0 || mp->mp_when > 3600 ||
767 mp->mp_howlong < 1 || mp->mp_howlong > (0xf * 30)) {
768 rv = EINVAL;
769 break;
772 /* Check for a pause currently running. */
773 if ((mlx->mlx_pause.mp_which != 0) &&
774 (mlx->mlx_pause.mp_when == 0)) {
775 rv = EBUSY;
776 break;
779 /* Looks ok, go with it. */
780 mlx->mlx_pause.mp_which = mp->mp_which;
781 mlx->mlx_pause.mp_when = time_second + mp->mp_when;
782 mlx->mlx_pause.mp_howlong =
783 mlx->mlx_pause.mp_when + mp->mp_howlong;
785 return (0);
787 case MLX_COMMAND:
788 rv = kauth_authorize_device_passthru(l->l_cred, dev,
789 KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL, data);
790 if (rv)
791 return (rv);
794 * Accept a command passthrough-style.
796 return (mlx_user_command(mlx, (struct mlx_usercommand *)data));
798 case MLX_REBUILDASYNC:
800 * Start a rebuild on a given SCSI disk
802 if (mlx->mlx_bg != 0) {
803 rb->rr_status = 0x0106;
804 rv = EBUSY;
805 break;
808 rb->rr_status = mlx_rebuild(mlx, rb->rr_channel, rb->rr_target);
809 switch (rb->rr_status) {
810 case 0:
811 rv = 0;
812 break;
813 case 0x10000:
814 rv = ENOMEM; /* Couldn't set up the command. */
815 break;
816 case 0x0002:
817 rv = EBUSY;
818 break;
819 case 0x0104:
820 rv = EIO;
821 break;
822 case 0x0105:
823 rv = ERANGE;
824 break;
825 case 0x0106:
826 rv = EBUSY;
827 break;
828 default:
829 rv = EINVAL;
830 break;
833 if (rv == 0)
834 mlx->mlx_bg = MLX_BG_REBUILD;
836 return (0);
838 case MLX_REBUILDSTAT:
840 * Get the status of the current rebuild or consistency check.
842 *rs = mlx->mlx_rebuildstat;
843 return (0);
845 case MLX_GET_SYSDRIVE:
847 * Return the system drive number matching the `ld' device
848 * unit in (arg), if it happens to belong to us.
850 for (i = 0; i < MLX_MAX_DRIVES; i++) {
851 ms = &mlx->mlx_sysdrive[i];
852 if (ms->ms_dv != NULL)
853 if (device_xname(ms->ms_dv)[2] == '0' + *arg) {
854 *arg = i;
855 return (0);
858 return (ENOENT);
860 case MLX_GET_CINFO:
862 * Return controller info.
864 memcpy(arg, &mlx->mlx_ci, sizeof(mlx->mlx_ci));
865 return (0);
868 switch (cmd) {
869 case MLXD_DETACH:
870 case MLXD_STATUS:
871 case MLXD_CHECKASYNC:
872 if ((u_int)*arg >= MLX_MAX_DRIVES)
873 return (EINVAL);
874 ms = &mlx->mlx_sysdrive[*arg];
875 if (*arg > MLX_MAX_DRIVES || ms->ms_dv == NULL)
876 return (ENOENT);
877 break;
879 default:
880 return (ENOTTY);
883 switch (cmd) {
884 case MLXD_DETACH:
886 * Disconnect from the specified drive; it may be about to go
887 * away.
889 return (config_detach(ms->ms_dv, 0));
891 case MLXD_STATUS:
893 * Return the current status of this drive.
895 *arg = ms->ms_state;
896 return (0);
898 case MLXD_CHECKASYNC:
900 * Start a background consistency check on this drive.
902 if (mlx->mlx_bg != 0) {
903 *arg = 0x0106;
904 return (EBUSY);
907 switch (result = mlx_check(mlx, *arg)) {
908 case 0:
909 rv = 0;
910 break;
911 case 0x10000:
912 rv = ENOMEM; /* Couldn't set up the command. */
913 break;
914 case 0x0002:
915 rv = EIO;
916 break;
917 case 0x0105:
918 rv = ERANGE;
919 break;
920 case 0x0106:
921 rv = EBUSY;
922 break;
923 default:
924 rv = EINVAL;
925 break;
928 if (rv == 0)
929 mlx->mlx_bg = MLX_BG_CHECK;
930 *arg = result;
931 return (rv);
934 return (ENOTTY); /* XXX shut up gcc */
937 static void
938 mlx_periodic_thread(void *cookie)
940 struct mlx_softc *mlx;
941 int i;
943 for (;;) {
944 for (i = 0; i < mlx_cd.cd_ndevs; i++)
945 if ((mlx = device_lookup_private(&mlx_cd, i)) != NULL)
946 if (mlx->mlx_ci.ci_iftype > 1)
947 mlx_periodic(mlx);
949 tsleep(mlx_periodic_thread, PWAIT, "mlxzzz", hz * 2);
953 static void
954 mlx_periodic(struct mlx_softc *mlx)
956 struct mlx_ccb *mc, *nmc;
957 int etype, s;
959 if ((mlx->mlx_pause.mp_which != 0) &&
960 (mlx->mlx_pause.mp_when > 0) &&
961 (time_second >= mlx->mlx_pause.mp_when)) {
963 * Start bus pause.
965 mlx_pause_action(mlx);
966 mlx->mlx_pause.mp_when = 0;
967 } else if ((mlx->mlx_pause.mp_which != 0) &&
968 (mlx->mlx_pause.mp_when == 0)) {
970 * Stop pause if required.
972 if (time_second >= mlx->mlx_pause.mp_howlong) {
973 mlx_pause_action(mlx);
974 mlx->mlx_pause.mp_which = 0;
976 } else if (time_second > (mlx->mlx_lastpoll + 10)) {
978 * Run normal periodic activities...
980 mlx->mlx_lastpoll = time_second;
983 * Check controller status.
985 if ((mlx->mlx_flags & MLXF_PERIODIC_CTLR) == 0) {
986 mlx->mlx_flags |= MLXF_PERIODIC_CTLR;
988 if (mlx->mlx_ci.ci_iftype <= 2)
989 etype = MLX_CMD_ENQUIRY_OLD;
990 else
991 etype = MLX_CMD_ENQUIRY;
993 mlx_enquire(mlx, etype, max(sizeof(struct mlx_enquiry),
994 sizeof(struct mlx_enquiry_old)),
995 mlx_periodic_enquiry, 1);
999 * Check system drive status.
1001 if ((mlx->mlx_flags & MLXF_PERIODIC_DRIVE) == 0) {
1002 mlx->mlx_flags |= MLXF_PERIODIC_DRIVE;
1003 mlx_enquire(mlx, MLX_CMD_ENQSYSDRIVE,
1004 sizeof(struct mlx_enq_sys_drive) * MLX_MAX_DRIVES,
1005 mlx_periodic_enquiry, 1);
1010 * Get drive rebuild/check status.
1012 if ((mlx->mlx_flags & MLXF_PERIODIC_REBUILD) == 0) {
1013 mlx->mlx_flags |= MLXF_PERIODIC_REBUILD;
1014 mlx_enquire(mlx, MLX_CMD_REBUILDSTAT,
1015 sizeof(struct mlx_rebuild_stat), mlx_periodic_rebuild, 1);
1019 * Time-out busy CCBs.
1021 s = splbio();
1022 for (mc = TAILQ_FIRST(&mlx->mlx_ccb_worklist); mc != NULL; mc = nmc) {
1023 nmc = TAILQ_NEXT(mc, mc_chain.tailq);
1024 if (mc->mc_expiry > time_second) {
1026 * The remaining CCBs will expire after this one, so
1027 * there's no point in going further.
1029 break;
1031 TAILQ_REMOVE(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
1032 mc->mc_status = MLX_STATUS_LOST;
1033 if (mc->mc_mx.mx_handler != NULL)
1034 (*mc->mc_mx.mx_handler)(mc);
1035 else if ((mc->mc_flags & MC_WAITING) != 0)
1036 wakeup(mc);
1038 splx(s);
1042 * Handle the result of an ENQUIRY command instigated by periodic status
1043 * polling.
1045 static void
1046 mlx_periodic_enquiry(struct mlx_ccb *mc)
1048 struct mlx_softc *mlx;
1049 struct mlx_enquiry *me;
1050 struct mlx_enquiry_old *meo;
1051 struct mlx_enq_sys_drive *mes;
1052 struct mlx_sysdrive *dr;
1053 const char *statestr;
1054 int i, j;
1055 u_int lsn;
1057 mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
1058 mlx_ccb_unmap(mlx, mc);
1061 * Command completed OK?
1063 if (mc->mc_status != 0) {
1064 aprint_error_dev(&mlx->mlx_dv, "periodic enquiry failed - %s\n",
1065 mlx_ccb_diagnose(mc));
1066 goto out;
1070 * Respond to command.
1072 switch (mc->mc_mbox[0]) {
1073 case MLX_CMD_ENQUIRY_OLD:
1075 * This is currently a bit fruitless, as we don't know how
1076 * to extract the eventlog pointer yet.
1078 me = (struct mlx_enquiry *)mc->mc_mx.mx_context;
1079 meo = (struct mlx_enquiry_old *)mc->mc_mx.mx_context;
1081 /* Convert data in-place to new format */
1082 i = sizeof(me->me_dead) / sizeof(me->me_dead[0]);
1083 while (--i >= 0) {
1084 me->me_dead[i].dd_chan = meo->me_dead[i].dd_chan;
1085 me->me_dead[i].dd_targ = meo->me_dead[i].dd_targ;
1088 me->me_misc_flags = 0;
1089 me->me_rebuild_count = meo->me_rebuild_count;
1090 me->me_dead_count = meo->me_dead_count;
1091 me->me_critical_sd_count = meo->me_critical_sd_count;
1092 me->me_event_log_seq_num = 0;
1093 me->me_offline_sd_count = meo->me_offline_sd_count;
1094 me->me_max_commands = meo->me_max_commands;
1095 me->me_rebuild_flag = meo->me_rebuild_flag;
1096 me->me_fwmajor = meo->me_fwmajor;
1097 me->me_fwminor = meo->me_fwminor;
1098 me->me_status_flags = meo->me_status_flags;
1099 me->me_flash_age = meo->me_flash_age;
1101 i = sizeof(me->me_drvsize) / sizeof(me->me_drvsize[0]);
1102 j = sizeof(meo->me_drvsize) / sizeof(meo->me_drvsize[0]);
1104 while (--i >= 0) {
1105 if (i >= j)
1106 me->me_drvsize[i] = 0;
1107 else
1108 me->me_drvsize[i] = meo->me_drvsize[i];
1111 me->me_num_sys_drvs = meo->me_num_sys_drvs;
1113 /* FALLTHROUGH */
1115 case MLX_CMD_ENQUIRY:
1117 * Generic controller status update. We could do more with
1118 * this than just checking the event log.
1120 me = (struct mlx_enquiry *)mc->mc_mx.mx_context;
1121 lsn = le16toh(me->me_event_log_seq_num);
1123 if (mlx->mlx_currevent == -1) {
1124 /* Initialise our view of the event log. */
1125 mlx->mlx_currevent = lsn;
1126 mlx->mlx_lastevent = lsn;
1127 } else if (lsn != mlx->mlx_lastevent &&
1128 (mlx->mlx_flags & MLXF_EVENTLOG_BUSY) == 0) {
1129 /* Record where current events are up to */
1130 mlx->mlx_currevent = lsn;
1132 /* Mark the event log as busy. */
1133 mlx->mlx_flags |= MLXF_EVENTLOG_BUSY;
1135 /* Drain new eventlog entries. */
1136 mlx_periodic_eventlog_poll(mlx);
1138 break;
1140 case MLX_CMD_ENQSYSDRIVE:
1142 * Perform drive status comparison to see if something
1143 * has failed. Don't perform the comparison if we're
1144 * reconfiguring, since the system drive table will be
1145 * changing.
1147 if ((mlx->mlx_flags & MLXF_RESCANNING) != 0)
1148 break;
1150 mes = (struct mlx_enq_sys_drive *)mc->mc_mx.mx_context;
1151 dr = &mlx->mlx_sysdrive[0];
1153 for (i = 0; i < mlx->mlx_numsysdrives; i++, dr++) {
1154 /* Has state been changed by controller? */
1155 if (dr->ms_state != mes[i].sd_state) {
1156 switch (mes[i].sd_state) {
1157 case MLX_SYSD_OFFLINE:
1158 statestr = "offline";
1159 break;
1161 case MLX_SYSD_ONLINE:
1162 statestr = "online";
1163 break;
1165 case MLX_SYSD_CRITICAL:
1166 statestr = "critical";
1167 break;
1169 default:
1170 statestr = "unknown";
1171 break;
1174 printf("%s: unit %d %s\n", device_xname(&mlx->mlx_dv),
1175 i, statestr);
1177 /* Save new state. */
1178 dr->ms_state = mes[i].sd_state;
1181 break;
1183 #ifdef DIAGNOSTIC
1184 default:
1185 printf("%s: mlx_periodic_enquiry: eh?\n",
1186 device_xname(&mlx->mlx_dv));
1187 break;
1188 #endif
1191 out:
1192 if (mc->mc_mbox[0] == MLX_CMD_ENQSYSDRIVE)
1193 mlx->mlx_flags &= ~MLXF_PERIODIC_DRIVE;
1194 else
1195 mlx->mlx_flags &= ~MLXF_PERIODIC_CTLR;
1197 free(mc->mc_mx.mx_context, M_DEVBUF);
1198 mlx_ccb_free(mlx, mc);
1202 * Instigate a poll for one event log message on (mlx). We only poll for
1203 * one message at a time, to keep our command usage down.
1205 static void
1206 mlx_periodic_eventlog_poll(struct mlx_softc *mlx)
1208 struct mlx_ccb *mc;
1209 void *result;
1210 int rv;
1212 result = NULL;
1214 if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
1215 goto out;
1217 if ((result = malloc(1024, M_DEVBUF, M_WAITOK)) == NULL) {
1218 rv = ENOMEM;
1219 goto out;
1221 if ((rv = mlx_ccb_map(mlx, mc, result, 1024, MC_XFER_IN)) != 0)
1222 goto out;
1223 if (mc->mc_nsgent != 1) {
1224 mlx_ccb_unmap(mlx, mc);
1225 printf("mlx_periodic_eventlog_poll: too many segs\n");
1226 goto out;
1229 /* Build the command to get one log entry. */
1230 mlx_make_type3(mc, MLX_CMD_LOGOP, MLX_LOGOP_GET, 1,
1231 mlx->mlx_lastevent, 0, 0, mc->mc_xfer_phys, 0);
1233 mc->mc_mx.mx_handler = mlx_periodic_eventlog_respond;
1234 mc->mc_mx.mx_dv = &mlx->mlx_dv;
1235 mc->mc_mx.mx_context = result;
1237 /* Start the command. */
1238 mlx_ccb_enqueue(mlx, mc);
1240 out:
1241 if (rv != 0) {
1242 if (mc != NULL)
1243 mlx_ccb_free(mlx, mc);
1244 if (result != NULL)
1245 free(result, M_DEVBUF);
1250 * Handle the result of polling for a log message, generate diagnostic
1251 * output. If this wasn't the last message waiting for us, we'll go collect
1252 * another.
1254 static void
1255 mlx_periodic_eventlog_respond(struct mlx_ccb *mc)
1257 struct mlx_softc *mlx;
1258 struct mlx_eventlog_entry *el;
1259 const char *reason;
1260 u_int8_t sensekey, chan, targ;
1262 mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
1263 el = mc->mc_mx.mx_context;
1264 mlx_ccb_unmap(mlx, mc);
1266 mlx->mlx_lastevent++;
1268 if (mc->mc_status == 0) {
1269 switch (el->el_type) {
1270 case MLX_LOGMSG_SENSE: /* sense data */
1271 sensekey = el->el_sense & 0x0f;
1272 chan = (el->el_target >> 4) & 0x0f;
1273 targ = el->el_target & 0x0f;
1276 * This is the only sort of message we understand at
1277 * the moment. The tests here are probably
1278 * incomplete.
1282 * Mylex vendor-specific message indicating a drive
1283 * was killed?
1285 if (sensekey == 9 && el->el_asc == 0x80) {
1286 if (el->el_asq < sizeof(mlx_sense_msgs) /
1287 sizeof(mlx_sense_msgs[0]))
1288 reason = mlx_sense_msgs[el->el_asq];
1289 else
1290 reason = "for unknown reason";
1292 printf("%s: physical drive %d:%d killed %s\n",
1293 device_xname(&mlx->mlx_dv), chan, targ, reason);
1297 * SCSI drive was reset?
1299 if (sensekey == 6 && el->el_asc == 0x29)
1300 printf("%s: physical drive %d:%d reset\n",
1301 device_xname(&mlx->mlx_dv), chan, targ);
1304 * SCSI drive error?
1306 if (!(sensekey == 0 ||
1307 (sensekey == 2 &&
1308 el->el_asc == 0x04 &&
1309 (el->el_asq == 0x01 || el->el_asq == 0x02)))) {
1310 printf("%s: physical drive %d:%d error log: "
1311 "sense = %d asc = %x asq = %x\n",
1312 device_xname(&mlx->mlx_dv), chan, targ, sensekey,
1313 el->el_asc, el->el_asq);
1314 printf("%s: info = %d:%d:%d:%d "
1315 " csi = %d:%d:%d:%d\n",
1316 device_xname(&mlx->mlx_dv),
1317 el->el_information[0],
1318 el->el_information[1],
1319 el->el_information[2],
1320 el->el_information[3],
1321 el->el_csi[0], el->el_csi[1],
1322 el->el_csi[2], el->el_csi[3]);
1325 break;
1327 default:
1328 aprint_error_dev(&mlx->mlx_dv, "unknown log message type 0x%x\n",
1329 el->el_type);
1330 break;
1332 } else {
1333 aprint_error_dev(&mlx->mlx_dv, "error reading message log - %s\n",
1334 mlx_ccb_diagnose(mc));
1337 * Give up on all the outstanding messages, as we may have
1338 * come unsynched.
1340 mlx->mlx_lastevent = mlx->mlx_currevent;
1343 free(mc->mc_mx.mx_context, M_DEVBUF);
1344 mlx_ccb_free(mlx, mc);
1347 * Is there another message to obtain?
1349 if (mlx->mlx_lastevent != mlx->mlx_currevent)
1350 mlx_periodic_eventlog_poll(mlx);
1351 else
1352 mlx->mlx_flags &= ~MLXF_EVENTLOG_BUSY;
1356 * Handle check/rebuild operations in progress.
1358 static void
1359 mlx_periodic_rebuild(struct mlx_ccb *mc)
1361 struct mlx_softc *mlx;
1362 const char *opstr;
1363 struct mlx_rebuild_status *mr;
1365 mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
1366 mr = mc->mc_mx.mx_context;
1367 mlx_ccb_unmap(mlx, mc);
1369 switch (mc->mc_status) {
1370 case 0:
1372 * Operation running, update stats.
1374 mlx->mlx_rebuildstat = *mr;
1376 /* Spontaneous rebuild/check? */
1377 if (mlx->mlx_bg == 0) {
1378 mlx->mlx_bg = MLX_BG_SPONTANEOUS;
1379 printf("%s: background check/rebuild started\n",
1380 device_xname(&mlx->mlx_dv));
1382 break;
1384 case 0x0105:
1386 * Nothing running, finalise stats and report.
1388 switch (mlx->mlx_bg) {
1389 case MLX_BG_CHECK:
1390 /* XXX Print drive? */
1391 opstr = "consistency check";
1392 break;
1394 case MLX_BG_REBUILD:
1395 /* XXX Print channel:target? */
1396 opstr = "drive rebuild";
1397 break;
1399 case MLX_BG_SPONTANEOUS:
1400 default:
1402 * If we have previously been non-idle, report the
1403 * transition
1405 if (mlx->mlx_rebuildstat.rs_code !=
1406 MLX_REBUILDSTAT_IDLE)
1407 opstr = "background check/rebuild";
1408 else
1409 opstr = NULL;
1412 if (opstr != NULL)
1413 printf("%s: %s completed\n", device_xname(&mlx->mlx_dv),
1414 opstr);
1416 mlx->mlx_bg = 0;
1417 mlx->mlx_rebuildstat.rs_code = MLX_REBUILDSTAT_IDLE;
1418 break;
1421 free(mc->mc_mx.mx_context, M_DEVBUF);
1422 mlx_ccb_free(mlx, mc);
1423 mlx->mlx_flags &= ~MLXF_PERIODIC_REBUILD;
1427 * It's time to perform a channel pause action for (mlx), either start or
1428 * stop the pause.
1430 static void
1431 mlx_pause_action(struct mlx_softc *mlx)
1433 struct mlx_ccb *mc;
1434 int failsafe, i, cmd;
1436 /* What are we doing here? */
1437 if (mlx->mlx_pause.mp_when == 0) {
1438 cmd = MLX_CMD_STARTCHANNEL;
1439 failsafe = 0;
1440 } else {
1441 cmd = MLX_CMD_STOPCHANNEL;
1444 * Channels will always start again after the failsafe
1445 * period, which is specified in multiples of 30 seconds.
1446 * This constrains us to a maximum pause of 450 seconds.
1448 failsafe = ((mlx->mlx_pause.mp_howlong - time_second) + 5) / 30;
1450 if (failsafe > 0xf) {
1451 failsafe = 0xf;
1452 mlx->mlx_pause.mp_howlong =
1453 time_second + (0xf * 30) - 5;
1457 /* Build commands for every channel requested. */
1458 for (i = 0; i < mlx->mlx_ci.ci_nchan; i++) {
1459 if ((1 << i) & mlx->mlx_pause.mp_which) {
1460 if (mlx_ccb_alloc(mlx, &mc, 1) != 0) {
1461 aprint_error_dev(&mlx->mlx_dv, "%s failed for channel %d\n",
1462 cmd == MLX_CMD_STOPCHANNEL ?
1463 "pause" : "resume", i);
1464 continue;
1467 /* Build the command. */
1468 mlx_make_type2(mc, cmd, (failsafe << 4) | i, 0, 0,
1469 0, 0, 0, 0, 0);
1470 mc->mc_mx.mx_handler = mlx_pause_done;
1471 mc->mc_mx.mx_dv = &mlx->mlx_dv;
1473 mlx_ccb_enqueue(mlx, mc);
1478 static void
1479 mlx_pause_done(struct mlx_ccb *mc)
1481 struct mlx_softc *mlx;
1482 int command, channel;
1484 mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
1485 command = mc->mc_mbox[0];
1486 channel = mc->mc_mbox[2] & 0xf;
1488 if (mc->mc_status != 0)
1489 aprint_error_dev(&mlx->mlx_dv, "%s command failed - %s\n",
1490 command == MLX_CMD_STOPCHANNEL ? "pause" : "resume",
1491 mlx_ccb_diagnose(mc));
1492 else if (command == MLX_CMD_STOPCHANNEL)
1493 printf("%s: channel %d pausing for %ld seconds\n",
1494 device_xname(&mlx->mlx_dv), channel,
1495 (long)(mlx->mlx_pause.mp_howlong - time_second));
1496 else
1497 printf("%s: channel %d resuming\n", device_xname(&mlx->mlx_dv),
1498 channel);
1500 mlx_ccb_free(mlx, mc);
1504 * Perform an Enquiry command using a type-3 command buffer and a return a
1505 * single linear result buffer. If the completion function is specified, it
1506 * will be called with the completed command (and the result response will
1507 * not be valid until that point). Otherwise, the command will either be
1508 * busy-waited for (interrupts must be blocked), or slept for.
1510 static void *
1511 mlx_enquire(struct mlx_softc *mlx, int command, size_t bufsize,
1512 void (*handler)(struct mlx_ccb *mc), int waitok)
1514 struct mlx_ccb *mc;
1515 void *result;
1516 int rv, mapped;
1518 result = NULL;
1519 mapped = 0;
1521 if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
1522 goto out;
1524 result = malloc(bufsize, M_DEVBUF, waitok ? M_WAITOK : M_NOWAIT);
1525 if (result == NULL) {
1526 printf("mlx_enquire: malloc() failed\n");
1527 goto out;
1529 if ((rv = mlx_ccb_map(mlx, mc, result, bufsize, MC_XFER_IN)) != 0)
1530 goto out;
1531 mapped = 1;
1532 if (mc->mc_nsgent != 1) {
1533 printf("mlx_enquire: too many segs\n");
1534 goto out;
1537 /* Build an enquiry command. */
1538 mlx_make_type2(mc, command, 0, 0, 0, 0, 0, 0, mc->mc_xfer_phys, 0);
1540 /* Do we want a completion callback? */
1541 if (handler != NULL) {
1542 mc->mc_mx.mx_context = result;
1543 mc->mc_mx.mx_dv = &mlx->mlx_dv;
1544 mc->mc_mx.mx_handler = handler;
1545 mlx_ccb_enqueue(mlx, mc);
1546 } else {
1547 /* Run the command in either polled or wait mode. */
1548 if (waitok)
1549 rv = mlx_ccb_wait(mlx, mc);
1550 else
1551 rv = mlx_ccb_poll(mlx, mc, 5000);
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);
1562 /* We got an error, and we allocated a result. */
1563 if (rv != 0 && result != NULL) {
1564 if (mc != NULL)
1565 mlx_ccb_free(mlx, mc);
1566 free(result, M_DEVBUF);
1567 result = NULL;
1570 return (result);
1574 * Perform a Flush command on the nominated controller.
1576 * May be called with interrupts enabled or disabled; will not return until
1577 * the flush operation completes or fails.
1580 mlx_flush(struct mlx_softc *mlx, int async)
1582 struct mlx_ccb *mc;
1583 int rv;
1585 if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
1586 goto out;
1588 /* Build a flush command and fire it off. */
1589 mlx_make_type2(mc, MLX_CMD_FLUSH, 0, 0, 0, 0, 0, 0, 0, 0);
1591 if (async)
1592 rv = mlx_ccb_wait(mlx, mc);
1593 else
1594 rv = mlx_ccb_poll(mlx, mc, MLX_TIMEOUT * 1000);
1595 if (rv != 0)
1596 goto out;
1598 /* Command completed OK? */
1599 if (mc->mc_status != 0) {
1600 aprint_error_dev(&mlx->mlx_dv, "FLUSH failed - %s\n",
1601 mlx_ccb_diagnose(mc));
1602 rv = EIO;
1604 out:
1605 if (mc != NULL)
1606 mlx_ccb_free(mlx, mc);
1608 return (rv);
1612 * Start a background consistency check on (drive).
1614 static int
1615 mlx_check(struct mlx_softc *mlx, int drive)
1617 struct mlx_ccb *mc;
1618 int rv;
1620 /* Get ourselves a command buffer. */
1621 rv = 0x10000;
1623 if (mlx_ccb_alloc(mlx, &mc, 1) != 0)
1624 goto out;
1626 /* Build a checkasync command, set the "fix it" flag. */
1627 mlx_make_type2(mc, MLX_CMD_CHECKASYNC, 0, 0, 0, 0, 0, drive | 0x80,
1628 0, 0);
1630 /* Start the command and wait for it to be returned. */
1631 if (mlx_ccb_wait(mlx, mc) != 0)
1632 goto out;
1634 /* Command completed OK? */
1635 if (mc->mc_status != 0)
1636 aprint_error_dev(&mlx->mlx_dv, "CHECK ASYNC failed - %s\n",
1637 mlx_ccb_diagnose(mc));
1638 else
1639 printf("%s: consistency check started",
1640 device_xname(mlx->mlx_sysdrive[drive].ms_dv));
1642 rv = mc->mc_status;
1643 out:
1644 if (mc != NULL)
1645 mlx_ccb_free(mlx, mc);
1647 return (rv);
1651 * Start a background rebuild of the physical drive at (channel),(target).
1653 * May be called with interrupts enabled or disabled; will return as soon as
1654 * the operation has started or been refused.
1656 static int
1657 mlx_rebuild(struct mlx_softc *mlx, int channel, int target)
1659 struct mlx_ccb *mc;
1660 int error;
1662 error = 0x10000;
1663 if (mlx_ccb_alloc(mlx, &mc, 1) != 0)
1664 goto out;
1666 /* Build a rebuildasync command, set the "fix it" flag. */
1667 mlx_make_type2(mc, MLX_CMD_REBUILDASYNC, channel, target, 0, 0, 0, 0,
1668 0, 0);
1670 /* Start the command and wait for it to be returned. */
1671 if (mlx_ccb_wait(mlx, mc) != 0)
1672 goto out;
1674 /* Command completed OK? */
1675 aprint_normal_dev(&mlx->mlx_dv, "");
1676 if (mc->mc_status != 0)
1677 printf("REBUILD ASYNC failed - %s\n", mlx_ccb_diagnose(mc));
1678 else
1679 printf("rebuild started for %d:%d\n", channel, target);
1681 error = mc->mc_status;
1683 out:
1684 if (mc != NULL)
1685 mlx_ccb_free(mlx, mc);
1687 return (error);
1691 * Take a command from user-space and try to run it.
1693 * XXX Note that this can't perform very much in the way of error checking,
1694 * XXX and as such, applications _must_ be considered trustworthy.
1696 * XXX Commands using S/G for data are not supported.
1698 static int
1699 mlx_user_command(struct mlx_softc *mlx, struct mlx_usercommand *mu)
1701 struct mlx_ccb *mc;
1702 struct mlx_dcdb *dcdb;
1703 void *kbuf;
1704 int rv, mapped;
1706 if ((mu->mu_bufdir & ~MU_XFER_MASK) != 0)
1707 return (EINVAL);
1709 kbuf = NULL;
1710 dcdb = NULL;
1711 mapped = 0;
1713 /* Get ourselves a command and copy in from user space. */
1714 if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0) {
1715 DPRINTF(("mlx_user_command: mlx_ccb_alloc = %d\n", rv));
1716 goto out;
1719 memcpy(mc->mc_mbox, mu->mu_command, sizeof(mc->mc_mbox));
1722 * If we need a buffer for data transfer, allocate one and copy in
1723 * its initial contents.
1725 if (mu->mu_datasize > 0) {
1726 if (mu->mu_datasize > MAXPHYS)
1727 return (EINVAL);
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;
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;
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;
1751 if (mc->mc_nsgent > 1) {
1752 DPRINTF(("mlx_user_command: too many s/g entries\n"));
1753 rv = EFBIG;
1754 goto out;
1756 mapped = 1;
1758 * If this is a passthrough SCSI command, the DCDB is packed at
1759 * the beginning of the data area. Fix up the DCDB to point to
1760 * the correct physical address and override any bufptr
1761 * supplied by the caller since we know what it's meant to be.
1763 if (mc->mc_mbox[0] == MLX_CMD_DIRECT_CDB) {
1764 dcdb = (struct mlx_dcdb *)kbuf;
1765 dcdb->dcdb_physaddr = mc->mc_xfer_phys + sizeof(*dcdb);
1766 mu->mu_bufptr = 8;
1772 * If there's a data buffer, fix up the command's buffer pointer.
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;
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;
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
1796 out:
1797 if (mc != NULL) {
1798 /* Copy out status and data */
1799 mu->mu_status = mc->mc_status;
1800 if (mapped)
1801 mlx_ccb_unmap(mlx, mc);
1802 mlx_ccb_free(mlx, mc);
1805 if (kbuf != NULL) {
1806 if (mu->mu_datasize > 0 && (mu->mu_bufdir & MU_XFER_IN) != 0) {
1807 rv = copyout(kbuf, mu->mu_buf, mu->mu_datasize);
1808 #ifdef DIAGNOSTIC
1809 if (rv != 0)
1810 printf("mlx_user_command: copyout = %d\n", rv);
1811 #endif
1814 if (kbuf != NULL)
1815 free(kbuf, M_DEVBUF);
1817 return (rv);
1821 * Allocate and initialise a CCB.
1824 mlx_ccb_alloc(struct mlx_softc *mlx, struct mlx_ccb **mcp, int control)
1826 struct mlx_ccb *mc;
1827 int s;
1829 s = splbio();
1830 mc = SLIST_FIRST(&mlx->mlx_ccb_freelist);
1831 if (control) {
1832 if (mlx->mlx_nccbs_ctrl >= MLX_NCCBS_CONTROL) {
1833 splx(s);
1834 *mcp = NULL;
1835 return (EAGAIN);
1837 mc->mc_flags |= MC_CONTROL;
1838 mlx->mlx_nccbs_ctrl++;
1840 SLIST_REMOVE_HEAD(&mlx->mlx_ccb_freelist, mc_chain.slist);
1841 splx(s);
1843 *mcp = mc;
1844 return (0);
1848 * Free a CCB.
1850 void
1851 mlx_ccb_free(struct mlx_softc *mlx, struct mlx_ccb *mc)
1853 int s;
1855 s = splbio();
1856 if ((mc->mc_flags & MC_CONTROL) != 0)
1857 mlx->mlx_nccbs_ctrl--;
1858 mc->mc_flags = 0;
1859 SLIST_INSERT_HEAD(&mlx->mlx_ccb_freelist, mc, mc_chain.slist);
1860 splx(s);
1864 * If a CCB is specified, enqueue it. Pull CCBs off the software queue in
1865 * the order that they were enqueued and try to submit their mailboxes to
1866 * the controller for execution.
1868 void
1869 mlx_ccb_enqueue(struct mlx_softc *mlx, struct mlx_ccb *mc)
1871 int s;
1873 s = splbio();
1875 if (mc != NULL)
1876 SIMPLEQ_INSERT_TAIL(&mlx->mlx_ccb_queue, mc, mc_chain.simpleq);
1878 while ((mc = SIMPLEQ_FIRST(&mlx->mlx_ccb_queue)) != NULL) {
1879 if (mlx_ccb_submit(mlx, mc) != 0)
1880 break;
1881 SIMPLEQ_REMOVE_HEAD(&mlx->mlx_ccb_queue, mc_chain.simpleq);
1882 TAILQ_INSERT_TAIL(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
1885 splx(s);
1889 * Map the specified CCB's data buffer onto the bus, and fill the
1890 * scatter-gather list.
1893 mlx_ccb_map(struct mlx_softc *mlx, struct mlx_ccb *mc, void *data, int size,
1894 int dir)
1896 struct mlx_sgentry *sge;
1897 int nsegs, i, rv, sgloff;
1898 bus_dmamap_t xfer;
1900 xfer = mc->mc_xfer_map;
1902 rv = bus_dmamap_load(mlx->mlx_dmat, xfer, data, size, NULL,
1903 BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
1904 ((dir & MC_XFER_IN) ? BUS_DMA_READ : BUS_DMA_WRITE));
1905 if (rv != 0)
1906 return (rv);
1908 nsegs = xfer->dm_nsegs;
1909 mc->mc_xfer_size = size;
1910 mc->mc_flags |= dir;
1911 mc->mc_nsgent = nsegs;
1912 mc->mc_xfer_phys = xfer->dm_segs[0].ds_addr;
1914 sgloff = MLX_SGL_SIZE * mc->mc_ident;
1915 sge = (struct mlx_sgentry *)((char *)mlx->mlx_sgls + sgloff);
1917 for (i = 0; i < nsegs; i++, sge++) {
1918 sge->sge_addr = htole32(xfer->dm_segs[i].ds_addr);
1919 sge->sge_count = htole32(xfer->dm_segs[i].ds_len);
1922 if ((dir & MC_XFER_OUT) != 0)
1923 i = BUS_DMASYNC_PREWRITE;
1924 else
1925 i = 0;
1926 if ((dir & MC_XFER_IN) != 0)
1927 i |= BUS_DMASYNC_PREREAD;
1929 bus_dmamap_sync(mlx->mlx_dmat, xfer, 0, mc->mc_xfer_size, i);
1930 bus_dmamap_sync(mlx->mlx_dmat, mlx->mlx_dmamap, sgloff,
1931 MLX_SGL_SIZE, BUS_DMASYNC_PREWRITE);
1933 return (0);
1937 * Unmap the specified CCB's data buffer.
1939 void
1940 mlx_ccb_unmap(struct mlx_softc *mlx, struct mlx_ccb *mc)
1942 int i;
1944 bus_dmamap_sync(mlx->mlx_dmat, mlx->mlx_dmamap,
1945 MLX_SGL_SIZE * mc->mc_ident, MLX_SGL_SIZE,
1946 BUS_DMASYNC_POSTWRITE);
1948 if ((mc->mc_flags & MC_XFER_OUT) != 0)
1949 i = BUS_DMASYNC_POSTWRITE;
1950 else
1951 i = 0;
1952 if ((mc->mc_flags & MC_XFER_IN) != 0)
1953 i |= BUS_DMASYNC_POSTREAD;
1955 bus_dmamap_sync(mlx->mlx_dmat, mc->mc_xfer_map, 0, mc->mc_xfer_size, i);
1956 bus_dmamap_unload(mlx->mlx_dmat, mc->mc_xfer_map);
1960 * Submit the CCB, and busy-wait for it to complete. Return non-zero on
1961 * timeout or submission error. Must be called with interrupts blocked.
1964 mlx_ccb_poll(struct mlx_softc *mlx, struct mlx_ccb *mc, int timo)
1966 int rv;
1968 mc->mc_mx.mx_handler = NULL;
1970 if ((rv = mlx_ccb_submit(mlx, mc)) != 0)
1971 return (rv);
1972 TAILQ_INSERT_TAIL(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
1974 for (timo *= 10; timo != 0; timo--) {
1975 mlx_intr(mlx);
1976 if (mc->mc_status != MLX_STATUS_BUSY)
1977 break;
1978 DELAY(100);
1981 if (timo != 0) {
1982 if (mc->mc_status != 0) {
1983 aprint_error_dev(&mlx->mlx_dv, "command failed - %s\n",
1984 mlx_ccb_diagnose(mc));
1985 rv = EIO;
1986 } else
1987 rv = 0;
1988 } else {
1989 printf("%s: command timed out\n", device_xname(&mlx->mlx_dv));
1990 rv = EIO;
1993 return (rv);
1997 * Enqueue the CCB, and sleep until it completes. Return non-zero on
1998 * timeout or error.
2001 mlx_ccb_wait(struct mlx_softc *mlx, struct mlx_ccb *mc)
2003 int s;
2005 mc->mc_flags |= MC_WAITING;
2006 mc->mc_mx.mx_handler = NULL;
2008 s = splbio();
2009 mlx_ccb_enqueue(mlx, mc);
2010 tsleep(mc, PRIBIO, "mlxwccb", 0);
2011 splx(s);
2013 if (mc->mc_status != 0) {
2014 aprint_error_dev(&mlx->mlx_dv, "command failed - %s\n",
2015 mlx_ccb_diagnose(mc));
2016 return (EIO);
2019 return (0);
2023 * Try to submit a CCB's mailbox to the controller for execution. Return
2024 * non-zero on timeout or error. Must be called with interrupts blocked.
2026 static int
2027 mlx_ccb_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
2029 int i, s, r;
2031 /* Save the ident so we can handle this command when complete. */
2032 mc->mc_mbox[1] = (u_int8_t)(mc->mc_ident + 1);
2034 /* Mark the command as currently being processed. */
2035 mc->mc_status = MLX_STATUS_BUSY;
2036 mc->mc_expiry = time_second + MLX_TIMEOUT;
2038 /* Spin waiting for the mailbox. */
2039 for (i = 100; i != 0; i--) {
2040 s = splbio();
2041 r = (*mlx->mlx_submit)(mlx, mc);
2042 splx(s);
2043 if (r != 0)
2044 break;
2045 DELAY(100);
2047 if (i != 0)
2048 return (0);
2050 DPRINTF(("mlx_ccb_submit: rejected; queueing\n"));
2051 mc->mc_status = MLX_STATUS_WEDGED;
2052 return (EIO);
2056 * Return a string that describes why a command has failed.
2058 const char *
2059 mlx_ccb_diagnose(struct mlx_ccb *mc)
2061 static char tbuf[80];
2062 int i;
2064 for (i = 0; i < sizeof(mlx_msgs) / sizeof(mlx_msgs[0]); i++)
2065 if ((mc->mc_mbox[0] == mlx_msgs[i].command ||
2066 mlx_msgs[i].command == 0) &&
2067 mc->mc_status == mlx_msgs[i].status) {
2068 snprintf(tbuf, sizeof(tbuf), "%s (0x%x)",
2069 mlx_status_msgs[mlx_msgs[i].msg], mc->mc_status);
2070 return (tbuf);
2073 snprintf(tbuf, sizeof(tbuf), "unknown response 0x%x for command 0x%x",
2074 (int)mc->mc_status, (int)mc->mc_mbox[0]);
2076 return (tbuf);
2080 * Poll the controller for completed commands. Returns non-zero if one or
2081 * more commands were completed. Must be called with interrupts blocked.
2084 mlx_intr(void *cookie)
2086 struct mlx_softc *mlx;
2087 struct mlx_ccb *mc;
2088 int result;
2089 u_int ident, status;
2091 mlx = cookie;
2092 result = 0;
2094 while ((*mlx->mlx_findcomplete)(mlx, &ident, &status) != 0) {
2095 result = 1;
2096 ident--;
2098 if (ident >= MLX_MAX_QUEUECNT) {
2099 aprint_error_dev(&mlx->mlx_dv, "bad completion returned\n");
2100 continue;
2103 mc = mlx->mlx_ccbs + ident;
2105 if (mc->mc_status != MLX_STATUS_BUSY) {
2106 aprint_error_dev(&mlx->mlx_dv, "bad completion returned\n");
2107 continue;
2110 TAILQ_REMOVE(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
2112 /* Record status and notify the initiator, if requested. */
2113 mc->mc_status = status;
2114 if (mc->mc_mx.mx_handler != NULL)
2115 (*mc->mc_mx.mx_handler)(mc);
2116 else if ((mc->mc_flags & MC_WAITING) != 0)
2117 wakeup(mc);
2120 /* If we've completed any commands, try posting some more. */
2121 if (result)
2122 mlx_ccb_enqueue(mlx, NULL);
2124 return (result);
2128 * Emit a string describing the firmware handshake status code, and return a
2129 * flag indicating whether the code represents a fatal error.
2131 * Error code interpretations are from the Linux driver, and don't directly
2132 * match the messages printed by Mylex's BIOS. This may change if
2133 * documentation on the codes is forthcoming.
2135 static int
2136 mlx_fw_message(struct mlx_softc *mlx, int error, int param1, int param2)
2138 const char *fmt;
2140 switch (error) {
2141 case 0x00:
2142 fmt = "physical drive %d:%d not responding";
2143 break;
2145 case 0x08:
2147 * We could be neater about this and give some indication
2148 * when we receive more of them.
2150 if ((mlx->mlx_flags & MLXF_SPINUP_REPORTED) == 0) {
2151 printf("%s: spinning up drives...\n",
2152 device_xname(&mlx->mlx_dv));
2153 mlx->mlx_flags |= MLXF_SPINUP_REPORTED;
2155 return (0);
2157 case 0x30:
2158 fmt = "configuration checksum error";
2159 break;
2161 case 0x60:
2162 fmt = "mirror race recovery failed";
2163 break;
2165 case 0x70:
2166 fmt = "mirror race recovery in progress";
2167 break;
2169 case 0x90:
2170 fmt = "physical drive %d:%d COD mismatch";
2171 break;
2173 case 0xa0:
2174 fmt = "logical drive installation aborted";
2175 break;
2177 case 0xb0:
2178 fmt = "mirror race on a critical system drive";
2179 break;
2181 case 0xd0:
2182 fmt = "new controller configuration found";
2183 break;
2185 case 0xf0:
2186 aprint_error_dev(&mlx->mlx_dv, "FATAL MEMORY PARITY ERROR\n");
2187 return (1);
2189 default:
2190 aprint_error_dev(&mlx->mlx_dv, "unknown firmware init error %02x:%02x:%02x\n",
2191 error, param1, param2);
2192 return (0);
2195 aprint_normal_dev(&mlx->mlx_dv, "");
2196 aprint_normal(fmt, param2, param1);
2197 aprint_normal("\n");
2199 return (0);