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