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