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