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