2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2012 Alexander Motin <mav@FreeBSD.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/module.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
38 #include <sys/endian.h>
39 #include <sys/malloc.h>
41 #include <sys/mutex.h>
42 #include <machine/stdarg.h>
43 #include <machine/resource.h>
44 #include <machine/bus.h>
46 #include <dev/led/led.h>
47 #include <dev/pci/pcivar.h>
48 #include <dev/pci/pcireg.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>
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);
66 ahci_em_probe(device_t dev)
69 device_set_desc_copy(dev, "AHCI enclosure management bridge");
70 return (BUS_PROBE_DEFAULT);
74 ahci_em_attach(device_t dev)
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;
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);
89 if (!(enc->r_memc = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
91 mtx_destroy(&enc->mtx);
94 enc->capsem = ATA_INL(enc->r_memc, 0);
96 if (!(enc->r_memt = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
101 if ((enc->capsem & (AHCI_EM_XMT | AHCI_EM_SMB)) == 0) {
103 if (!(enc->r_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
111 if (ahci_em_reset(dev) != 0) {
116 /* Create the device queue for our SIM. */
117 devq = cam_simq_alloc(1);
119 device_printf(dev, "Unable to allocate SIM queue\n");
123 /* Construct SIM entry */
124 enc->sim = cam_sim_alloc(ahciemaction, ahciempoll, "ahciem", enc,
125 device_get_unit(dev), &enc->mtx,
127 if (enc->sim == NULL) {
129 device_printf(dev, "Unable to allocate SIM\n");
133 if (xpt_bus_register(enc->sim, dev, 0) != CAM_SUCCESS) {
134 device_printf(dev, "unable to register xpt bus\n");
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");
144 mtx_unlock(&enc->mtx);
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":"");
156 if ((enc->capsem & AHCI_EM_LED)) {
157 for (c = 0; c < enc->channels; c++) {
158 if ((enc->ichannels & (1 << c)) == 0)
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;
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);
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);
187 xpt_bus_deregister(cam_sim_path(enc->sim));
189 cam_sim_free(enc->sim, /*free_devq*/TRUE);
191 mtx_unlock(&enc->mtx);
193 bus_release_resource(dev, SYS_RES_MEMORY, 2, enc->r_memr);
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);
203 ahci_em_detach(device_t dev)
205 struct ahci_enclosure *enc = device_get_softc(dev);
208 for (i = 0; i < enc->channels * AHCI_NUM_LEDS; i++) {
209 if (enc->leds[i].led)
210 led_destroy(enc->leds[i].led);
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);
219 bus_release_resource(dev, SYS_RES_MEMORY, 0, enc->r_memc);
220 bus_release_resource(dev, SYS_RES_MEMORY, 1, enc->r_memt);
222 bus_release_resource(dev, SYS_RES_MEMORY, 2, enc->r_memr);
223 mtx_destroy(&enc->mtx);
228 ahci_em_reset(device_t dev)
230 struct ahci_enclosure *enc;
233 enc = device_get_softc(dev);
234 ATA_OUTL(enc->r_memc, 0, AHCI_EM_RST);
236 while ((ATA_INL(enc->r_memc, 0) & AHCI_EM_RST) &&
240 device_printf(dev, "EM timeout\n");
243 for (i = 0; i < enc->channels; i++)
244 ahci_em_setleds(dev, i);
249 ahci_em_suspend(device_t dev)
251 struct ahci_enclosure *enc = device_get_softc(dev);
254 xpt_freeze_simq(enc->sim, 1);
255 mtx_unlock(&enc->mtx);
260 ahci_em_resume(device_t dev)
262 struct ahci_enclosure *enc = device_get_softc(dev);
266 xpt_release_simq(enc->sim, TRUE);
267 mtx_unlock(&enc->mtx);
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),
280 static driver_t ahciem_driver = {
283 sizeof(struct ahci_enclosure)
285 DRIVER_MODULE(ahciem, ahci, ahciem_driver, ahciem_devclass, NULL, NULL);
288 ahci_em_setleds(device_t dev, int c)
290 struct ahci_enclosure *enc;
294 enc = device_get_softc(dev);
297 if (enc->status[c][2] & SESCTL_RQSACT) /* Activity */
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 */
303 else if (enc->status[c][3] & SESCTL_RQSFLT) /* Fault */
307 while (ATA_INL(enc->r_memc, 0) & (AHCI_EM_TM | AHCI_EM_RST) &&
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);
318 ahci_em_led(void *priv, int onoff)
320 struct ahci_led *led;
321 struct ahci_enclosure *enc;
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;
331 enc->status[c][2] |= 0x80;
333 enc->status[c][2] &= ~0x80;
336 enc->status[c][2] |= SESCTL_RQSID;
338 enc->status[c][2] &= ~SESCTL_RQSID;
341 enc->status[c][3] |= SESCTL_RQSFLT;
343 enc->status[c][3] &= SESCTL_RQSFLT;
345 ahci_em_setleds(led->dev, c);
349 ahci_check_ids(union ccb *ccb)
352 if (ccb->ccb_h.target_id != 0) {
353 ccb->ccb_h.status = CAM_TID_INVALID;
357 if (ccb->ccb_h.target_lun != 0) {
358 ccb->ccb_h.status = CAM_LUN_INVALID;
366 ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb)
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;
378 enc = device_get_softc(dev);
379 buf = ccb->ataio.data_ptr;
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;
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;
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);
418 ccb->ccb_h.status = CAM_REQ_CMP;
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;
429 bzero(buf, ccb->ataio.dxfer_len);
430 page->hdr.page_code = 0x01;
431 scsi_ulto2b(4 + sizeof(*ed) + sizeof(*td) + 11,
433 ed = (struct ses_enc_desc *)&buf[8];
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;
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),
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);
466 ads->common.bytes[0] |= SES_OBJSTAT_UNKNOWN;
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;
476 ads->common.bytes[0] |= SES_OBJSTAT_NOTINSTALLED;
478 ads->common.bytes[3] |= SESCTL_DEVOFF;
481 ccb->ccb_h.status = CAM_REQ_CMP;
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] &
496 enc->status[i][2] = ads->bytes[1] &
497 (SESCTL_RQSACT | SESCTL_RQSID);
498 enc->status[i][3] = ads->bytes[2] &
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] &
505 enc->status[i][2] = ads0->bytes[1] &
506 (SESCTL_RQSACT | SESCTL_RQSID);
507 enc->status[i][3] = ads0->bytes[2] &
509 ahci_em_setleds(dev, i);
512 ccb->ccb_h.status = CAM_REQ_CMP;
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);
531 ccb->ccb_h.status = CAM_REQ_CMP;
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,
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);
549 elma->element_index = 1 + i;
550 ch = ahci_getch(device_get_parent(dev), i);
552 elma->base.byte0 |= 0x80;
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);
562 ccb->ccb_h.status = CAM_REQ_CMP;
566 ccb->ccb_h.status = CAM_REQ_INVALID;
572 ahci_em_begin_transaction(device_t dev, union ccb *ccb)
574 struct ahci_enclosure *enc;
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;
584 ccb->ccb_h.status = CAM_REQ_CMP;
589 if (enc->capsem & AHCI_EM_LED) {
590 ahci_em_emulate_ses_on_led(dev, ccb);
593 device_printf(dev, "Unsupported enclosure interface\n");
595 ccb->ccb_h.status = CAM_REQ_INVALID;
600 ahciemaction(struct cam_sim *sim, union ccb *ccb)
602 device_t dev, parent;
603 struct ahci_enclosure *enc;
605 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
606 ("ahciemaction func_code=%x\n", ccb->ccb_h.func_code));
608 enc = cam_sim_softc(sim);
610 switch (ccb->ccb_h.func_code) {
611 case XPT_ATA_IO: /* Execute the requested I/O operation */
612 if (ahci_check_ids(ccb))
614 ahci_em_begin_transaction(dev, ccb);
616 case XPT_RESET_BUS: /* Reset the specified bus */
617 case XPT_RESET_DEV: /* Bus Device Reset the specified device */
619 ccb->ccb_h.status = CAM_REQ_CMP;
621 case XPT_PATH_INQ: /* Path routing inquiry */
623 struct ccb_pathinq *cpi = &ccb->cpi;
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;
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;
653 ccb->ccb_h.status = CAM_REQ_INVALID;
660 ahciempoll(struct cam_sim *sim)