2 * Copyright (c) 2012 Alexander Motin <mav@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer,
10 * without modification, immediately at the beginning of the file.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/module.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
36 #include <sys/endian.h>
37 #include <sys/malloc.h>
39 #include <sys/mutex.h>
40 #include <machine/stdarg.h>
41 #include <machine/resource.h>
42 #include <machine/bus.h>
44 #include <dev/led/led.h>
45 #include <dev/pci/pcivar.h>
46 #include <dev/pci/pcireg.h>
50 #include <cam/cam_ccb.h>
51 #include <cam/cam_sim.h>
52 #include <cam/cam_xpt_sim.h>
53 #include <cam/cam_debug.h>
54 #include <cam/scsi/scsi_ses.h>
56 /* local prototypes */
57 static void ahciemaction(struct cam_sim *sim, union ccb *ccb);
58 static void ahciempoll(struct cam_sim *sim);
59 static int ahci_em_reset(device_t dev);
60 static void ahci_em_led(void *priv, int onoff);
61 static void ahci_em_setleds(device_t dev, int c);
64 ahci_em_probe(device_t dev)
67 device_set_desc_copy(dev, "AHCI enclosure management bridge");
72 ahci_em_attach(device_t dev)
74 device_t parent = device_get_parent(dev);
75 struct ahci_controller *ctlr = device_get_softc(parent);
76 struct ahci_enclosure *enc = device_get_softc(dev);
77 struct cam_devq *devq;
82 enc->quirks = ctlr->quirks;
83 enc->channels = ctlr->channels;
84 enc->ichannels = ctlr->ichannels;
85 mtx_init(&enc->mtx, "AHCI enclosure lock", NULL, MTX_DEF);
87 if (!(enc->r_memc = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
90 enc->capsem = ATA_INL(enc->r_memc, 0);
92 if (!(enc->r_memt = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
97 if ((enc->capsem & (AHCI_EM_XMT | AHCI_EM_SMB)) == 0) {
99 if (!(enc->r_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
109 /* Create the device queue for our SIM. */
110 devq = cam_simq_alloc(1);
112 device_printf(dev, "Unable to allocate SIM queue\n");
116 /* Construct SIM entry */
117 enc->sim = cam_sim_alloc(ahciemaction, ahciempoll, "ahciem", enc,
118 device_get_unit(dev), &enc->mtx,
120 if (enc->sim == NULL) {
122 device_printf(dev, "Unable to allocate SIM\n");
126 if (xpt_bus_register(enc->sim, dev, 0) != CAM_SUCCESS) {
127 device_printf(dev, "unable to register xpt bus\n");
131 if (xpt_create_path(&enc->path, /*periph*/NULL, cam_sim_path(enc->sim),
132 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
133 device_printf(dev, "Unable to create path\n");
137 mtx_unlock(&enc->mtx);
139 device_printf(dev, "Caps:%s%s%s%s%s%s%s%s\n",
140 (enc->capsem & AHCI_EM_PM) ? " PM":"",
141 (enc->capsem & AHCI_EM_ALHD) ? " ALHD":"",
142 (enc->capsem & AHCI_EM_XMT) ? " XMT":"",
143 (enc->capsem & AHCI_EM_SMB) ? " SMB":"",
144 (enc->capsem & AHCI_EM_SGPIO) ? " SGPIO":"",
145 (enc->capsem & AHCI_EM_SES2) ? " SES-2":"",
146 (enc->capsem & AHCI_EM_SAFTE) ? " SAF-TE":"",
147 (enc->capsem & AHCI_EM_LED) ? " LED":"");
149 if ((enc->capsem & AHCI_EM_LED)) {
150 for (c = 0; c < enc->channels; c++) {
151 if ((enc->ichannels & (1 << c)) == 0)
153 for (i = 0; i < AHCI_NUM_LEDS; i++) {
154 enc->leds[c * AHCI_NUM_LEDS + i].dev = dev;
155 enc->leds[c * AHCI_NUM_LEDS + i].num =
156 c * AHCI_NUM_LEDS + i;
158 if ((enc->capsem & AHCI_EM_ALHD) == 0) {
159 snprintf(buf, sizeof(buf), "%s.%d.act",
160 device_get_nameunit(parent), c);
161 enc->leds[c * AHCI_NUM_LEDS + 0].led =
162 led_create(ahci_em_led,
163 &enc->leds[c * AHCI_NUM_LEDS + 0], buf);
165 snprintf(buf, sizeof(buf), "%s.%d.locate",
166 device_get_nameunit(parent), c);
167 enc->leds[c * AHCI_NUM_LEDS + 1].led =
168 led_create(ahci_em_led,
169 &enc->leds[c * AHCI_NUM_LEDS + 1], buf);
170 snprintf(buf, sizeof(buf), "%s.%d.fault",
171 device_get_nameunit(parent), c);
172 enc->leds[c * AHCI_NUM_LEDS + 2].led =
173 led_create(ahci_em_led,
174 &enc->leds[c * AHCI_NUM_LEDS + 2], buf);
180 xpt_bus_deregister(cam_sim_path(enc->sim));
182 cam_sim_free(enc->sim, /*free_devq*/TRUE);
184 mtx_unlock(&enc->mtx);
186 bus_release_resource(dev, SYS_RES_MEMORY, 2, enc->r_memr);
189 bus_release_resource(dev, SYS_RES_MEMORY, 1, enc->r_memt);
190 bus_release_resource(dev, SYS_RES_MEMORY, 0, enc->r_memc);
191 mtx_destroy(&enc->mtx);
196 ahci_em_detach(device_t dev)
198 struct ahci_enclosure *enc = device_get_softc(dev);
201 for (i = 0; i < enc->channels * AHCI_NUM_LEDS; i++) {
202 if (enc->leds[i].led)
203 led_destroy(enc->leds[i].led);
206 xpt_async(AC_LOST_DEVICE, enc->path, NULL);
207 xpt_free_path(enc->path);
208 xpt_bus_deregister(cam_sim_path(enc->sim));
209 cam_sim_free(enc->sim, /*free_devq*/TRUE);
210 mtx_unlock(&enc->mtx);
212 bus_release_resource(dev, SYS_RES_MEMORY, 0, enc->r_memc);
213 bus_release_resource(dev, SYS_RES_MEMORY, 1, enc->r_memt);
215 bus_release_resource(dev, SYS_RES_MEMORY, 2, enc->r_memr);
216 mtx_destroy(&enc->mtx);
221 ahci_em_reset(device_t dev)
223 struct ahci_enclosure *enc;
226 enc = device_get_softc(dev);
227 ATA_OUTL(enc->r_memc, 0, AHCI_EM_RST);
229 while ((ATA_INL(enc->r_memc, 0) & AHCI_EM_RST) &&
233 device_printf(dev, "EM timeout\n");
236 for (i = 0; i < enc->channels; i++)
237 ahci_em_setleds(dev, i);
242 ahci_em_suspend(device_t dev)
244 struct ahci_enclosure *enc = device_get_softc(dev);
247 xpt_freeze_simq(enc->sim, 1);
248 mtx_unlock(&enc->mtx);
253 ahci_em_resume(device_t dev)
255 struct ahci_enclosure *enc = device_get_softc(dev);
259 xpt_release_simq(enc->sim, TRUE);
260 mtx_unlock(&enc->mtx);
264 devclass_t ahciem_devclass;
265 static device_method_t ahciem_methods[] = {
266 DEVMETHOD(device_probe, ahci_em_probe),
267 DEVMETHOD(device_attach, ahci_em_attach),
268 DEVMETHOD(device_detach, ahci_em_detach),
269 DEVMETHOD(device_suspend, ahci_em_suspend),
270 DEVMETHOD(device_resume, ahci_em_resume),
273 static driver_t ahciem_driver = {
276 sizeof(struct ahci_enclosure)
278 DRIVER_MODULE(ahciem, ahci, ahciem_driver, ahciem_devclass, 0, 0);
281 ahci_em_setleds(device_t dev, int c)
283 struct ahci_enclosure *enc;
287 enc = device_get_softc(dev);
290 if (enc->status[c][2] & 0x80) /* Activity */
292 if (enc->status[c][2] & SESCTL_RQSID) /* Identification */
294 else if (enc->status[c][3] & SESCTL_RQSFLT) /* Fault */
296 else if (enc->status[c][1] & 0x02) /* Rebuild */
297 val |= (1 << 6) | (1 << 3);
300 while (ATA_INL(enc->r_memc, 0) & (AHCI_EM_TM | AHCI_EM_RST) &&
304 device_printf(dev, "Transmit timeout\n");
305 ATA_OUTL(enc->r_memt, 0, (1 << 8) | (0 << 16) | (0 << 24));
306 ATA_OUTL(enc->r_memt, 4, c | (0 << 8) | (val << 16));
307 ATA_OUTL(enc->r_memc, 0, AHCI_EM_TM);
311 ahci_em_led(void *priv, int onoff)
313 struct ahci_led *led;
314 struct ahci_enclosure *enc;
317 led = (struct ahci_led *)priv;
318 enc = device_get_softc(led->dev);
319 c = led->num / AHCI_NUM_LEDS;
320 l = led->num % AHCI_NUM_LEDS;
324 enc->status[c][2] |= 0x80;
326 enc->status[c][2] &= ~0x80;
329 enc->status[c][2] |= SESCTL_RQSID;
331 enc->status[c][2] &= ~SESCTL_RQSID;
334 enc->status[c][3] |= SESCTL_RQSFLT;
336 enc->status[c][3] &= SESCTL_RQSFLT;
338 ahci_em_setleds(led->dev, c);
342 ahci_check_ids(device_t dev, union ccb *ccb)
345 if (ccb->ccb_h.target_id != 0) {
346 ccb->ccb_h.status = CAM_TID_INVALID;
350 if (ccb->ccb_h.target_lun != 0) {
351 ccb->ccb_h.status = CAM_LUN_INVALID;
359 ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb)
361 struct ahci_enclosure *enc;
362 struct ses_status_page *page;
363 struct ses_status_array_dev_slot *ads, *ads0;
364 struct ses_elm_desc_hdr *elmd;
368 enc = device_get_softc(dev);
369 buf = ccb->ataio.data_ptr;
371 /* General request validation. */
372 if (ccb->ataio.cmd.command != ATA_SEP_ATTN ||
373 ccb->ataio.dxfer_len < ccb->ataio.cmd.sector_count * 4) {
374 ccb->ccb_h.status = CAM_REQ_INVALID;
379 if (ccb->ataio.cmd.features == 0xEC &&
380 ccb->ataio.cmd.sector_count >= 16) {
381 bzero(buf, ccb->ataio.dxfer_len);
382 buf[0] = 64; /* Valid bytes. */
383 buf[2] = 0x30; /* NAA Locally Assigned. */
384 strncpy(&buf[3], device_get_nameunit(dev), 7);
385 strncpy(&buf[10], "AHCI ", SID_VENDOR_SIZE);
386 strncpy(&buf[18], "SGPIO Enclosure ", SID_PRODUCT_SIZE);
387 strncpy(&buf[34], "1.00", SID_REVISION_SIZE);
388 strncpy(&buf[39], "0001", 4);
389 strncpy(&buf[43], "S-E-S ", 6);
390 strncpy(&buf[49], "2.00", 4);
391 ccb->ccb_h.status = CAM_REQ_CMP;
395 /* SEMB RECEIVE DIAGNOSTIC RESULT (0) */
396 page = (struct ses_status_page *)buf;
397 if (ccb->ataio.cmd.lba_low == 0x02 &&
398 ccb->ataio.cmd.features == 0x00 &&
399 ccb->ataio.cmd.sector_count >= 2) {
400 bzero(buf, ccb->ataio.dxfer_len);
401 page->hdr.page_code = 0;
402 scsi_ulto2b(4, page->hdr.length);
407 ccb->ccb_h.status = CAM_REQ_CMP;
411 /* SEMB RECEIVE DIAGNOSTIC RESULT (1) */
412 if (ccb->ataio.cmd.lba_low == 0x02 &&
413 ccb->ataio.cmd.features == 0x01 &&
414 ccb->ataio.cmd.sector_count >= 13) {
415 struct ses_enc_desc *ed;
416 struct ses_elm_type_desc *td;
418 bzero(buf, ccb->ataio.dxfer_len);
419 page->hdr.page_code = 0x01;
420 scsi_ulto2b(4 + 4 + 36 + 4, page->hdr.length);
421 ed = (struct ses_enc_desc *)&buf[8];
426 strncpy(ed->vendor_id, "AHCI ", SID_VENDOR_SIZE);
427 strncpy(ed->product_id, "SGPIO Enclosure ", SID_PRODUCT_SIZE);
428 strncpy(ed->product_rev, " ", SID_REVISION_SIZE);
429 td = (struct ses_elm_type_desc *)ses_enc_desc_next(ed);
430 td->etype_elm_type = 0x17;
431 td->etype_maxelt = enc->channels;
432 td->etype_subenc = 0;
433 td->etype_txt_len = 0;
434 ccb->ccb_h.status = CAM_REQ_CMP;
438 /* SEMB RECEIVE DIAGNOSTIC RESULT (2) */
439 if (ccb->ataio.cmd.lba_low == 0x02 &&
440 ccb->ataio.cmd.features == 0x02 &&
441 ccb->ataio.cmd.sector_count >= (3 + enc->channels)) {
442 bzero(buf, ccb->ataio.dxfer_len);
443 page->hdr.page_code = 0x02;
444 scsi_ulto2b(4 + 4 * (1 + enc->channels),
446 for (i = 0; i < enc->channels; i++) {
447 ads = &page->elements[i + 1].array_dev_slot;
448 memcpy(ads, enc->status[i], 4);
449 ads->common.bytes[0] |=
450 (enc->ichannels & (1 << i)) ?
451 SES_OBJSTAT_UNKNOWN :
452 SES_OBJSTAT_NOTINSTALLED;
454 ccb->ccb_h.status = CAM_REQ_CMP;
458 /* SEMB SEND DIAGNOSTIC (2) */
459 if (ccb->ataio.cmd.lba_low == 0x82 &&
460 ccb->ataio.cmd.features == 0x02 &&
461 ccb->ataio.cmd.sector_count >= (3 + enc->channels)) {
462 ads0 = &page->elements[0].array_dev_slot;
463 for (i = 0; i < enc->channels; i++) {
464 ads = &page->elements[i + 1].array_dev_slot;
465 if (ads->common.bytes[0] & SESCTL_CSEL) {
466 enc->status[i][0] = 0;
468 ads->bytes[0] & 0x02;
470 ads->bytes[1] & (0x80 | SESCTL_RQSID);
472 ads->bytes[2] & SESCTL_RQSFLT;
473 ahci_em_setleds(dev, i);
474 } else if (ads0->common.bytes[0] & SESCTL_CSEL) {
475 enc->status[i][0] = 0;
477 ads0->bytes[0] & 0x02;
479 ads0->bytes[1] & (0x80 | SESCTL_RQSID);
481 ads0->bytes[2] & SESCTL_RQSFLT;
482 ahci_em_setleds(dev, i);
485 ccb->ccb_h.status = CAM_REQ_CMP;
489 /* SEMB RECEIVE DIAGNOSTIC RESULT (7) */
490 if (ccb->ataio.cmd.lba_low == 0x02 &&
491 ccb->ataio.cmd.features == 0x07 &&
492 ccb->ataio.cmd.sector_count >= (3 + 3 * enc->channels)) {
493 bzero(buf, ccb->ataio.dxfer_len);
494 page->hdr.page_code = 0x07;
495 scsi_ulto2b(4 + 4 + 12 * enc->channels,
497 for (i = 0; i < enc->channels; i++) {
498 elmd = (struct ses_elm_desc_hdr *)&buf[8 + 4 + 12 * i];
499 scsi_ulto2b(8, elmd->length);
500 snprintf((char *)(elmd + 1), 9, "SLOT %03d", i);
502 ccb->ccb_h.status = CAM_REQ_CMP;
506 ccb->ccb_h.status = CAM_REQ_INVALID;
512 ahci_em_begin_transaction(device_t dev, union ccb *ccb)
514 struct ahci_enclosure *enc;
517 enc = device_get_softc(dev);
518 res = &ccb->ataio.res;
519 bzero(res, sizeof(*res));
520 if ((ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) &&
521 (ccb->ataio.cmd.control & ATA_A_RESET)) {
522 res->lba_high = 0xc3;
524 ccb->ccb_h.status = CAM_REQ_CMP;
529 if (enc->capsem & AHCI_EM_LED) {
530 ahci_em_emulate_ses_on_led(dev, ccb);
533 device_printf(dev, "Unsupported enclosure interface\n");
535 ccb->ccb_h.status = CAM_REQ_INVALID;
540 ahciemaction(struct cam_sim *sim, union ccb *ccb)
542 device_t dev, parent;
543 struct ahci_enclosure *enc;
545 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
546 ("ahciemaction func_code=%x\n", ccb->ccb_h.func_code));
548 enc = cam_sim_softc(sim);
550 switch (ccb->ccb_h.func_code) {
551 case XPT_ATA_IO: /* Execute the requested I/O operation */
552 if (ahci_check_ids(dev, ccb))
554 ahci_em_begin_transaction(dev, ccb);
556 case XPT_RESET_BUS: /* Reset the specified bus */
557 case XPT_RESET_DEV: /* Bus Device Reset the specified device */
559 ccb->ccb_h.status = CAM_REQ_CMP;
561 case XPT_PATH_INQ: /* Path routing inquiry */
563 struct ccb_pathinq *cpi = &ccb->cpi;
565 parent = device_get_parent(dev);
566 cpi->version_num = 1; /* XXX??? */
567 cpi->hba_inquiry = PI_SDTR_ABLE;
568 cpi->target_sprt = 0;
569 cpi->hba_misc = PIM_SEQSCAN;
570 cpi->hba_eng_cnt = 0;
573 cpi->initiator_id = 0;
574 cpi->bus_id = cam_sim_bus(sim);
575 cpi->base_transfer_speed = 150000;
576 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
577 strncpy(cpi->hba_vid, "AHCI", HBA_IDLEN);
578 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
579 cpi->unit_number = cam_sim_unit(sim);
580 cpi->transport = XPORT_SATA;
581 cpi->transport_version = XPORT_VERSION_UNSPECIFIED;
582 cpi->protocol = PROTO_ATA;
583 cpi->protocol_version = PROTO_VERSION_UNSPECIFIED;
584 cpi->maxio = MAXPHYS;
585 cpi->hba_vendor = pci_get_vendor(parent);
586 cpi->hba_device = pci_get_device(parent);
587 cpi->hba_subvendor = pci_get_subvendor(parent);
588 cpi->hba_subdevice = pci_get_subdevice(parent);
589 cpi->ccb_h.status = CAM_REQ_CMP;
593 ccb->ccb_h.status = CAM_REQ_INVALID;
600 ahciempoll(struct cam_sim *sim)