xref: /freebsd/sys/dev/ahci/ahciem.c (revision ba3c1f5972d7b90feb6e6da47905ff2757e0fe57)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2012 Alexander Motin <mav@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer,
12  *    without modification, immediately at the beginning of the file.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <sys/module.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/bus.h>
37 #include <sys/conf.h>
38 #include <sys/endian.h>
39 #include <sys/malloc.h>
40 #include <sys/lock.h>
41 #include <sys/mutex.h>
42 #include <machine/stdarg.h>
43 #include <machine/resource.h>
44 #include <machine/bus.h>
45 #include <sys/rman.h>
46 #include <dev/led/led.h>
47 #include <dev/pci/pcivar.h>
48 #include <dev/pci/pcireg.h>
49 #include "ahci.h"
50 
51 #include <cam/cam.h>
52 #include <cam/cam_ccb.h>
53 #include <cam/cam_sim.h>
54 #include <cam/cam_xpt_sim.h>
55 #include <cam/cam_debug.h>
56 #include <cam/scsi/scsi_ses.h>
57 
58 /* local prototypes */
59 static void ahciemaction(struct cam_sim *sim, union ccb *ccb);
60 static void ahciempoll(struct cam_sim *sim);
61 static int ahci_em_reset(device_t dev);
62 static void ahci_em_led(void *priv, int onoff);
63 static void ahci_em_setleds(device_t dev, int c);
64 
65 static int
66 ahci_em_probe(device_t dev)
67 {
68 
69 	device_set_desc_copy(dev, "AHCI enclosure management bridge");
70 	return (BUS_PROBE_DEFAULT);
71 }
72 
73 static int
74 ahci_em_attach(device_t dev)
75 {
76 	device_t parent = device_get_parent(dev);
77 	struct ahci_controller *ctlr = device_get_softc(parent);
78 	struct ahci_enclosure *enc = device_get_softc(dev);
79 	struct cam_devq *devq;
80 	int i, c, rid, error;
81 	char buf[32];
82 
83 	enc->dev = dev;
84 	enc->quirks = ctlr->quirks;
85 	enc->channels = ctlr->channels;
86 	enc->ichannels = ctlr->ichannels;
87 	mtx_init(&enc->mtx, "AHCI enclosure lock", NULL, MTX_DEF);
88 	rid = 0;
89 	if ((enc->r_memc = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
90 	    &rid, RF_ACTIVE)) != NULL) {
91 		enc->capsem = ATA_INL(enc->r_memc, 0);
92 		rid = 1;
93 		if (!(enc->r_memt = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
94 		    &rid, RF_ACTIVE))) {
95 			error = ENXIO;
96 			goto err0;
97 		}
98 	} else {
99 		enc->capsem = AHCI_EM_XMT | AHCI_EM_SMB | AHCI_EM_LED;
100 		enc->r_memt = NULL;
101 	}
102 	if ((enc->capsem & (AHCI_EM_XMT | AHCI_EM_SMB)) == 0) {
103 		rid = 2;
104 		if (!(enc->r_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
105 		    &rid, RF_ACTIVE))) {
106 			error = ENXIO;
107 			goto err0;
108 		}
109 	} else
110 		enc->r_memr = NULL;
111 	mtx_lock(&enc->mtx);
112 	if (ahci_em_reset(dev) != 0) {
113 	    error = ENXIO;
114 	    goto err1;
115 	}
116 	rid = ATA_IRQ_RID;
117 	/* Create the device queue for our SIM. */
118 	devq = cam_simq_alloc(1);
119 	if (devq == NULL) {
120 		device_printf(dev, "Unable to allocate SIM queue\n");
121 		error = ENOMEM;
122 		goto err1;
123 	}
124 	/* Construct SIM entry */
125 	enc->sim = cam_sim_alloc(ahciemaction, ahciempoll, "ahciem", enc,
126 	    device_get_unit(dev), &enc->mtx,
127 	    1, 0, devq);
128 	if (enc->sim == NULL) {
129 		cam_simq_free(devq);
130 		device_printf(dev, "Unable to allocate SIM\n");
131 		error = ENOMEM;
132 		goto err1;
133 	}
134 	if (xpt_bus_register(enc->sim, dev, 0) != CAM_SUCCESS) {
135 		device_printf(dev, "unable to register xpt bus\n");
136 		error = ENXIO;
137 		goto err2;
138 	}
139 	if (xpt_create_path(&enc->path, /*periph*/NULL, cam_sim_path(enc->sim),
140 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
141 		device_printf(dev, "Unable to create path\n");
142 		error = ENXIO;
143 		goto err3;
144 	}
145 	mtx_unlock(&enc->mtx);
146 	if (bootverbose) {
147 		device_printf(dev, "Caps:%s%s%s%s%s%s%s%s\n",
148 		    (enc->capsem & AHCI_EM_PM) ? " PM":"",
149 		    (enc->capsem & AHCI_EM_ALHD) ? " ALHD":"",
150 		    (enc->capsem & AHCI_EM_XMT) ? " XMT":"",
151 		    (enc->capsem & AHCI_EM_SMB) ? " SMB":"",
152 		    (enc->capsem & AHCI_EM_SGPIO) ? " SGPIO":"",
153 		    (enc->capsem & AHCI_EM_SES2) ? " SES-2":"",
154 		    (enc->capsem & AHCI_EM_SAFTE) ? " SAF-TE":"",
155 		    (enc->capsem & AHCI_EM_LED) ? " LED":"");
156 	}
157 	if ((enc->capsem & AHCI_EM_LED)) {
158 		for (c = 0; c < enc->channels; c++) {
159 			if ((enc->ichannels & (1 << c)) == 0)
160 				continue;
161 			for (i = 0; i < AHCI_NUM_LEDS; i++) {
162 				enc->leds[c * AHCI_NUM_LEDS + i].dev = dev;
163 				enc->leds[c * AHCI_NUM_LEDS + i].num =
164 				    c * AHCI_NUM_LEDS + i;
165 			}
166 			if ((enc->capsem & AHCI_EM_ALHD) == 0) {
167 				snprintf(buf, sizeof(buf), "%s.%d.act",
168 				    device_get_nameunit(parent), c);
169 				enc->leds[c * AHCI_NUM_LEDS + 0].led =
170 				    led_create(ahci_em_led,
171 				    &enc->leds[c * AHCI_NUM_LEDS + 0], buf);
172 			}
173 			snprintf(buf, sizeof(buf), "%s.%d.locate",
174 			    device_get_nameunit(parent), c);
175 			enc->leds[c * AHCI_NUM_LEDS + 1].led =
176 			    led_create(ahci_em_led,
177 			    &enc->leds[c * AHCI_NUM_LEDS + 1], buf);
178 			snprintf(buf, sizeof(buf), "%s.%d.fault",
179 			    device_get_nameunit(parent), c);
180 			enc->leds[c * AHCI_NUM_LEDS + 2].led =
181 			    led_create(ahci_em_led,
182 			    &enc->leds[c * AHCI_NUM_LEDS + 2], buf);
183 		}
184 	}
185 	return (0);
186 
187 err3:
188 	xpt_bus_deregister(cam_sim_path(enc->sim));
189 err2:
190 	cam_sim_free(enc->sim, /*free_devq*/TRUE);
191 err1:
192 	mtx_unlock(&enc->mtx);
193 	if (enc->r_memr)
194 		bus_release_resource(dev, SYS_RES_MEMORY, 2, enc->r_memr);
195 err0:
196 	if (enc->r_memt)
197 		bus_release_resource(dev, SYS_RES_MEMORY, 1, enc->r_memt);
198 	if (enc->r_memc)
199 		bus_release_resource(dev, SYS_RES_MEMORY, 0, enc->r_memc);
200 	mtx_destroy(&enc->mtx);
201 	return (error);
202 }
203 
204 static int
205 ahci_em_detach(device_t dev)
206 {
207 	struct ahci_enclosure *enc = device_get_softc(dev);
208 	int i;
209 
210 	for (i = 0; i < enc->channels * AHCI_NUM_LEDS; i++) {
211 		if (enc->leds[i].led)
212 			led_destroy(enc->leds[i].led);
213 	}
214 	mtx_lock(&enc->mtx);
215 	xpt_async(AC_LOST_DEVICE, enc->path, NULL);
216 	xpt_free_path(enc->path);
217 	xpt_bus_deregister(cam_sim_path(enc->sim));
218 	cam_sim_free(enc->sim, /*free_devq*/TRUE);
219 	mtx_unlock(&enc->mtx);
220 
221 	if (enc->r_memc)
222 		bus_release_resource(dev, SYS_RES_MEMORY, 0, enc->r_memc);
223 	if (enc->r_memt)
224 		bus_release_resource(dev, SYS_RES_MEMORY, 1, enc->r_memt);
225 	if (enc->r_memr)
226 		bus_release_resource(dev, SYS_RES_MEMORY, 2, enc->r_memr);
227 	mtx_destroy(&enc->mtx);
228 	return (0);
229 }
230 
231 static int
232 ahci_em_reset(device_t dev)
233 {
234 	struct ahci_enclosure *enc;
235 	int i, timeout;
236 
237 	enc = device_get_softc(dev);
238 	if (enc->r_memc == NULL)
239 		return (0);
240 	ATA_OUTL(enc->r_memc, 0, AHCI_EM_RST);
241 	timeout = 1000;
242 	while ((ATA_INL(enc->r_memc, 0) & AHCI_EM_RST) &&
243 	    --timeout > 0)
244 		DELAY(1000);
245 	if (timeout == 0) {
246 		device_printf(dev, "EM timeout\n");
247 		return (1);
248 	}
249 	for (i = 0; i < enc->channels; i++)
250 		ahci_em_setleds(dev, i);
251 	return (0);
252 }
253 
254 static int
255 ahci_em_suspend(device_t dev)
256 {
257 	struct ahci_enclosure *enc = device_get_softc(dev);
258 
259 	mtx_lock(&enc->mtx);
260 	xpt_freeze_simq(enc->sim, 1);
261 	mtx_unlock(&enc->mtx);
262 	return (0);
263 }
264 
265 static int
266 ahci_em_resume(device_t dev)
267 {
268 	struct ahci_enclosure *enc = device_get_softc(dev);
269 
270 	mtx_lock(&enc->mtx);
271 	ahci_em_reset(dev);
272 	xpt_release_simq(enc->sim, TRUE);
273 	mtx_unlock(&enc->mtx);
274 	return (0);
275 }
276 
277 static device_method_t ahciem_methods[] = {
278 	DEVMETHOD(device_probe,     ahci_em_probe),
279 	DEVMETHOD(device_attach,    ahci_em_attach),
280 	DEVMETHOD(device_detach,    ahci_em_detach),
281 	DEVMETHOD(device_suspend,   ahci_em_suspend),
282 	DEVMETHOD(device_resume,    ahci_em_resume),
283 	DEVMETHOD_END
284 };
285 static driver_t ahciem_driver = {
286         "ahciem",
287         ahciem_methods,
288         sizeof(struct ahci_enclosure)
289 };
290 DRIVER_MODULE(ahciem, ahci, ahciem_driver, NULL, NULL);
291 
292 static void
293 ahci_em_setleds(device_t dev, int c)
294 {
295 	struct ahci_enclosure *enc;
296 	int timeout;
297 	int16_t val;
298 
299 	enc = device_get_softc(dev);
300 	if (enc->r_memc == NULL)
301 		return;
302 
303 	val = 0;
304 	if (enc->status[c][2] & SESCTL_RQSACT)		/* Activity */
305 		val |= (1 << 0);
306 	if (enc->status[c][1] & SESCTL_RQSRR)		/* Rebuild */
307 		val |= (1 << 6) | (1 << 3);
308 	else if (enc->status[c][2] & SESCTL_RQSID)	/* Identification */
309 		val |= (1 << 3);
310 	else if (enc->status[c][3] & SESCTL_RQSFLT)	/* Fault */
311 		val |= (1 << 6);
312 
313 	timeout = 10000;
314 	while (ATA_INL(enc->r_memc, 0) & (AHCI_EM_TM | AHCI_EM_RST) &&
315 	    --timeout > 0)
316 		DELAY(100);
317 	if (timeout == 0)
318 		device_printf(dev, "Transmit timeout\n");
319 	ATA_OUTL(enc->r_memt, 0, (1 << 8) | (0 << 16) | (0 << 24));
320 	ATA_OUTL(enc->r_memt, 4, c | (0 << 8) | (val << 16));
321 	ATA_OUTL(enc->r_memc, 0, AHCI_EM_TM);
322 }
323 
324 static void
325 ahci_em_led(void *priv, int onoff)
326 {
327 	struct ahci_led *led;
328 	struct ahci_enclosure *enc;
329 	int c, l;
330 
331 	led = (struct ahci_led *)priv;
332 	enc = device_get_softc(led->dev);
333 	c = led->num / AHCI_NUM_LEDS;
334 	l = led->num % AHCI_NUM_LEDS;
335 
336 	if (l == 0) {
337 		if (onoff)
338 			enc->status[c][2] |= 0x80;
339 		else
340 			enc->status[c][2] &= ~0x80;
341 	} else if (l == 1) {
342 		if (onoff)
343 			enc->status[c][2] |= SESCTL_RQSID;
344 		else
345 			enc->status[c][2] &= ~SESCTL_RQSID;
346 	} else if (l == 2) {
347 		if (onoff)
348 			enc->status[c][3] |= SESCTL_RQSFLT;
349 		else
350 			enc->status[c][3] &= SESCTL_RQSFLT;
351 	}
352 	ahci_em_setleds(led->dev, c);
353 }
354 
355 static int
356 ahci_check_ids(union ccb *ccb)
357 {
358 
359 	if (ccb->ccb_h.target_id != 0) {
360 		ccb->ccb_h.status = CAM_TID_INVALID;
361 		xpt_done(ccb);
362 		return (-1);
363 	}
364 	if (ccb->ccb_h.target_lun != 0) {
365 		ccb->ccb_h.status = CAM_LUN_INVALID;
366 		xpt_done(ccb);
367 		return (-1);
368 	}
369 	return (0);
370 }
371 
372 static void
373 ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb)
374 {
375 	struct ahci_enclosure *enc;
376 	struct ahci_channel *ch;
377 	struct ses_status_page *page;
378 	struct ses_status_array_dev_slot *ads, *ads0;
379 	struct ses_elm_desc_hdr *elmd;
380 	struct ses_elm_addlstatus_eip_hdr *elma;
381 	struct ses_elm_ata_hdr *elmb;
382 	uint8_t *buf;
383 	int i;
384 
385 	enc = device_get_softc(dev);
386 	buf = ccb->ataio.data_ptr;
387 
388 	/* General request validation. */
389 	if (ccb->ataio.cmd.command != ATA_SEP_ATTN ||
390 	    ccb->ataio.dxfer_len < ccb->ataio.cmd.sector_count * 4) {
391 		ccb->ccb_h.status = CAM_REQ_INVALID;
392 		goto out;
393 	}
394 
395 	/* SEMB IDENTIFY */
396 	if (ccb->ataio.cmd.features == 0xEC &&
397 	    ccb->ataio.cmd.sector_count >= 16) {
398 		bzero(buf, ccb->ataio.dxfer_len);
399 		buf[0] = 64;		/* Valid bytes. */
400 		buf[2] = 0x30;		/* NAA Locally Assigned. */
401 		strncpy(&buf[3], device_get_nameunit(dev), 7);
402 		strncpy(&buf[10], "AHCI    ", SID_VENDOR_SIZE);
403 		strncpy(&buf[18], "SGPIO Enclosure ", SID_PRODUCT_SIZE);
404 		strncpy(&buf[34], "2.00", SID_REVISION_SIZE);
405 		strncpy(&buf[39], "0001", 4);
406 		strncpy(&buf[43], "S-E-S ", 6);
407 		strncpy(&buf[49], "2.00", 4);
408 		ccb->ccb_h.status = CAM_REQ_CMP;
409 		goto out;
410 	}
411 
412 	/* SEMB RECEIVE DIAGNOSTIC RESULT (0) */
413 	page = (struct ses_status_page *)buf;
414 	if (ccb->ataio.cmd.lba_low == 0x02 &&
415 	    ccb->ataio.cmd.features == 0x00 &&
416 	    ccb->ataio.cmd.sector_count >= 3) {
417 		bzero(buf, ccb->ataio.dxfer_len);
418 		page->hdr.page_code = 0;
419 		scsi_ulto2b(5, page->hdr.length);
420 		buf[4] = 0x00;
421 		buf[5] = 0x01;
422 		buf[6] = 0x02;
423 		buf[7] = 0x07;
424 		buf[8] = 0x0a;
425 		ccb->ccb_h.status = CAM_REQ_CMP;
426 		goto out;
427 	}
428 
429 	/* SEMB RECEIVE DIAGNOSTIC RESULT (1) */
430 	if (ccb->ataio.cmd.lba_low == 0x02 &&
431 	    ccb->ataio.cmd.features == 0x01 &&
432 	    ccb->ataio.cmd.sector_count >= 16) {
433 		struct ses_enc_desc *ed;
434 		struct ses_elm_type_desc *td;
435 
436 		bzero(buf, ccb->ataio.dxfer_len);
437 		page->hdr.page_code = 0x01;
438 		scsi_ulto2b(4 + sizeof(*ed) + sizeof(*td) + 11,
439 		    page->hdr.length);
440 		ed = (struct ses_enc_desc *)&buf[8];
441 		ed->byte0 = 0x11;
442 		ed->subenc_id = 0;
443 		ed->num_types = 1;
444 		ed->length = 36;
445 		ed->logical_id[0] = 0x30;	/* NAA Locally Assigned. */
446 		strncpy(&ed->logical_id[1], device_get_nameunit(dev), 7);
447 		strncpy(ed->vendor_id, "AHCI    ", SID_VENDOR_SIZE);
448 		strncpy(ed->product_id, "SGPIO Enclosure ", SID_PRODUCT_SIZE);
449 		strncpy(ed->product_rev, "2.00", SID_REVISION_SIZE);
450 		td = (struct ses_elm_type_desc *)ses_enc_desc_next(ed);
451 		td->etype_elm_type = 0x17;
452 		td->etype_maxelt = enc->channels;
453 		td->etype_subenc = 0;
454 		td->etype_txt_len = 11;
455 		snprintf((char *)(td + 1), 12, "Drive Slots");
456 		ccb->ccb_h.status = CAM_REQ_CMP;
457 		goto out;
458 	}
459 
460 	/* SEMB RECEIVE DIAGNOSTIC RESULT (2) */
461 	if (ccb->ataio.cmd.lba_low == 0x02 &&
462 	    ccb->ataio.cmd.features == 0x02 &&
463 	    ccb->ataio.cmd.sector_count >= (3 + enc->channels)) {
464 		bzero(buf, ccb->ataio.dxfer_len);
465 		page->hdr.page_code = 0x02;
466 		scsi_ulto2b(4 + 4 * (1 + enc->channels),
467 		    page->hdr.length);
468 		for (i = 0; i < enc->channels; i++) {
469 			ads = &page->elements[i + 1].array_dev_slot;
470 			memcpy(ads, enc->status[i], 4);
471 			ch = ahci_getch(device_get_parent(dev), i);
472 			if (ch == NULL) {
473 				ads->common.bytes[0] |= SES_OBJSTAT_UNKNOWN;
474 				continue;
475 			}
476 			if (ch->pm_present)
477 				ads->common.bytes[0] |= SES_OBJSTAT_UNKNOWN;
478 			else if (ch->devices)
479 				ads->common.bytes[0] |= SES_OBJSTAT_OK;
480 			else if (ch->disablephy)
481 				ads->common.bytes[0] |= SES_OBJSTAT_NOTAVAIL;
482 			else
483 				ads->common.bytes[0] |= SES_OBJSTAT_NOTINSTALLED;
484 			if (ch->disablephy)
485 				ads->common.bytes[3] |= SESCTL_DEVOFF;
486 			ahci_putch(ch);
487 		}
488 		ccb->ccb_h.status = CAM_REQ_CMP;
489 		goto out;
490 	}
491 
492 	/* SEMB SEND DIAGNOSTIC (2) */
493 	if (ccb->ataio.cmd.lba_low == 0x82 &&
494 	    ccb->ataio.cmd.features == 0x02 &&
495 	    ccb->ataio.cmd.sector_count >= (3 + enc->channels)) {
496 		ads0 = &page->elements[0].array_dev_slot;
497 		for (i = 0; i < enc->channels; i++) {
498 			ads = &page->elements[i + 1].array_dev_slot;
499 			if (ads->common.bytes[0] & SESCTL_CSEL) {
500 				enc->status[i][0] = 0;
501 				enc->status[i][1] = ads->bytes[0] &
502 				    SESCTL_RQSRR;
503 				enc->status[i][2] = ads->bytes[1] &
504 				    (SESCTL_RQSACT | SESCTL_RQSID);
505 				enc->status[i][3] = ads->bytes[2] &
506 				    SESCTL_RQSFLT;
507 				ahci_em_setleds(dev, i);
508 			} else if (ads0->common.bytes[0] & SESCTL_CSEL) {
509 				enc->status[i][0] = 0;
510 				enc->status[i][1] = ads0->bytes[0] &
511 				    SESCTL_RQSRR;
512 				enc->status[i][2] = ads0->bytes[1] &
513 				    (SESCTL_RQSACT | SESCTL_RQSID);
514 				enc->status[i][3] = ads0->bytes[2] &
515 				    SESCTL_RQSFLT;
516 				ahci_em_setleds(dev, i);
517 			}
518 		}
519 		ccb->ccb_h.status = CAM_REQ_CMP;
520 		goto out;
521 	}
522 
523 	/* SEMB RECEIVE DIAGNOSTIC RESULT (7) */
524 	if (ccb->ataio.cmd.lba_low == 0x02 &&
525 	    ccb->ataio.cmd.features == 0x07 &&
526 	    ccb->ataio.cmd.sector_count >= (6 + 3 * enc->channels)) {
527 		bzero(buf, ccb->ataio.dxfer_len);
528 		page->hdr.page_code = 0x07;
529 		scsi_ulto2b(4 + 15 + 11 * enc->channels, page->hdr.length);
530 		elmd = (struct ses_elm_desc_hdr *)&buf[8];
531 		scsi_ulto2b(11, elmd->length);
532 		snprintf((char *)(elmd + 1), 12, "Drive Slots");
533 		for (i = 0; i < enc->channels; i++) {
534 			elmd = (struct ses_elm_desc_hdr *)&buf[8 + 15 + 11 * i];
535 			scsi_ulto2b(7, elmd->length);
536 			snprintf((char *)(elmd + 1), 8, "Slot %02d", i);
537 		}
538 		ccb->ccb_h.status = CAM_REQ_CMP;
539 		goto out;
540 	}
541 
542 	/* SEMB RECEIVE DIAGNOSTIC RESULT (a) */
543 	if (ccb->ataio.cmd.lba_low == 0x02 &&
544 	    ccb->ataio.cmd.features == 0x0a &&
545 	    ccb->ataio.cmd.sector_count >= (2 + 3 * enc->channels)) {
546 		bzero(buf, ccb->ataio.dxfer_len);
547 		page->hdr.page_code = 0x0a;
548 		scsi_ulto2b(4 + (sizeof(*elma) + sizeof(*elmb)) * enc->channels,
549 		    page->hdr.length);
550 		for (i = 0; i < enc->channels; i++) {
551 			elma = (struct ses_elm_addlstatus_eip_hdr *)&buf[
552 			    8 + (sizeof(*elma) + sizeof(*elmb)) * i];
553 			elma->base.byte0 = 0x10 | SPSP_PROTO_ATA;
554 			elma->base.length = 2 + sizeof(*elmb);
555 			elma->byte2 = 0x01;
556 			elma->element_index = 1 + i;
557 			ch = ahci_getch(device_get_parent(dev), i);
558 			if (ch == NULL) {
559 				elma->base.byte0 |= 0x80;
560 				continue;
561 			}
562 			if (ch->devices == 0 || ch->pm_present)
563 				elma->base.byte0 |= 0x80;
564 			elmb = (struct ses_elm_ata_hdr *)(elma + 1);
565 			scsi_ulto4b(cam_sim_path(ch->sim), elmb->bus);
566 			scsi_ulto4b(0, elmb->target);
567 			ahci_putch(ch);
568 		}
569 		ccb->ccb_h.status = CAM_REQ_CMP;
570 		goto out;
571 	}
572 
573 	ccb->ccb_h.status = CAM_REQ_INVALID;
574 out:
575 	xpt_done(ccb);
576 }
577 
578 static void
579 ahci_em_begin_transaction(device_t dev, union ccb *ccb)
580 {
581 	struct ahci_enclosure *enc;
582 	struct ata_res *res;
583 
584 	enc = device_get_softc(dev);
585 	res = &ccb->ataio.res;
586 	bzero(res, sizeof(*res));
587 	if ((ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) &&
588 	    (ccb->ataio.cmd.control & ATA_A_RESET)) {
589 		res->lba_high = 0xc3;
590 		res->lba_mid = 0x3c;
591 		ccb->ccb_h.status = CAM_REQ_CMP;
592 		xpt_done(ccb);
593 		return;
594 	}
595 
596 	if (enc->capsem & AHCI_EM_LED) {
597 		ahci_em_emulate_ses_on_led(dev, ccb);
598 		return;
599 	} else
600 		device_printf(dev, "Unsupported enclosure interface\n");
601 
602 	ccb->ccb_h.status = CAM_REQ_INVALID;
603 	xpt_done(ccb);
604 }
605 
606 static void
607 ahciemaction(struct cam_sim *sim, union ccb *ccb)
608 {
609 	device_t dev, parent;
610 	struct ahci_enclosure *enc;
611 
612 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
613 	    ("ahciemaction func_code=%x\n", ccb->ccb_h.func_code));
614 
615 	enc = cam_sim_softc(sim);
616 	dev = enc->dev;
617 	switch (ccb->ccb_h.func_code) {
618 	case XPT_ATA_IO:	/* Execute the requested I/O operation */
619 		if (ahci_check_ids(ccb))
620 			return;
621 		ahci_em_begin_transaction(dev, ccb);
622 		return;
623 	case XPT_RESET_BUS:		/* Reset the specified bus */
624 	case XPT_RESET_DEV:	/* Bus Device Reset the specified device */
625 		ahci_em_reset(dev);
626 		ccb->ccb_h.status = CAM_REQ_CMP;
627 		break;
628 	case XPT_PATH_INQ:		/* Path routing inquiry */
629 	{
630 		struct ccb_pathinq *cpi = &ccb->cpi;
631 
632 		parent = device_get_parent(dev);
633 		cpi->version_num = 1; /* XXX??? */
634 		cpi->hba_inquiry = PI_SDTR_ABLE;
635 		cpi->target_sprt = 0;
636 		cpi->hba_misc = PIM_SEQSCAN;
637 		cpi->hba_eng_cnt = 0;
638 		cpi->max_target = 0;
639 		cpi->max_lun = 0;
640 		cpi->initiator_id = 0;
641 		cpi->bus_id = cam_sim_bus(sim);
642 		cpi->base_transfer_speed = 150000;
643 		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
644 		strlcpy(cpi->hba_vid, "AHCI", HBA_IDLEN);
645 		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
646 		cpi->unit_number = cam_sim_unit(sim);
647 		cpi->transport = XPORT_SATA;
648 		cpi->transport_version = XPORT_VERSION_UNSPECIFIED;
649 		cpi->protocol = PROTO_ATA;
650 		cpi->protocol_version = PROTO_VERSION_UNSPECIFIED;
651 		cpi->maxio = maxphys;
652 		cpi->hba_vendor = pci_get_vendor(parent);
653 		cpi->hba_device = pci_get_device(parent);
654 		cpi->hba_subvendor = pci_get_subvendor(parent);
655 		cpi->hba_subdevice = pci_get_subdevice(parent);
656 		cpi->ccb_h.status = CAM_REQ_CMP;
657 		break;
658 	}
659 	default:
660 		ccb->ccb_h.status = CAM_REQ_INVALID;
661 		break;
662 	}
663 	xpt_done(ccb);
664 }
665 
666 static void
667 ahciempoll(struct cam_sim *sim)
668 {
669 
670 }
671