xref: /netbsd-src/sys/dev/pci/mly.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /*	$NetBSD: mly.c,v 1.39 2008/06/08 12:43:52 tsutsui 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, Thor Lancelot Simon, and Eric Haszlakiewicz.
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  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*-
33  * Copyright (c) 2000, 2001 Michael Smith
34  * Copyright (c) 2000 BSDi
35  * All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  * 2. Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in the
44  *    documentation and/or other materials provided with the distribution.
45  *
46  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
47  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
50  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56  * SUCH DAMAGE.
57  *
58  * from FreeBSD: mly.c,v 1.8 2001/07/14 00:12:22 msmith Exp
59  */
60 
61 /*
62  * Driver for the Mylex AcceleRAID and eXtremeRAID family with v6 firmware.
63  *
64  * TODO:
65  *
66  * o Make mly->mly_btl a hash, then MLY_BTL_RESCAN becomes a SIMPLEQ.
67  * o Handle FC and multiple LUNs.
68  * o Fix mmbox usage.
69  * o Fix transfer speed fudge.
70  */
71 
72 #include <sys/cdefs.h>
73 __KERNEL_RCSID(0, "$NetBSD: mly.c,v 1.39 2008/06/08 12:43:52 tsutsui Exp $");
74 
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/device.h>
78 #include <sys/kernel.h>
79 #include <sys/queue.h>
80 #include <sys/buf.h>
81 #include <sys/endian.h>
82 #include <sys/conf.h>
83 #include <sys/malloc.h>
84 #include <sys/ioctl.h>
85 #include <sys/scsiio.h>
86 #include <sys/kthread.h>
87 #include <sys/kauth.h>
88 
89 #include <uvm/uvm_extern.h>
90 
91 #include <sys/bus.h>
92 
93 #include <dev/scsipi/scsi_all.h>
94 #include <dev/scsipi/scsipi_all.h>
95 #include <dev/scsipi/scsiconf.h>
96 
97 #include <dev/pci/pcireg.h>
98 #include <dev/pci/pcivar.h>
99 #include <dev/pci/pcidevs.h>
100 
101 #include <dev/pci/mlyreg.h>
102 #include <dev/pci/mlyio.h>
103 #include <dev/pci/mlyvar.h>
104 #include <dev/pci/mly_tables.h>
105 
106 static void	mly_attach(struct device *, struct device *, void *);
107 static int	mly_match(struct device *, struct cfdata *, void *);
108 static const	struct mly_ident *mly_find_ident(struct pci_attach_args *);
109 static int	mly_fwhandshake(struct mly_softc *);
110 static int	mly_flush(struct mly_softc *);
111 static int	mly_intr(void *);
112 static void	mly_shutdown(void *);
113 
114 static int	mly_alloc_ccbs(struct mly_softc *);
115 static void	mly_check_event(struct mly_softc *);
116 static void	mly_complete_event(struct mly_softc *, struct mly_ccb *);
117 static void	mly_complete_rescan(struct mly_softc *, struct mly_ccb *);
118 static int	mly_dmamem_alloc(struct mly_softc *, int, bus_dmamap_t *,
119 				 void **, bus_addr_t *, bus_dma_segment_t *);
120 static void	mly_dmamem_free(struct mly_softc *, int, bus_dmamap_t,
121 				void *, bus_dma_segment_t *);
122 static int	mly_enable_mmbox(struct mly_softc *);
123 static void	mly_fetch_event(struct mly_softc *);
124 static int	mly_get_controllerinfo(struct mly_softc *);
125 static int	mly_get_eventstatus(struct mly_softc *);
126 static int	mly_ioctl(struct mly_softc *, struct mly_cmd_ioctl *,
127 			  void **, size_t, void *, size_t *);
128 static void	mly_padstr(char *, const char *, int);
129 static void	mly_process_event(struct mly_softc *, struct mly_event *);
130 static void	mly_release_ccbs(struct mly_softc *);
131 static int	mly_scan_btl(struct mly_softc *, int, int);
132 static void	mly_scan_channel(struct mly_softc *, int);
133 static void	mly_thread(void *);
134 
135 static int	mly_ccb_alloc(struct mly_softc *, struct mly_ccb **);
136 static void	mly_ccb_complete(struct mly_softc *, struct mly_ccb *);
137 static void	mly_ccb_enqueue(struct mly_softc *, struct mly_ccb *);
138 static void	mly_ccb_free(struct mly_softc *, struct mly_ccb *);
139 static int	mly_ccb_map(struct mly_softc *, struct mly_ccb *);
140 static int	mly_ccb_poll(struct mly_softc *, struct mly_ccb *, int);
141 static int	mly_ccb_submit(struct mly_softc *, struct mly_ccb *);
142 static void	mly_ccb_unmap(struct mly_softc *, struct mly_ccb *);
143 static int	mly_ccb_wait(struct mly_softc *, struct mly_ccb *, int);
144 
145 static void	mly_get_xfer_mode(struct mly_softc *, int,
146 				  struct scsipi_xfer_mode *);
147 static void	mly_scsipi_complete(struct mly_softc *, struct mly_ccb *);
148 static int	mly_scsipi_ioctl(struct scsipi_channel *, u_long, void *,
149 				 int, struct proc *);
150 static void	mly_scsipi_minphys(struct buf *);
151 static void	mly_scsipi_request(struct scsipi_channel *,
152 				   scsipi_adapter_req_t, void *);
153 
154 static int	mly_user_command(struct mly_softc *, struct mly_user_command *);
155 static int	mly_user_health(struct mly_softc *, struct mly_user_health *);
156 
157 extern struct	cfdriver mly_cd;
158 
159 CFATTACH_DECL(mly, sizeof(struct mly_softc),
160     mly_match, mly_attach, NULL, NULL);
161 
162 dev_type_open(mlyopen);
163 dev_type_close(mlyclose);
164 dev_type_ioctl(mlyioctl);
165 
166 const struct cdevsw mly_cdevsw = {
167 	mlyopen, mlyclose, noread, nowrite, mlyioctl,
168 	nostop, notty, nopoll, nommap, nokqfilter, D_OTHER,
169 };
170 
171 static struct mly_ident {
172 	u_short	vendor;
173 	u_short	product;
174 	u_short	subvendor;
175 	u_short	subproduct;
176 	int	hwif;
177 	const char	*desc;
178 } const mly_ident[] = {
179 	{
180 		PCI_VENDOR_MYLEX,
181 		PCI_PRODUCT_MYLEX_EXTREMERAID,
182 		PCI_VENDOR_MYLEX,
183 		0x0040,
184 		MLY_HWIF_STRONGARM,
185 		"eXtremeRAID 2000"
186 	},
187 	{
188 		PCI_VENDOR_MYLEX,
189 		PCI_PRODUCT_MYLEX_EXTREMERAID,
190 		PCI_VENDOR_MYLEX,
191 		0x0030,
192 		MLY_HWIF_STRONGARM,
193 		"eXtremeRAID 3000"
194 	},
195 	{
196 		PCI_VENDOR_MYLEX,
197 		PCI_PRODUCT_MYLEX_ACCELERAID,
198 		PCI_VENDOR_MYLEX,
199 		0x0050,
200 		MLY_HWIF_I960RX,
201 		"AcceleRAID 352"
202 	},
203 	{
204 		PCI_VENDOR_MYLEX,
205 		PCI_PRODUCT_MYLEX_ACCELERAID,
206 		PCI_VENDOR_MYLEX,
207 		0x0052,
208 		MLY_HWIF_I960RX,
209 		"AcceleRAID 170"
210 	},
211 	{
212 		PCI_VENDOR_MYLEX,
213 		PCI_PRODUCT_MYLEX_ACCELERAID,
214 		PCI_VENDOR_MYLEX,
215 		0x0054,
216 		MLY_HWIF_I960RX,
217 		"AcceleRAID 160"
218 	},
219 };
220 
221 static void	*mly_sdh;
222 
223 /*
224  * Try to find a `mly_ident' entry corresponding to this board.
225  */
226 static const struct mly_ident *
227 mly_find_ident(struct pci_attach_args *pa)
228 {
229 	const struct mly_ident *mpi, *maxmpi;
230 	pcireg_t reg;
231 
232 	mpi = mly_ident;
233 	maxmpi = mpi + sizeof(mly_ident) / sizeof(mly_ident[0]);
234 
235 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_I2O)
236 		return (NULL);
237 
238 	for (; mpi < maxmpi; mpi++) {
239 		if (PCI_VENDOR(pa->pa_id) != mpi->vendor ||
240 		    PCI_PRODUCT(pa->pa_id) != mpi->product)
241 			continue;
242 
243 		if (mpi->subvendor == 0x0000)
244 			return (mpi);
245 
246 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
247 
248 		if (PCI_VENDOR(reg) == mpi->subvendor &&
249 		    PCI_PRODUCT(reg) == mpi->subproduct)
250 			return (mpi);
251 	}
252 
253 	return (NULL);
254 }
255 
256 /*
257  * Match a supported board.
258  */
259 static int
260 mly_match(struct device *parent, struct cfdata *cfdata,
261     void *aux)
262 {
263 
264 	return (mly_find_ident(aux) != NULL);
265 }
266 
267 /*
268  * Attach a supported board.
269  */
270 static void
271 mly_attach(struct device *parent, struct device *self, void *aux)
272 {
273 	struct pci_attach_args *pa;
274 	struct mly_softc *mly;
275 	struct mly_ioctl_getcontrollerinfo *mi;
276 	const struct mly_ident *ident;
277 	pci_chipset_tag_t pc;
278 	pci_intr_handle_t ih;
279 	bus_space_handle_t memh, ioh;
280 	bus_space_tag_t memt, iot;
281 	pcireg_t reg;
282 	const char *intrstr;
283 	int ior, memr, i, rv, state;
284 	struct scsipi_adapter *adapt;
285 	struct scsipi_channel *chan;
286 
287 	mly = (struct mly_softc *)self;
288 	pa = aux;
289 	pc = pa->pa_pc;
290 	ident = mly_find_ident(pa);
291 	state = 0;
292 
293 	mly->mly_dmat = pa->pa_dmat;
294 	mly->mly_hwif = ident->hwif;
295 
296 	printf(": Mylex %s\n", ident->desc);
297 
298 	/*
299 	 * Map the PCI register window.
300 	 */
301 	memr = -1;
302 	ior = -1;
303 
304 	for (i = 0x10; i <= 0x14; i += 4) {
305 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag, i);
306 
307 		if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) {
308 			if (ior == -1 && PCI_MAPREG_IO_SIZE(reg) != 0)
309 				ior = i;
310 		} else {
311 			if (memr == -1 && PCI_MAPREG_MEM_SIZE(reg) != 0)
312 				memr = i;
313 		}
314 	}
315 
316 	if (memr != -1)
317 		if (pci_mapreg_map(pa, memr, PCI_MAPREG_TYPE_MEM, 0,
318 		    &memt, &memh, NULL, NULL))
319 			memr = -1;
320 	if (ior != -1)
321 		if (pci_mapreg_map(pa, ior, PCI_MAPREG_TYPE_IO, 0,
322 		    &iot, &ioh, NULL, NULL))
323 		    	ior = -1;
324 
325 	if (memr != -1) {
326 		mly->mly_iot = memt;
327 		mly->mly_ioh = memh;
328 	} else if (ior != -1) {
329 		mly->mly_iot = iot;
330 		mly->mly_ioh = ioh;
331 	} else {
332 		aprint_error_dev(self, "can't map i/o or memory space\n");
333 		return;
334 	}
335 
336 	/*
337 	 * Enable the device.
338 	 */
339 	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
340 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
341 	    reg | PCI_COMMAND_MASTER_ENABLE);
342 
343 	/*
344 	 * Map and establish the interrupt.
345 	 */
346 	if (pci_intr_map(pa, &ih)) {
347 		aprint_error_dev(self, "can't map interrupt\n");
348 		return;
349 	}
350 	intrstr = pci_intr_string(pc, ih);
351 	mly->mly_ih = pci_intr_establish(pc, ih, IPL_BIO, mly_intr, mly);
352 	if (mly->mly_ih == NULL) {
353 		aprint_error_dev(self, "can't establish interrupt");
354 		if (intrstr != NULL)
355 			printf(" at %s", intrstr);
356 		printf("\n");
357 		return;
358 	}
359 
360 	if (intrstr != NULL)
361 		printf("%s: interrupting at %s\n", device_xname(&mly->mly_dv),
362 		    intrstr);
363 
364 	/*
365 	 * Take care of interface-specific tasks.
366 	 */
367 	switch (mly->mly_hwif) {
368 	case MLY_HWIF_I960RX:
369 		mly->mly_doorbell_true = 0x00;
370 		mly->mly_cmd_mailbox = MLY_I960RX_COMMAND_MAILBOX;
371 		mly->mly_status_mailbox = MLY_I960RX_STATUS_MAILBOX;
372 		mly->mly_idbr = MLY_I960RX_IDBR;
373 		mly->mly_odbr = MLY_I960RX_ODBR;
374 		mly->mly_error_status = MLY_I960RX_ERROR_STATUS;
375 		mly->mly_interrupt_status = MLY_I960RX_INTERRUPT_STATUS;
376 		mly->mly_interrupt_mask = MLY_I960RX_INTERRUPT_MASK;
377 		break;
378 
379 	case MLY_HWIF_STRONGARM:
380 		mly->mly_doorbell_true = 0xff;
381 		mly->mly_cmd_mailbox = MLY_STRONGARM_COMMAND_MAILBOX;
382 		mly->mly_status_mailbox = MLY_STRONGARM_STATUS_MAILBOX;
383 		mly->mly_idbr = MLY_STRONGARM_IDBR;
384 		mly->mly_odbr = MLY_STRONGARM_ODBR;
385 		mly->mly_error_status = MLY_STRONGARM_ERROR_STATUS;
386 		mly->mly_interrupt_status = MLY_STRONGARM_INTERRUPT_STATUS;
387 		mly->mly_interrupt_mask = MLY_STRONGARM_INTERRUPT_MASK;
388 		break;
389 	}
390 
391 	/*
392 	 * Allocate and map the scatter/gather lists.
393 	 */
394 	rv = mly_dmamem_alloc(mly, MLY_SGL_SIZE * MLY_MAX_CCBS,
395 	    &mly->mly_sg_dmamap, (void **)&mly->mly_sg,
396 	    &mly->mly_sg_busaddr, &mly->mly_sg_seg);
397 	if (rv) {
398 		printf("%s: unable to allocate S/G maps\n",
399 		    device_xname(&mly->mly_dv));
400 		goto bad;
401 	}
402 	state++;
403 
404 	/*
405 	 * Allocate and map the memory mailbox.
406 	 */
407 	rv = mly_dmamem_alloc(mly, sizeof(struct mly_mmbox),
408 	    &mly->mly_mmbox_dmamap, (void **)&mly->mly_mmbox,
409 	    &mly->mly_mmbox_busaddr, &mly->mly_mmbox_seg);
410 	if (rv) {
411 		aprint_error_dev(&mly->mly_dv, "unable to allocate mailboxes\n");
412 		goto bad;
413 	}
414 	state++;
415 
416 	/*
417 	 * Initialise per-controller queues.
418 	 */
419 	SLIST_INIT(&mly->mly_ccb_free);
420 	SIMPLEQ_INIT(&mly->mly_ccb_queue);
421 
422 	/*
423 	 * Disable interrupts before we start talking to the controller.
424 	 */
425 	mly_outb(mly, mly->mly_interrupt_mask, MLY_INTERRUPT_MASK_DISABLE);
426 
427 	/*
428 	 * Wait for the controller to come ready, handshaking with the
429 	 * firmware if required.  This is typically only necessary on
430 	 * platforms where the controller BIOS does not run.
431 	 */
432 	if (mly_fwhandshake(mly)) {
433 		aprint_error_dev(&mly->mly_dv, "unable to bring controller online\n");
434 		goto bad;
435 	}
436 
437 	/*
438 	 * Allocate initial command buffers, obtain controller feature
439 	 * information, and then reallocate command buffers, since we'll
440 	 * know how many we want.
441 	 */
442 	if (mly_alloc_ccbs(mly)) {
443 		aprint_error_dev(&mly->mly_dv, "unable to allocate CCBs\n");
444 		goto bad;
445 	}
446 	state++;
447 	if (mly_get_controllerinfo(mly)) {
448 		aprint_error_dev(&mly->mly_dv, "unable to retrieve controller info\n");
449 		goto bad;
450 	}
451 	mly_release_ccbs(mly);
452 	if (mly_alloc_ccbs(mly)) {
453 		aprint_error_dev(&mly->mly_dv, "unable to allocate CCBs\n");
454 		state--;
455 		goto bad;
456 	}
457 
458 	/*
459 	 * Get the current event counter for health purposes, populate the
460 	 * initial health status buffer.
461 	 */
462 	if (mly_get_eventstatus(mly)) {
463 		aprint_error_dev(&mly->mly_dv, "unable to retrieve event status\n");
464 		goto bad;
465 	}
466 
467 	/*
468 	 * Enable memory-mailbox mode.
469 	 */
470 	if (mly_enable_mmbox(mly)) {
471 		aprint_error_dev(&mly->mly_dv, "unable to enable memory mailbox\n");
472 		goto bad;
473 	}
474 
475 	/*
476 	 * Print a little information about the controller.
477 	 */
478 	mi = mly->mly_controllerinfo;
479 
480 	printf("%s: %d physical channel%s, firmware %d.%02d-%d-%02d "
481 	    "(%02d%02d%02d%02d), %dMB RAM\n", device_xname(&mly->mly_dv),
482 	    mi->physical_channels_present,
483 	    (mi->physical_channels_present) > 1 ? "s" : "",
484 	    mi->fw_major, mi->fw_minor, mi->fw_turn, mi->fw_build,
485 	    mi->fw_century, mi->fw_year, mi->fw_month, mi->fw_day,
486 	    le16toh(mi->memory_size));
487 
488 	/*
489 	 * Register our `shutdownhook'.
490 	 */
491 	if (mly_sdh == NULL)
492 		shutdownhook_establish(mly_shutdown, NULL);
493 
494 	/*
495 	 * Clear any previous BTL information.  For each bus that scsipi
496 	 * wants to scan, we'll receive the SCBUSIOLLSCAN ioctl and retrieve
497 	 * all BTL info at that point.
498 	 */
499 	memset(&mly->mly_btl, 0, sizeof(mly->mly_btl));
500 
501 	mly->mly_nchans = mly->mly_controllerinfo->physical_channels_present +
502 	    mly->mly_controllerinfo->virtual_channels_present;
503 
504 	/*
505 	 * Attach to scsipi.
506 	 */
507 	adapt = &mly->mly_adapt;
508 	memset(adapt, 0, sizeof(*adapt));
509 	adapt->adapt_dev = &mly->mly_dv;
510 	adapt->adapt_nchannels = mly->mly_nchans;
511 	adapt->adapt_openings = mly->mly_ncmds - MLY_CCBS_RESV;
512 	adapt->adapt_max_periph = mly->mly_ncmds - MLY_CCBS_RESV;
513 	adapt->adapt_request = mly_scsipi_request;
514 	adapt->adapt_minphys = mly_scsipi_minphys;
515 	adapt->adapt_ioctl = mly_scsipi_ioctl;
516 
517 	for (i = 0; i < mly->mly_nchans; i++) {
518 		chan = &mly->mly_chans[i];
519 		memset(chan, 0, sizeof(*chan));
520 		chan->chan_adapter = adapt;
521 		chan->chan_bustype = &scsi_bustype;
522 		chan->chan_channel = i;
523 		chan->chan_ntargets = MLY_MAX_TARGETS;
524 		chan->chan_nluns = MLY_MAX_LUNS;
525 		chan->chan_id = mly->mly_controllerparam->initiator_id;
526 		chan->chan_flags = SCSIPI_CHAN_NOSETTLE;
527 		config_found(&mly->mly_dv, chan, scsiprint);
528 	}
529 
530 	/*
531 	 * Now enable interrupts...
532 	 */
533 	mly_outb(mly, mly->mly_interrupt_mask, MLY_INTERRUPT_MASK_ENABLE);
534 
535 	/*
536 	 * Finally, create our monitoring thread.
537 	 */
538 	mly->mly_state |= MLY_STATE_INITOK;
539 	rv = kthread_create(PRI_NONE, 0, NULL, mly_thread, mly,
540 	    &mly->mly_thread, "%s", device_xname(&mly->mly_dv));
541  	if (rv != 0)
542 		aprint_error_dev(&mly->mly_dv, "unable to create thread (%d)\n",
543 		    rv);
544 	return;
545 
546  bad:
547 	if (state > 2)
548 		mly_release_ccbs(mly);
549 	if (state > 1)
550 		mly_dmamem_free(mly, sizeof(struct mly_mmbox),
551 		    mly->mly_mmbox_dmamap, (void *)mly->mly_mmbox,
552 		    &mly->mly_mmbox_seg);
553 	if (state > 0)
554 		mly_dmamem_free(mly, MLY_SGL_SIZE * MLY_MAX_CCBS,
555 		    mly->mly_sg_dmamap, (void *)mly->mly_sg,
556 		    &mly->mly_sg_seg);
557 }
558 
559 /*
560  * Scan all possible devices on the specified channel.
561  */
562 static void
563 mly_scan_channel(struct mly_softc *mly, int bus)
564 {
565 	int s, target;
566 
567 	for (target = 0; target < MLY_MAX_TARGETS; target++) {
568 		s = splbio();
569 		if (!mly_scan_btl(mly, bus, target)) {
570 			tsleep(&mly->mly_btl[bus][target], PRIBIO, "mlyscan",
571 			    0);
572 		}
573 		splx(s);
574 	}
575 }
576 
577 /*
578  * Shut down all configured `mly' devices.
579  */
580 static void
581 mly_shutdown(void *cookie)
582 {
583 	struct mly_softc *mly;
584 	int i;
585 
586 	for (i = 0; i < mly_cd.cd_ndevs; i++) {
587 		if ((mly = device_lookup_private(&mly_cd, i)) == NULL)
588 			continue;
589 
590 		if (mly_flush(mly))
591 			aprint_error_dev(&mly->mly_dv, "unable to flush cache\n");
592 	}
593 }
594 
595 /*
596  * Fill in the mly_controllerinfo and mly_controllerparam fields in the
597  * softc.
598  */
599 static int
600 mly_get_controllerinfo(struct mly_softc *mly)
601 {
602 	struct mly_cmd_ioctl mci;
603 	int rv;
604 
605 	/*
606 	 * Build the getcontrollerinfo ioctl and send it.
607 	 */
608 	memset(&mci, 0, sizeof(mci));
609 	mci.sub_ioctl = MDACIOCTL_GETCONTROLLERINFO;
610 	rv = mly_ioctl(mly, &mci, (void **)&mly->mly_controllerinfo,
611 	    sizeof(*mly->mly_controllerinfo), NULL, NULL);
612 	if (rv != 0)
613 		return (rv);
614 
615 	/*
616 	 * Build the getcontrollerparameter ioctl and send it.
617 	 */
618 	memset(&mci, 0, sizeof(mci));
619 	mci.sub_ioctl = MDACIOCTL_GETCONTROLLERPARAMETER;
620 	rv = mly_ioctl(mly, &mci, (void **)&mly->mly_controllerparam,
621 	    sizeof(*mly->mly_controllerparam), NULL, NULL);
622 
623 	return (rv);
624 }
625 
626 /*
627  * Rescan a device, possibly as a consequence of getting an event which
628  * suggests that it may have changed.  Must be called with interrupts
629  * blocked.
630  */
631 static int
632 mly_scan_btl(struct mly_softc *mly, int bus, int target)
633 {
634 	struct mly_ccb *mc;
635 	struct mly_cmd_ioctl *mci;
636 	int rv;
637 
638 	if (target == mly->mly_controllerparam->initiator_id) {
639 		mly->mly_btl[bus][target].mb_flags = MLY_BTL_PROTECTED;
640 		return (EIO);
641 	}
642 
643 	/* Don't re-scan if a scan is already in progress. */
644 	if ((mly->mly_btl[bus][target].mb_flags & MLY_BTL_SCANNING) != 0)
645 		return (EBUSY);
646 
647 	/* Get a command. */
648 	if ((rv = mly_ccb_alloc(mly, &mc)) != 0)
649 		return (rv);
650 
651 	/* Set up the data buffer. */
652 	mc->mc_data = malloc(sizeof(union mly_devinfo),
653 	    M_DEVBUF, M_NOWAIT|M_ZERO);
654 
655 	mc->mc_flags |= MLY_CCB_DATAIN;
656 	mc->mc_complete = mly_complete_rescan;
657 
658 	/*
659 	 * Build the ioctl.
660 	 */
661 	mci = (struct mly_cmd_ioctl *)&mc->mc_packet->ioctl;
662 	mci->opcode = MDACMD_IOCTL;
663 	mci->timeout = 30 | MLY_TIMEOUT_SECONDS;
664 	memset(&mci->param, 0, sizeof(mci->param));
665 
666 	if (MLY_BUS_IS_VIRTUAL(mly, bus)) {
667 		mc->mc_length = sizeof(struct mly_ioctl_getlogdevinfovalid);
668 		mci->data_size = htole32(mc->mc_length);
669 		mci->sub_ioctl = MDACIOCTL_GETLOGDEVINFOVALID;
670 		_lto3l(MLY_LOGADDR(0, MLY_LOGDEV_ID(mly, bus, target)),
671 		    mci->addr);
672 	} else {
673 		mc->mc_length = sizeof(struct mly_ioctl_getphysdevinfovalid);
674 		mci->data_size = htole32(mc->mc_length);
675 		mci->sub_ioctl = MDACIOCTL_GETPHYSDEVINFOVALID;
676 		_lto3l(MLY_PHYADDR(0, bus, target, 0), mci->addr);
677 	}
678 
679 	/*
680 	 * Dispatch the command.
681 	 */
682 	if ((rv = mly_ccb_map(mly, mc)) != 0) {
683 		free(mc->mc_data, M_DEVBUF);
684 		mly_ccb_free(mly, mc);
685 		return(rv);
686 	}
687 
688 	mly->mly_btl[bus][target].mb_flags |= MLY_BTL_SCANNING;
689 	mly_ccb_enqueue(mly, mc);
690 	return (0);
691 }
692 
693 /*
694  * Handle the completion of a rescan operation.
695  */
696 static void
697 mly_complete_rescan(struct mly_softc *mly, struct mly_ccb *mc)
698 {
699 	struct mly_ioctl_getlogdevinfovalid *ldi;
700 	struct mly_ioctl_getphysdevinfovalid *pdi;
701 	struct mly_cmd_ioctl *mci;
702 	struct mly_btl btl, *btlp;
703 	struct scsipi_xfer_mode xm;
704 	int bus, target, rescan;
705 	u_int tmp;
706 
707 	mly_ccb_unmap(mly, mc);
708 
709 	/*
710 	 * Recover the bus and target from the command.  We need these even
711 	 * in the case where we don't have a useful response.
712 	 */
713 	mci = (struct mly_cmd_ioctl *)&mc->mc_packet->ioctl;
714 	tmp = _3ltol(mci->addr);
715 	rescan = 0;
716 
717 	if (mci->sub_ioctl == MDACIOCTL_GETLOGDEVINFOVALID) {
718 		bus = MLY_LOGDEV_BUS(mly, MLY_LOGADDR_DEV(tmp));
719 		target = MLY_LOGDEV_TARGET(mly, MLY_LOGADDR_DEV(tmp));
720 	} else {
721 		bus = MLY_PHYADDR_CHANNEL(tmp);
722 		target = MLY_PHYADDR_TARGET(tmp);
723 	}
724 
725 	btlp = &mly->mly_btl[bus][target];
726 
727 	/* The default result is 'no device'. */
728 	memset(&btl, 0, sizeof(btl));
729 	btl.mb_flags = MLY_BTL_PROTECTED;
730 
731 	/* If the rescan completed OK, we have possibly-new BTL data. */
732 	if (mc->mc_status != 0)
733 		goto out;
734 
735 	if (mc->mc_length == sizeof(*ldi)) {
736 		ldi = (struct mly_ioctl_getlogdevinfovalid *)mc->mc_data;
737 		tmp = le32toh(ldi->logical_device_number);
738 
739 		if (MLY_LOGDEV_BUS(mly, tmp) != bus ||
740 		    MLY_LOGDEV_TARGET(mly, tmp) != target) {
741 #ifdef MLYDEBUG
742 			printf("%s: WARNING: BTL rescan (logical) for %d:%d "
743 			    "returned data for %d:%d instead\n",
744 			   device_xname(&mly->mly_dv), bus, target,
745 			   MLY_LOGDEV_BUS(mly, tmp),
746 			   MLY_LOGDEV_TARGET(mly, tmp));
747 #endif
748 			goto out;
749 		}
750 
751 		btl.mb_flags = MLY_BTL_LOGICAL | MLY_BTL_TQING;
752 		btl.mb_type = ldi->raid_level;
753 		btl.mb_state = ldi->state;
754 	} else if (mc->mc_length == sizeof(*pdi)) {
755 		pdi = (struct mly_ioctl_getphysdevinfovalid *)mc->mc_data;
756 
757 		if (pdi->channel != bus || pdi->target != target) {
758 #ifdef MLYDEBUG
759 			printf("%s: WARNING: BTL rescan (physical) for %d:%d "
760 			    " returned data for %d:%d instead\n",
761 			   device_xname(&mly->mly_dv),
762 			   bus, target, pdi->channel, pdi->target);
763 #endif
764 			goto out;
765 		}
766 
767 		btl.mb_flags = MLY_BTL_PHYSICAL;
768 		btl.mb_type = MLY_DEVICE_TYPE_PHYSICAL;
769 		btl.mb_state = pdi->state;
770 		btl.mb_speed = pdi->speed;
771 		btl.mb_width = pdi->width;
772 
773 		if (pdi->state != MLY_DEVICE_STATE_UNCONFIGURED)
774 			btl.mb_flags |= MLY_BTL_PROTECTED;
775 		if (pdi->command_tags != 0)
776 			btl.mb_flags |= MLY_BTL_TQING;
777 	} else {
778 		printf("%s: BTL rescan result invalid\n", device_xname(&mly->mly_dv));
779 		goto out;
780 	}
781 
782 	/* Decide whether we need to rescan the device. */
783 	if (btl.mb_flags != btlp->mb_flags ||
784 	    btl.mb_speed != btlp->mb_speed ||
785 	    btl.mb_width != btlp->mb_width)
786 		rescan = 1;
787 
788  out:
789 	*btlp = btl;
790 
791 	if (rescan && (btl.mb_flags & MLY_BTL_PROTECTED) == 0) {
792 		xm.xm_target = target;
793 		mly_get_xfer_mode(mly, bus, &xm);
794 		/* XXX SCSI mid-layer rescan goes here. */
795 	}
796 
797 	/* Wake anybody waiting on the device to be rescanned. */
798 	wakeup(btlp);
799 
800 	free(mc->mc_data, M_DEVBUF);
801 	mly_ccb_free(mly, mc);
802 }
803 
804 /*
805  * Get the current health status and set the 'next event' counter to suit.
806  */
807 static int
808 mly_get_eventstatus(struct mly_softc *mly)
809 {
810 	struct mly_cmd_ioctl mci;
811 	struct mly_health_status *mh;
812 	int rv;
813 
814 	/* Build the gethealthstatus ioctl and send it. */
815 	memset(&mci, 0, sizeof(mci));
816 	mh = NULL;
817 	mci.sub_ioctl = MDACIOCTL_GETHEALTHSTATUS;
818 
819 	rv = mly_ioctl(mly, &mci, (void *)&mh, sizeof(*mh), NULL, NULL);
820 	if (rv)
821 		return (rv);
822 
823 	/* Get the event counter. */
824 	mly->mly_event_change = le32toh(mh->change_counter);
825 	mly->mly_event_waiting = le32toh(mh->next_event);
826 	mly->mly_event_counter = le32toh(mh->next_event);
827 
828 	/* Save the health status into the memory mailbox */
829 	memcpy(&mly->mly_mmbox->mmm_health.status, mh, sizeof(*mh));
830 
831 	bus_dmamap_sync(mly->mly_dmat, mly->mly_mmbox_dmamap,
832 	    offsetof(struct mly_mmbox, mmm_health),
833 	    sizeof(mly->mly_mmbox->mmm_health),
834 	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
835 
836 	free(mh, M_DEVBUF);
837 	return (0);
838 }
839 
840 /*
841  * Enable memory mailbox mode.
842  */
843 static int
844 mly_enable_mmbox(struct mly_softc *mly)
845 {
846 	struct mly_cmd_ioctl mci;
847 	u_int8_t *sp;
848 	u_int64_t tmp;
849 	int rv;
850 
851 	/* Build the ioctl and send it. */
852 	memset(&mci, 0, sizeof(mci));
853 	mci.sub_ioctl = MDACIOCTL_SETMEMORYMAILBOX;
854 
855 	/* Set buffer addresses. */
856 	tmp = mly->mly_mmbox_busaddr + offsetof(struct mly_mmbox, mmm_command);
857 	mci.param.setmemorymailbox.command_mailbox_physaddr = htole64(tmp);
858 
859 	tmp = mly->mly_mmbox_busaddr + offsetof(struct mly_mmbox, mmm_status);
860 	mci.param.setmemorymailbox.status_mailbox_physaddr = htole64(tmp);
861 
862 	tmp = mly->mly_mmbox_busaddr + offsetof(struct mly_mmbox, mmm_health);
863 	mci.param.setmemorymailbox.health_buffer_physaddr = htole64(tmp);
864 
865 	/* Set buffer sizes - abuse of data_size field is revolting. */
866 	sp = (u_int8_t *)&mci.data_size;
867 	sp[0] = (sizeof(union mly_cmd_packet) * MLY_MMBOX_COMMANDS) >> 10;
868 	sp[1] = (sizeof(union mly_status_packet) * MLY_MMBOX_STATUS) >> 10;
869 	mci.param.setmemorymailbox.health_buffer_size =
870 	    sizeof(union mly_health_region) >> 10;
871 
872 	rv = mly_ioctl(mly, &mci, NULL, 0, NULL, NULL);
873 	if (rv)
874 		return (rv);
875 
876 	mly->mly_state |= MLY_STATE_MMBOX_ACTIVE;
877 	return (0);
878 }
879 
880 /*
881  * Flush all pending I/O from the controller.
882  */
883 static int
884 mly_flush(struct mly_softc *mly)
885 {
886 	struct mly_cmd_ioctl mci;
887 
888 	/* Build the ioctl */
889 	memset(&mci, 0, sizeof(mci));
890 	mci.sub_ioctl = MDACIOCTL_FLUSHDEVICEDATA;
891 	mci.param.deviceoperation.operation_device =
892 	    MLY_OPDEVICE_PHYSICAL_CONTROLLER;
893 
894 	/* Pass it off to the controller */
895 	return (mly_ioctl(mly, &mci, NULL, 0, NULL, NULL));
896 }
897 
898 /*
899  * Perform an ioctl command.
900  *
901  * If (data) is not NULL, the command requires data transfer to the
902  * controller.  If (*data) is NULL the command requires data transfer from
903  * the controller, and we will allocate a buffer for it.
904  */
905 static int
906 mly_ioctl(struct mly_softc *mly, struct mly_cmd_ioctl *ioctl, void **data,
907 	  size_t datasize, void *sense_buffer,
908 	  size_t *sense_length)
909 {
910 	struct mly_ccb *mc;
911 	struct mly_cmd_ioctl *mci;
912 	u_int8_t status;
913 	int rv;
914 
915 	mc = NULL;
916 	if ((rv = mly_ccb_alloc(mly, &mc)) != 0)
917 		goto bad;
918 
919 	/*
920 	 * Copy the ioctl structure, but save some important fields and then
921 	 * fixup.
922 	 */
923 	mci = &mc->mc_packet->ioctl;
924 	ioctl->sense_buffer_address = htole64(mci->sense_buffer_address);
925 	ioctl->maximum_sense_size = mci->maximum_sense_size;
926 	*mci = *ioctl;
927 	mci->opcode = MDACMD_IOCTL;
928 	mci->timeout = 30 | MLY_TIMEOUT_SECONDS;
929 
930 	/* Handle the data buffer. */
931 	if (data != NULL) {
932 		if (*data == NULL) {
933 			/* Allocate data buffer */
934 			mc->mc_data = malloc(datasize, M_DEVBUF, M_NOWAIT);
935 			mc->mc_flags |= MLY_CCB_DATAIN;
936 		} else {
937 			mc->mc_data = *data;
938 			mc->mc_flags |= MLY_CCB_DATAOUT;
939 		}
940 		mc->mc_length = datasize;
941 		mc->mc_packet->generic.data_size = htole32(datasize);
942 	}
943 
944 	/* Run the command. */
945 	if (datasize > 0)
946 		if ((rv = mly_ccb_map(mly, mc)) != 0)
947 			goto bad;
948 	rv = mly_ccb_poll(mly, mc, 30000);
949 	if (datasize > 0)
950 		mly_ccb_unmap(mly, mc);
951 	if (rv != 0)
952 		goto bad;
953 
954 	/* Clean up and return any data. */
955 	status = mc->mc_status;
956 
957 	if (status != 0)
958 		printf("mly_ioctl: command status %d\n", status);
959 
960 	if (mc->mc_sense > 0 && sense_buffer != NULL) {
961 		memcpy(sense_buffer, mc->mc_packet, mc->mc_sense);
962 		*sense_length = mc->mc_sense;
963 		goto bad;
964 	}
965 
966 	/* Should we return a data pointer? */
967 	if (data != NULL && *data == NULL)
968 		*data = mc->mc_data;
969 
970 	/* Command completed OK. */
971 	rv = (status != 0 ? EIO : 0);
972 
973  bad:
974 	if (mc != NULL) {
975 		/* Do we need to free a data buffer we allocated? */
976 		if (rv != 0 && mc->mc_data != NULL &&
977 		    (data == NULL || *data == NULL))
978 			free(mc->mc_data, M_DEVBUF);
979 		mly_ccb_free(mly, mc);
980 	}
981 
982 	return (rv);
983 }
984 
985 /*
986  * Check for event(s) outstanding in the controller.
987  */
988 static void
989 mly_check_event(struct mly_softc *mly)
990 {
991 
992 	bus_dmamap_sync(mly->mly_dmat, mly->mly_mmbox_dmamap,
993 	    offsetof(struct mly_mmbox, mmm_health),
994 	    sizeof(mly->mly_mmbox->mmm_health),
995 	    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
996 
997 	/*
998 	 * The controller may have updated the health status information, so
999 	 * check for it here.  Note that the counters are all in host
1000 	 * memory, so this check is very cheap.  Also note that we depend on
1001 	 * checking on completion
1002 	 */
1003 	if (le32toh(mly->mly_mmbox->mmm_health.status.change_counter) !=
1004 	    mly->mly_event_change) {
1005 		mly->mly_event_change =
1006 		    le32toh(mly->mly_mmbox->mmm_health.status.change_counter);
1007 		mly->mly_event_waiting =
1008 		    le32toh(mly->mly_mmbox->mmm_health.status.next_event);
1009 
1010 		/* Wake up anyone that might be interested in this. */
1011 		wakeup(&mly->mly_event_change);
1012 	}
1013 
1014 	bus_dmamap_sync(mly->mly_dmat, mly->mly_mmbox_dmamap,
1015 	    offsetof(struct mly_mmbox, mmm_health),
1016 	    sizeof(mly->mly_mmbox->mmm_health),
1017 	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
1018 
1019 	if (mly->mly_event_counter != mly->mly_event_waiting)
1020 		mly_fetch_event(mly);
1021 }
1022 
1023 /*
1024  * Fetch one event from the controller.  If we fail due to resource
1025  * starvation, we'll be retried the next time a command completes.
1026  */
1027 static void
1028 mly_fetch_event(struct mly_softc *mly)
1029 {
1030 	struct mly_ccb *mc;
1031 	struct mly_cmd_ioctl *mci;
1032 	int s;
1033 	u_int32_t event;
1034 
1035 	/* Get a command. */
1036 	if (mly_ccb_alloc(mly, &mc))
1037 		return;
1038 
1039 	/* Set up the data buffer. */
1040 	mc->mc_data = malloc(sizeof(struct mly_event), M_DEVBUF,
1041 	    M_NOWAIT|M_ZERO);
1042 
1043 	mc->mc_length = sizeof(struct mly_event);
1044 	mc->mc_flags |= MLY_CCB_DATAIN;
1045 	mc->mc_complete = mly_complete_event;
1046 
1047 	/*
1048 	 * Get an event number to fetch.  It's possible that we've raced
1049 	 * with another context for the last event, in which case there will
1050 	 * be no more events.
1051 	 */
1052 	s = splbio();
1053 	if (mly->mly_event_counter == mly->mly_event_waiting) {
1054 		splx(s);
1055 		free(mc->mc_data, M_DEVBUF);
1056 		mly_ccb_free(mly, mc);
1057 		return;
1058 	}
1059 	event = mly->mly_event_counter++;
1060 	splx(s);
1061 
1062 	/*
1063 	 * Build the ioctl.
1064 	 *
1065 	 * At this point we are committed to sending this request, as it
1066 	 * will be the only one constructed for this particular event
1067 	 * number.
1068 	 */
1069 	mci = (struct mly_cmd_ioctl *)&mc->mc_packet->ioctl;
1070 	mci->opcode = MDACMD_IOCTL;
1071 	mci->data_size = htole32(sizeof(struct mly_event));
1072 	_lto3l(MLY_PHYADDR(0, 0, (event >> 16) & 0xff, (event >> 24) & 0xff),
1073 	    mci->addr);
1074 	mci->timeout = 30 | MLY_TIMEOUT_SECONDS;
1075 	mci->sub_ioctl = MDACIOCTL_GETEVENT;
1076 	mci->param.getevent.sequence_number_low = htole16(event & 0xffff);
1077 
1078 	/*
1079 	 * Submit the command.
1080 	 */
1081 	if (mly_ccb_map(mly, mc) != 0)
1082 		goto bad;
1083 	mly_ccb_enqueue(mly, mc);
1084 	return;
1085 
1086  bad:
1087 	printf("%s: couldn't fetch event %u\n", device_xname(&mly->mly_dv), event);
1088 	free(mc->mc_data, M_DEVBUF);
1089 	mly_ccb_free(mly, mc);
1090 }
1091 
1092 /*
1093  * Handle the completion of an event poll.
1094  */
1095 static void
1096 mly_complete_event(struct mly_softc *mly, struct mly_ccb *mc)
1097 {
1098 	struct mly_event *me;
1099 
1100 	me = (struct mly_event *)mc->mc_data;
1101 	mly_ccb_unmap(mly, mc);
1102 	mly_ccb_free(mly, mc);
1103 
1104 	/* If the event was successfully fetched, process it. */
1105 	if (mc->mc_status == SCSI_OK)
1106 		mly_process_event(mly, me);
1107 	else
1108 		aprint_error_dev(&mly->mly_dv, "unable to fetch event; status = 0x%x\n",
1109 		    mc->mc_status);
1110 
1111 	free(me, M_DEVBUF);
1112 
1113 	/* Check for another event. */
1114 	mly_check_event(mly);
1115 }
1116 
1117 /*
1118  * Process a controller event.  Called with interrupts blocked (i.e., at
1119  * interrupt time).
1120  */
1121 static void
1122 mly_process_event(struct mly_softc *mly, struct mly_event *me)
1123 {
1124 	struct scsi_sense_data *ssd;
1125 	int bus, target, event, class, action;
1126 	const char *fp, *tp;
1127 
1128 	ssd = (struct scsi_sense_data *)&me->sense[0];
1129 
1130 	/*
1131 	 * Errors can be reported using vendor-unique sense data.  In this
1132 	 * case, the event code will be 0x1c (Request sense data present),
1133 	 * the sense key will be 0x09 (vendor specific), the MSB of the ASC
1134 	 * will be set, and the actual event code will be a 16-bit value
1135 	 * comprised of the ASCQ (low byte) and low seven bits of the ASC
1136 	 * (low seven bits of the high byte).
1137 	 */
1138 	if (le32toh(me->code) == 0x1c &&
1139 	    SSD_SENSE_KEY(ssd->flags) == SKEY_VENDOR_SPECIFIC &&
1140 	    (ssd->asc & 0x80) != 0) {
1141 		event = ((int)(ssd->asc & ~0x80) << 8) +
1142 		    ssd->ascq;
1143 	} else
1144 		event = le32toh(me->code);
1145 
1146 	/* Look up event, get codes. */
1147 	fp = mly_describe_code(mly_table_event, event);
1148 
1149 	/* Quiet event? */
1150 	class = fp[0];
1151 #ifdef notyet
1152 	if (isupper(class) && bootverbose)
1153 		class = tolower(class);
1154 #endif
1155 
1156 	/* Get action code, text string. */
1157 	action = fp[1];
1158 	tp = fp + 3;
1159 
1160 	/*
1161 	 * Print some information about the event.
1162 	 *
1163 	 * This code uses a table derived from the corresponding portion of
1164 	 * the Linux driver, and thus the parser is very similar.
1165 	 */
1166 	switch (class) {
1167 	case 'p':
1168 		/*
1169 		 * Error on physical drive.
1170 		 */
1171 		printf("%s: physical device %d:%d %s\n", device_xname(&mly->mly_dv),
1172 		    me->channel, me->target, tp);
1173 		if (action == 'r')
1174 			mly->mly_btl[me->channel][me->target].mb_flags |=
1175 			    MLY_BTL_RESCAN;
1176 		break;
1177 
1178 	case 'l':
1179 	case 'm':
1180 		/*
1181 		 * Error on logical unit, or message about logical unit.
1182 	 	 */
1183 		bus = MLY_LOGDEV_BUS(mly, me->lun);
1184 		target = MLY_LOGDEV_TARGET(mly, me->lun);
1185 		printf("%s: logical device %d:%d %s\n", device_xname(&mly->mly_dv),
1186 		    bus, target, tp);
1187 		if (action == 'r')
1188 			mly->mly_btl[bus][target].mb_flags |= MLY_BTL_RESCAN;
1189 		break;
1190 
1191 	case 's':
1192 		/*
1193 		 * Report of sense data.
1194 		 */
1195 		if ((SSD_SENSE_KEY(ssd->flags) == SKEY_NO_SENSE ||
1196 		     SSD_SENSE_KEY(ssd->flags) == SKEY_NOT_READY) &&
1197 		    ssd->asc == 0x04 &&
1198 		    (ssd->ascq == 0x01 ||
1199 		     ssd->ascq == 0x02)) {
1200 			/* Ignore NO_SENSE or NOT_READY in one case */
1201 			break;
1202 		}
1203 
1204 		/*
1205 		 * XXX Should translate this if SCSIVERBOSE.
1206 		 */
1207 		printf("%s: physical device %d:%d %s\n", device_xname(&mly->mly_dv),
1208 		    me->channel, me->target, tp);
1209 		printf("%s:  sense key %d  asc %02x  ascq %02x\n",
1210 		    device_xname(&mly->mly_dv), SSD_SENSE_KEY(ssd->flags),
1211 		    ssd->asc, ssd->ascq);
1212 		printf("%s:  info %x%x%x%x  csi %x%x%x%x\n",
1213 		    device_xname(&mly->mly_dv), ssd->info[0], ssd->info[1],
1214 		    ssd->info[2], ssd->info[3], ssd->csi[0],
1215 		    ssd->csi[1], ssd->csi[2],
1216 		    ssd->csi[3]);
1217 		if (action == 'r')
1218 			mly->mly_btl[me->channel][me->target].mb_flags |=
1219 			    MLY_BTL_RESCAN;
1220 		break;
1221 
1222 	case 'e':
1223 		printf("%s: ", device_xname(&mly->mly_dv));
1224 		printf(tp, me->target, me->lun);
1225 		break;
1226 
1227 	case 'c':
1228 		printf("%s: controller %s\n", device_xname(&mly->mly_dv), tp);
1229 		break;
1230 
1231 	case '?':
1232 		printf("%s: %s - %d\n", device_xname(&mly->mly_dv), tp, event);
1233 		break;
1234 
1235 	default:
1236 		/* Probably a 'noisy' event being ignored. */
1237 		break;
1238 	}
1239 }
1240 
1241 /*
1242  * Perform periodic activities.
1243  */
1244 static void
1245 mly_thread(void *cookie)
1246 {
1247 	struct mly_softc *mly;
1248 	struct mly_btl *btl;
1249 	int s, bus, target, done;
1250 
1251 	mly = (struct mly_softc *)cookie;
1252 
1253 	for (;;) {
1254 		/* Check for new events. */
1255 		mly_check_event(mly);
1256 
1257 		/* Re-scan up to 1 device. */
1258 		s = splbio();
1259 		done = 0;
1260 		for (bus = 0; bus < mly->mly_nchans && !done; bus++) {
1261 			for (target = 0; target < MLY_MAX_TARGETS; target++) {
1262 				/* Perform device rescan? */
1263 				btl = &mly->mly_btl[bus][target];
1264 				if ((btl->mb_flags & MLY_BTL_RESCAN) != 0) {
1265 					btl->mb_flags ^= MLY_BTL_RESCAN;
1266 					mly_scan_btl(mly, bus, target);
1267 					done = 1;
1268 					break;
1269 				}
1270 			}
1271 		}
1272 		splx(s);
1273 
1274 		/* Sleep for N seconds. */
1275 		tsleep(mly_thread, PWAIT, "mlyzzz",
1276 		    hz * MLY_PERIODIC_INTERVAL);
1277 	}
1278 }
1279 
1280 /*
1281  * Submit a command to the controller and poll on completion.  Return
1282  * non-zero on timeout.
1283  */
1284 static int
1285 mly_ccb_poll(struct mly_softc *mly, struct mly_ccb *mc, int timo)
1286 {
1287 	int rv;
1288 
1289 	if ((rv = mly_ccb_submit(mly, mc)) != 0)
1290 		return (rv);
1291 
1292 	for (timo *= 10; timo != 0; timo--) {
1293 		if ((mc->mc_flags & MLY_CCB_COMPLETE) != 0)
1294 			break;
1295 		mly_intr(mly);
1296 		DELAY(100);
1297 	}
1298 
1299 	return (timo == 0);
1300 }
1301 
1302 /*
1303  * Submit a command to the controller and sleep on completion.  Return
1304  * non-zero on timeout.
1305  */
1306 static int
1307 mly_ccb_wait(struct mly_softc *mly, struct mly_ccb *mc, int timo)
1308 {
1309 	int rv, s;
1310 
1311 	mly_ccb_enqueue(mly, mc);
1312 
1313 	s = splbio();
1314 	if ((mc->mc_flags & MLY_CCB_COMPLETE) != 0) {
1315 		splx(s);
1316 		return (0);
1317 	}
1318 	rv = tsleep(mc, PRIBIO, "mlywccb", timo * hz / 1000);
1319 	splx(s);
1320 
1321 	return (rv);
1322 }
1323 
1324 /*
1325  * If a CCB is specified, enqueue it.  Pull CCBs off the software queue in
1326  * the order that they were enqueued and try to submit their command blocks
1327  * to the controller for execution.
1328  */
1329 void
1330 mly_ccb_enqueue(struct mly_softc *mly, struct mly_ccb *mc)
1331 {
1332 	int s;
1333 
1334 	s = splbio();
1335 
1336 	if (mc != NULL)
1337 		SIMPLEQ_INSERT_TAIL(&mly->mly_ccb_queue, mc, mc_link.simpleq);
1338 
1339 	while ((mc = SIMPLEQ_FIRST(&mly->mly_ccb_queue)) != NULL) {
1340 		if (mly_ccb_submit(mly, mc))
1341 			break;
1342 		SIMPLEQ_REMOVE_HEAD(&mly->mly_ccb_queue, mc_link.simpleq);
1343 	}
1344 
1345 	splx(s);
1346 }
1347 
1348 /*
1349  * Deliver a command to the controller.
1350  */
1351 static int
1352 mly_ccb_submit(struct mly_softc *mly, struct mly_ccb *mc)
1353 {
1354 	union mly_cmd_packet *pkt;
1355 	int s, off;
1356 
1357 	mc->mc_packet->generic.command_id = htole16(mc->mc_slot);
1358 
1359 	bus_dmamap_sync(mly->mly_dmat, mly->mly_pkt_dmamap,
1360 	    mc->mc_packetphys - mly->mly_pkt_busaddr,
1361 	    sizeof(union mly_cmd_packet),
1362 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1363 
1364 	s = splbio();
1365 
1366 	/*
1367 	 * Do we have to use the hardware mailbox?
1368 	 */
1369 	if ((mly->mly_state & MLY_STATE_MMBOX_ACTIVE) == 0) {
1370 		/*
1371 		 * Check to see if the controller is ready for us.
1372 		 */
1373 		if (mly_idbr_true(mly, MLY_HM_CMDSENT)) {
1374 			splx(s);
1375 			return (EBUSY);
1376 		}
1377 
1378 		/*
1379 		 * It's ready, send the command.
1380 		 */
1381 		mly_outl(mly, mly->mly_cmd_mailbox,
1382 		    (u_int64_t)mc->mc_packetphys & 0xffffffff);
1383 		mly_outl(mly, mly->mly_cmd_mailbox + 4,
1384 		    (u_int64_t)mc->mc_packetphys >> 32);
1385 		mly_outb(mly, mly->mly_idbr, MLY_HM_CMDSENT);
1386 	} else {
1387 		pkt = &mly->mly_mmbox->mmm_command[mly->mly_mmbox_cmd_idx];
1388 		off = (char *)pkt - (char *)mly->mly_mmbox;
1389 
1390 		bus_dmamap_sync(mly->mly_dmat, mly->mly_mmbox_dmamap,
1391 		    off, sizeof(mly->mly_mmbox->mmm_command[0]),
1392 		    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
1393 
1394 		/* Check to see if the next index is free yet. */
1395 		if (pkt->mmbox.flag != 0) {
1396 			splx(s);
1397 			return (EBUSY);
1398 		}
1399 
1400 		/* Copy in new command */
1401 		memcpy(pkt->mmbox.data, mc->mc_packet->mmbox.data,
1402 		    sizeof(pkt->mmbox.data));
1403 
1404 		/* Copy flag last. */
1405 		pkt->mmbox.flag = mc->mc_packet->mmbox.flag;
1406 
1407 		bus_dmamap_sync(mly->mly_dmat, mly->mly_mmbox_dmamap,
1408 		    off, sizeof(mly->mly_mmbox->mmm_command[0]),
1409 		    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
1410 
1411 		/* Signal controller and update index. */
1412 		mly_outb(mly, mly->mly_idbr, MLY_AM_CMDSENT);
1413 		mly->mly_mmbox_cmd_idx =
1414 		    (mly->mly_mmbox_cmd_idx + 1) % MLY_MMBOX_COMMANDS;
1415 	}
1416 
1417 	splx(s);
1418 	return (0);
1419 }
1420 
1421 /*
1422  * Pick up completed commands from the controller and handle accordingly.
1423  */
1424 int
1425 mly_intr(void *cookie)
1426 {
1427 	struct mly_ccb *mc;
1428 	union mly_status_packet	*sp;
1429 	u_int16_t slot;
1430 	int forus, off;
1431 	struct mly_softc *mly;
1432 
1433 	mly = cookie;
1434 	forus = 0;
1435 
1436 	/*
1437 	 * Pick up hardware-mailbox commands.
1438 	 */
1439 	if (mly_odbr_true(mly, MLY_HM_STSREADY)) {
1440 		slot = mly_inw(mly, mly->mly_status_mailbox);
1441 
1442 		if (slot < MLY_SLOT_MAX) {
1443 			mc = mly->mly_ccbs + (slot - MLY_SLOT_START);
1444 			mc->mc_status =
1445 			    mly_inb(mly, mly->mly_status_mailbox + 2);
1446 			mc->mc_sense =
1447 			    mly_inb(mly, mly->mly_status_mailbox + 3);
1448 			mc->mc_resid =
1449 			    mly_inl(mly, mly->mly_status_mailbox + 4);
1450 
1451 			mly_ccb_complete(mly, mc);
1452 		} else {
1453 			/* Slot 0xffff may mean "extremely bogus command". */
1454 			printf("%s: got HM completion for illegal slot %u\n",
1455 			    device_xname(&mly->mly_dv), slot);
1456 		}
1457 
1458 		/* Unconditionally acknowledge status. */
1459 		mly_outb(mly, mly->mly_odbr, MLY_HM_STSREADY);
1460 		mly_outb(mly, mly->mly_idbr, MLY_HM_STSACK);
1461 		forus = 1;
1462 	}
1463 
1464 	/*
1465 	 * Pick up memory-mailbox commands.
1466 	 */
1467 	if (mly_odbr_true(mly, MLY_AM_STSREADY)) {
1468 		for (;;) {
1469 			sp = &mly->mly_mmbox->mmm_status[mly->mly_mmbox_sts_idx];
1470 			off = (char *)sp - (char *)mly->mly_mmbox;
1471 
1472 			bus_dmamap_sync(mly->mly_dmat, mly->mly_mmbox_dmamap,
1473 			    off, sizeof(mly->mly_mmbox->mmm_command[0]),
1474 			    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
1475 
1476 			/* Check for more status. */
1477 			if (sp->mmbox.flag == 0)
1478 				break;
1479 
1480 			/* Get slot number. */
1481 			slot = le16toh(sp->status.command_id);
1482 			if (slot < MLY_SLOT_MAX) {
1483 				mc = mly->mly_ccbs + (slot - MLY_SLOT_START);
1484 				mc->mc_status = sp->status.status;
1485 				mc->mc_sense = sp->status.sense_length;
1486 				mc->mc_resid = le32toh(sp->status.residue);
1487 				mly_ccb_complete(mly, mc);
1488 			} else {
1489 				/*
1490 				 * Slot 0xffff may mean "extremely bogus
1491 				 * command".
1492 				 */
1493 				printf("%s: got AM completion for illegal "
1494 				    "slot %u at %d\n", device_xname(&mly->mly_dv),
1495 				    slot, mly->mly_mmbox_sts_idx);
1496 			}
1497 
1498 			/* Clear and move to next index. */
1499 			sp->mmbox.flag = 0;
1500 			mly->mly_mmbox_sts_idx =
1501 			    (mly->mly_mmbox_sts_idx + 1) % MLY_MMBOX_STATUS;
1502 		}
1503 
1504 		/* Acknowledge that we have collected status value(s). */
1505 		mly_outb(mly, mly->mly_odbr, MLY_AM_STSREADY);
1506 		forus = 1;
1507 	}
1508 
1509 	/*
1510 	 * Run the queue.
1511 	 */
1512 	if (forus && ! SIMPLEQ_EMPTY(&mly->mly_ccb_queue))
1513 		mly_ccb_enqueue(mly, NULL);
1514 
1515 	return (forus);
1516 }
1517 
1518 /*
1519  * Process completed commands
1520  */
1521 static void
1522 mly_ccb_complete(struct mly_softc *mly, struct mly_ccb *mc)
1523 {
1524 	void (*complete)(struct mly_softc *, struct mly_ccb *);
1525 
1526 	bus_dmamap_sync(mly->mly_dmat, mly->mly_pkt_dmamap,
1527 	    mc->mc_packetphys - mly->mly_pkt_busaddr,
1528 	    sizeof(union mly_cmd_packet),
1529 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1530 
1531 	complete = mc->mc_complete;
1532 	mc->mc_flags |= MLY_CCB_COMPLETE;
1533 
1534 	/*
1535 	 * Call completion handler or wake up sleeping consumer.
1536 	 */
1537 	if (complete != NULL)
1538 		(*complete)(mly, mc);
1539 	else
1540 		wakeup(mc);
1541 }
1542 
1543 /*
1544  * Allocate a command.
1545  */
1546 int
1547 mly_ccb_alloc(struct mly_softc *mly, struct mly_ccb **mcp)
1548 {
1549 	struct mly_ccb *mc;
1550 	int s;
1551 
1552 	s = splbio();
1553 	mc = SLIST_FIRST(&mly->mly_ccb_free);
1554 	if (mc != NULL)
1555 		SLIST_REMOVE_HEAD(&mly->mly_ccb_free, mc_link.slist);
1556 	splx(s);
1557 
1558 	*mcp = mc;
1559 	return (mc == NULL ? EAGAIN : 0);
1560 }
1561 
1562 /*
1563  * Release a command back to the freelist.
1564  */
1565 void
1566 mly_ccb_free(struct mly_softc *mly, struct mly_ccb *mc)
1567 {
1568 	int s;
1569 
1570 	/*
1571 	 * Fill in parts of the command that may cause confusion if a
1572 	 * consumer doesn't when we are later allocated.
1573 	 */
1574 	mc->mc_data = NULL;
1575 	mc->mc_flags = 0;
1576 	mc->mc_complete = NULL;
1577 	mc->mc_private = NULL;
1578 	mc->mc_packet->generic.command_control = 0;
1579 
1580 	/*
1581 	 * By default, we set up to overwrite the command packet with sense
1582 	 * information.
1583 	 */
1584 	mc->mc_packet->generic.sense_buffer_address =
1585 	    htole64(mc->mc_packetphys);
1586 	mc->mc_packet->generic.maximum_sense_size =
1587 	    sizeof(union mly_cmd_packet);
1588 
1589 	s = splbio();
1590 	SLIST_INSERT_HEAD(&mly->mly_ccb_free, mc, mc_link.slist);
1591 	splx(s);
1592 }
1593 
1594 /*
1595  * Allocate and initialize command and packet structures.
1596  *
1597  * If the controller supports fewer than MLY_MAX_CCBS commands, limit our
1598  * allocation to that number.  If we don't yet know how many commands the
1599  * controller supports, allocate a very small set (suitable for initialization
1600  * purposes only).
1601  */
1602 static int
1603 mly_alloc_ccbs(struct mly_softc *mly)
1604 {
1605 	struct mly_ccb *mc;
1606 	int i, rv;
1607 
1608 	if (mly->mly_controllerinfo == NULL)
1609 		mly->mly_ncmds = MLY_CCBS_RESV;
1610 	else {
1611 		i = le16toh(mly->mly_controllerinfo->maximum_parallel_commands);
1612 		mly->mly_ncmds = min(MLY_MAX_CCBS, i);
1613 	}
1614 
1615 	/*
1616 	 * Allocate enough space for all the command packets in one chunk
1617 	 * and map them permanently into controller-visible space.
1618 	 */
1619 	rv = mly_dmamem_alloc(mly,
1620 	    mly->mly_ncmds * sizeof(union mly_cmd_packet),
1621 	    &mly->mly_pkt_dmamap, (void **)&mly->mly_pkt,
1622 	    &mly->mly_pkt_busaddr, &mly->mly_pkt_seg);
1623 	if (rv)
1624 		return (rv);
1625 
1626 	mly->mly_ccbs = malloc(sizeof(struct mly_ccb) * mly->mly_ncmds,
1627 	    M_DEVBUF, M_NOWAIT|M_ZERO);
1628 
1629 	for (i = 0; i < mly->mly_ncmds; i++) {
1630 		mc = mly->mly_ccbs + i;
1631 		mc->mc_slot = MLY_SLOT_START + i;
1632 		mc->mc_packet = mly->mly_pkt + i;
1633 		mc->mc_packetphys = mly->mly_pkt_busaddr +
1634 		    (i * sizeof(union mly_cmd_packet));
1635 
1636 		rv = bus_dmamap_create(mly->mly_dmat, MLY_MAX_XFER,
1637 		    MLY_MAX_SEGS, MLY_MAX_XFER, 0,
1638 		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
1639 		    &mc->mc_datamap);
1640 		if (rv) {
1641 			mly_release_ccbs(mly);
1642 			return (rv);
1643 		}
1644 
1645 		mly_ccb_free(mly, mc);
1646 	}
1647 
1648 	return (0);
1649 }
1650 
1651 /*
1652  * Free all the storage held by commands.
1653  *
1654  * Must be called with all commands on the free list.
1655  */
1656 static void
1657 mly_release_ccbs(struct mly_softc *mly)
1658 {
1659 	struct mly_ccb *mc;
1660 
1661 	/* Throw away command buffer DMA maps. */
1662 	while (mly_ccb_alloc(mly, &mc) == 0)
1663 		bus_dmamap_destroy(mly->mly_dmat, mc->mc_datamap);
1664 
1665 	/* Release CCB storage. */
1666 	free(mly->mly_ccbs, M_DEVBUF);
1667 
1668 	/* Release the packet storage. */
1669 	mly_dmamem_free(mly, mly->mly_ncmds * sizeof(union mly_cmd_packet),
1670 	    mly->mly_pkt_dmamap, (void *)mly->mly_pkt, &mly->mly_pkt_seg);
1671 }
1672 
1673 /*
1674  * Map a command into controller-visible space.
1675  */
1676 static int
1677 mly_ccb_map(struct mly_softc *mly, struct mly_ccb *mc)
1678 {
1679 	struct mly_cmd_generic *gen;
1680 	struct mly_sg_entry *sg;
1681 	bus_dma_segment_t *ds;
1682 	int flg, nseg, rv;
1683 
1684 #ifdef DIAGNOSTIC
1685 	/* Don't map more than once. */
1686 	if ((mc->mc_flags & MLY_CCB_MAPPED) != 0)
1687 		panic("mly_ccb_map: already mapped");
1688 	mc->mc_flags |= MLY_CCB_MAPPED;
1689 
1690 	/* Does the command have a data buffer? */
1691 	if (mc->mc_data == NULL)
1692 		panic("mly_ccb_map: no data buffer");
1693 #endif
1694 
1695 	rv = bus_dmamap_load(mly->mly_dmat, mc->mc_datamap, mc->mc_data,
1696 	    mc->mc_length, NULL, BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
1697 	    ((mc->mc_flags & MLY_CCB_DATAIN) != 0 ?
1698 	    BUS_DMA_READ : BUS_DMA_WRITE));
1699 	if (rv != 0)
1700 		return (rv);
1701 
1702 	gen = &mc->mc_packet->generic;
1703 
1704 	/*
1705 	 * Can we use the transfer structure directly?
1706 	 */
1707 	if ((nseg = mc->mc_datamap->dm_nsegs) <= 2) {
1708 		mc->mc_sgoff = -1;
1709 		sg = &gen->transfer.direct.sg[0];
1710 	} else {
1711 		mc->mc_sgoff = (mc->mc_slot - MLY_SLOT_START) *
1712 		    MLY_MAX_SEGS;
1713 		sg = mly->mly_sg + mc->mc_sgoff;
1714 		gen->command_control |= MLY_CMDCTL_EXTENDED_SG_TABLE;
1715 		gen->transfer.indirect.entries[0] = htole16(nseg);
1716 		gen->transfer.indirect.table_physaddr[0] =
1717 		    htole64(mly->mly_sg_busaddr +
1718 		    (mc->mc_sgoff * sizeof(struct mly_sg_entry)));
1719 	}
1720 
1721 	/*
1722 	 * Fill the S/G table.
1723 	 */
1724 	for (ds = mc->mc_datamap->dm_segs; nseg != 0; nseg--, sg++, ds++) {
1725 		sg->physaddr = htole64(ds->ds_addr);
1726 		sg->length = htole64(ds->ds_len);
1727 	}
1728 
1729 	/*
1730 	 * Sync up the data map.
1731 	 */
1732 	if ((mc->mc_flags & MLY_CCB_DATAIN) != 0)
1733 		flg = BUS_DMASYNC_PREREAD;
1734 	else /* if ((mc->mc_flags & MLY_CCB_DATAOUT) != 0) */ {
1735 		gen->command_control |= MLY_CMDCTL_DATA_DIRECTION;
1736 		flg = BUS_DMASYNC_PREWRITE;
1737 	}
1738 
1739 	bus_dmamap_sync(mly->mly_dmat, mc->mc_datamap, 0, mc->mc_length, flg);
1740 
1741 	/*
1742 	 * Sync up the chained S/G table, if we're using one.
1743 	 */
1744 	if (mc->mc_sgoff == -1)
1745 		return (0);
1746 
1747 	bus_dmamap_sync(mly->mly_dmat, mly->mly_sg_dmamap, mc->mc_sgoff,
1748 	    MLY_SGL_SIZE, BUS_DMASYNC_PREWRITE);
1749 
1750 	return (0);
1751 }
1752 
1753 /*
1754  * Unmap a command from controller-visible space.
1755  */
1756 static void
1757 mly_ccb_unmap(struct mly_softc *mly, struct mly_ccb *mc)
1758 {
1759 	int flg;
1760 
1761 #ifdef DIAGNOSTIC
1762 	if ((mc->mc_flags & MLY_CCB_MAPPED) == 0)
1763 		panic("mly_ccb_unmap: not mapped");
1764 	mc->mc_flags &= ~MLY_CCB_MAPPED;
1765 #endif
1766 
1767 	if ((mc->mc_flags & MLY_CCB_DATAIN) != 0)
1768 		flg = BUS_DMASYNC_POSTREAD;
1769 	else /* if ((mc->mc_flags & MLY_CCB_DATAOUT) != 0) */
1770 		flg = BUS_DMASYNC_POSTWRITE;
1771 
1772 	bus_dmamap_sync(mly->mly_dmat, mc->mc_datamap, 0, mc->mc_length, flg);
1773 	bus_dmamap_unload(mly->mly_dmat, mc->mc_datamap);
1774 
1775 	if (mc->mc_sgoff == -1)
1776 		return;
1777 
1778 	bus_dmamap_sync(mly->mly_dmat, mly->mly_sg_dmamap, mc->mc_sgoff,
1779 	    MLY_SGL_SIZE, BUS_DMASYNC_POSTWRITE);
1780 }
1781 
1782 /*
1783  * Adjust the size of each I/O before it passes to the SCSI layer.
1784  */
1785 static void
1786 mly_scsipi_minphys(struct buf *bp)
1787 {
1788 
1789 	if (bp->b_bcount > MLY_MAX_XFER)
1790 		bp->b_bcount = MLY_MAX_XFER;
1791 	minphys(bp);
1792 }
1793 
1794 /*
1795  * Start a SCSI command.
1796  */
1797 static void
1798 mly_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req,
1799 		   void *arg)
1800 {
1801 	struct mly_ccb *mc;
1802 	struct mly_cmd_scsi_small *ss;
1803 	struct scsipi_xfer *xs;
1804 	struct scsipi_periph *periph;
1805 	struct mly_softc *mly;
1806 	struct mly_btl *btl;
1807 	int s, tmp;
1808 
1809 	mly = (void *)chan->chan_adapter->adapt_dev;
1810 
1811 	switch (req) {
1812 	case ADAPTER_REQ_RUN_XFER:
1813 		xs = arg;
1814 		periph = xs->xs_periph;
1815 		btl = &mly->mly_btl[chan->chan_channel][periph->periph_target];
1816 		s = splbio();
1817 		tmp = btl->mb_flags;
1818 		splx(s);
1819 
1820 		/*
1821 		 * Check for I/O attempt to a protected or non-existant
1822 		 * device.
1823 		 */
1824 		if ((tmp & MLY_BTL_PROTECTED) != 0) {
1825 			xs->error = XS_SELTIMEOUT;
1826 			scsipi_done(xs);
1827 			break;
1828 		}
1829 
1830 #ifdef DIAGNOSTIC
1831 		/* XXX Increase if/when we support large SCSI commands. */
1832 		if (xs->cmdlen > MLY_CMD_SCSI_SMALL_CDB) {
1833 			printf("%s: cmd too large\n", device_xname(&mly->mly_dv));
1834 			xs->error = XS_DRIVER_STUFFUP;
1835 			scsipi_done(xs);
1836 			break;
1837 		}
1838 #endif
1839 
1840 		if (mly_ccb_alloc(mly, &mc)) {
1841 			xs->error = XS_RESOURCE_SHORTAGE;
1842 			scsipi_done(xs);
1843 			break;
1844 		}
1845 
1846 		/* Build the command. */
1847 		mc->mc_data = xs->data;
1848 		mc->mc_length = xs->datalen;
1849 		mc->mc_complete = mly_scsipi_complete;
1850 		mc->mc_private = xs;
1851 
1852 		/* Build the packet for the controller. */
1853 		ss = &mc->mc_packet->scsi_small;
1854 		ss->opcode = MDACMD_SCSI;
1855 #ifdef notdef
1856 		/*
1857 		 * XXX FreeBSD does this, but it doesn't fix anything,
1858 		 * XXX and appears potentially harmful.
1859 		 */
1860 		ss->command_control |= MLY_CMDCTL_DISABLE_DISCONNECT;
1861 #endif
1862 
1863 		ss->data_size = htole32(xs->datalen);
1864 		_lto3l(MLY_PHYADDR(0, chan->chan_channel,
1865 		    periph->periph_target, periph->periph_lun), ss->addr);
1866 
1867 		if (xs->timeout < 60 * 1000)
1868 			ss->timeout = xs->timeout / 1000 |
1869 			    MLY_TIMEOUT_SECONDS;
1870 		else if (xs->timeout < 60 * 60 * 1000)
1871 			ss->timeout = xs->timeout / (60 * 1000) |
1872 			    MLY_TIMEOUT_MINUTES;
1873 		else
1874 			ss->timeout = xs->timeout / (60 * 60 * 1000) |
1875 			    MLY_TIMEOUT_HOURS;
1876 
1877 		ss->maximum_sense_size = sizeof(xs->sense);
1878 		ss->cdb_length = xs->cmdlen;
1879 		memcpy(ss->cdb, xs->cmd, xs->cmdlen);
1880 
1881 		if (mc->mc_length != 0) {
1882 			if ((xs->xs_control & XS_CTL_DATA_OUT) != 0)
1883 				mc->mc_flags |= MLY_CCB_DATAOUT;
1884 			else /* if ((xs->xs_control & XS_CTL_DATA_IN) != 0) */
1885 				mc->mc_flags |= MLY_CCB_DATAIN;
1886 
1887 			if (mly_ccb_map(mly, mc) != 0) {
1888 				xs->error = XS_DRIVER_STUFFUP;
1889 				mly_ccb_free(mly, mc);
1890 				scsipi_done(xs);
1891 				break;
1892 			}
1893 		}
1894 
1895 		/*
1896 		 * Give the command to the controller.
1897 		 */
1898 		if ((xs->xs_control & XS_CTL_POLL) != 0) {
1899 			if (mly_ccb_poll(mly, mc, xs->timeout + 5000)) {
1900 				xs->error = XS_REQUEUE;
1901 				if (mc->mc_length != 0)
1902 					mly_ccb_unmap(mly, mc);
1903 				mly_ccb_free(mly, mc);
1904 				scsipi_done(xs);
1905 			}
1906 		} else
1907 			mly_ccb_enqueue(mly, mc);
1908 
1909 		break;
1910 
1911 	case ADAPTER_REQ_GROW_RESOURCES:
1912 		/*
1913 		 * Not supported.
1914 		 */
1915 		break;
1916 
1917 	case ADAPTER_REQ_SET_XFER_MODE:
1918 		/*
1919 		 * We can't change the transfer mode, but at least let
1920 		 * scsipi know what the adapter has negotiated.
1921 		 */
1922 		mly_get_xfer_mode(mly, chan->chan_channel, arg);
1923 		break;
1924 	}
1925 }
1926 
1927 /*
1928  * Handle completion of a SCSI command.
1929  */
1930 static void
1931 mly_scsipi_complete(struct mly_softc *mly, struct mly_ccb *mc)
1932 {
1933 	struct scsipi_xfer *xs;
1934 	struct scsipi_channel *chan;
1935 	struct scsipi_inquiry_data *inq;
1936 	struct mly_btl *btl;
1937 	int target, sl, s;
1938 	const char *p;
1939 
1940 	xs = mc->mc_private;
1941 	xs->status = mc->mc_status;
1942 
1943 	/*
1944 	 * XXX The `resid' value as returned by the controller appears to be
1945 	 * bogus, so we always set it to zero.  Is it perhaps the transfer
1946 	 * count?
1947 	 */
1948 	xs->resid = 0; /* mc->mc_resid; */
1949 
1950 	if (mc->mc_length != 0)
1951 		mly_ccb_unmap(mly, mc);
1952 
1953 	switch (mc->mc_status) {
1954 	case SCSI_OK:
1955 		/*
1956 		 * In order to report logical device type and status, we
1957 		 * overwrite the result of the INQUIRY command to logical
1958 		 * devices.
1959 		 */
1960 		if (xs->cmd->opcode == INQUIRY) {
1961 			chan = xs->xs_periph->periph_channel;
1962 			target = xs->xs_periph->periph_target;
1963 			btl = &mly->mly_btl[chan->chan_channel][target];
1964 
1965 			s = splbio();
1966 			if ((btl->mb_flags & MLY_BTL_LOGICAL) != 0) {
1967 				inq = (struct scsipi_inquiry_data *)xs->data;
1968 				mly_padstr(inq->vendor, "MYLEX", 8);
1969 				p = mly_describe_code(mly_table_device_type,
1970 				    btl->mb_type);
1971 				mly_padstr(inq->product, p, 16);
1972 				p = mly_describe_code(mly_table_device_state,
1973 				    btl->mb_state);
1974 				mly_padstr(inq->revision, p, 4);
1975 			}
1976 			splx(s);
1977 		}
1978 
1979 		xs->error = XS_NOERROR;
1980 		break;
1981 
1982 	case SCSI_CHECK:
1983 		sl = mc->mc_sense;
1984 		if (sl > sizeof(xs->sense.scsi_sense))
1985 			sl = sizeof(xs->sense.scsi_sense);
1986 		memcpy(&xs->sense.scsi_sense, mc->mc_packet, sl);
1987 		xs->error = XS_SENSE;
1988 		break;
1989 
1990 	case SCSI_BUSY:
1991 	case SCSI_QUEUE_FULL:
1992 		xs->error = XS_BUSY;
1993 		break;
1994 
1995 	default:
1996 		printf("%s: unknown SCSI status 0x%x\n",
1997 		    device_xname(&mly->mly_dv), xs->status);
1998 		xs->error = XS_DRIVER_STUFFUP;
1999 		break;
2000 	}
2001 
2002 	mly_ccb_free(mly, mc);
2003 	scsipi_done(xs);
2004 }
2005 
2006 /*
2007  * Notify scsipi about a target's transfer mode.
2008  */
2009 static void
2010 mly_get_xfer_mode(struct mly_softc *mly, int bus, struct scsipi_xfer_mode *xm)
2011 {
2012 	struct mly_btl *btl;
2013 	int s;
2014 
2015 	btl = &mly->mly_btl[bus][xm->xm_target];
2016 	xm->xm_mode = 0;
2017 
2018 	s = splbio();
2019 
2020 	if ((btl->mb_flags & MLY_BTL_PHYSICAL) != 0) {
2021 		if (btl->mb_speed == 0) {
2022 			xm->xm_period = 0;
2023 			xm->xm_offset = 0;
2024 		} else {
2025 			xm->xm_period = 12;			/* XXX */
2026 			xm->xm_offset = 8;			/* XXX */
2027 			xm->xm_mode |= PERIPH_CAP_SYNC;		/* XXX */
2028 		}
2029 
2030 		switch (btl->mb_width) {
2031 		case 32:
2032 			xm->xm_mode = PERIPH_CAP_WIDE32;
2033 			break;
2034 		case 16:
2035 			xm->xm_mode = PERIPH_CAP_WIDE16;
2036 			break;
2037 		default:
2038 			xm->xm_mode = 0;
2039 			break;
2040 		}
2041 	} else /* ((btl->mb_flags & MLY_BTL_LOGICAL) != 0) */ {
2042 		xm->xm_mode = PERIPH_CAP_WIDE16 | PERIPH_CAP_SYNC;
2043 		xm->xm_period = 12;
2044 		xm->xm_offset = 8;
2045 	}
2046 
2047 	if ((btl->mb_flags & MLY_BTL_TQING) != 0)
2048 		xm->xm_mode |= PERIPH_CAP_TQING;
2049 
2050 	splx(s);
2051 
2052 	scsipi_async_event(&mly->mly_chans[bus], ASYNC_EVENT_XFER_MODE, xm);
2053 }
2054 
2055 /*
2056  * ioctl hook; used here only to initiate low-level rescans.
2057  */
2058 static int
2059 mly_scsipi_ioctl(struct scsipi_channel *chan, u_long cmd, void *data,
2060     int flag, struct proc *p)
2061 {
2062 	struct mly_softc *mly;
2063 	int rv;
2064 
2065 	mly = (struct mly_softc *)chan->chan_adapter->adapt_dev;
2066 
2067 	switch (cmd) {
2068 	case SCBUSIOLLSCAN:
2069 		mly_scan_channel(mly, chan->chan_channel);
2070 		rv = 0;
2071 		break;
2072 	default:
2073 		rv = ENOTTY;
2074 		break;
2075 	}
2076 
2077 	return (rv);
2078 }
2079 
2080 /*
2081  * Handshake with the firmware while the card is being initialized.
2082  */
2083 static int
2084 mly_fwhandshake(struct mly_softc *mly)
2085 {
2086 	u_int8_t error, param0, param1;
2087 	int spinup;
2088 
2089 	spinup = 0;
2090 
2091 	/* Set HM_STSACK and let the firmware initialize. */
2092 	mly_outb(mly, mly->mly_idbr, MLY_HM_STSACK);
2093 	DELAY(1000);	/* too short? */
2094 
2095 	/* If HM_STSACK is still true, the controller is initializing. */
2096 	if (!mly_idbr_true(mly, MLY_HM_STSACK))
2097 		return (0);
2098 
2099 	printf("%s: controller initialization started\n",
2100 	    device_xname(&mly->mly_dv));
2101 
2102 	/*
2103 	 * Spin waiting for initialization to finish, or for a message to be
2104 	 * delivered.
2105 	 */
2106 	while (mly_idbr_true(mly, MLY_HM_STSACK)) {
2107 		/* Check for a message */
2108 		if (!mly_error_valid(mly))
2109 			continue;
2110 
2111 		error = mly_inb(mly, mly->mly_error_status) & ~MLY_MSG_EMPTY;
2112 		param0 = mly_inb(mly, mly->mly_cmd_mailbox);
2113 		param1 = mly_inb(mly, mly->mly_cmd_mailbox + 1);
2114 
2115 		switch (error) {
2116 		case MLY_MSG_SPINUP:
2117 			if (!spinup) {
2118 				printf("%s: drive spinup in progress\n",
2119 				    device_xname(&mly->mly_dv));
2120 				spinup = 1;
2121 			}
2122 			break;
2123 
2124 		case MLY_MSG_RACE_RECOVERY_FAIL:
2125 			printf("%s: mirror race recovery failed - \n",
2126 			    device_xname(&mly->mly_dv));
2127 			printf("%s: one or more drives offline\n",
2128 			    device_xname(&mly->mly_dv));
2129 			break;
2130 
2131 		case MLY_MSG_RACE_IN_PROGRESS:
2132 			printf("%s: mirror race recovery in progress\n",
2133 			    device_xname(&mly->mly_dv));
2134 			break;
2135 
2136 		case MLY_MSG_RACE_ON_CRITICAL:
2137 			printf("%s: mirror race recovery on critical drive\n",
2138 			    device_xname(&mly->mly_dv));
2139 			break;
2140 
2141 		case MLY_MSG_PARITY_ERROR:
2142 			printf("%s: FATAL MEMORY PARITY ERROR\n",
2143 			    device_xname(&mly->mly_dv));
2144 			return (ENXIO);
2145 
2146 		default:
2147 			printf("%s: unknown initialization code 0x%x\n",
2148 			    device_xname(&mly->mly_dv), error);
2149 			break;
2150 		}
2151 	}
2152 
2153 	return (0);
2154 }
2155 
2156 /*
2157  * Space-fill a character string
2158  */
2159 static void
2160 mly_padstr(char *dst, const char *src, int len)
2161 {
2162 
2163 	while (len-- > 0) {
2164 		if (*src != '\0')
2165 			*dst++ = *src++;
2166 		else
2167 			*dst++ = ' ';
2168 	}
2169 }
2170 
2171 /*
2172  * Allocate DMA safe memory.
2173  */
2174 static int
2175 mly_dmamem_alloc(struct mly_softc *mly, int size, bus_dmamap_t *dmamap,
2176 		 void **kva, bus_addr_t *paddr, bus_dma_segment_t *seg)
2177 {
2178 	int rseg, rv, state;
2179 
2180 	state = 0;
2181 
2182 	if ((rv = bus_dmamem_alloc(mly->mly_dmat, size, PAGE_SIZE, 0,
2183 	    seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
2184 		aprint_error_dev(&mly->mly_dv, "dmamem_alloc = %d\n", rv);
2185 		goto bad;
2186 	}
2187 
2188 	state++;
2189 
2190 	if ((rv = bus_dmamem_map(mly->mly_dmat, seg, 1, size, kva,
2191 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
2192 		aprint_error_dev(&mly->mly_dv, "dmamem_map = %d\n", rv);
2193 		goto bad;
2194 	}
2195 
2196 	state++;
2197 
2198 	if ((rv = bus_dmamap_create(mly->mly_dmat, size, size, 1, 0,
2199 	    BUS_DMA_NOWAIT, dmamap)) != 0) {
2200 		aprint_error_dev(&mly->mly_dv, "dmamap_create = %d\n", rv);
2201 		goto bad;
2202 	}
2203 
2204 	state++;
2205 
2206 	if ((rv = bus_dmamap_load(mly->mly_dmat, *dmamap, *kva, size,
2207 	    NULL, BUS_DMA_NOWAIT)) != 0) {
2208 		aprint_error_dev(&mly->mly_dv, "dmamap_load = %d\n", rv);
2209 		goto bad;
2210 	}
2211 
2212 	*paddr = (*dmamap)->dm_segs[0].ds_addr;
2213 	memset(*kva, 0, size);
2214 	return (0);
2215 
2216  bad:
2217 	if (state > 2)
2218 		bus_dmamap_destroy(mly->mly_dmat, *dmamap);
2219 	if (state > 1)
2220 		bus_dmamem_unmap(mly->mly_dmat, *kva, size);
2221 	if (state > 0)
2222 		bus_dmamem_free(mly->mly_dmat, seg, 1);
2223 
2224 	return (rv);
2225 }
2226 
2227 /*
2228  * Free DMA safe memory.
2229  */
2230 static void
2231 mly_dmamem_free(struct mly_softc *mly, int size, bus_dmamap_t dmamap,
2232 		void *kva, bus_dma_segment_t *seg)
2233 {
2234 
2235 	bus_dmamap_unload(mly->mly_dmat, dmamap);
2236 	bus_dmamap_destroy(mly->mly_dmat, dmamap);
2237 	bus_dmamem_unmap(mly->mly_dmat, kva, size);
2238 	bus_dmamem_free(mly->mly_dmat, seg, 1);
2239 }
2240 
2241 
2242 /*
2243  * Accept an open operation on the control device.
2244  */
2245 int
2246 mlyopen(dev_t dev, int flag, int mode, struct lwp *l)
2247 {
2248 	struct mly_softc *mly;
2249 
2250 	if ((mly = device_lookup_private(&mly_cd, minor(dev))) == NULL)
2251 		return (ENXIO);
2252 	if ((mly->mly_state & MLY_STATE_INITOK) == 0)
2253 		return (ENXIO);
2254 	if ((mly->mly_state & MLY_STATE_OPEN) != 0)
2255 		return (EBUSY);
2256 
2257 	mly->mly_state |= MLY_STATE_OPEN;
2258 	return (0);
2259 }
2260 
2261 /*
2262  * Accept the last close on the control device.
2263  */
2264 int
2265 mlyclose(dev_t dev, int flag, int mode,
2266     struct lwp *l)
2267 {
2268 	struct mly_softc *mly;
2269 
2270 	mly = device_lookup_private(&mly_cd, minor(dev));
2271 	mly->mly_state &= ~MLY_STATE_OPEN;
2272 	return (0);
2273 }
2274 
2275 /*
2276  * Handle control operations.
2277  */
2278 int
2279 mlyioctl(dev_t dev, u_long cmd, void *data, int flag,
2280     struct lwp *l)
2281 {
2282 	struct mly_softc *mly;
2283 	int rv;
2284 
2285 	mly = device_lookup_private(&mly_cd, minor(dev));
2286 
2287 	switch (cmd) {
2288 	case MLYIO_COMMAND:
2289 		rv = kauth_authorize_device_passthru(l->l_cred, dev,
2290 		    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL, data);
2291 		if (rv)
2292 			break;
2293 
2294 		rv = mly_user_command(mly, (void *)data);
2295 		break;
2296 	case MLYIO_HEALTH:
2297 		rv = mly_user_health(mly, (void *)data);
2298 		break;
2299 	default:
2300 		rv = ENOTTY;
2301 		break;
2302 	}
2303 
2304 	return (rv);
2305 }
2306 
2307 /*
2308  * Execute a command passed in from userspace.
2309  *
2310  * The control structure contains the actual command for the controller, as
2311  * well as the user-space data pointer and data size, and an optional sense
2312  * buffer size/pointer.  On completion, the data size is adjusted to the
2313  * command residual, and the sense buffer size to the size of the returned
2314  * sense data.
2315  */
2316 static int
2317 mly_user_command(struct mly_softc *mly, struct mly_user_command *uc)
2318 {
2319 	struct mly_ccb	*mc;
2320 	int rv, mapped;
2321 
2322 	if ((rv = mly_ccb_alloc(mly, &mc)) != 0)
2323 		return (rv);
2324 
2325 	mapped = 0;
2326 	mc->mc_data = NULL;
2327 
2328 	/*
2329 	 * Handle data size/direction.
2330 	 */
2331 	if ((mc->mc_length = abs(uc->DataTransferLength)) != 0) {
2332 		if (mc->mc_length > MAXPHYS) {
2333 			rv = EINVAL;
2334 			goto out;
2335 		}
2336 
2337 		mc->mc_data = malloc(mc->mc_length, M_DEVBUF, M_WAITOK);
2338 		if (mc->mc_data == NULL) {
2339 			rv = ENOMEM;
2340 			goto out;
2341 		}
2342 
2343 		if (uc->DataTransferLength > 0) {
2344 			mc->mc_flags |= MLY_CCB_DATAIN;
2345 			memset(mc->mc_data, 0, mc->mc_length);
2346 		}
2347 
2348 		if (uc->DataTransferLength < 0) {
2349 			mc->mc_flags |= MLY_CCB_DATAOUT;
2350 			rv = copyin(uc->DataTransferBuffer, mc->mc_data,
2351 			    mc->mc_length);
2352 			if (rv != 0)
2353 				goto out;
2354 		}
2355 
2356 		if ((rv = mly_ccb_map(mly, mc)) != 0)
2357 			goto out;
2358 		mapped = 1;
2359 	}
2360 
2361 	/* Copy in the command and execute it. */
2362 	memcpy(mc->mc_packet, &uc->CommandMailbox, sizeof(uc->CommandMailbox));
2363 
2364 	if ((rv = mly_ccb_wait(mly, mc, 60000)) != 0)
2365 		goto out;
2366 
2367 	/* Return the data to userspace. */
2368 	if (uc->DataTransferLength > 0) {
2369 		rv = copyout(mc->mc_data, uc->DataTransferBuffer,
2370 		    mc->mc_length);
2371 		if (rv != 0)
2372 			goto out;
2373 	}
2374 
2375 	/* Return the sense buffer to userspace. */
2376 	if (uc->RequestSenseLength > 0 && mc->mc_sense > 0) {
2377 		rv = copyout(mc->mc_packet, uc->RequestSenseBuffer,
2378 		    min(uc->RequestSenseLength, mc->mc_sense));
2379 		if (rv != 0)
2380 			goto out;
2381 	}
2382 
2383 	/* Return command results to userspace (caller will copy out). */
2384 	uc->DataTransferLength = mc->mc_resid;
2385 	uc->RequestSenseLength = min(uc->RequestSenseLength, mc->mc_sense);
2386 	uc->CommandStatus = mc->mc_status;
2387 	rv = 0;
2388 
2389  out:
2390  	if (mapped)
2391  		mly_ccb_unmap(mly, mc);
2392 	if (mc->mc_data != NULL)
2393 		free(mc->mc_data, M_DEVBUF);
2394 	mly_ccb_free(mly, mc);
2395 
2396 	return (rv);
2397 }
2398 
2399 /*
2400  * Return health status to userspace.  If the health change index in the
2401  * user structure does not match that currently exported by the controller,
2402  * we return the current status immediately.  Otherwise, we block until
2403  * either interrupted or new status is delivered.
2404  */
2405 static int
2406 mly_user_health(struct mly_softc *mly, struct mly_user_health *uh)
2407 {
2408 	struct mly_health_status mh;
2409 	int rv, s;
2410 
2411 	/* Fetch the current health status from userspace. */
2412 	rv = copyin(uh->HealthStatusBuffer, &mh, sizeof(mh));
2413 	if (rv != 0)
2414 		return (rv);
2415 
2416 	/* spin waiting for a status update */
2417 	s = splbio();
2418 	if (mly->mly_event_change == mh.change_counter)
2419 		rv = tsleep(&mly->mly_event_change, PRIBIO | PCATCH,
2420 		    "mlyhealth", 0);
2421 	splx(s);
2422 
2423 	if (rv == 0) {
2424 		/*
2425 		 * Copy the controller's health status buffer out (there is
2426 		 * a race here if it changes again).
2427 		 */
2428 		rv = copyout(&mly->mly_mmbox->mmm_health.status,
2429 		    uh->HealthStatusBuffer, sizeof(uh->HealthStatusBuffer));
2430 	}
2431 
2432 	return (rv);
2433 }
2434