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