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