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 */
59static void ahciemaction(struct cam_sim *sim, union ccb *ccb);
60static void ahciempoll(struct cam_sim *sim);
61static int ahci_em_reset(device_t dev);
62static void ahci_em_led(void *priv, int onoff);
63static void ahci_em_setleds(device_t dev, int c);
64
65static int
66ahci_em_probe(device_t dev)
67{
68
69	device_set_desc_copy(dev, "AHCI enclosure management bridge");
70	return (BUS_PROBE_DEFAULT);
71}
72
73static int
74ahci_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
186err3:
187	xpt_bus_deregister(cam_sim_path(enc->sim));
188err2:
189	cam_sim_free(enc->sim, /*free_devq*/TRUE);
190err1:
191	mtx_unlock(&enc->mtx);
192	if (enc->r_memr)
193		bus_release_resource(dev, SYS_RES_MEMORY, 2, enc->r_memr);
194err0:
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
202static int
203ahci_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
227static int
228ahci_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
248static int
249ahci_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
259static int
260ahci_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
271devclass_t ahciem_devclass;
272static 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};
280static driver_t ahciem_driver = {
281        "ahciem",
282        ahciem_methods,
283        sizeof(struct ahci_enclosure)
284};
285DRIVER_MODULE(ahciem, ahci, ahciem_driver, ahciem_devclass, NULL, NULL);
286
287static void
288ahci_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] & SESCTL_RQSACT)		/* Activity */
298		val |= (1 << 0);
299	if (enc->status[c][1] & SESCTL_RQSRR)		/* Rebuild */
300		val |= (1 << 6) | (1 << 3);
301	else if (enc->status[c][2] & SESCTL_RQSID)	/* Identification */
302		val |= (1 << 3);
303	else if (enc->status[c][3] & SESCTL_RQSFLT)	/* Fault */
304		val |= (1 << 6);
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
317static void
318ahci_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
348static int
349ahci_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
365static void
366ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb)
367{
368	struct ahci_enclosure *enc;
369	struct ahci_channel *ch;
370	struct ses_status_page *page;
371	struct ses_status_array_dev_slot *ads, *ads0;
372	struct ses_elm_desc_hdr *elmd;
373	struct ses_elm_addlstatus_eip_hdr *elma;
374	struct ses_elm_ata_hdr *elmb;
375	uint8_t *buf;
376	int i;
377
378	enc = device_get_softc(dev);
379	buf = ccb->ataio.data_ptr;
380
381	/* General request validation. */
382	if (ccb->ataio.cmd.command != ATA_SEP_ATTN ||
383	    ccb->ataio.dxfer_len < ccb->ataio.cmd.sector_count * 4) {
384		ccb->ccb_h.status = CAM_REQ_INVALID;
385		goto out;
386	}
387
388	/* SEMB IDENTIFY */
389	if (ccb->ataio.cmd.features == 0xEC &&
390	    ccb->ataio.cmd.sector_count >= 16) {
391		bzero(buf, ccb->ataio.dxfer_len);
392		buf[0] = 64;		/* Valid bytes. */
393		buf[2] = 0x30;		/* NAA Locally Assigned. */
394		strncpy(&buf[3], device_get_nameunit(dev), 7);
395		strncpy(&buf[10], "AHCI    ", SID_VENDOR_SIZE);
396		strncpy(&buf[18], "SGPIO Enclosure ", SID_PRODUCT_SIZE);
397		strncpy(&buf[34], "2.00", SID_REVISION_SIZE);
398		strncpy(&buf[39], "0001", 4);
399		strncpy(&buf[43], "S-E-S ", 6);
400		strncpy(&buf[49], "2.00", 4);
401		ccb->ccb_h.status = CAM_REQ_CMP;
402		goto out;
403	}
404
405	/* SEMB RECEIVE DIAGNOSTIC RESULT (0) */
406	page = (struct ses_status_page *)buf;
407	if (ccb->ataio.cmd.lba_low == 0x02 &&
408	    ccb->ataio.cmd.features == 0x00 &&
409	    ccb->ataio.cmd.sector_count >= 3) {
410		bzero(buf, ccb->ataio.dxfer_len);
411		page->hdr.page_code = 0;
412		scsi_ulto2b(5, page->hdr.length);
413		buf[4] = 0x00;
414		buf[5] = 0x01;
415		buf[6] = 0x02;
416		buf[7] = 0x07;
417		buf[8] = 0x0a;
418		ccb->ccb_h.status = CAM_REQ_CMP;
419		goto out;
420	}
421
422	/* SEMB RECEIVE DIAGNOSTIC RESULT (1) */
423	if (ccb->ataio.cmd.lba_low == 0x02 &&
424	    ccb->ataio.cmd.features == 0x01 &&
425	    ccb->ataio.cmd.sector_count >= 16) {
426		struct ses_enc_desc *ed;
427		struct ses_elm_type_desc *td;
428
429		bzero(buf, ccb->ataio.dxfer_len);
430		page->hdr.page_code = 0x01;
431		scsi_ulto2b(4 + sizeof(*ed) + sizeof(*td) + 11,
432		    page->hdr.length);
433		ed = (struct ses_enc_desc *)&buf[8];
434		ed->byte0 = 0x11;
435		ed->subenc_id = 0;
436		ed->num_types = 1;
437		ed->length = 36;
438		ed->logical_id[0] = 0x30;	/* NAA Locally Assigned. */
439		strncpy(&ed->logical_id[1], device_get_nameunit(dev), 7);
440		strncpy(ed->vendor_id, "AHCI    ", SID_VENDOR_SIZE);
441		strncpy(ed->product_id, "SGPIO Enclosure ", SID_PRODUCT_SIZE);
442		strncpy(ed->product_rev, "2.00", SID_REVISION_SIZE);
443		td = (struct ses_elm_type_desc *)ses_enc_desc_next(ed);
444		td->etype_elm_type = 0x17;
445		td->etype_maxelt = enc->channels;
446		td->etype_subenc = 0;
447		td->etype_txt_len = 11;
448		snprintf((char *)(td + 1), 12, "Drive Slots");
449		ccb->ccb_h.status = CAM_REQ_CMP;
450		goto out;
451	}
452
453	/* SEMB RECEIVE DIAGNOSTIC RESULT (2) */
454	if (ccb->ataio.cmd.lba_low == 0x02 &&
455	    ccb->ataio.cmd.features == 0x02 &&
456	    ccb->ataio.cmd.sector_count >= (3 + enc->channels)) {
457		bzero(buf, ccb->ataio.dxfer_len);
458		page->hdr.page_code = 0x02;
459		scsi_ulto2b(4 + 4 * (1 + enc->channels),
460		    page->hdr.length);
461		for (i = 0; i < enc->channels; i++) {
462			ads = &page->elements[i + 1].array_dev_slot;
463			memcpy(ads, enc->status[i], 4);
464			ch = ahci_getch(device_get_parent(dev), i);
465			if (ch == NULL) {
466				ads->common.bytes[0] |= SES_OBJSTAT_UNKNOWN;
467				continue;
468			}
469			if (ch->pm_present)
470				ads->common.bytes[0] |= SES_OBJSTAT_UNKNOWN;
471			else if (ch->devices)
472				ads->common.bytes[0] |= SES_OBJSTAT_OK;
473			else if (ch->disablephy)
474				ads->common.bytes[0] |= SES_OBJSTAT_NOTAVAIL;
475			else
476				ads->common.bytes[0] |= SES_OBJSTAT_NOTINSTALLED;
477			if (ch->disablephy)
478				ads->common.bytes[3] |= SESCTL_DEVOFF;
479			ahci_putch(ch);
480		}
481		ccb->ccb_h.status = CAM_REQ_CMP;
482		goto out;
483	}
484
485	/* SEMB SEND DIAGNOSTIC (2) */
486	if (ccb->ataio.cmd.lba_low == 0x82 &&
487	    ccb->ataio.cmd.features == 0x02 &&
488	    ccb->ataio.cmd.sector_count >= (3 + enc->channels)) {
489		ads0 = &page->elements[0].array_dev_slot;
490		for (i = 0; i < enc->channels; i++) {
491			ads = &page->elements[i + 1].array_dev_slot;
492			if (ads->common.bytes[0] & SESCTL_CSEL) {
493				enc->status[i][0] = 0;
494				enc->status[i][1] = ads->bytes[0] &
495				    SESCTL_RQSRR;
496				enc->status[i][2] = ads->bytes[1] &
497				    (SESCTL_RQSACT | SESCTL_RQSID);
498				enc->status[i][3] = ads->bytes[2] &
499				    SESCTL_RQSFLT;
500				ahci_em_setleds(dev, i);
501			} else if (ads0->common.bytes[0] & SESCTL_CSEL) {
502				enc->status[i][0] = 0;
503				enc->status[i][1] = ads0->bytes[0] &
504				    SESCTL_RQSRR;
505				enc->status[i][2] = ads0->bytes[1] &
506				    (SESCTL_RQSACT | SESCTL_RQSID);
507				enc->status[i][3] = ads0->bytes[2] &
508				    SESCTL_RQSFLT;
509				ahci_em_setleds(dev, i);
510			}
511		}
512		ccb->ccb_h.status = CAM_REQ_CMP;
513		goto out;
514	}
515
516	/* SEMB RECEIVE DIAGNOSTIC RESULT (7) */
517	if (ccb->ataio.cmd.lba_low == 0x02 &&
518	    ccb->ataio.cmd.features == 0x07 &&
519	    ccb->ataio.cmd.sector_count >= (6 + 3 * enc->channels)) {
520		bzero(buf, ccb->ataio.dxfer_len);
521		page->hdr.page_code = 0x07;
522		scsi_ulto2b(4 + 15 + 11 * enc->channels, page->hdr.length);
523		elmd = (struct ses_elm_desc_hdr *)&buf[8];
524		scsi_ulto2b(11, elmd->length);
525		snprintf((char *)(elmd + 1), 12, "Drive Slots");
526		for (i = 0; i < enc->channels; i++) {
527			elmd = (struct ses_elm_desc_hdr *)&buf[8 + 15 + 11 * i];
528			scsi_ulto2b(7, elmd->length);
529			snprintf((char *)(elmd + 1), 8, "Slot %02d", i);
530		}
531		ccb->ccb_h.status = CAM_REQ_CMP;
532		goto out;
533	}
534
535	/* SEMB RECEIVE DIAGNOSTIC RESULT (a) */
536	if (ccb->ataio.cmd.lba_low == 0x02 &&
537	    ccb->ataio.cmd.features == 0x0a &&
538	    ccb->ataio.cmd.sector_count >= (2 + 3 * enc->channels)) {
539		bzero(buf, ccb->ataio.dxfer_len);
540		page->hdr.page_code = 0x0a;
541		scsi_ulto2b(4 + (sizeof(*elma) + sizeof(*elmb)) * enc->channels,
542		    page->hdr.length);
543		for (i = 0; i < enc->channels; i++) {
544			elma = (struct ses_elm_addlstatus_eip_hdr *)&buf[
545			    8 + (sizeof(*elma) + sizeof(*elmb)) * i];
546			elma->base.byte0 = 0x10 | SPSP_PROTO_ATA;
547			elma->base.length = 2 + sizeof(*elmb);
548			elma->byte2 = 0x01;
549			elma->element_index = 1 + i;
550			ch = ahci_getch(device_get_parent(dev), i);
551			if (ch == NULL) {
552				elma->base.byte0 |= 0x80;
553				continue;
554			}
555			if (ch->devices == 0 || ch->pm_present)
556				elma->base.byte0 |= 0x80;
557			elmb = (struct ses_elm_ata_hdr *)(elma + 1);
558			scsi_ulto4b(cam_sim_path(ch->sim), elmb->bus);
559			scsi_ulto4b(0, elmb->target);
560			ahci_putch(ch);
561		}
562		ccb->ccb_h.status = CAM_REQ_CMP;
563		goto out;
564	}
565
566	ccb->ccb_h.status = CAM_REQ_INVALID;
567out:
568	xpt_done(ccb);
569}
570
571static void
572ahci_em_begin_transaction(device_t dev, union ccb *ccb)
573{
574	struct ahci_enclosure *enc;
575	struct ata_res *res;
576
577	enc = device_get_softc(dev);
578	res = &ccb->ataio.res;
579	bzero(res, sizeof(*res));
580	if ((ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) &&
581	    (ccb->ataio.cmd.control & ATA_A_RESET)) {
582		res->lba_high = 0xc3;
583		res->lba_mid = 0x3c;
584		ccb->ccb_h.status = CAM_REQ_CMP;
585		xpt_done(ccb);
586		return;
587	}
588
589	if (enc->capsem & AHCI_EM_LED) {
590		ahci_em_emulate_ses_on_led(dev, ccb);
591		return;
592	} else
593		device_printf(dev, "Unsupported enclosure interface\n");
594
595	ccb->ccb_h.status = CAM_REQ_INVALID;
596	xpt_done(ccb);
597}
598
599static void
600ahciemaction(struct cam_sim *sim, union ccb *ccb)
601{
602	device_t dev, parent;
603	struct ahci_enclosure *enc;
604
605	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
606	    ("ahciemaction func_code=%x\n", ccb->ccb_h.func_code));
607
608	enc = cam_sim_softc(sim);
609	dev = enc->dev;
610	switch (ccb->ccb_h.func_code) {
611	case XPT_ATA_IO:	/* Execute the requested I/O operation */
612		if (ahci_check_ids(ccb))
613			return;
614		ahci_em_begin_transaction(dev, ccb);
615		return;
616	case XPT_RESET_BUS:		/* Reset the specified bus */
617	case XPT_RESET_DEV:	/* Bus Device Reset the specified device */
618		ahci_em_reset(dev);
619		ccb->ccb_h.status = CAM_REQ_CMP;
620		break;
621	case XPT_PATH_INQ:		/* Path routing inquiry */
622	{
623		struct ccb_pathinq *cpi = &ccb->cpi;
624
625		parent = device_get_parent(dev);
626		cpi->version_num = 1; /* XXX??? */
627		cpi->hba_inquiry = PI_SDTR_ABLE;
628		cpi->target_sprt = 0;
629		cpi->hba_misc = PIM_SEQSCAN;
630		cpi->hba_eng_cnt = 0;
631		cpi->max_target = 0;
632		cpi->max_lun = 0;
633		cpi->initiator_id = 0;
634		cpi->bus_id = cam_sim_bus(sim);
635		cpi->base_transfer_speed = 150000;
636		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
637		strlcpy(cpi->hba_vid, "AHCI", HBA_IDLEN);
638		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
639		cpi->unit_number = cam_sim_unit(sim);
640		cpi->transport = XPORT_SATA;
641		cpi->transport_version = XPORT_VERSION_UNSPECIFIED;
642		cpi->protocol = PROTO_ATA;
643		cpi->protocol_version = PROTO_VERSION_UNSPECIFIED;
644		cpi->maxio = maxphys;
645		cpi->hba_vendor = pci_get_vendor(parent);
646		cpi->hba_device = pci_get_device(parent);
647		cpi->hba_subvendor = pci_get_subvendor(parent);
648		cpi->hba_subdevice = pci_get_subdevice(parent);
649		cpi->ccb_h.status = CAM_REQ_CMP;
650		break;
651	}
652	default:
653		ccb->ccb_h.status = CAM_REQ_INVALID;
654		break;
655	}
656	xpt_done(ccb);
657}
658
659static void
660ahciempoll(struct cam_sim *sim)
661{
662
663}
664