1238805Smav/*-
2238805Smav * Copyright (c) 2012 Alexander Motin <mav@FreeBSD.org>
3238805Smav * All rights reserved.
4238805Smav *
5238805Smav * Redistribution and use in source and binary forms, with or without
6238805Smav * modification, are permitted provided that the following conditions
7238805Smav * are met:
8238805Smav * 1. Redistributions of source code must retain the above copyright
9238805Smav *    notice, this list of conditions and the following disclaimer,
10238805Smav *    without modification, immediately at the beginning of the file.
11238805Smav * 2. Redistributions in binary form must reproduce the above copyright
12238805Smav *    notice, this list of conditions and the following disclaimer in the
13238805Smav *    documentation and/or other materials provided with the distribution.
14238805Smav *
15238805Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16238805Smav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17238805Smav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18238805Smav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19238805Smav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20238805Smav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21238805Smav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22238805Smav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23238805Smav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24238805Smav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25238805Smav */
26238805Smav
27238805Smav#include <sys/cdefs.h>
28238805Smav__FBSDID("$FreeBSD$");
29238805Smav
30238805Smav#include <sys/param.h>
31238805Smav#include <sys/module.h>
32238805Smav#include <sys/systm.h>
33238805Smav#include <sys/kernel.h>
34238805Smav#include <sys/bus.h>
35238805Smav#include <sys/conf.h>
36238805Smav#include <sys/endian.h>
37238805Smav#include <sys/malloc.h>
38238805Smav#include <sys/lock.h>
39238805Smav#include <sys/mutex.h>
40238805Smav#include <machine/stdarg.h>
41238805Smav#include <machine/resource.h>
42238805Smav#include <machine/bus.h>
43238805Smav#include <sys/rman.h>
44238805Smav#include <dev/led/led.h>
45238805Smav#include <dev/pci/pcivar.h>
46238805Smav#include <dev/pci/pcireg.h>
47238805Smav#include "ahci.h"
48238805Smav
49238805Smav#include <cam/cam.h>
50238805Smav#include <cam/cam_ccb.h>
51238805Smav#include <cam/cam_sim.h>
52238805Smav#include <cam/cam_xpt_sim.h>
53238805Smav#include <cam/cam_debug.h>
54238805Smav#include <cam/scsi/scsi_ses.h>
55238805Smav
56238805Smav/* local prototypes */
57238805Smavstatic void ahciemaction(struct cam_sim *sim, union ccb *ccb);
58238805Smavstatic void ahciempoll(struct cam_sim *sim);
59238805Smavstatic int ahci_em_reset(device_t dev);
60238805Smavstatic void ahci_em_led(void *priv, int onoff);
61238805Smavstatic void ahci_em_setleds(device_t dev, int c);
62238805Smav
63238805Smavstatic int
64238805Smavahci_em_probe(device_t dev)
65238805Smav{
66238805Smav
67238805Smav	device_set_desc_copy(dev, "AHCI enclosure management bridge");
68238805Smav	return (0);
69238805Smav}
70238805Smav
71238805Smavstatic int
72238805Smavahci_em_attach(device_t dev)
73238805Smav{
74238805Smav	device_t parent = device_get_parent(dev);
75238805Smav	struct ahci_controller *ctlr = device_get_softc(parent);
76238805Smav	struct ahci_enclosure *enc = device_get_softc(dev);
77238805Smav	struct cam_devq *devq;
78238805Smav	int i, c, rid, error;
79238805Smav	char buf[32];
80238805Smav
81238805Smav	enc->dev = dev;
82238805Smav	enc->quirks = ctlr->quirks;
83238805Smav	enc->channels = ctlr->channels;
84238805Smav	enc->ichannels = ctlr->ichannels;
85238805Smav	mtx_init(&enc->mtx, "AHCI enclosure lock", NULL, MTX_DEF);
86238805Smav	rid = 0;
87238805Smav	if (!(enc->r_memc = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
88238805Smav	    &rid, RF_ACTIVE)))
89238805Smav		return (ENXIO);
90241844Seadler	enc->capsem = ATA_INL(enc->r_memc, 0);
91238805Smav	rid = 1;
92238805Smav	if (!(enc->r_memt = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
93238805Smav	    &rid, RF_ACTIVE))) {
94238805Smav		error = ENXIO;
95238805Smav		goto err0;
96238805Smav	}
97238805Smav	if ((enc->capsem & (AHCI_EM_XMT | AHCI_EM_SMB)) == 0) {
98238805Smav		rid = 2;
99238805Smav		if (!(enc->r_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
100238805Smav		    &rid, RF_ACTIVE))) {
101238805Smav			error = ENXIO;
102238805Smav			goto err0;
103238805Smav		}
104238805Smav	} else
105238805Smav		enc->r_memr = NULL;
106238805Smav	mtx_lock(&enc->mtx);
107249089Smav	if (ahci_em_reset(dev) != 0) {
108249089Smav	    error = ENXIO;
109249089Smav	    goto err1;
110249089Smav	}
111238805Smav	rid = ATA_IRQ_RID;
112238805Smav	/* Create the device queue for our SIM. */
113238805Smav	devq = cam_simq_alloc(1);
114238805Smav	if (devq == NULL) {
115238805Smav		device_printf(dev, "Unable to allocate SIM queue\n");
116238805Smav		error = ENOMEM;
117238805Smav		goto err1;
118238805Smav	}
119238805Smav	/* Construct SIM entry */
120238805Smav	enc->sim = cam_sim_alloc(ahciemaction, ahciempoll, "ahciem", enc,
121238805Smav	    device_get_unit(dev), &enc->mtx,
122238805Smav	    1, 0, devq);
123238805Smav	if (enc->sim == NULL) {
124238805Smav		cam_simq_free(devq);
125238805Smav		device_printf(dev, "Unable to allocate SIM\n");
126238805Smav		error = ENOMEM;
127238805Smav		goto err1;
128238805Smav	}
129238805Smav	if (xpt_bus_register(enc->sim, dev, 0) != CAM_SUCCESS) {
130238805Smav		device_printf(dev, "unable to register xpt bus\n");
131238805Smav		error = ENXIO;
132238805Smav		goto err2;
133238805Smav	}
134238805Smav	if (xpt_create_path(&enc->path, /*periph*/NULL, cam_sim_path(enc->sim),
135238805Smav	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
136238805Smav		device_printf(dev, "Unable to create path\n");
137238805Smav		error = ENXIO;
138238805Smav		goto err3;
139238805Smav	}
140238805Smav	mtx_unlock(&enc->mtx);
141238805Smav	if (bootverbose) {
142238805Smav		device_printf(dev, "Caps:%s%s%s%s%s%s%s%s\n",
143238805Smav		    (enc->capsem & AHCI_EM_PM) ? " PM":"",
144238805Smav		    (enc->capsem & AHCI_EM_ALHD) ? " ALHD":"",
145238805Smav		    (enc->capsem & AHCI_EM_XMT) ? " XMT":"",
146238805Smav		    (enc->capsem & AHCI_EM_SMB) ? " SMB":"",
147238805Smav		    (enc->capsem & AHCI_EM_SGPIO) ? " SGPIO":"",
148238805Smav		    (enc->capsem & AHCI_EM_SES2) ? " SES-2":"",
149238805Smav		    (enc->capsem & AHCI_EM_SAFTE) ? " SAF-TE":"",
150238805Smav		    (enc->capsem & AHCI_EM_LED) ? " LED":"");
151238805Smav	}
152238805Smav	if ((enc->capsem & AHCI_EM_LED)) {
153238805Smav		for (c = 0; c < enc->channels; c++) {
154238805Smav			if ((enc->ichannels & (1 << c)) == 0)
155238805Smav				continue;
156238805Smav			for (i = 0; i < AHCI_NUM_LEDS; i++) {
157238805Smav				enc->leds[c * AHCI_NUM_LEDS + i].dev = dev;
158238805Smav				enc->leds[c * AHCI_NUM_LEDS + i].num =
159238805Smav				    c * AHCI_NUM_LEDS + i;
160238805Smav			}
161238805Smav			if ((enc->capsem & AHCI_EM_ALHD) == 0) {
162238805Smav				snprintf(buf, sizeof(buf), "%s.%d.act",
163238805Smav				    device_get_nameunit(parent), c);
164238805Smav				enc->leds[c * AHCI_NUM_LEDS + 0].led =
165238805Smav				    led_create(ahci_em_led,
166238805Smav				    &enc->leds[c * AHCI_NUM_LEDS + 0], buf);
167238805Smav			}
168238805Smav			snprintf(buf, sizeof(buf), "%s.%d.locate",
169238805Smav			    device_get_nameunit(parent), c);
170238805Smav			enc->leds[c * AHCI_NUM_LEDS + 1].led =
171238805Smav			    led_create(ahci_em_led,
172238805Smav			    &enc->leds[c * AHCI_NUM_LEDS + 1], buf);
173238805Smav			snprintf(buf, sizeof(buf), "%s.%d.fault",
174238805Smav			    device_get_nameunit(parent), c);
175238805Smav			enc->leds[c * AHCI_NUM_LEDS + 2].led =
176238805Smav			    led_create(ahci_em_led,
177238805Smav			    &enc->leds[c * AHCI_NUM_LEDS + 2], buf);
178238805Smav		}
179238805Smav	}
180238805Smav	return (0);
181238805Smav
182238805Smaverr3:
183238805Smav	xpt_bus_deregister(cam_sim_path(enc->sim));
184238805Smaverr2:
185238805Smav	cam_sim_free(enc->sim, /*free_devq*/TRUE);
186238805Smaverr1:
187238805Smav	mtx_unlock(&enc->mtx);
188238805Smav	if (enc->r_memr)
189238805Smav		bus_release_resource(dev, SYS_RES_MEMORY, 2, enc->r_memr);
190238805Smaverr0:
191238805Smav	if (enc->r_memt)
192238805Smav		bus_release_resource(dev, SYS_RES_MEMORY, 1, enc->r_memt);
193238805Smav	bus_release_resource(dev, SYS_RES_MEMORY, 0, enc->r_memc);
194238805Smav	mtx_destroy(&enc->mtx);
195238805Smav	return (error);
196238805Smav}
197238805Smav
198238805Smavstatic int
199238805Smavahci_em_detach(device_t dev)
200238805Smav{
201238805Smav	struct ahci_enclosure *enc = device_get_softc(dev);
202238805Smav	int i;
203238805Smav
204238805Smav	for (i = 0; i < enc->channels * AHCI_NUM_LEDS; i++) {
205238805Smav		if (enc->leds[i].led)
206238805Smav			led_destroy(enc->leds[i].led);
207238805Smav	}
208238805Smav	mtx_lock(&enc->mtx);
209238805Smav	xpt_async(AC_LOST_DEVICE, enc->path, NULL);
210238805Smav	xpt_free_path(enc->path);
211238805Smav	xpt_bus_deregister(cam_sim_path(enc->sim));
212238805Smav	cam_sim_free(enc->sim, /*free_devq*/TRUE);
213238805Smav	mtx_unlock(&enc->mtx);
214238805Smav
215238805Smav	bus_release_resource(dev, SYS_RES_MEMORY, 0, enc->r_memc);
216238805Smav	bus_release_resource(dev, SYS_RES_MEMORY, 1, enc->r_memt);
217238805Smav	if (enc->r_memr)
218238805Smav		bus_release_resource(dev, SYS_RES_MEMORY, 2, enc->r_memr);
219238805Smav	mtx_destroy(&enc->mtx);
220238805Smav	return (0);
221238805Smav}
222238805Smav
223238805Smavstatic int
224238805Smavahci_em_reset(device_t dev)
225238805Smav{
226238805Smav	struct ahci_enclosure *enc;
227238805Smav	int i, timeout;
228238805Smav
229238805Smav	enc = device_get_softc(dev);
230238805Smav	ATA_OUTL(enc->r_memc, 0, AHCI_EM_RST);
231238805Smav	timeout = 1000;
232238805Smav	while ((ATA_INL(enc->r_memc, 0) & AHCI_EM_RST) &&
233238805Smav	    --timeout > 0)
234238805Smav		DELAY(1000);
235238805Smav	if (timeout == 0) {
236238805Smav		device_printf(dev, "EM timeout\n");
237238805Smav		return (1);
238238805Smav	}
239238805Smav	for (i = 0; i < enc->channels; i++)
240238805Smav		ahci_em_setleds(dev, i);
241238805Smav	return (0);
242238805Smav}
243238805Smav
244238805Smavstatic int
245238805Smavahci_em_suspend(device_t dev)
246238805Smav{
247238805Smav	struct ahci_enclosure *enc = device_get_softc(dev);
248238805Smav
249238805Smav	mtx_lock(&enc->mtx);
250238805Smav	xpt_freeze_simq(enc->sim, 1);
251238805Smav	mtx_unlock(&enc->mtx);
252238805Smav	return (0);
253238805Smav}
254238805Smav
255238805Smavstatic int
256238805Smavahci_em_resume(device_t dev)
257238805Smav{
258238805Smav	struct ahci_enclosure *enc = device_get_softc(dev);
259238805Smav
260238805Smav	mtx_lock(&enc->mtx);
261238805Smav	ahci_em_reset(dev);
262238805Smav	xpt_release_simq(enc->sim, TRUE);
263238805Smav	mtx_unlock(&enc->mtx);
264238805Smav	return (0);
265238805Smav}
266238805Smav
267238805Smavdevclass_t ahciem_devclass;
268238805Smavstatic device_method_t ahciem_methods[] = {
269238805Smav	DEVMETHOD(device_probe,     ahci_em_probe),
270238805Smav	DEVMETHOD(device_attach,    ahci_em_attach),
271238805Smav	DEVMETHOD(device_detach,    ahci_em_detach),
272238805Smav	DEVMETHOD(device_suspend,   ahci_em_suspend),
273238805Smav	DEVMETHOD(device_resume,    ahci_em_resume),
274238805Smav	{ 0, 0 }
275238805Smav};
276238805Smavstatic driver_t ahciem_driver = {
277238805Smav        "ahciem",
278238805Smav        ahciem_methods,
279238805Smav        sizeof(struct ahci_enclosure)
280238805Smav};
281238805SmavDRIVER_MODULE(ahciem, ahci, ahciem_driver, ahciem_devclass, 0, 0);
282238805Smav
283238805Smavstatic void
284238805Smavahci_em_setleds(device_t dev, int c)
285238805Smav{
286238805Smav	struct ahci_enclosure *enc;
287238805Smav	int timeout;
288238805Smav	int16_t val;
289238805Smav
290238805Smav	enc = device_get_softc(dev);
291238805Smav
292238805Smav	val = 0;
293238805Smav	if (enc->status[c][2] & 0x80)		/* Activity */
294238805Smav		val |= (1 << 0);
295238805Smav	if (enc->status[c][2] & SESCTL_RQSID)	/* Identification */
296238805Smav		val |= (1 << 3);
297238805Smav	else if (enc->status[c][3] & SESCTL_RQSFLT)	/* Fault */
298238805Smav		val |= (1 << 6);
299238805Smav	else if (enc->status[c][1] & 0x02)		/* Rebuild */
300238805Smav		val |= (1 << 6) | (1 << 3);
301238805Smav
302238805Smav	timeout = 10000;
303238805Smav	while (ATA_INL(enc->r_memc, 0) & (AHCI_EM_TM | AHCI_EM_RST) &&
304238805Smav	    --timeout > 0)
305238805Smav		DELAY(100);
306238805Smav	if (timeout == 0)
307238805Smav		device_printf(dev, "Transmit timeout\n");
308238805Smav	ATA_OUTL(enc->r_memt, 0, (1 << 8) | (0 << 16) | (0 << 24));
309238805Smav	ATA_OUTL(enc->r_memt, 4, c | (0 << 8) | (val << 16));
310238805Smav	ATA_OUTL(enc->r_memc, 0, AHCI_EM_TM);
311238805Smav}
312238805Smav
313238805Smavstatic void
314238805Smavahci_em_led(void *priv, int onoff)
315238805Smav{
316238805Smav	struct ahci_led *led;
317238805Smav	struct ahci_enclosure *enc;
318238805Smav	int c, l;
319238805Smav
320238805Smav	led = (struct ahci_led *)priv;
321238805Smav	enc = device_get_softc(led->dev);
322238805Smav	c = led->num / AHCI_NUM_LEDS;
323238805Smav	l = led->num % AHCI_NUM_LEDS;
324238805Smav
325238805Smav	if (l == 0) {
326238805Smav		if (onoff)
327238805Smav			enc->status[c][2] |= 0x80;
328238805Smav		else
329238805Smav			enc->status[c][2] &= ~0x80;
330238805Smav	} else if (l == 1) {
331238805Smav		if (onoff)
332238805Smav			enc->status[c][2] |= SESCTL_RQSID;
333238805Smav		else
334238805Smav			enc->status[c][2] &= ~SESCTL_RQSID;
335238805Smav	} else if (l == 2) {
336238805Smav		if (onoff)
337238805Smav			enc->status[c][3] |= SESCTL_RQSFLT;
338238805Smav		else
339238805Smav			enc->status[c][3] &= SESCTL_RQSFLT;
340238805Smav	}
341238805Smav	ahci_em_setleds(led->dev, c);
342238805Smav}
343238805Smav
344238805Smavstatic int
345238805Smavahci_check_ids(device_t dev, union ccb *ccb)
346238805Smav{
347238805Smav
348238805Smav	if (ccb->ccb_h.target_id != 0) {
349238805Smav		ccb->ccb_h.status = CAM_TID_INVALID;
350238805Smav		xpt_done(ccb);
351238805Smav		return (-1);
352238805Smav	}
353238805Smav	if (ccb->ccb_h.target_lun != 0) {
354238805Smav		ccb->ccb_h.status = CAM_LUN_INVALID;
355238805Smav		xpt_done(ccb);
356238805Smav		return (-1);
357238805Smav	}
358238805Smav	return (0);
359238805Smav}
360238805Smav
361238805Smavstatic void
362238805Smavahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb)
363238805Smav{
364238805Smav	struct ahci_enclosure *enc;
365238805Smav	struct ses_status_page *page;
366238805Smav	struct ses_status_array_dev_slot *ads, *ads0;
367238805Smav	struct ses_elm_desc_hdr *elmd;
368238805Smav	uint8_t *buf;
369238805Smav	int i;
370238805Smav
371238805Smav	enc = device_get_softc(dev);
372238805Smav	buf = ccb->ataio.data_ptr;
373238805Smav
374238805Smav	/* General request validation. */
375238805Smav	if (ccb->ataio.cmd.command != ATA_SEP_ATTN ||
376238805Smav	    ccb->ataio.dxfer_len < ccb->ataio.cmd.sector_count * 4) {
377238805Smav		ccb->ccb_h.status = CAM_REQ_INVALID;
378238805Smav		goto out;
379238805Smav	}
380238805Smav
381238805Smav	/* SEMB IDENTIFY */
382238805Smav	if (ccb->ataio.cmd.features == 0xEC &&
383238805Smav	    ccb->ataio.cmd.sector_count >= 16) {
384238805Smav		bzero(buf, ccb->ataio.dxfer_len);
385238805Smav		buf[0] = 64;		/* Valid bytes. */
386239693Smav		buf[2] = 0x30;		/* NAA Locally Assigned. */
387239693Smav		strncpy(&buf[3], device_get_nameunit(dev), 7);
388238805Smav		strncpy(&buf[10], "AHCI    ", SID_VENDOR_SIZE);
389238805Smav		strncpy(&buf[18], "SGPIO Enclosure ", SID_PRODUCT_SIZE);
390238805Smav		strncpy(&buf[34], "1.00", SID_REVISION_SIZE);
391238805Smav		strncpy(&buf[39], "0001", 4);
392238805Smav		strncpy(&buf[43], "S-E-S ", 6);
393238805Smav		strncpy(&buf[49], "2.00", 4);
394238805Smav		ccb->ccb_h.status = CAM_REQ_CMP;
395238805Smav		goto out;
396238805Smav	}
397238805Smav
398238805Smav	/* SEMB RECEIVE DIAGNOSTIC RESULT (0) */
399238805Smav	page = (struct ses_status_page *)buf;
400238805Smav	if (ccb->ataio.cmd.lba_low == 0x02 &&
401238805Smav	    ccb->ataio.cmd.features == 0x00 &&
402238805Smav	    ccb->ataio.cmd.sector_count >= 2) {
403238805Smav		bzero(buf, ccb->ataio.dxfer_len);
404238805Smav		page->hdr.page_code = 0;
405242719Smav		scsi_ulto2b(4, page->hdr.length);
406238805Smav		buf[4] = 0;
407238805Smav		buf[5] = 1;
408238805Smav		buf[6] = 2;
409242719Smav		buf[7] = 7;
410238805Smav		ccb->ccb_h.status = CAM_REQ_CMP;
411238805Smav		goto out;
412238805Smav	}
413238805Smav
414238805Smav	/* SEMB RECEIVE DIAGNOSTIC RESULT (1) */
415238805Smav	if (ccb->ataio.cmd.lba_low == 0x02 &&
416238805Smav	    ccb->ataio.cmd.features == 0x01 &&
417238805Smav	    ccb->ataio.cmd.sector_count >= 13) {
418238805Smav		struct ses_enc_desc *ed;
419238805Smav		struct ses_elm_type_desc *td;
420238805Smav
421238805Smav		bzero(buf, ccb->ataio.dxfer_len);
422238805Smav		page->hdr.page_code = 0x01;
423238805Smav		scsi_ulto2b(4 + 4 + 36 + 4, page->hdr.length);
424238805Smav		ed = (struct ses_enc_desc *)&buf[8];
425238805Smav		ed->byte0 = 0x11;
426238805Smav		ed->subenc_id = 0;
427238805Smav		ed->num_types = 1;
428238805Smav		ed->length = 36;
429238805Smav		strncpy(ed->vendor_id, "AHCI    ", SID_VENDOR_SIZE);
430238805Smav		strncpy(ed->product_id, "SGPIO Enclosure ", SID_PRODUCT_SIZE);
431238805Smav		strncpy(ed->product_rev, "    ", SID_REVISION_SIZE);
432238805Smav		td = (struct ses_elm_type_desc *)ses_enc_desc_next(ed);
433238805Smav		td->etype_elm_type = 0x17;
434238805Smav		td->etype_maxelt = enc->channels;
435238805Smav		td->etype_subenc = 0;
436238805Smav		td->etype_txt_len = 0;
437238805Smav		ccb->ccb_h.status = CAM_REQ_CMP;
438238805Smav		goto out;
439238805Smav	}
440238805Smav
441238805Smav	/* SEMB RECEIVE DIAGNOSTIC RESULT (2) */
442238805Smav	if (ccb->ataio.cmd.lba_low == 0x02 &&
443238805Smav	    ccb->ataio.cmd.features == 0x02 &&
444238805Smav	    ccb->ataio.cmd.sector_count >= (3 + enc->channels)) {
445238805Smav		bzero(buf, ccb->ataio.dxfer_len);
446238805Smav		page->hdr.page_code = 0x02;
447238805Smav		scsi_ulto2b(4 + 4 * (1 + enc->channels),
448238805Smav		    page->hdr.length);
449238805Smav		for (i = 0; i < enc->channels; i++) {
450238805Smav			ads = &page->elements[i + 1].array_dev_slot;
451238805Smav			memcpy(ads, enc->status[i], 4);
452238805Smav			ads->common.bytes[0] |=
453238805Smav			    (enc->ichannels & (1 << i)) ?
454238805Smav			     SES_OBJSTAT_UNKNOWN :
455238805Smav			     SES_OBJSTAT_NOTINSTALLED;
456238805Smav		}
457238805Smav		ccb->ccb_h.status = CAM_REQ_CMP;
458238805Smav		goto out;
459238805Smav	}
460238805Smav
461238805Smav	/* SEMB SEND DIAGNOSTIC (2) */
462238805Smav	if (ccb->ataio.cmd.lba_low == 0x82 &&
463238805Smav	    ccb->ataio.cmd.features == 0x02 &&
464238805Smav	    ccb->ataio.cmd.sector_count >= (3 + enc->channels)) {
465238805Smav		ads0 = &page->elements[0].array_dev_slot;
466238805Smav		for (i = 0; i < enc->channels; i++) {
467238805Smav			ads = &page->elements[i + 1].array_dev_slot;
468238805Smav			if (ads->common.bytes[0] & SESCTL_CSEL) {
469238805Smav				enc->status[i][0] = 0;
470238805Smav				enc->status[i][1] =
471238805Smav				    ads->bytes[0] & 0x02;
472238805Smav				enc->status[i][2] =
473238805Smav				    ads->bytes[1] & (0x80 | SESCTL_RQSID);
474238805Smav				enc->status[i][3] =
475238805Smav				    ads->bytes[2] & SESCTL_RQSFLT;
476238805Smav				ahci_em_setleds(dev, i);
477238805Smav			} else if (ads0->common.bytes[0] & SESCTL_CSEL) {
478238805Smav				enc->status[i][0] = 0;
479238805Smav				enc->status[i][1] =
480238805Smav				    ads0->bytes[0] & 0x02;
481238805Smav				enc->status[i][2] =
482238805Smav				    ads0->bytes[1] & (0x80 | SESCTL_RQSID);
483238805Smav				enc->status[i][3] =
484238805Smav				    ads0->bytes[2] & SESCTL_RQSFLT;
485238805Smav				ahci_em_setleds(dev, i);
486238805Smav			}
487238805Smav		}
488238805Smav		ccb->ccb_h.status = CAM_REQ_CMP;
489238805Smav		goto out;
490238805Smav	}
491238805Smav
492238805Smav	/* SEMB RECEIVE DIAGNOSTIC RESULT (7) */
493238805Smav	if (ccb->ataio.cmd.lba_low == 0x02 &&
494238805Smav	    ccb->ataio.cmd.features == 0x07 &&
495238805Smav	    ccb->ataio.cmd.sector_count >= (3 + 3 * enc->channels)) {
496238805Smav		bzero(buf, ccb->ataio.dxfer_len);
497238805Smav		page->hdr.page_code = 0x07;
498238805Smav		scsi_ulto2b(4 + 4 + 12 * enc->channels,
499238805Smav		    page->hdr.length);
500238805Smav		for (i = 0; i < enc->channels; i++) {
501238805Smav			elmd = (struct ses_elm_desc_hdr *)&buf[8 + 4 + 12 * i];
502238805Smav			scsi_ulto2b(8, elmd->length);
503238805Smav			snprintf((char *)(elmd + 1), 9, "SLOT %03d", i);
504238805Smav		}
505238805Smav		ccb->ccb_h.status = CAM_REQ_CMP;
506238805Smav		goto out;
507238805Smav	}
508238805Smav
509238805Smav	ccb->ccb_h.status = CAM_REQ_INVALID;
510238805Smavout:
511238805Smav	xpt_done(ccb);
512238805Smav}
513238805Smav
514238805Smavstatic void
515238805Smavahci_em_begin_transaction(device_t dev, union ccb *ccb)
516238805Smav{
517238805Smav	struct ahci_enclosure *enc;
518238805Smav	struct ata_res *res;
519238805Smav
520238805Smav	enc = device_get_softc(dev);
521238805Smav	res = &ccb->ataio.res;
522238805Smav	bzero(res, sizeof(*res));
523238805Smav	if ((ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) &&
524238805Smav	    (ccb->ataio.cmd.control & ATA_A_RESET)) {
525238805Smav		res->lba_high = 0xc3;
526238805Smav		res->lba_mid = 0x3c;
527238805Smav		ccb->ccb_h.status = CAM_REQ_CMP;
528238805Smav		xpt_done(ccb);
529238805Smav		return;
530238805Smav	}
531238805Smav
532238805Smav	if (enc->capsem & AHCI_EM_LED) {
533238805Smav		ahci_em_emulate_ses_on_led(dev, ccb);
534238805Smav		return;
535238805Smav	} else
536238805Smav		device_printf(dev, "Unsupported enclosure interface\n");
537238805Smav
538238805Smav	ccb->ccb_h.status = CAM_REQ_INVALID;
539238805Smav	xpt_done(ccb);
540238805Smav}
541238805Smav
542238805Smavstatic void
543238805Smavahciemaction(struct cam_sim *sim, union ccb *ccb)
544238805Smav{
545238805Smav	device_t dev, parent;
546238805Smav	struct ahci_enclosure *enc;
547238805Smav
548238805Smav	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
549238805Smav	    ("ahciemaction func_code=%x\n", ccb->ccb_h.func_code));
550238805Smav
551238805Smav	enc = cam_sim_softc(sim);
552238805Smav	dev = enc->dev;
553238805Smav	switch (ccb->ccb_h.func_code) {
554238805Smav	case XPT_ATA_IO:	/* Execute the requested I/O operation */
555238805Smav		if (ahci_check_ids(dev, ccb))
556238805Smav			return;
557238805Smav		ahci_em_begin_transaction(dev, ccb);
558238805Smav		return;
559238805Smav	case XPT_RESET_BUS:		/* Reset the specified bus */
560238805Smav	case XPT_RESET_DEV:	/* Bus Device Reset the specified device */
561238805Smav		ahci_em_reset(dev);
562238805Smav		ccb->ccb_h.status = CAM_REQ_CMP;
563238805Smav		break;
564238805Smav	case XPT_PATH_INQ:		/* Path routing inquiry */
565238805Smav	{
566238805Smav		struct ccb_pathinq *cpi = &ccb->cpi;
567238805Smav
568238805Smav		parent = device_get_parent(dev);
569238805Smav		cpi->version_num = 1; /* XXX??? */
570238805Smav		cpi->hba_inquiry = PI_SDTR_ABLE;
571238805Smav		cpi->target_sprt = 0;
572238805Smav		cpi->hba_misc = PIM_SEQSCAN;
573238805Smav		cpi->hba_eng_cnt = 0;
574238805Smav		cpi->max_target = 0;
575238805Smav		cpi->max_lun = 0;
576238805Smav		cpi->initiator_id = 0;
577238805Smav		cpi->bus_id = cam_sim_bus(sim);
578238805Smav		cpi->base_transfer_speed = 150000;
579238805Smav		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
580238805Smav		strncpy(cpi->hba_vid, "AHCI", HBA_IDLEN);
581238805Smav		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
582238805Smav		cpi->unit_number = cam_sim_unit(sim);
583238805Smav		cpi->transport = XPORT_SATA;
584238805Smav		cpi->transport_version = XPORT_VERSION_UNSPECIFIED;
585238805Smav		cpi->protocol = PROTO_ATA;
586238805Smav		cpi->protocol_version = PROTO_VERSION_UNSPECIFIED;
587238805Smav		cpi->maxio = MAXPHYS;
588238805Smav		cpi->hba_vendor = pci_get_vendor(parent);
589238805Smav		cpi->hba_device = pci_get_device(parent);
590238805Smav		cpi->hba_subvendor = pci_get_subvendor(parent);
591238805Smav		cpi->hba_subdevice = pci_get_subdevice(parent);
592238805Smav		cpi->ccb_h.status = CAM_REQ_CMP;
593238805Smav		break;
594238805Smav	}
595238805Smav	default:
596238805Smav		ccb->ccb_h.status = CAM_REQ_INVALID;
597238805Smav		break;
598238805Smav	}
599238805Smav	xpt_done(ccb);
600238805Smav}
601238805Smav
602238805Smavstatic void
603238805Smavahciempoll(struct cam_sim *sim)
604238805Smav{
605238805Smav
606238805Smav}
607