xref: /freebsd/sys/dev/ahci/ahciem.c (revision d8a0fe102c0cfdfcd5b818f850eff09d8536c9bc)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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))) {
91 		mtx_destroy(&enc->mtx);
92 		return (ENXIO);
93 	}
94 	enc->capsem = ATA_INL(enc->r_memc, 0);
95 	rid = 1;
96 	if (!(enc->r_memt = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
97 	    &rid, RF_ACTIVE))) {
98 		error = ENXIO;
99 		goto err0;
100 	}
101 	if ((enc->capsem & (AHCI_EM_XMT | AHCI_EM_SMB)) == 0) {
102 		rid = 2;
103 		if (!(enc->r_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
104 		    &rid, RF_ACTIVE))) {
105 			error = ENXIO;
106 			goto err0;
107 		}
108 	} else
109 		enc->r_memr = NULL;
110 	mtx_lock(&enc->mtx);
111 	if (ahci_em_reset(dev) != 0) {
112 	    error = ENXIO;
113 	    goto err1;
114 	}
115 	rid = ATA_IRQ_RID;
116 	/* Create the device queue for our SIM. */
117 	devq = cam_simq_alloc(1);
118 	if (devq == NULL) {
119 		device_printf(dev, "Unable to allocate SIM queue\n");
120 		error = ENOMEM;
121 		goto err1;
122 	}
123 	/* Construct SIM entry */
124 	enc->sim = cam_sim_alloc(ahciemaction, ahciempoll, "ahciem", enc,
125 	    device_get_unit(dev), &enc->mtx,
126 	    1, 0, devq);
127 	if (enc->sim == NULL) {
128 		cam_simq_free(devq);
129 		device_printf(dev, "Unable to allocate SIM\n");
130 		error = ENOMEM;
131 		goto err1;
132 	}
133 	if (xpt_bus_register(enc->sim, dev, 0) != CAM_SUCCESS) {
134 		device_printf(dev, "unable to register xpt bus\n");
135 		error = ENXIO;
136 		goto err2;
137 	}
138 	if (xpt_create_path(&enc->path, /*periph*/NULL, cam_sim_path(enc->sim),
139 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
140 		device_printf(dev, "Unable to create path\n");
141 		error = ENXIO;
142 		goto err3;
143 	}
144 	mtx_unlock(&enc->mtx);
145 	if (bootverbose) {
146 		device_printf(dev, "Caps:%s%s%s%s%s%s%s%s\n",
147 		    (enc->capsem & AHCI_EM_PM) ? " PM":"",
148 		    (enc->capsem & AHCI_EM_ALHD) ? " ALHD":"",
149 		    (enc->capsem & AHCI_EM_XMT) ? " XMT":"",
150 		    (enc->capsem & AHCI_EM_SMB) ? " SMB":"",
151 		    (enc->capsem & AHCI_EM_SGPIO) ? " SGPIO":"",
152 		    (enc->capsem & AHCI_EM_SES2) ? " SES-2":"",
153 		    (enc->capsem & AHCI_EM_SAFTE) ? " SAF-TE":"",
154 		    (enc->capsem & AHCI_EM_LED) ? " LED":"");
155 	}
156 	if ((enc->capsem & AHCI_EM_LED)) {
157 		for (c = 0; c < enc->channels; c++) {
158 			if ((enc->ichannels & (1 << c)) == 0)
159 				continue;
160 			for (i = 0; i < AHCI_NUM_LEDS; i++) {
161 				enc->leds[c * AHCI_NUM_LEDS + i].dev = dev;
162 				enc->leds[c * AHCI_NUM_LEDS + i].num =
163 				    c * AHCI_NUM_LEDS + i;
164 			}
165 			if ((enc->capsem & AHCI_EM_ALHD) == 0) {
166 				snprintf(buf, sizeof(buf), "%s.%d.act",
167 				    device_get_nameunit(parent), c);
168 				enc->leds[c * AHCI_NUM_LEDS + 0].led =
169 				    led_create(ahci_em_led,
170 				    &enc->leds[c * AHCI_NUM_LEDS + 0], buf);
171 			}
172 			snprintf(buf, sizeof(buf), "%s.%d.locate",
173 			    device_get_nameunit(parent), c);
174 			enc->leds[c * AHCI_NUM_LEDS + 1].led =
175 			    led_create(ahci_em_led,
176 			    &enc->leds[c * AHCI_NUM_LEDS + 1], buf);
177 			snprintf(buf, sizeof(buf), "%s.%d.fault",
178 			    device_get_nameunit(parent), c);
179 			enc->leds[c * AHCI_NUM_LEDS + 2].led =
180 			    led_create(ahci_em_led,
181 			    &enc->leds[c * AHCI_NUM_LEDS + 2], buf);
182 		}
183 	}
184 	return (0);
185 
186 err3:
187 	xpt_bus_deregister(cam_sim_path(enc->sim));
188 err2:
189 	cam_sim_free(enc->sim, /*free_devq*/TRUE);
190 err1:
191 	mtx_unlock(&enc->mtx);
192 	if (enc->r_memr)
193 		bus_release_resource(dev, SYS_RES_MEMORY, 2, enc->r_memr);
194 err0:
195 	if (enc->r_memt)
196 		bus_release_resource(dev, SYS_RES_MEMORY, 1, enc->r_memt);
197 	bus_release_resource(dev, SYS_RES_MEMORY, 0, enc->r_memc);
198 	mtx_destroy(&enc->mtx);
199 	return (error);
200 }
201 
202 static int
203 ahci_em_detach(device_t dev)
204 {
205 	struct ahci_enclosure *enc = device_get_softc(dev);
206 	int i;
207 
208 	for (i = 0; i < enc->channels * AHCI_NUM_LEDS; i++) {
209 		if (enc->leds[i].led)
210 			led_destroy(enc->leds[i].led);
211 	}
212 	mtx_lock(&enc->mtx);
213 	xpt_async(AC_LOST_DEVICE, enc->path, NULL);
214 	xpt_free_path(enc->path);
215 	xpt_bus_deregister(cam_sim_path(enc->sim));
216 	cam_sim_free(enc->sim, /*free_devq*/TRUE);
217 	mtx_unlock(&enc->mtx);
218 
219 	bus_release_resource(dev, SYS_RES_MEMORY, 0, enc->r_memc);
220 	bus_release_resource(dev, SYS_RES_MEMORY, 1, enc->r_memt);
221 	if (enc->r_memr)
222 		bus_release_resource(dev, SYS_RES_MEMORY, 2, enc->r_memr);
223 	mtx_destroy(&enc->mtx);
224 	return (0);
225 }
226 
227 static int
228 ahci_em_reset(device_t dev)
229 {
230 	struct ahci_enclosure *enc;
231 	int i, timeout;
232 
233 	enc = device_get_softc(dev);
234 	ATA_OUTL(enc->r_memc, 0, AHCI_EM_RST);
235 	timeout = 1000;
236 	while ((ATA_INL(enc->r_memc, 0) & AHCI_EM_RST) &&
237 	    --timeout > 0)
238 		DELAY(1000);
239 	if (timeout == 0) {
240 		device_printf(dev, "EM timeout\n");
241 		return (1);
242 	}
243 	for (i = 0; i < enc->channels; i++)
244 		ahci_em_setleds(dev, i);
245 	return (0);
246 }
247 
248 static int
249 ahci_em_suspend(device_t dev)
250 {
251 	struct ahci_enclosure *enc = device_get_softc(dev);
252 
253 	mtx_lock(&enc->mtx);
254 	xpt_freeze_simq(enc->sim, 1);
255 	mtx_unlock(&enc->mtx);
256 	return (0);
257 }
258 
259 static int
260 ahci_em_resume(device_t dev)
261 {
262 	struct ahci_enclosure *enc = device_get_softc(dev);
263 
264 	mtx_lock(&enc->mtx);
265 	ahci_em_reset(dev);
266 	xpt_release_simq(enc->sim, TRUE);
267 	mtx_unlock(&enc->mtx);
268 	return (0);
269 }
270 
271 devclass_t ahciem_devclass;
272 static device_method_t ahciem_methods[] = {
273 	DEVMETHOD(device_probe,     ahci_em_probe),
274 	DEVMETHOD(device_attach,    ahci_em_attach),
275 	DEVMETHOD(device_detach,    ahci_em_detach),
276 	DEVMETHOD(device_suspend,   ahci_em_suspend),
277 	DEVMETHOD(device_resume,    ahci_em_resume),
278 	DEVMETHOD_END
279 };
280 static driver_t ahciem_driver = {
281         "ahciem",
282         ahciem_methods,
283         sizeof(struct ahci_enclosure)
284 };
285 DRIVER_MODULE(ahciem, ahci, ahciem_driver, ahciem_devclass, NULL, NULL);
286 
287 static void
288 ahci_em_setleds(device_t dev, int c)
289 {
290 	struct ahci_enclosure *enc;
291 	int timeout;
292 	int16_t val;
293 
294 	enc = device_get_softc(dev);
295 
296 	val = 0;
297 	if (enc->status[c][2] & 0x80)		/* Activity */
298 		val |= (1 << 0);
299 	if (enc->status[c][2] & SESCTL_RQSID)	/* Identification */
300 		val |= (1 << 3);
301 	else if (enc->status[c][3] & SESCTL_RQSFLT)	/* Fault */
302 		val |= (1 << 6);
303 	else if (enc->status[c][1] & 0x02)		/* Rebuild */
304 		val |= (1 << 6) | (1 << 3);
305 
306 	timeout = 10000;
307 	while (ATA_INL(enc->r_memc, 0) & (AHCI_EM_TM | AHCI_EM_RST) &&
308 	    --timeout > 0)
309 		DELAY(100);
310 	if (timeout == 0)
311 		device_printf(dev, "Transmit timeout\n");
312 	ATA_OUTL(enc->r_memt, 0, (1 << 8) | (0 << 16) | (0 << 24));
313 	ATA_OUTL(enc->r_memt, 4, c | (0 << 8) | (val << 16));
314 	ATA_OUTL(enc->r_memc, 0, AHCI_EM_TM);
315 }
316 
317 static void
318 ahci_em_led(void *priv, int onoff)
319 {
320 	struct ahci_led *led;
321 	struct ahci_enclosure *enc;
322 	int c, l;
323 
324 	led = (struct ahci_led *)priv;
325 	enc = device_get_softc(led->dev);
326 	c = led->num / AHCI_NUM_LEDS;
327 	l = led->num % AHCI_NUM_LEDS;
328 
329 	if (l == 0) {
330 		if (onoff)
331 			enc->status[c][2] |= 0x80;
332 		else
333 			enc->status[c][2] &= ~0x80;
334 	} else if (l == 1) {
335 		if (onoff)
336 			enc->status[c][2] |= SESCTL_RQSID;
337 		else
338 			enc->status[c][2] &= ~SESCTL_RQSID;
339 	} else if (l == 2) {
340 		if (onoff)
341 			enc->status[c][3] |= SESCTL_RQSFLT;
342 		else
343 			enc->status[c][3] &= SESCTL_RQSFLT;
344 	}
345 	ahci_em_setleds(led->dev, c);
346 }
347 
348 static int
349 ahci_check_ids(union ccb *ccb)
350 {
351 
352 	if (ccb->ccb_h.target_id != 0) {
353 		ccb->ccb_h.status = CAM_TID_INVALID;
354 		xpt_done(ccb);
355 		return (-1);
356 	}
357 	if (ccb->ccb_h.target_lun != 0) {
358 		ccb->ccb_h.status = CAM_LUN_INVALID;
359 		xpt_done(ccb);
360 		return (-1);
361 	}
362 	return (0);
363 }
364 
365 static void
366 ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb)
367 {
368 	struct ahci_enclosure *enc;
369 	struct ses_status_page *page;
370 	struct ses_status_array_dev_slot *ads, *ads0;
371 	struct ses_elm_desc_hdr *elmd;
372 	uint8_t *buf;
373 	int i;
374 
375 	enc = device_get_softc(dev);
376 	buf = ccb->ataio.data_ptr;
377 
378 	/* General request validation. */
379 	if (ccb->ataio.cmd.command != ATA_SEP_ATTN ||
380 	    ccb->ataio.dxfer_len < ccb->ataio.cmd.sector_count * 4) {
381 		ccb->ccb_h.status = CAM_REQ_INVALID;
382 		goto out;
383 	}
384 
385 	/* SEMB IDENTIFY */
386 	if (ccb->ataio.cmd.features == 0xEC &&
387 	    ccb->ataio.cmd.sector_count >= 16) {
388 		bzero(buf, ccb->ataio.dxfer_len);
389 		buf[0] = 64;		/* Valid bytes. */
390 		buf[2] = 0x30;		/* NAA Locally Assigned. */
391 		strncpy(&buf[3], device_get_nameunit(dev), 7);
392 		strncpy(&buf[10], "AHCI    ", SID_VENDOR_SIZE);
393 		strncpy(&buf[18], "SGPIO Enclosure ", SID_PRODUCT_SIZE);
394 		strncpy(&buf[34], "1.00", SID_REVISION_SIZE);
395 		strncpy(&buf[39], "0001", 4);
396 		strncpy(&buf[43], "S-E-S ", 6);
397 		strncpy(&buf[49], "2.00", 4);
398 		ccb->ccb_h.status = CAM_REQ_CMP;
399 		goto out;
400 	}
401 
402 	/* SEMB RECEIVE DIAGNOSTIC RESULT (0) */
403 	page = (struct ses_status_page *)buf;
404 	if (ccb->ataio.cmd.lba_low == 0x02 &&
405 	    ccb->ataio.cmd.features == 0x00 &&
406 	    ccb->ataio.cmd.sector_count >= 2) {
407 		bzero(buf, ccb->ataio.dxfer_len);
408 		page->hdr.page_code = 0;
409 		scsi_ulto2b(4, page->hdr.length);
410 		buf[4] = 0;
411 		buf[5] = 1;
412 		buf[6] = 2;
413 		buf[7] = 7;
414 		ccb->ccb_h.status = CAM_REQ_CMP;
415 		goto out;
416 	}
417 
418 	/* SEMB RECEIVE DIAGNOSTIC RESULT (1) */
419 	if (ccb->ataio.cmd.lba_low == 0x02 &&
420 	    ccb->ataio.cmd.features == 0x01 &&
421 	    ccb->ataio.cmd.sector_count >= 13) {
422 		struct ses_enc_desc *ed;
423 		struct ses_elm_type_desc *td;
424 
425 		bzero(buf, ccb->ataio.dxfer_len);
426 		page->hdr.page_code = 0x01;
427 		scsi_ulto2b(4 + 4 + 36 + 4, page->hdr.length);
428 		ed = (struct ses_enc_desc *)&buf[8];
429 		ed->byte0 = 0x11;
430 		ed->subenc_id = 0;
431 		ed->num_types = 1;
432 		ed->length = 36;
433 		strncpy(ed->vendor_id, "AHCI    ", SID_VENDOR_SIZE);
434 		strncpy(ed->product_id, "SGPIO Enclosure ", SID_PRODUCT_SIZE);
435 		strncpy(ed->product_rev, "    ", SID_REVISION_SIZE);
436 		td = (struct ses_elm_type_desc *)ses_enc_desc_next(ed);
437 		td->etype_elm_type = 0x17;
438 		td->etype_maxelt = enc->channels;
439 		td->etype_subenc = 0;
440 		td->etype_txt_len = 0;
441 		ccb->ccb_h.status = CAM_REQ_CMP;
442 		goto out;
443 	}
444 
445 	/* SEMB RECEIVE DIAGNOSTIC RESULT (2) */
446 	if (ccb->ataio.cmd.lba_low == 0x02 &&
447 	    ccb->ataio.cmd.features == 0x02 &&
448 	    ccb->ataio.cmd.sector_count >= (3 + enc->channels)) {
449 		bzero(buf, ccb->ataio.dxfer_len);
450 		page->hdr.page_code = 0x02;
451 		scsi_ulto2b(4 + 4 * (1 + enc->channels),
452 		    page->hdr.length);
453 		for (i = 0; i < enc->channels; i++) {
454 			ads = &page->elements[i + 1].array_dev_slot;
455 			memcpy(ads, enc->status[i], 4);
456 			ads->common.bytes[0] |=
457 			    (enc->ichannels & (1 << i)) ?
458 			     SES_OBJSTAT_UNKNOWN :
459 			     SES_OBJSTAT_NOTINSTALLED;
460 		}
461 		ccb->ccb_h.status = CAM_REQ_CMP;
462 		goto out;
463 	}
464 
465 	/* SEMB SEND DIAGNOSTIC (2) */
466 	if (ccb->ataio.cmd.lba_low == 0x82 &&
467 	    ccb->ataio.cmd.features == 0x02 &&
468 	    ccb->ataio.cmd.sector_count >= (3 + enc->channels)) {
469 		ads0 = &page->elements[0].array_dev_slot;
470 		for (i = 0; i < enc->channels; i++) {
471 			ads = &page->elements[i + 1].array_dev_slot;
472 			if (ads->common.bytes[0] & SESCTL_CSEL) {
473 				enc->status[i][0] = 0;
474 				enc->status[i][1] =
475 				    ads->bytes[0] & 0x02;
476 				enc->status[i][2] =
477 				    ads->bytes[1] & (0x80 | SESCTL_RQSID);
478 				enc->status[i][3] =
479 				    ads->bytes[2] & SESCTL_RQSFLT;
480 				ahci_em_setleds(dev, i);
481 			} else if (ads0->common.bytes[0] & SESCTL_CSEL) {
482 				enc->status[i][0] = 0;
483 				enc->status[i][1] =
484 				    ads0->bytes[0] & 0x02;
485 				enc->status[i][2] =
486 				    ads0->bytes[1] & (0x80 | SESCTL_RQSID);
487 				enc->status[i][3] =
488 				    ads0->bytes[2] & SESCTL_RQSFLT;
489 				ahci_em_setleds(dev, i);
490 			}
491 		}
492 		ccb->ccb_h.status = CAM_REQ_CMP;
493 		goto out;
494 	}
495 
496 	/* SEMB RECEIVE DIAGNOSTIC RESULT (7) */
497 	if (ccb->ataio.cmd.lba_low == 0x02 &&
498 	    ccb->ataio.cmd.features == 0x07 &&
499 	    ccb->ataio.cmd.sector_count >= (3 + 3 * enc->channels)) {
500 		bzero(buf, ccb->ataio.dxfer_len);
501 		page->hdr.page_code = 0x07;
502 		scsi_ulto2b(4 + 4 + 12 * enc->channels,
503 		    page->hdr.length);
504 		for (i = 0; i < enc->channels; i++) {
505 			elmd = (struct ses_elm_desc_hdr *)&buf[8 + 4 + 12 * i];
506 			scsi_ulto2b(8, elmd->length);
507 			snprintf((char *)(elmd + 1), 9, "SLOT %03d", i);
508 		}
509 		ccb->ccb_h.status = CAM_REQ_CMP;
510 		goto out;
511 	}
512 
513 	ccb->ccb_h.status = CAM_REQ_INVALID;
514 out:
515 	xpt_done(ccb);
516 }
517 
518 static void
519 ahci_em_begin_transaction(device_t dev, union ccb *ccb)
520 {
521 	struct ahci_enclosure *enc;
522 	struct ata_res *res;
523 
524 	enc = device_get_softc(dev);
525 	res = &ccb->ataio.res;
526 	bzero(res, sizeof(*res));
527 	if ((ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) &&
528 	    (ccb->ataio.cmd.control & ATA_A_RESET)) {
529 		res->lba_high = 0xc3;
530 		res->lba_mid = 0x3c;
531 		ccb->ccb_h.status = CAM_REQ_CMP;
532 		xpt_done(ccb);
533 		return;
534 	}
535 
536 	if (enc->capsem & AHCI_EM_LED) {
537 		ahci_em_emulate_ses_on_led(dev, ccb);
538 		return;
539 	} else
540 		device_printf(dev, "Unsupported enclosure interface\n");
541 
542 	ccb->ccb_h.status = CAM_REQ_INVALID;
543 	xpt_done(ccb);
544 }
545 
546 static void
547 ahciemaction(struct cam_sim *sim, union ccb *ccb)
548 {
549 	device_t dev, parent;
550 	struct ahci_enclosure *enc;
551 
552 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
553 	    ("ahciemaction func_code=%x\n", ccb->ccb_h.func_code));
554 
555 	enc = cam_sim_softc(sim);
556 	dev = enc->dev;
557 	switch (ccb->ccb_h.func_code) {
558 	case XPT_ATA_IO:	/* Execute the requested I/O operation */
559 		if (ahci_check_ids(ccb))
560 			return;
561 		ahci_em_begin_transaction(dev, ccb);
562 		return;
563 	case XPT_RESET_BUS:		/* Reset the specified bus */
564 	case XPT_RESET_DEV:	/* Bus Device Reset the specified device */
565 		ahci_em_reset(dev);
566 		ccb->ccb_h.status = CAM_REQ_CMP;
567 		break;
568 	case XPT_PATH_INQ:		/* Path routing inquiry */
569 	{
570 		struct ccb_pathinq *cpi = &ccb->cpi;
571 
572 		parent = device_get_parent(dev);
573 		cpi->version_num = 1; /* XXX??? */
574 		cpi->hba_inquiry = PI_SDTR_ABLE;
575 		cpi->target_sprt = 0;
576 		cpi->hba_misc = PIM_SEQSCAN;
577 		cpi->hba_eng_cnt = 0;
578 		cpi->max_target = 0;
579 		cpi->max_lun = 0;
580 		cpi->initiator_id = 0;
581 		cpi->bus_id = cam_sim_bus(sim);
582 		cpi->base_transfer_speed = 150000;
583 		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
584 		strlcpy(cpi->hba_vid, "AHCI", HBA_IDLEN);
585 		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
586 		cpi->unit_number = cam_sim_unit(sim);
587 		cpi->transport = XPORT_SATA;
588 		cpi->transport_version = XPORT_VERSION_UNSPECIFIED;
589 		cpi->protocol = PROTO_ATA;
590 		cpi->protocol_version = PROTO_VERSION_UNSPECIFIED;
591 		cpi->maxio = MAXPHYS;
592 		cpi->hba_vendor = pci_get_vendor(parent);
593 		cpi->hba_device = pci_get_device(parent);
594 		cpi->hba_subvendor = pci_get_subvendor(parent);
595 		cpi->hba_subdevice = pci_get_subdevice(parent);
596 		cpi->ccb_h.status = CAM_REQ_CMP;
597 		break;
598 	}
599 	default:
600 		ccb->ccb_h.status = CAM_REQ_INVALID;
601 		break;
602 	}
603 	xpt_done(ccb);
604 }
605 
606 static void
607 ahciempoll(struct cam_sim *sim)
608 {
609 
610 }
611