]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ahci/ahciem.c
MFC r367615:
[FreeBSD/FreeBSD.git] / sys / dev / ahci / ahciem.c
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 */
59 static void ahciemaction(struct cam_sim *sim, union ccb *ccb);
60 static void ahciempoll(struct cam_sim *sim);
61 static int ahci_em_reset(device_t dev);
62 static void ahci_em_led(void *priv, int onoff);
63 static void ahci_em_setleds(device_t dev, int c);
64
65 static int
66 ahci_em_probe(device_t dev)
67 {
68
69         device_set_desc_copy(dev, "AHCI enclosure management bridge");
70         return (BUS_PROBE_DEFAULT);
71 }
72
73 static int
74 ahci_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
186 err3:
187         xpt_bus_deregister(cam_sim_path(enc->sim));
188 err2:
189         cam_sim_free(enc->sim, /*free_devq*/TRUE);
190 err1:
191         mtx_unlock(&enc->mtx);
192         if (enc->r_memr)
193                 bus_release_resource(dev, SYS_RES_MEMORY, 2, enc->r_memr);
194 err0:
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
202 static int
203 ahci_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
227 static int
228 ahci_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
248 static int
249 ahci_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
259 static int
260 ahci_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
271 devclass_t ahciem_devclass;
272 static 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 };
280 static driver_t ahciem_driver = {
281         "ahciem",
282         ahciem_methods,
283         sizeof(struct ahci_enclosure)
284 };
285 DRIVER_MODULE(ahciem, ahci, ahciem_driver, ahciem_devclass, NULL, NULL);
286
287 static void
288 ahci_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
317 static void
318 ahci_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
348 static int
349 ahci_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
365 static void
366 ahci_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;
567 out:
568         xpt_done(ccb);
569 }
570
571 static void
572 ahci_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
599 static void
600 ahciemaction(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
659 static void
660 ahciempoll(struct cam_sim *sim)
661 {
662
663 }