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