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