xref: /freebsd-src/sys/dev/ahci/ahciem.c (revision a74b496507329665c6aa8d0ef2ea42c2fbd88c48)
1d19f06b3SAlexander Motin /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
4d19f06b3SAlexander Motin  * Copyright (c) 2012 Alexander Motin <mav@FreeBSD.org>
5d19f06b3SAlexander Motin  * All rights reserved.
6d19f06b3SAlexander Motin  *
7d19f06b3SAlexander Motin  * Redistribution and use in source and binary forms, with or without
8d19f06b3SAlexander Motin  * modification, are permitted provided that the following conditions
9d19f06b3SAlexander Motin  * are met:
10d19f06b3SAlexander Motin  * 1. Redistributions of source code must retain the above copyright
11d19f06b3SAlexander Motin  *    notice, this list of conditions and the following disclaimer,
12d19f06b3SAlexander Motin  *    without modification, immediately at the beginning of the file.
13d19f06b3SAlexander Motin  * 2. Redistributions in binary form must reproduce the above copyright
14d19f06b3SAlexander Motin  *    notice, this list of conditions and the following disclaimer in the
15d19f06b3SAlexander Motin  *    documentation and/or other materials provided with the distribution.
16d19f06b3SAlexander Motin  *
17d19f06b3SAlexander Motin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18d19f06b3SAlexander Motin  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19d19f06b3SAlexander Motin  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20d19f06b3SAlexander Motin  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21d19f06b3SAlexander Motin  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22d19f06b3SAlexander Motin  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23d19f06b3SAlexander Motin  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24d19f06b3SAlexander Motin  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25d19f06b3SAlexander Motin  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26d19f06b3SAlexander Motin  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27d19f06b3SAlexander Motin  */
28d19f06b3SAlexander Motin 
29d19f06b3SAlexander Motin #include <sys/param.h>
30d19f06b3SAlexander Motin #include <sys/module.h>
31d19f06b3SAlexander Motin #include <sys/systm.h>
32d19f06b3SAlexander Motin #include <sys/kernel.h>
33d19f06b3SAlexander Motin #include <sys/bus.h>
34d19f06b3SAlexander Motin #include <sys/conf.h>
35d19f06b3SAlexander Motin #include <sys/endian.h>
36d19f06b3SAlexander Motin #include <sys/malloc.h>
37d19f06b3SAlexander Motin #include <sys/lock.h>
38d19f06b3SAlexander Motin #include <sys/mutex.h>
39d19f06b3SAlexander Motin #include <machine/stdarg.h>
40d19f06b3SAlexander Motin #include <machine/resource.h>
41d19f06b3SAlexander Motin #include <machine/bus.h>
42d19f06b3SAlexander Motin #include <sys/rman.h>
43d19f06b3SAlexander Motin #include <dev/led/led.h>
44d19f06b3SAlexander Motin #include <dev/pci/pcivar.h>
45d19f06b3SAlexander Motin #include <dev/pci/pcireg.h>
46d19f06b3SAlexander Motin #include "ahci.h"
47d19f06b3SAlexander Motin 
48d19f06b3SAlexander Motin #include <cam/cam.h>
49d19f06b3SAlexander Motin #include <cam/cam_ccb.h>
50d19f06b3SAlexander Motin #include <cam/cam_sim.h>
51d19f06b3SAlexander Motin #include <cam/cam_xpt_sim.h>
52d19f06b3SAlexander Motin #include <cam/cam_debug.h>
53d19f06b3SAlexander Motin #include <cam/scsi/scsi_ses.h>
54d19f06b3SAlexander Motin 
55d19f06b3SAlexander Motin /* local prototypes */
56d19f06b3SAlexander Motin static void ahciemaction(struct cam_sim *sim, union ccb *ccb);
57d19f06b3SAlexander Motin static void ahciempoll(struct cam_sim *sim);
58d19f06b3SAlexander Motin static int ahci_em_reset(device_t dev);
59d19f06b3SAlexander Motin static void ahci_em_led(void *priv, int onoff);
60d19f06b3SAlexander Motin static void ahci_em_setleds(device_t dev, int c);
61d19f06b3SAlexander Motin 
62d19f06b3SAlexander Motin static int
ahci_em_probe(device_t dev)63d19f06b3SAlexander Motin ahci_em_probe(device_t dev)
64d19f06b3SAlexander Motin {
65d19f06b3SAlexander Motin 
66*a74b4965SMark Johnston 	device_set_desc(dev, "AHCI enclosure management bridge");
673036de3cSAlexander Motin 	return (BUS_PROBE_DEFAULT);
68d19f06b3SAlexander Motin }
69d19f06b3SAlexander Motin 
70d19f06b3SAlexander Motin static int
ahci_em_attach(device_t dev)71d19f06b3SAlexander Motin ahci_em_attach(device_t dev)
72d19f06b3SAlexander Motin {
73d19f06b3SAlexander Motin 	device_t parent = device_get_parent(dev);
74d19f06b3SAlexander Motin 	struct ahci_controller *ctlr = device_get_softc(parent);
75d19f06b3SAlexander Motin 	struct ahci_enclosure *enc = device_get_softc(dev);
76d19f06b3SAlexander Motin 	struct cam_devq *devq;
77d19f06b3SAlexander Motin 	int i, c, rid, error;
78d19f06b3SAlexander Motin 	char buf[32];
79d19f06b3SAlexander Motin 
80d19f06b3SAlexander Motin 	enc->dev = dev;
81d19f06b3SAlexander Motin 	enc->quirks = ctlr->quirks;
82d19f06b3SAlexander Motin 	enc->channels = ctlr->channels;
83d19f06b3SAlexander Motin 	enc->ichannels = ctlr->ichannels;
84d19f06b3SAlexander Motin 	mtx_init(&enc->mtx, "AHCI enclosure lock", NULL, MTX_DEF);
85d19f06b3SAlexander Motin 	rid = 0;
869aba757eSAlexander Motin 	if ((enc->r_memc = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
879aba757eSAlexander Motin 	    &rid, RF_ACTIVE)) != NULL) {
88db702c59SEitan Adler 		enc->capsem = ATA_INL(enc->r_memc, 0);
89d19f06b3SAlexander Motin 		rid = 1;
90d19f06b3SAlexander Motin 		if (!(enc->r_memt = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
91d19f06b3SAlexander Motin 		    &rid, RF_ACTIVE))) {
92d19f06b3SAlexander Motin 			error = ENXIO;
93d19f06b3SAlexander Motin 			goto err0;
94d19f06b3SAlexander Motin 		}
959aba757eSAlexander Motin 	} else {
969aba757eSAlexander Motin 		enc->capsem = AHCI_EM_XMT | AHCI_EM_SMB | AHCI_EM_LED;
979aba757eSAlexander Motin 		enc->r_memt = NULL;
989aba757eSAlexander Motin 	}
99d19f06b3SAlexander Motin 	if ((enc->capsem & (AHCI_EM_XMT | AHCI_EM_SMB)) == 0) {
100d19f06b3SAlexander Motin 		rid = 2;
101d19f06b3SAlexander Motin 		if (!(enc->r_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
102d19f06b3SAlexander Motin 		    &rid, RF_ACTIVE))) {
103d19f06b3SAlexander Motin 			error = ENXIO;
104d19f06b3SAlexander Motin 			goto err0;
105d19f06b3SAlexander Motin 		}
106d19f06b3SAlexander Motin 	} else
107d19f06b3SAlexander Motin 		enc->r_memr = NULL;
108d19f06b3SAlexander Motin 	mtx_lock(&enc->mtx);
109c6eeee5eSAlexander Motin 	if (ahci_em_reset(dev) != 0) {
110c6eeee5eSAlexander Motin 	    error = ENXIO;
111c6eeee5eSAlexander Motin 	    goto err1;
112c6eeee5eSAlexander Motin 	}
113d19f06b3SAlexander Motin 	rid = ATA_IRQ_RID;
114d19f06b3SAlexander Motin 	/* Create the device queue for our SIM. */
115d19f06b3SAlexander Motin 	devq = cam_simq_alloc(1);
116d19f06b3SAlexander Motin 	if (devq == NULL) {
117d19f06b3SAlexander Motin 		device_printf(dev, "Unable to allocate SIM queue\n");
118d19f06b3SAlexander Motin 		error = ENOMEM;
119d19f06b3SAlexander Motin 		goto err1;
120d19f06b3SAlexander Motin 	}
121d19f06b3SAlexander Motin 	/* Construct SIM entry */
122d19f06b3SAlexander Motin 	enc->sim = cam_sim_alloc(ahciemaction, ahciempoll, "ahciem", enc,
123d19f06b3SAlexander Motin 	    device_get_unit(dev), &enc->mtx,
124d19f06b3SAlexander Motin 	    1, 0, devq);
125d19f06b3SAlexander Motin 	if (enc->sim == NULL) {
126d19f06b3SAlexander Motin 		cam_simq_free(devq);
127d19f06b3SAlexander Motin 		device_printf(dev, "Unable to allocate SIM\n");
128d19f06b3SAlexander Motin 		error = ENOMEM;
129d19f06b3SAlexander Motin 		goto err1;
130d19f06b3SAlexander Motin 	}
131d19f06b3SAlexander Motin 	if (xpt_bus_register(enc->sim, dev, 0) != CAM_SUCCESS) {
132d19f06b3SAlexander Motin 		device_printf(dev, "unable to register xpt bus\n");
133d19f06b3SAlexander Motin 		error = ENXIO;
134d19f06b3SAlexander Motin 		goto err2;
135d19f06b3SAlexander Motin 	}
136d19f06b3SAlexander Motin 	if (xpt_create_path(&enc->path, /*periph*/NULL, cam_sim_path(enc->sim),
137d19f06b3SAlexander Motin 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
138d19f06b3SAlexander Motin 		device_printf(dev, "Unable to create path\n");
139d19f06b3SAlexander Motin 		error = ENXIO;
140d19f06b3SAlexander Motin 		goto err3;
141d19f06b3SAlexander Motin 	}
142d19f06b3SAlexander Motin 	mtx_unlock(&enc->mtx);
143d19f06b3SAlexander Motin 	if (bootverbose) {
144d19f06b3SAlexander Motin 		device_printf(dev, "Caps:%s%s%s%s%s%s%s%s\n",
145d19f06b3SAlexander Motin 		    (enc->capsem & AHCI_EM_PM) ? " PM":"",
146d19f06b3SAlexander Motin 		    (enc->capsem & AHCI_EM_ALHD) ? " ALHD":"",
147d19f06b3SAlexander Motin 		    (enc->capsem & AHCI_EM_XMT) ? " XMT":"",
148d19f06b3SAlexander Motin 		    (enc->capsem & AHCI_EM_SMB) ? " SMB":"",
149d19f06b3SAlexander Motin 		    (enc->capsem & AHCI_EM_SGPIO) ? " SGPIO":"",
150d19f06b3SAlexander Motin 		    (enc->capsem & AHCI_EM_SES2) ? " SES-2":"",
151d19f06b3SAlexander Motin 		    (enc->capsem & AHCI_EM_SAFTE) ? " SAF-TE":"",
152d19f06b3SAlexander Motin 		    (enc->capsem & AHCI_EM_LED) ? " LED":"");
153d19f06b3SAlexander Motin 	}
154d19f06b3SAlexander Motin 	if ((enc->capsem & AHCI_EM_LED)) {
155d19f06b3SAlexander Motin 		for (c = 0; c < enc->channels; c++) {
156d19f06b3SAlexander Motin 			if ((enc->ichannels & (1 << c)) == 0)
157d19f06b3SAlexander Motin 				continue;
158d19f06b3SAlexander Motin 			for (i = 0; i < AHCI_NUM_LEDS; i++) {
159d19f06b3SAlexander Motin 				enc->leds[c * AHCI_NUM_LEDS + i].dev = dev;
160d19f06b3SAlexander Motin 				enc->leds[c * AHCI_NUM_LEDS + i].num =
161d19f06b3SAlexander Motin 				    c * AHCI_NUM_LEDS + i;
162d19f06b3SAlexander Motin 			}
163d19f06b3SAlexander Motin 			if ((enc->capsem & AHCI_EM_ALHD) == 0) {
164d19f06b3SAlexander Motin 				snprintf(buf, sizeof(buf), "%s.%d.act",
165d19f06b3SAlexander Motin 				    device_get_nameunit(parent), c);
166d19f06b3SAlexander Motin 				enc->leds[c * AHCI_NUM_LEDS + 0].led =
167d19f06b3SAlexander Motin 				    led_create(ahci_em_led,
168d19f06b3SAlexander Motin 				    &enc->leds[c * AHCI_NUM_LEDS + 0], buf);
169d19f06b3SAlexander Motin 			}
170d19f06b3SAlexander Motin 			snprintf(buf, sizeof(buf), "%s.%d.locate",
171d19f06b3SAlexander Motin 			    device_get_nameunit(parent), c);
172d19f06b3SAlexander Motin 			enc->leds[c * AHCI_NUM_LEDS + 1].led =
173d19f06b3SAlexander Motin 			    led_create(ahci_em_led,
174d19f06b3SAlexander Motin 			    &enc->leds[c * AHCI_NUM_LEDS + 1], buf);
175d19f06b3SAlexander Motin 			snprintf(buf, sizeof(buf), "%s.%d.fault",
176d19f06b3SAlexander Motin 			    device_get_nameunit(parent), c);
177d19f06b3SAlexander Motin 			enc->leds[c * AHCI_NUM_LEDS + 2].led =
178d19f06b3SAlexander Motin 			    led_create(ahci_em_led,
179d19f06b3SAlexander Motin 			    &enc->leds[c * AHCI_NUM_LEDS + 2], buf);
180d19f06b3SAlexander Motin 		}
181d19f06b3SAlexander Motin 	}
182d19f06b3SAlexander Motin 	return (0);
183d19f06b3SAlexander Motin 
184d19f06b3SAlexander Motin err3:
185d19f06b3SAlexander Motin 	xpt_bus_deregister(cam_sim_path(enc->sim));
186d19f06b3SAlexander Motin err2:
187d19f06b3SAlexander Motin 	cam_sim_free(enc->sim, /*free_devq*/TRUE);
188d19f06b3SAlexander Motin err1:
189d19f06b3SAlexander Motin 	mtx_unlock(&enc->mtx);
190d19f06b3SAlexander Motin 	if (enc->r_memr)
191d19f06b3SAlexander Motin 		bus_release_resource(dev, SYS_RES_MEMORY, 2, enc->r_memr);
192d19f06b3SAlexander Motin err0:
193d19f06b3SAlexander Motin 	if (enc->r_memt)
194d19f06b3SAlexander Motin 		bus_release_resource(dev, SYS_RES_MEMORY, 1, enc->r_memt);
1959aba757eSAlexander Motin 	if (enc->r_memc)
196d19f06b3SAlexander Motin 		bus_release_resource(dev, SYS_RES_MEMORY, 0, enc->r_memc);
197d19f06b3SAlexander Motin 	mtx_destroy(&enc->mtx);
198d19f06b3SAlexander Motin 	return (error);
199d19f06b3SAlexander Motin }
200d19f06b3SAlexander Motin 
201d19f06b3SAlexander Motin static int
ahci_em_detach(device_t dev)202d19f06b3SAlexander Motin ahci_em_detach(device_t dev)
203d19f06b3SAlexander Motin {
204d19f06b3SAlexander Motin 	struct ahci_enclosure *enc = device_get_softc(dev);
205d19f06b3SAlexander Motin 	int i;
206d19f06b3SAlexander Motin 
207d19f06b3SAlexander Motin 	for (i = 0; i < enc->channels * AHCI_NUM_LEDS; i++) {
208d19f06b3SAlexander Motin 		if (enc->leds[i].led)
209d19f06b3SAlexander Motin 			led_destroy(enc->leds[i].led);
210d19f06b3SAlexander Motin 	}
211d19f06b3SAlexander Motin 	mtx_lock(&enc->mtx);
212d19f06b3SAlexander Motin 	xpt_async(AC_LOST_DEVICE, enc->path, NULL);
213d19f06b3SAlexander Motin 	xpt_free_path(enc->path);
214d19f06b3SAlexander Motin 	xpt_bus_deregister(cam_sim_path(enc->sim));
215d19f06b3SAlexander Motin 	cam_sim_free(enc->sim, /*free_devq*/TRUE);
216d19f06b3SAlexander Motin 	mtx_unlock(&enc->mtx);
217d19f06b3SAlexander Motin 
2189aba757eSAlexander Motin 	if (enc->r_memc)
219d19f06b3SAlexander Motin 		bus_release_resource(dev, SYS_RES_MEMORY, 0, enc->r_memc);
2209aba757eSAlexander Motin 	if (enc->r_memt)
221d19f06b3SAlexander Motin 		bus_release_resource(dev, SYS_RES_MEMORY, 1, enc->r_memt);
222d19f06b3SAlexander Motin 	if (enc->r_memr)
223d19f06b3SAlexander Motin 		bus_release_resource(dev, SYS_RES_MEMORY, 2, enc->r_memr);
224d19f06b3SAlexander Motin 	mtx_destroy(&enc->mtx);
225d19f06b3SAlexander Motin 	return (0);
226d19f06b3SAlexander Motin }
227d19f06b3SAlexander Motin 
228d19f06b3SAlexander Motin static int
ahci_em_reset(device_t dev)229d19f06b3SAlexander Motin ahci_em_reset(device_t dev)
230d19f06b3SAlexander Motin {
231d19f06b3SAlexander Motin 	struct ahci_enclosure *enc;
232d19f06b3SAlexander Motin 	int i, timeout;
233d19f06b3SAlexander Motin 
234d19f06b3SAlexander Motin 	enc = device_get_softc(dev);
2359aba757eSAlexander Motin 	if (enc->r_memc == NULL)
2369aba757eSAlexander Motin 		return (0);
237d19f06b3SAlexander Motin 	ATA_OUTL(enc->r_memc, 0, AHCI_EM_RST);
238d19f06b3SAlexander Motin 	timeout = 1000;
239d19f06b3SAlexander Motin 	while ((ATA_INL(enc->r_memc, 0) & AHCI_EM_RST) &&
240d19f06b3SAlexander Motin 	    --timeout > 0)
241d19f06b3SAlexander Motin 		DELAY(1000);
242d19f06b3SAlexander Motin 	if (timeout == 0) {
243d19f06b3SAlexander Motin 		device_printf(dev, "EM timeout\n");
244d19f06b3SAlexander Motin 		return (1);
245d19f06b3SAlexander Motin 	}
246d19f06b3SAlexander Motin 	for (i = 0; i < enc->channels; i++)
247d19f06b3SAlexander Motin 		ahci_em_setleds(dev, i);
248d19f06b3SAlexander Motin 	return (0);
249d19f06b3SAlexander Motin }
250d19f06b3SAlexander Motin 
251d19f06b3SAlexander Motin static int
ahci_em_suspend(device_t dev)252d19f06b3SAlexander Motin ahci_em_suspend(device_t dev)
253d19f06b3SAlexander Motin {
254d19f06b3SAlexander Motin 	struct ahci_enclosure *enc = device_get_softc(dev);
255d19f06b3SAlexander Motin 
256d19f06b3SAlexander Motin 	mtx_lock(&enc->mtx);
257d19f06b3SAlexander Motin 	xpt_freeze_simq(enc->sim, 1);
258d19f06b3SAlexander Motin 	mtx_unlock(&enc->mtx);
259d19f06b3SAlexander Motin 	return (0);
260d19f06b3SAlexander Motin }
261d19f06b3SAlexander Motin 
262d19f06b3SAlexander Motin static int
ahci_em_resume(device_t dev)263d19f06b3SAlexander Motin ahci_em_resume(device_t dev)
264d19f06b3SAlexander Motin {
265d19f06b3SAlexander Motin 	struct ahci_enclosure *enc = device_get_softc(dev);
266d19f06b3SAlexander Motin 
267d19f06b3SAlexander Motin 	mtx_lock(&enc->mtx);
268d19f06b3SAlexander Motin 	ahci_em_reset(dev);
269d19f06b3SAlexander Motin 	xpt_release_simq(enc->sim, TRUE);
270d19f06b3SAlexander Motin 	mtx_unlock(&enc->mtx);
271d19f06b3SAlexander Motin 	return (0);
272d19f06b3SAlexander Motin }
273d19f06b3SAlexander Motin 
274d19f06b3SAlexander Motin static device_method_t ahciem_methods[] = {
275d19f06b3SAlexander Motin 	DEVMETHOD(device_probe,     ahci_em_probe),
276d19f06b3SAlexander Motin 	DEVMETHOD(device_attach,    ahci_em_attach),
277d19f06b3SAlexander Motin 	DEVMETHOD(device_detach,    ahci_em_detach),
278d19f06b3SAlexander Motin 	DEVMETHOD(device_suspend,   ahci_em_suspend),
279d19f06b3SAlexander Motin 	DEVMETHOD(device_resume,    ahci_em_resume),
28021190895SMarius Strobl 	DEVMETHOD_END
281d19f06b3SAlexander Motin };
282d19f06b3SAlexander Motin static driver_t ahciem_driver = {
283d19f06b3SAlexander Motin         "ahciem",
284d19f06b3SAlexander Motin         ahciem_methods,
285d19f06b3SAlexander Motin         sizeof(struct ahci_enclosure)
286d19f06b3SAlexander Motin };
28707c15a9dSJohn Baldwin DRIVER_MODULE(ahciem, ahci, ahciem_driver, NULL, NULL);
288d19f06b3SAlexander Motin 
289d19f06b3SAlexander Motin static void
ahci_em_setleds(device_t dev,int c)290d19f06b3SAlexander Motin ahci_em_setleds(device_t dev, int c)
291d19f06b3SAlexander Motin {
292d19f06b3SAlexander Motin 	struct ahci_enclosure *enc;
293d19f06b3SAlexander Motin 	int timeout;
294d19f06b3SAlexander Motin 	int16_t val;
295d19f06b3SAlexander Motin 
296d19f06b3SAlexander Motin 	enc = device_get_softc(dev);
2979aba757eSAlexander Motin 	if (enc->r_memc == NULL)
2989aba757eSAlexander Motin 		return;
299d19f06b3SAlexander Motin 
300d19f06b3SAlexander Motin 	val = 0;
30153f5ac13SAlexander Motin 	if (enc->status[c][2] & SESCTL_RQSACT)		/* Activity */
302d19f06b3SAlexander Motin 		val |= (1 << 0);
30353f5ac13SAlexander Motin 	if (enc->status[c][1] & SESCTL_RQSRR)		/* Rebuild */
30453f5ac13SAlexander Motin 		val |= (1 << 6) | (1 << 3);
30553f5ac13SAlexander Motin 	else if (enc->status[c][2] & SESCTL_RQSID)	/* Identification */
306d19f06b3SAlexander Motin 		val |= (1 << 3);
307d19f06b3SAlexander Motin 	else if (enc->status[c][3] & SESCTL_RQSFLT)	/* Fault */
308d19f06b3SAlexander Motin 		val |= (1 << 6);
309d19f06b3SAlexander Motin 
310d19f06b3SAlexander Motin 	timeout = 10000;
311d19f06b3SAlexander Motin 	while (ATA_INL(enc->r_memc, 0) & (AHCI_EM_TM | AHCI_EM_RST) &&
312d19f06b3SAlexander Motin 	    --timeout > 0)
313d19f06b3SAlexander Motin 		DELAY(100);
314d19f06b3SAlexander Motin 	if (timeout == 0)
315d19f06b3SAlexander Motin 		device_printf(dev, "Transmit timeout\n");
316d19f06b3SAlexander Motin 	ATA_OUTL(enc->r_memt, 0, (1 << 8) | (0 << 16) | (0 << 24));
317d19f06b3SAlexander Motin 	ATA_OUTL(enc->r_memt, 4, c | (0 << 8) | (val << 16));
318d19f06b3SAlexander Motin 	ATA_OUTL(enc->r_memc, 0, AHCI_EM_TM);
319d19f06b3SAlexander Motin }
320d19f06b3SAlexander Motin 
321d19f06b3SAlexander Motin static void
ahci_em_led(void * priv,int onoff)322d19f06b3SAlexander Motin ahci_em_led(void *priv, int onoff)
323d19f06b3SAlexander Motin {
324d19f06b3SAlexander Motin 	struct ahci_led *led;
325d19f06b3SAlexander Motin 	struct ahci_enclosure *enc;
326d19f06b3SAlexander Motin 	int c, l;
327d19f06b3SAlexander Motin 
328d19f06b3SAlexander Motin 	led = (struct ahci_led *)priv;
329d19f06b3SAlexander Motin 	enc = device_get_softc(led->dev);
330d19f06b3SAlexander Motin 	c = led->num / AHCI_NUM_LEDS;
331d19f06b3SAlexander Motin 	l = led->num % AHCI_NUM_LEDS;
332d19f06b3SAlexander Motin 
333d19f06b3SAlexander Motin 	if (l == 0) {
334d19f06b3SAlexander Motin 		if (onoff)
335d19f06b3SAlexander Motin 			enc->status[c][2] |= 0x80;
336d19f06b3SAlexander Motin 		else
337d19f06b3SAlexander Motin 			enc->status[c][2] &= ~0x80;
338d19f06b3SAlexander Motin 	} else if (l == 1) {
339d19f06b3SAlexander Motin 		if (onoff)
340d19f06b3SAlexander Motin 			enc->status[c][2] |= SESCTL_RQSID;
341d19f06b3SAlexander Motin 		else
342d19f06b3SAlexander Motin 			enc->status[c][2] &= ~SESCTL_RQSID;
343d19f06b3SAlexander Motin 	} else if (l == 2) {
344d19f06b3SAlexander Motin 		if (onoff)
345d19f06b3SAlexander Motin 			enc->status[c][3] |= SESCTL_RQSFLT;
346d19f06b3SAlexander Motin 		else
347d19f06b3SAlexander Motin 			enc->status[c][3] &= SESCTL_RQSFLT;
348d19f06b3SAlexander Motin 	}
349d19f06b3SAlexander Motin 	ahci_em_setleds(led->dev, c);
350d19f06b3SAlexander Motin }
351d19f06b3SAlexander Motin 
352d19f06b3SAlexander Motin static int
ahci_check_ids(union ccb * ccb)353fcd7f38fSAlexander Motin ahci_check_ids(union ccb *ccb)
354d19f06b3SAlexander Motin {
355d19f06b3SAlexander Motin 
356d19f06b3SAlexander Motin 	if (ccb->ccb_h.target_id != 0) {
357d19f06b3SAlexander Motin 		ccb->ccb_h.status = CAM_TID_INVALID;
358d19f06b3SAlexander Motin 		xpt_done(ccb);
359d19f06b3SAlexander Motin 		return (-1);
360d19f06b3SAlexander Motin 	}
361d19f06b3SAlexander Motin 	if (ccb->ccb_h.target_lun != 0) {
362d19f06b3SAlexander Motin 		ccb->ccb_h.status = CAM_LUN_INVALID;
363d19f06b3SAlexander Motin 		xpt_done(ccb);
364d19f06b3SAlexander Motin 		return (-1);
365d19f06b3SAlexander Motin 	}
366d19f06b3SAlexander Motin 	return (0);
367d19f06b3SAlexander Motin }
368d19f06b3SAlexander Motin 
369d19f06b3SAlexander Motin static void
ahci_em_emulate_ses_on_led(device_t dev,union ccb * ccb)370d19f06b3SAlexander Motin ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb)
371d19f06b3SAlexander Motin {
372d19f06b3SAlexander Motin 	struct ahci_enclosure *enc;
37353f5ac13SAlexander Motin 	struct ahci_channel *ch;
374d19f06b3SAlexander Motin 	struct ses_status_page *page;
375d19f06b3SAlexander Motin 	struct ses_status_array_dev_slot *ads, *ads0;
376d19f06b3SAlexander Motin 	struct ses_elm_desc_hdr *elmd;
37753f5ac13SAlexander Motin 	struct ses_elm_addlstatus_eip_hdr *elma;
37853f5ac13SAlexander Motin 	struct ses_elm_ata_hdr *elmb;
379d19f06b3SAlexander Motin 	uint8_t *buf;
380d19f06b3SAlexander Motin 	int i;
381d19f06b3SAlexander Motin 
382d19f06b3SAlexander Motin 	enc = device_get_softc(dev);
383d19f06b3SAlexander Motin 	buf = ccb->ataio.data_ptr;
384d19f06b3SAlexander Motin 
385d19f06b3SAlexander Motin 	/* General request validation. */
386d19f06b3SAlexander Motin 	if (ccb->ataio.cmd.command != ATA_SEP_ATTN ||
387d19f06b3SAlexander Motin 	    ccb->ataio.dxfer_len < ccb->ataio.cmd.sector_count * 4) {
388d19f06b3SAlexander Motin 		ccb->ccb_h.status = CAM_REQ_INVALID;
389d19f06b3SAlexander Motin 		goto out;
390d19f06b3SAlexander Motin 	}
391d19f06b3SAlexander Motin 
392d19f06b3SAlexander Motin 	/* SEMB IDENTIFY */
393d19f06b3SAlexander Motin 	if (ccb->ataio.cmd.features == 0xEC &&
394d19f06b3SAlexander Motin 	    ccb->ataio.cmd.sector_count >= 16) {
395d19f06b3SAlexander Motin 		bzero(buf, ccb->ataio.dxfer_len);
396d19f06b3SAlexander Motin 		buf[0] = 64;		/* Valid bytes. */
397cf977ac2SAlexander Motin 		buf[2] = 0x30;		/* NAA Locally Assigned. */
398cf977ac2SAlexander Motin 		strncpy(&buf[3], device_get_nameunit(dev), 7);
399d19f06b3SAlexander Motin 		strncpy(&buf[10], "AHCI    ", SID_VENDOR_SIZE);
400d19f06b3SAlexander Motin 		strncpy(&buf[18], "SGPIO Enclosure ", SID_PRODUCT_SIZE);
40153f5ac13SAlexander Motin 		strncpy(&buf[34], "2.00", SID_REVISION_SIZE);
402d19f06b3SAlexander Motin 		strncpy(&buf[39], "0001", 4);
403d19f06b3SAlexander Motin 		strncpy(&buf[43], "S-E-S ", 6);
404d19f06b3SAlexander Motin 		strncpy(&buf[49], "2.00", 4);
405d19f06b3SAlexander Motin 		ccb->ccb_h.status = CAM_REQ_CMP;
406d19f06b3SAlexander Motin 		goto out;
407d19f06b3SAlexander Motin 	}
408d19f06b3SAlexander Motin 
409d19f06b3SAlexander Motin 	/* SEMB RECEIVE DIAGNOSTIC RESULT (0) */
410d19f06b3SAlexander Motin 	page = (struct ses_status_page *)buf;
411d19f06b3SAlexander Motin 	if (ccb->ataio.cmd.lba_low == 0x02 &&
412d19f06b3SAlexander Motin 	    ccb->ataio.cmd.features == 0x00 &&
41353f5ac13SAlexander Motin 	    ccb->ataio.cmd.sector_count >= 3) {
414d19f06b3SAlexander Motin 		bzero(buf, ccb->ataio.dxfer_len);
415d19f06b3SAlexander Motin 		page->hdr.page_code = 0;
41653f5ac13SAlexander Motin 		scsi_ulto2b(5, page->hdr.length);
41753f5ac13SAlexander Motin 		buf[4] = 0x00;
41853f5ac13SAlexander Motin 		buf[5] = 0x01;
41953f5ac13SAlexander Motin 		buf[6] = 0x02;
42053f5ac13SAlexander Motin 		buf[7] = 0x07;
42153f5ac13SAlexander Motin 		buf[8] = 0x0a;
422d19f06b3SAlexander Motin 		ccb->ccb_h.status = CAM_REQ_CMP;
423d19f06b3SAlexander Motin 		goto out;
424d19f06b3SAlexander Motin 	}
425d19f06b3SAlexander Motin 
426d19f06b3SAlexander Motin 	/* SEMB RECEIVE DIAGNOSTIC RESULT (1) */
427d19f06b3SAlexander Motin 	if (ccb->ataio.cmd.lba_low == 0x02 &&
428d19f06b3SAlexander Motin 	    ccb->ataio.cmd.features == 0x01 &&
42953f5ac13SAlexander Motin 	    ccb->ataio.cmd.sector_count >= 16) {
430d19f06b3SAlexander Motin 		struct ses_enc_desc *ed;
431d19f06b3SAlexander Motin 		struct ses_elm_type_desc *td;
432d19f06b3SAlexander Motin 
433d19f06b3SAlexander Motin 		bzero(buf, ccb->ataio.dxfer_len);
434d19f06b3SAlexander Motin 		page->hdr.page_code = 0x01;
43553f5ac13SAlexander Motin 		scsi_ulto2b(4 + sizeof(*ed) + sizeof(*td) + 11,
43653f5ac13SAlexander Motin 		    page->hdr.length);
437d19f06b3SAlexander Motin 		ed = (struct ses_enc_desc *)&buf[8];
438d19f06b3SAlexander Motin 		ed->byte0 = 0x11;
439d19f06b3SAlexander Motin 		ed->subenc_id = 0;
440d19f06b3SAlexander Motin 		ed->num_types = 1;
441d19f06b3SAlexander Motin 		ed->length = 36;
44253f5ac13SAlexander Motin 		ed->logical_id[0] = 0x30;	/* NAA Locally Assigned. */
44353f5ac13SAlexander Motin 		strncpy(&ed->logical_id[1], device_get_nameunit(dev), 7);
444d19f06b3SAlexander Motin 		strncpy(ed->vendor_id, "AHCI    ", SID_VENDOR_SIZE);
445d19f06b3SAlexander Motin 		strncpy(ed->product_id, "SGPIO Enclosure ", SID_PRODUCT_SIZE);
44653f5ac13SAlexander Motin 		strncpy(ed->product_rev, "2.00", SID_REVISION_SIZE);
447d19f06b3SAlexander Motin 		td = (struct ses_elm_type_desc *)ses_enc_desc_next(ed);
448d19f06b3SAlexander Motin 		td->etype_elm_type = 0x17;
449d19f06b3SAlexander Motin 		td->etype_maxelt = enc->channels;
450d19f06b3SAlexander Motin 		td->etype_subenc = 0;
45153f5ac13SAlexander Motin 		td->etype_txt_len = 11;
45253f5ac13SAlexander Motin 		snprintf((char *)(td + 1), 12, "Drive Slots");
453d19f06b3SAlexander Motin 		ccb->ccb_h.status = CAM_REQ_CMP;
454d19f06b3SAlexander Motin 		goto out;
455d19f06b3SAlexander Motin 	}
456d19f06b3SAlexander Motin 
457d19f06b3SAlexander Motin 	/* SEMB RECEIVE DIAGNOSTIC RESULT (2) */
458d19f06b3SAlexander Motin 	if (ccb->ataio.cmd.lba_low == 0x02 &&
459d19f06b3SAlexander Motin 	    ccb->ataio.cmd.features == 0x02 &&
460d19f06b3SAlexander Motin 	    ccb->ataio.cmd.sector_count >= (3 + enc->channels)) {
461d19f06b3SAlexander Motin 		bzero(buf, ccb->ataio.dxfer_len);
462d19f06b3SAlexander Motin 		page->hdr.page_code = 0x02;
463d19f06b3SAlexander Motin 		scsi_ulto2b(4 + 4 * (1 + enc->channels),
464d19f06b3SAlexander Motin 		    page->hdr.length);
465d19f06b3SAlexander Motin 		for (i = 0; i < enc->channels; i++) {
466d19f06b3SAlexander Motin 			ads = &page->elements[i + 1].array_dev_slot;
467d19f06b3SAlexander Motin 			memcpy(ads, enc->status[i], 4);
46853f5ac13SAlexander Motin 			ch = ahci_getch(device_get_parent(dev), i);
46953f5ac13SAlexander Motin 			if (ch == NULL) {
47053f5ac13SAlexander Motin 				ads->common.bytes[0] |= SES_OBJSTAT_UNKNOWN;
47153f5ac13SAlexander Motin 				continue;
47253f5ac13SAlexander Motin 			}
47353f5ac13SAlexander Motin 			if (ch->pm_present)
47453f5ac13SAlexander Motin 				ads->common.bytes[0] |= SES_OBJSTAT_UNKNOWN;
47553f5ac13SAlexander Motin 			else if (ch->devices)
47653f5ac13SAlexander Motin 				ads->common.bytes[0] |= SES_OBJSTAT_OK;
47753f5ac13SAlexander Motin 			else if (ch->disablephy)
47853f5ac13SAlexander Motin 				ads->common.bytes[0] |= SES_OBJSTAT_NOTAVAIL;
47953f5ac13SAlexander Motin 			else
48053f5ac13SAlexander Motin 				ads->common.bytes[0] |= SES_OBJSTAT_NOTINSTALLED;
48153f5ac13SAlexander Motin 			if (ch->disablephy)
48253f5ac13SAlexander Motin 				ads->common.bytes[3] |= SESCTL_DEVOFF;
48353f5ac13SAlexander Motin 			ahci_putch(ch);
484d19f06b3SAlexander Motin 		}
485d19f06b3SAlexander Motin 		ccb->ccb_h.status = CAM_REQ_CMP;
486d19f06b3SAlexander Motin 		goto out;
487d19f06b3SAlexander Motin 	}
488d19f06b3SAlexander Motin 
489d19f06b3SAlexander Motin 	/* SEMB SEND DIAGNOSTIC (2) */
490d19f06b3SAlexander Motin 	if (ccb->ataio.cmd.lba_low == 0x82 &&
491d19f06b3SAlexander Motin 	    ccb->ataio.cmd.features == 0x02 &&
492d19f06b3SAlexander Motin 	    ccb->ataio.cmd.sector_count >= (3 + enc->channels)) {
493d19f06b3SAlexander Motin 		ads0 = &page->elements[0].array_dev_slot;
494d19f06b3SAlexander Motin 		for (i = 0; i < enc->channels; i++) {
495d19f06b3SAlexander Motin 			ads = &page->elements[i + 1].array_dev_slot;
496d19f06b3SAlexander Motin 			if (ads->common.bytes[0] & SESCTL_CSEL) {
497d19f06b3SAlexander Motin 				enc->status[i][0] = 0;
49853f5ac13SAlexander Motin 				enc->status[i][1] = ads->bytes[0] &
49953f5ac13SAlexander Motin 				    SESCTL_RQSRR;
50053f5ac13SAlexander Motin 				enc->status[i][2] = ads->bytes[1] &
50153f5ac13SAlexander Motin 				    (SESCTL_RQSACT | SESCTL_RQSID);
50253f5ac13SAlexander Motin 				enc->status[i][3] = ads->bytes[2] &
50353f5ac13SAlexander Motin 				    SESCTL_RQSFLT;
504d19f06b3SAlexander Motin 				ahci_em_setleds(dev, i);
505d19f06b3SAlexander Motin 			} else if (ads0->common.bytes[0] & SESCTL_CSEL) {
506d19f06b3SAlexander Motin 				enc->status[i][0] = 0;
50753f5ac13SAlexander Motin 				enc->status[i][1] = ads0->bytes[0] &
50853f5ac13SAlexander Motin 				    SESCTL_RQSRR;
50953f5ac13SAlexander Motin 				enc->status[i][2] = ads0->bytes[1] &
51053f5ac13SAlexander Motin 				    (SESCTL_RQSACT | SESCTL_RQSID);
51153f5ac13SAlexander Motin 				enc->status[i][3] = ads0->bytes[2] &
51253f5ac13SAlexander Motin 				    SESCTL_RQSFLT;
513d19f06b3SAlexander Motin 				ahci_em_setleds(dev, i);
514d19f06b3SAlexander Motin 			}
515d19f06b3SAlexander Motin 		}
516d19f06b3SAlexander Motin 		ccb->ccb_h.status = CAM_REQ_CMP;
517d19f06b3SAlexander Motin 		goto out;
518d19f06b3SAlexander Motin 	}
519d19f06b3SAlexander Motin 
520d19f06b3SAlexander Motin 	/* SEMB RECEIVE DIAGNOSTIC RESULT (7) */
521d19f06b3SAlexander Motin 	if (ccb->ataio.cmd.lba_low == 0x02 &&
522d19f06b3SAlexander Motin 	    ccb->ataio.cmd.features == 0x07 &&
52353f5ac13SAlexander Motin 	    ccb->ataio.cmd.sector_count >= (6 + 3 * enc->channels)) {
524d19f06b3SAlexander Motin 		bzero(buf, ccb->ataio.dxfer_len);
525d19f06b3SAlexander Motin 		page->hdr.page_code = 0x07;
52653f5ac13SAlexander Motin 		scsi_ulto2b(4 + 15 + 11 * enc->channels, page->hdr.length);
52753f5ac13SAlexander Motin 		elmd = (struct ses_elm_desc_hdr *)&buf[8];
52853f5ac13SAlexander Motin 		scsi_ulto2b(11, elmd->length);
52953f5ac13SAlexander Motin 		snprintf((char *)(elmd + 1), 12, "Drive Slots");
53053f5ac13SAlexander Motin 		for (i = 0; i < enc->channels; i++) {
53153f5ac13SAlexander Motin 			elmd = (struct ses_elm_desc_hdr *)&buf[8 + 15 + 11 * i];
53253f5ac13SAlexander Motin 			scsi_ulto2b(7, elmd->length);
53353f5ac13SAlexander Motin 			snprintf((char *)(elmd + 1), 8, "Slot %02d", i);
53453f5ac13SAlexander Motin 		}
53553f5ac13SAlexander Motin 		ccb->ccb_h.status = CAM_REQ_CMP;
53653f5ac13SAlexander Motin 		goto out;
53753f5ac13SAlexander Motin 	}
53853f5ac13SAlexander Motin 
53953f5ac13SAlexander Motin 	/* SEMB RECEIVE DIAGNOSTIC RESULT (a) */
54053f5ac13SAlexander Motin 	if (ccb->ataio.cmd.lba_low == 0x02 &&
54153f5ac13SAlexander Motin 	    ccb->ataio.cmd.features == 0x0a &&
54253f5ac13SAlexander Motin 	    ccb->ataio.cmd.sector_count >= (2 + 3 * enc->channels)) {
54353f5ac13SAlexander Motin 		bzero(buf, ccb->ataio.dxfer_len);
54453f5ac13SAlexander Motin 		page->hdr.page_code = 0x0a;
54553f5ac13SAlexander Motin 		scsi_ulto2b(4 + (sizeof(*elma) + sizeof(*elmb)) * enc->channels,
546d19f06b3SAlexander Motin 		    page->hdr.length);
547d19f06b3SAlexander Motin 		for (i = 0; i < enc->channels; i++) {
54853f5ac13SAlexander Motin 			elma = (struct ses_elm_addlstatus_eip_hdr *)&buf[
54953f5ac13SAlexander Motin 			    8 + (sizeof(*elma) + sizeof(*elmb)) * i];
55053f5ac13SAlexander Motin 			elma->base.byte0 = 0x10 | SPSP_PROTO_ATA;
55153f5ac13SAlexander Motin 			elma->base.length = 2 + sizeof(*elmb);
55253f5ac13SAlexander Motin 			elma->byte2 = 0x01;
55353f5ac13SAlexander Motin 			elma->element_index = 1 + i;
55453f5ac13SAlexander Motin 			ch = ahci_getch(device_get_parent(dev), i);
55553f5ac13SAlexander Motin 			if (ch == NULL) {
55653f5ac13SAlexander Motin 				elma->base.byte0 |= 0x80;
55753f5ac13SAlexander Motin 				continue;
55853f5ac13SAlexander Motin 			}
55953f5ac13SAlexander Motin 			if (ch->devices == 0 || ch->pm_present)
56053f5ac13SAlexander Motin 				elma->base.byte0 |= 0x80;
56153f5ac13SAlexander Motin 			elmb = (struct ses_elm_ata_hdr *)(elma + 1);
56253f5ac13SAlexander Motin 			scsi_ulto4b(cam_sim_path(ch->sim), elmb->bus);
56353f5ac13SAlexander Motin 			scsi_ulto4b(0, elmb->target);
56453f5ac13SAlexander Motin 			ahci_putch(ch);
565d19f06b3SAlexander Motin 		}
566d19f06b3SAlexander Motin 		ccb->ccb_h.status = CAM_REQ_CMP;
567d19f06b3SAlexander Motin 		goto out;
568d19f06b3SAlexander Motin 	}
569d19f06b3SAlexander Motin 
570d19f06b3SAlexander Motin 	ccb->ccb_h.status = CAM_REQ_INVALID;
571d19f06b3SAlexander Motin out:
572d19f06b3SAlexander Motin 	xpt_done(ccb);
573d19f06b3SAlexander Motin }
574d19f06b3SAlexander Motin 
575d19f06b3SAlexander Motin static void
ahci_em_begin_transaction(device_t dev,union ccb * ccb)576d19f06b3SAlexander Motin ahci_em_begin_transaction(device_t dev, union ccb *ccb)
577d19f06b3SAlexander Motin {
578d19f06b3SAlexander Motin 	struct ahci_enclosure *enc;
579d19f06b3SAlexander Motin 	struct ata_res *res;
580d19f06b3SAlexander Motin 
581d19f06b3SAlexander Motin 	enc = device_get_softc(dev);
582d19f06b3SAlexander Motin 	res = &ccb->ataio.res;
583d19f06b3SAlexander Motin 	bzero(res, sizeof(*res));
584d19f06b3SAlexander Motin 	if ((ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) &&
585d19f06b3SAlexander Motin 	    (ccb->ataio.cmd.control & ATA_A_RESET)) {
586d19f06b3SAlexander Motin 		res->lba_high = 0xc3;
587d19f06b3SAlexander Motin 		res->lba_mid = 0x3c;
588d19f06b3SAlexander Motin 		ccb->ccb_h.status = CAM_REQ_CMP;
589d19f06b3SAlexander Motin 		xpt_done(ccb);
590d19f06b3SAlexander Motin 		return;
591d19f06b3SAlexander Motin 	}
592d19f06b3SAlexander Motin 
593d19f06b3SAlexander Motin 	if (enc->capsem & AHCI_EM_LED) {
594d19f06b3SAlexander Motin 		ahci_em_emulate_ses_on_led(dev, ccb);
595d19f06b3SAlexander Motin 		return;
596d19f06b3SAlexander Motin 	} else
597d19f06b3SAlexander Motin 		device_printf(dev, "Unsupported enclosure interface\n");
598d19f06b3SAlexander Motin 
599d19f06b3SAlexander Motin 	ccb->ccb_h.status = CAM_REQ_INVALID;
600d19f06b3SAlexander Motin 	xpt_done(ccb);
601d19f06b3SAlexander Motin }
602d19f06b3SAlexander Motin 
603d19f06b3SAlexander Motin static void
ahciemaction(struct cam_sim * sim,union ccb * ccb)604d19f06b3SAlexander Motin ahciemaction(struct cam_sim *sim, union ccb *ccb)
605d19f06b3SAlexander Motin {
606d19f06b3SAlexander Motin 	device_t dev, parent;
607d19f06b3SAlexander Motin 	struct ahci_enclosure *enc;
608d19f06b3SAlexander Motin 
609d19f06b3SAlexander Motin 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
610d19f06b3SAlexander Motin 	    ("ahciemaction func_code=%x\n", ccb->ccb_h.func_code));
611d19f06b3SAlexander Motin 
612d19f06b3SAlexander Motin 	enc = cam_sim_softc(sim);
613d19f06b3SAlexander Motin 	dev = enc->dev;
614d19f06b3SAlexander Motin 	switch (ccb->ccb_h.func_code) {
615d19f06b3SAlexander Motin 	case XPT_ATA_IO:	/* Execute the requested I/O operation */
616fcd7f38fSAlexander Motin 		if (ahci_check_ids(ccb))
617d19f06b3SAlexander Motin 			return;
618d19f06b3SAlexander Motin 		ahci_em_begin_transaction(dev, ccb);
619d19f06b3SAlexander Motin 		return;
620d19f06b3SAlexander Motin 	case XPT_RESET_BUS:		/* Reset the specified bus */
621d19f06b3SAlexander Motin 	case XPT_RESET_DEV:	/* Bus Device Reset the specified device */
622d19f06b3SAlexander Motin 		ahci_em_reset(dev);
623d19f06b3SAlexander Motin 		ccb->ccb_h.status = CAM_REQ_CMP;
624d19f06b3SAlexander Motin 		break;
625d19f06b3SAlexander Motin 	case XPT_PATH_INQ:		/* Path routing inquiry */
626d19f06b3SAlexander Motin 	{
627d19f06b3SAlexander Motin 		struct ccb_pathinq *cpi = &ccb->cpi;
628d19f06b3SAlexander Motin 
629d19f06b3SAlexander Motin 		parent = device_get_parent(dev);
630d19f06b3SAlexander Motin 		cpi->version_num = 1; /* XXX??? */
631d19f06b3SAlexander Motin 		cpi->hba_inquiry = PI_SDTR_ABLE;
632d19f06b3SAlexander Motin 		cpi->target_sprt = 0;
633d19f06b3SAlexander Motin 		cpi->hba_misc = PIM_SEQSCAN;
634d19f06b3SAlexander Motin 		cpi->hba_eng_cnt = 0;
635d19f06b3SAlexander Motin 		cpi->max_target = 0;
636d19f06b3SAlexander Motin 		cpi->max_lun = 0;
637d19f06b3SAlexander Motin 		cpi->initiator_id = 0;
638d19f06b3SAlexander Motin 		cpi->bus_id = cam_sim_bus(sim);
639d19f06b3SAlexander Motin 		cpi->base_transfer_speed = 150000;
6404195c7deSAlan Somers 		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
6414195c7deSAlan Somers 		strlcpy(cpi->hba_vid, "AHCI", HBA_IDLEN);
6424195c7deSAlan Somers 		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
643d19f06b3SAlexander Motin 		cpi->unit_number = cam_sim_unit(sim);
644d19f06b3SAlexander Motin 		cpi->transport = XPORT_SATA;
645d19f06b3SAlexander Motin 		cpi->transport_version = XPORT_VERSION_UNSPECIFIED;
646d19f06b3SAlexander Motin 		cpi->protocol = PROTO_ATA;
647d19f06b3SAlexander Motin 		cpi->protocol_version = PROTO_VERSION_UNSPECIFIED;
648cd853791SKonstantin Belousov 		cpi->maxio = maxphys;
649d19f06b3SAlexander Motin 		cpi->hba_vendor = pci_get_vendor(parent);
650d19f06b3SAlexander Motin 		cpi->hba_device = pci_get_device(parent);
651d19f06b3SAlexander Motin 		cpi->hba_subvendor = pci_get_subvendor(parent);
652d19f06b3SAlexander Motin 		cpi->hba_subdevice = pci_get_subdevice(parent);
653d19f06b3SAlexander Motin 		cpi->ccb_h.status = CAM_REQ_CMP;
654d19f06b3SAlexander Motin 		break;
655d19f06b3SAlexander Motin 	}
656d19f06b3SAlexander Motin 	default:
657d19f06b3SAlexander Motin 		ccb->ccb_h.status = CAM_REQ_INVALID;
658d19f06b3SAlexander Motin 		break;
659d19f06b3SAlexander Motin 	}
660d19f06b3SAlexander Motin 	xpt_done(ccb);
661d19f06b3SAlexander Motin }
662d19f06b3SAlexander Motin 
663d19f06b3SAlexander Motin static void
ahciempoll(struct cam_sim * sim)664d19f06b3SAlexander Motin ahciempoll(struct cam_sim *sim)
665d19f06b3SAlexander Motin {
666d19f06b3SAlexander Motin 
667d19f06b3SAlexander Motin }
668