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