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