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