siis.c revision 208414
11558Srgrimes/*- 21558Srgrimes * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org> 31558Srgrimes * All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer, 101558Srgrimes * without modification, immediately at the beginning of the file. 111558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121558Srgrimes * notice, this list of conditions and the following disclaimer in the 131558Srgrimes * documentation and/or other materials provided with the distribution. 141558Srgrimes * 151558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 161558Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 171558Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 181558Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 191558Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 201558Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 211558Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 221558Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 231558Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 241558Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 251558Srgrimes */ 261558Srgrimes 271558Srgrimes#include <sys/cdefs.h> 281558Srgrimes__FBSDID("$FreeBSD: head/sys/dev/siis/siis.c 208414 2010-05-22 08:30:47Z mav $"); 291558Srgrimes 301558Srgrimes#include <sys/param.h> 311558Srgrimes#include <sys/module.h> 321558Srgrimes#include <sys/systm.h> 331558Srgrimes#include <sys/kernel.h> 3437663Scharnier#include <sys/ata.h> 351558Srgrimes#include <sys/bus.h> 361558Srgrimes#include <sys/endian.h> 372999Swollman#include <sys/malloc.h> 381558Srgrimes#include <sys/lock.h> 39105267Scharnier#include <sys/mutex.h> 401558Srgrimes#include <sys/sema.h> 4137663Scharnier#include <sys/taskqueue.h> 42105267Scharnier#include <vm/uma.h> 4337663Scharnier#include <machine/stdarg.h> 441558Srgrimes#include <machine/resource.h> 45105267Scharnier#include <machine/bus.h> 46105267Scharnier#include <sys/rman.h> 47105267Scharnier#include <dev/pci/pcivar.h> 481558Srgrimes#include <dev/pci/pcireg.h> 491558Srgrimes#include "siis.h" 5074462Salfred 511558Srgrimes#include <cam/cam.h> 521558Srgrimes#include <cam/cam_ccb.h> 5324330Sguido#include <cam/cam_sim.h> 5496622Siedowse#include <cam/cam_xpt_sim.h> 5596622Siedowse#include <cam/cam_debug.h> 561558Srgrimes 571558Srgrimes/* local prototypes */ 58109363Smbrstatic int siis_setup_interrupt(device_t dev); 591558Srgrimesstatic void siis_intr(void *data); 6074462Salfredstatic int siis_suspend(device_t dev); 6174462Salfredstatic int siis_resume(device_t dev); 621558Srgrimesstatic int siis_ch_init(device_t dev); 639336Sdfrstatic int siis_ch_deinit(device_t dev); 6483653Speterstatic int siis_ch_suspend(device_t dev); 651558Srgrimesstatic int siis_ch_resume(device_t dev); 661558Srgrimesstatic void siis_ch_intr_locked(void *data); 671558Srgrimesstatic void siis_ch_intr(void *data); 681558Srgrimesstatic void siis_begin_transaction(device_t dev, union ccb *ccb); 6937663Scharnierstatic void siis_dmasetprd(void *arg, bus_dma_segment_t *segs, int nsegs, int error); 701558Srgrimesstatic void siis_execute_transaction(struct siis_slot *slot); 711558Srgrimesstatic void siis_timeout(struct siis_slot *slot); 72149433Spjdstatic void siis_end_transaction(struct siis_slot *slot, enum siis_err_type et); 73103949Smikestatic int siis_setup_fis(device_t dev, struct siis_cmd *ctp, union ccb *ccb, int tag); 741558Srgrimesstatic void siis_dmainit(device_t dev); 751558Srgrimesstatic void siis_dmasetupc_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); 761558Srgrimesstatic void siis_dmafini(device_t dev); 771558Srgrimesstatic void siis_slotsalloc(device_t dev); 781558Srgrimesstatic void siis_slotsfree(device_t dev); 791558Srgrimesstatic void siis_reset(device_t dev); 801558Srgrimesstatic void siis_portinit(device_t dev); 811558Srgrimesstatic int siis_wait_ready(device_t dev, int t); 82158857Srodrigc 831558Srgrimesstatic int siis_sata_connect(struct siis_channel *ch); 841558Srgrimes 851558Srgrimesstatic void siis_issue_read_log(device_t dev); 861558Srgrimesstatic void siis_process_read_log(device_t dev, union ccb *ccb); 871558Srgrimes 881558Srgrimesstatic void siisaction(struct cam_sim *sim, union ccb *ccb); 891558Srgrimesstatic void siispoll(struct cam_sim *sim); 901558Srgrimes 911558SrgrimesMALLOC_DEFINE(M_SIIS, "SIIS driver", "SIIS driver data buffers"); 921558Srgrimes 931558Srgrimesstatic struct { 941558Srgrimes uint32_t id; 951558Srgrimes const char *name; 961558Srgrimes int ports; 971558Srgrimes int quirks; 981558Srgrimes#define SIIS_Q_SNTF 1 991558Srgrimes#define SIIS_Q_NOMSI 2 1001558Srgrimes} siis_ids[] = { 1011558Srgrimes {0x31241095, "SiI3124", 4, 0}, 1021558Srgrimes {0x31248086, "SiI3124", 4, 0}, 1031558Srgrimes {0x31321095, "SiI3132", 2, SIIS_Q_SNTF|SIIS_Q_NOMSI}, 1041558Srgrimes {0x02421095, "SiI3132", 2, SIIS_Q_SNTF|SIIS_Q_NOMSI}, 1051558Srgrimes {0x02441095, "SiI3132", 2, SIIS_Q_SNTF|SIIS_Q_NOMSI}, 1069336Sdfr {0x31311095, "SiI3131", 1, SIIS_Q_SNTF|SIIS_Q_NOMSI}, 1071558Srgrimes {0x35311095, "SiI3531", 1, SIIS_Q_SNTF|SIIS_Q_NOMSI}, 1081558Srgrimes {0, NULL, 0, 0} 1091558Srgrimes}; 1101558Srgrimes 1111558Srgrimesstatic int 1121558Srgrimessiis_probe(device_t dev) 1131558Srgrimes{ 1141558Srgrimes char buf[64]; 11527447Sdfr int i; 1161558Srgrimes uint32_t devid = pci_get_devid(dev); 1171558Srgrimes 1181558Srgrimes for (i = 0; siis_ids[i].id != 0; i++) { 1191558Srgrimes if (siis_ids[i].id == devid) { 1201558Srgrimes snprintf(buf, sizeof(buf), "%s SATA controller", 12174462Salfred siis_ids[i].name); 12275801Siedowse device_set_desc_copy(dev, buf); 12342144Sdfr return (BUS_PROBE_VENDOR); 1241558Srgrimes } 1251558Srgrimes } 1261558Srgrimes return (ENXIO); 12774462Salfred} 1281558Srgrimes 1291558Srgrimesstatic int 1301558Srgrimessiis_attach(device_t dev) 1311558Srgrimes{ 1321558Srgrimes struct siis_controller *ctlr = device_get_softc(dev); 1331558Srgrimes uint32_t devid = pci_get_devid(dev); 1341558Srgrimes device_t child; 1351558Srgrimes int error, i, unit; 1361558Srgrimes 1371558Srgrimes ctlr->dev = dev; 1381558Srgrimes for (i = 0; siis_ids[i].id != 0; i++) { 1391558Srgrimes if (siis_ids[i].id == devid) 14075641Siedowse break; 1417401Swpaul } 1421558Srgrimes ctlr->quirks = siis_ids[i].quirks; 1431558Srgrimes /* Global memory */ 1449336Sdfr ctlr->r_grid = PCIR_BAR(0); 1451558Srgrimes if (!(ctlr->r_gmem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 1461558Srgrimes &ctlr->r_grid, RF_ACTIVE))) 1471558Srgrimes return (ENXIO); 1481558Srgrimes ctlr->gctl = ATA_INL(ctlr->r_gmem, SIIS_GCTL); 1499336Sdfr /* Channels memory */ 1509336Sdfr ctlr->r_rid = PCIR_BAR(2); 1519336Sdfr if (!(ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 1529336Sdfr &ctlr->r_rid, RF_ACTIVE))) 1539336Sdfr return (ENXIO); 1549336Sdfr /* Setup our own memory management for channels. */ 1551558Srgrimes ctlr->sc_iomem.rm_start = rman_get_start(ctlr->r_mem); 15692882Simp ctlr->sc_iomem.rm_end = rman_get_end(ctlr->r_mem); 15792882Simp ctlr->sc_iomem.rm_type = RMAN_ARRAY; 15892882Simp ctlr->sc_iomem.rm_descr = "I/O memory addresses"; 15992882Simp if ((error = rman_init(&ctlr->sc_iomem)) != 0) { 16092882Simp bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem); 16192882Simp bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_grid, ctlr->r_gmem); 16275801Siedowse return (error); 16392882Simp } 164172827Smatteo if ((error = rman_manage_region(&ctlr->sc_iomem, 16575635Siedowse rman_get_start(ctlr->r_mem), rman_get_end(ctlr->r_mem))) != 0) { 16692882Simp bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem); 16792882Simp bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_grid, ctlr->r_gmem); 16892882Simp rman_fini(&ctlr->sc_iomem); 16992882Simp return (error); 17092882Simp } 17192882Simp pci_enable_busmaster(dev); 17292882Simp /* Reset controller */ 17392882Simp siis_resume(dev); 17492882Simp /* Number of HW channels */ 17592882Simp ctlr->channels = siis_ids[i].ports; 17692882Simp /* Setup interrupts. */ 17792882Simp if (siis_setup_interrupt(dev)) { 17892882Simp bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem); 17992882Simp bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_grid, ctlr->r_gmem); 18092882Simp rman_fini(&ctlr->sc_iomem); 18192882Simp return ENXIO; 18292882Simp } 18392882Simp /* Attach all channels on this controller */ 18492882Simp for (unit = 0; unit < ctlr->channels; unit++) { 18592882Simp child = device_add_child(dev, "siisch", -1); 18692882Simp if (child == NULL) 18775754Siedowse device_printf(dev, "failed to add channel device\n"); 18875801Siedowse else 18992882Simp device_set_ivars(child, (void *)(intptr_t)unit); 19092882Simp } 19192882Simp bus_generic_attach(dev); 19292882Simp return 0; 193100117Salfred} 19475801Siedowse 19575801Siedowsestatic int 19675801Siedowsesiis_detach(device_t dev) 19792882Simp{ 19892882Simp struct siis_controller *ctlr = device_get_softc(dev); 19992882Simp device_t *children; 20092882Simp int nchildren, i; 201100117Salfred 20292882Simp /* Detach & delete all children */ 20392882Simp if (!device_get_children(dev, &children, &nchildren)) { 20492882Simp for (i = 0; i < nchildren; i++) 2051558Srgrimes device_delete_child(dev, children[i]); 2061558Srgrimes free(children, M_TEMP); 2071558Srgrimes } 2081558Srgrimes /* Free interrupts. */ 209166440Spjd if (ctlr->irq.r_irq) { 210166440Spjd bus_teardown_intr(dev, ctlr->irq.r_irq, 211172827Smatteo ctlr->irq.handle); 21272650Sgreen bus_release_resource(dev, SYS_RES_IRQ, 21391354Sdd ctlr->irq.r_irq_rid, ctlr->irq.r_irq); 21472650Sgreen } 2151558Srgrimes pci_release_msi(dev); 21672650Sgreen /* Free memory. */ 21772650Sgreen rman_fini(&ctlr->sc_iomem); 2181558Srgrimes bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem); 21925087Sdfr bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_grid, ctlr->r_gmem); 2209336Sdfr return (0); 221172827Smatteo} 2229336Sdfr 223121767Speterstatic int 22475754Siedowsesiis_suspend(device_t dev) 225172827Smatteo{ 22674462Salfred struct siis_controller *ctlr = device_get_softc(dev); 227172827Smatteo 228172827Smatteo bus_generic_suspend(dev); 2291558Srgrimes /* Put controller into reset state. */ 23074462Salfred ctlr->gctl |= SIIS_GCTL_GRESET; 23174462Salfred ATA_OUTL(ctlr->r_gmem, SIIS_GCTL, ctlr->gctl); 232149433Spjd return 0; 23375801Siedowse} 2341558Srgrimes 2351558Srgrimesstatic int 23683653Spetersiis_resume(device_t dev) 2371558Srgrimes{ 2381558Srgrimes struct siis_controller *ctlr = device_get_softc(dev); 2391558Srgrimes 24075801Siedowse /* Set PCIe max read request size to at least 1024 bytes */ 241100336Sjoerg if (pci_get_max_read_req(dev) < 1024) 24274462Salfred pci_set_max_read_req(dev, 1024); 2431558Srgrimes /* Put controller into reset state. */ 2441558Srgrimes ctlr->gctl |= SIIS_GCTL_GRESET; 2451558Srgrimes ATA_OUTL(ctlr->r_gmem, SIIS_GCTL, ctlr->gctl); 24692882Simp DELAY(10000); 2471558Srgrimes /* Get controller out of reset state and enable port interrupts. */ 2481558Srgrimes ctlr->gctl &= ~(SIIS_GCTL_GRESET | SIIS_GCTL_I2C_IE); 2491558Srgrimes ctlr->gctl |= 0x0000000f; 2501558Srgrimes ATA_OUTL(ctlr->r_gmem, SIIS_GCTL, ctlr->gctl); 2511558Srgrimes return (bus_generic_resume(dev)); 2521558Srgrimes} 2531558Srgrimes 2541558Srgrimesstatic int 2551558Srgrimessiis_setup_interrupt(device_t dev) 2561558Srgrimes{ 2571558Srgrimes struct siis_controller *ctlr = device_get_softc(dev); 2581558Srgrimes int msi = ctlr->quirks & SIIS_Q_NOMSI ? 0 : 1; 2591558Srgrimes 2601558Srgrimes /* Process hints. */ 2611558Srgrimes resource_int_value(device_get_name(dev), 2621558Srgrimes device_get_unit(dev), "msi", &msi); 2631558Srgrimes if (msi < 0) 26475754Siedowse msi = 0; 265172827Smatteo else if (msi > 0) 266172827Smatteo msi = min(1, pci_msi_count(dev)); 267172827Smatteo /* Allocate MSI if needed/present. */ 268149433Spjd if (msi && pci_alloc_msi(dev, &msi) != 0) 269172827Smatteo msi = 0; 270172827Smatteo /* Allocate all IRQs. */ 271109363Smbr ctlr->irq.r_irq_rid = msi ? 1 : 0; 2721558Srgrimes if (!(ctlr->irq.r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 27374462Salfred &ctlr->irq.r_irq_rid, RF_SHAREABLE | RF_ACTIVE))) { 274150214Spjd device_printf(dev, "unable to map interrupt\n"); 275149433Spjd return ENXIO; 276149433Spjd } 277149433Spjd if ((bus_setup_intr(dev, ctlr->irq.r_irq, ATA_INTR_FLAGS, NULL, 278149433Spjd siis_intr, ctlr, &ctlr->irq.handle))) { 279149433Spjd /* SOS XXX release r_irq */ 28074462Salfred device_printf(dev, "unable to setup interrupt\n"); 28174462Salfred return ENXIO; 28274462Salfred } 28374462Salfred return (0); 28474462Salfred} 28574462Salfred 28683687Speter/* 28783687Speter * Common case interrupt handler. 28883687Speter */ 28983687Speterstatic void 2902999Swollmansiis_intr(void *data) 2912999Swollman{ 292172827Smatteo struct siis_controller *ctlr = (struct siis_controller *)data; 2931558Srgrimes u_int32_t is; 29425087Sdfr void *arg; 29525087Sdfr int unit; 29625087Sdfr 2979336Sdfr is = ATA_INL(ctlr->r_gmem, SIIS_IS); 2989336Sdfr for (unit = 0; unit < ctlr->channels; unit++) { 2999336Sdfr if ((is & SIIS_IS_PORT(unit)) != 0 && 3009336Sdfr (arg = ctlr->interrupt[unit].argument)) { 3019336Sdfr ctlr->interrupt[unit].function(arg); 3029336Sdfr } 3038688Sphk } 3048688Sphk /* Acknowledge interrupt, if MSI enabled. */ 3058688Sphk if (ctlr->irq.r_irq_rid) { 30631656Sguido ATA_OUTL(ctlr->r_gmem, SIIS_GCTL, 307121767Speter ctlr->gctl | SIIS_GCTL_MSIACK); 30831656Sguido } 309126572Sbms} 310126572Sbms 311126572Sbmsstatic struct resource * 312126572Sbmssiis_alloc_resource(device_t dev, device_t child, int type, int *rid, 313126572Sbms u_long start, u_long end, u_long count, u_int flags) 314126572Sbms{ 315172827Smatteo struct siis_controller *ctlr = device_get_softc(dev); 316126572Sbms int unit = ((struct siis_channel *)device_get_softc(child))->unit; 317172827Smatteo struct resource *res = NULL; 318172827Smatteo int offset = unit << 13; 319172827Smatteo long st; 320172827Smatteo 321172827Smatteo switch (type) { 322172827Smatteo case SYS_RES_MEMORY: 323172827Smatteo st = rman_get_start(ctlr->r_mem); 324172827Smatteo res = rman_reserve_resource(&ctlr->sc_iomem, st + offset, 325172827Smatteo st + offset + 0x2000, 0x2000, RF_ACTIVE, child); 326172827Smatteo if (res) { 327172827Smatteo bus_space_handle_t bsh; 328172827Smatteo bus_space_tag_t bst; 329172827Smatteo bsh = rman_get_bushandle(ctlr->r_mem); 330172827Smatteo bst = rman_get_bustag(ctlr->r_mem); 331172827Smatteo bus_space_subregion(bst, bsh, offset, 0x2000, &bsh); 332172827Smatteo rman_set_bushandle(res, bsh); 333172827Smatteo rman_set_bustag(res, bst); 334172827Smatteo } 335172827Smatteo break; 336172827Smatteo case SYS_RES_IRQ: 337172827Smatteo if (*rid == ATA_IRQ_RID) 3381558Srgrimes res = ctlr->irq.r_irq; 33937663Scharnier break; 3401558Srgrimes } 3411558Srgrimes return (res); 3421558Srgrimes} 3431558Srgrimes 3441558Srgrimesstatic int 3451558Srgrimessiis_release_resource(device_t dev, device_t child, int type, int rid, 346166440Spjd struct resource *r) 347166440Spjd{ 348166440Spjd 349166440Spjd switch (type) { 3501558Srgrimes case SYS_RES_MEMORY: 3511558Srgrimes rman_release_resource(r); 35237663Scharnier return (0); 3531558Srgrimes case SYS_RES_IRQ: 3541558Srgrimes if (rid != ATA_IRQ_RID) 35537663Scharnier return ENOENT; 3561558Srgrimes return (0); 3571558Srgrimes } 35837663Scharnier return (EINVAL); 3591558Srgrimes} 3601558Srgrimes 3611558Srgrimesstatic int 3621558Srgrimessiis_setup_intr(device_t dev, device_t child, struct resource *irq, 3631558Srgrimes int flags, driver_filter_t *filter, driver_intr_t *function, 36475754Siedowse void *argument, void **cookiep) 36574462Salfred{ 366164394Srodrigc struct siis_controller *ctlr = device_get_softc(dev); 367149433Spjd int unit = (intptr_t)device_get_ivars(child); 368149433Spjd 369149433Spjd if (filter != NULL) { 37074462Salfred printf("siis.c: we cannot use a filter here\n"); 37174462Salfred return (EINVAL); 372109363Smbr } 373109363Smbr ctlr->interrupt[unit].function = function; 37424759Sguido ctlr->interrupt[unit].argument = argument; 37583687Speter return (0); 37683687Speter} 37783687Speter 37824759Sguidostatic int 37924759Sguidosiis_teardown_intr(device_t dev, device_t child, struct resource *irq, 38024759Sguido void *cookie) 38124330Sguido{ 382126572Sbms struct siis_controller *ctlr = device_get_softc(dev); 383172827Smatteo int unit = (intptr_t)device_get_ivars(child); 384172827Smatteo 385172827Smatteo ctlr->interrupt[unit].function = NULL; 386172827Smatteo ctlr->interrupt[unit].argument = NULL; 387172827Smatteo return (0); 388172827Smatteo} 389172827Smatteo 390172827Smatteostatic int 391172827Smatteosiis_print_child(device_t dev, device_t child) 392172827Smatteo{ 393172827Smatteo int retval; 394172827Smatteo 395172827Smatteo retval = bus_print_child_header(dev, child); 396172827Smatteo retval += printf(" at channel %d", 397172827Smatteo (int)(intptr_t)device_get_ivars(child)); 398172827Smatteo retval += bus_print_child_footer(dev, child); 399172827Smatteo 400172827Smatteo return (retval); 401172827Smatteo} 402172827Smatteo 403172827Smatteostatic int 404172827Smatteosiis_child_location_str(device_t dev, device_t child, char *buf, 405172827Smatteo size_t buflen) 406172827Smatteo{ 407172827Smatteo 408172827Smatteo snprintf(buf, buflen, "channel=%d", 409172827Smatteo (int)(intptr_t)device_get_ivars(child)); 410172827Smatteo return (0); 411172827Smatteo} 412172827Smatteo 413172827Smatteodevclass_t siis_devclass; 414172827Smatteostatic device_method_t siis_methods[] = { 415172827Smatteo DEVMETHOD(device_probe, siis_probe), 416172827Smatteo DEVMETHOD(device_attach, siis_attach), 417172827Smatteo DEVMETHOD(device_detach, siis_detach), 418126572Sbms DEVMETHOD(device_suspend, siis_suspend), 419172827Smatteo DEVMETHOD(device_resume, siis_resume), 42074462Salfred DEVMETHOD(bus_print_child, siis_print_child), 421172827Smatteo DEVMETHOD(bus_alloc_resource, siis_alloc_resource), 42274462Salfred DEVMETHOD(bus_release_resource, siis_release_resource), 42374462Salfred DEVMETHOD(bus_setup_intr, siis_setup_intr), 424172827Smatteo DEVMETHOD(bus_teardown_intr,siis_teardown_intr), 425172827Smatteo DEVMETHOD(bus_child_location_str, siis_child_location_str), 426172827Smatteo { 0, 0 } 427172827Smatteo}; 428172827Smatteostatic driver_t siis_driver = { 429172827Smatteo "siis", 430172827Smatteo siis_methods, 431172827Smatteo sizeof(struct siis_controller) 432172827Smatteo}; 43374462SalfredDRIVER_MODULE(siis, pci, siis_driver, siis_devclass, 0, 0); 434172827SmatteoMODULE_VERSION(siis, 1); 43574462SalfredMODULE_DEPEND(siis, cam, 1, 1, 1); 43674462Salfred 43774462Salfredstatic int 4381558Srgrimessiis_ch_probe(device_t dev) 4391558Srgrimes{ 44075754Siedowse 44175754Siedowse device_set_desc_copy(dev, "SIIS channel"); 44275754Siedowse return (0); 44375754Siedowse} 44475754Siedowse 44575754Siedowsestatic int 44675754Siedowsesiis_ch_attach(device_t dev) 44775754Siedowse{ 44875754Siedowse struct siis_controller *ctlr = device_get_softc(device_get_parent(dev)); 44975754Siedowse struct siis_channel *ch = device_get_softc(dev); 45075754Siedowse struct cam_devq *devq; 45175754Siedowse int rid, error, i, sata_rev = 0; 45275754Siedowse 45375754Siedowse ch->dev = dev; 45475754Siedowse ch->unit = (intptr_t)device_get_ivars(dev); 45575754Siedowse ch->quirks = ctlr->quirks; 45675754Siedowse resource_int_value(device_get_name(dev), 45775754Siedowse device_get_unit(dev), "pm_level", &ch->pm_level); 45875754Siedowse resource_int_value(device_get_name(dev), 45975754Siedowse device_get_unit(dev), "sata_rev", &sata_rev); 460172827Smatteo for (i = 0; i < 16; i++) { 461172827Smatteo ch->user[i].revision = sata_rev; 462172827Smatteo ch->user[i].mode = 0; 463172827Smatteo ch->user[i].bytecount = 8192; 464172827Smatteo ch->user[i].tags = SIIS_MAX_SLOTS; 465172827Smatteo ch->curr[i] = ch->user[i]; 466172827Smatteo if (ch->pm_level) 467172827Smatteo ch->user[i].caps = CTS_SATA_CAPS_H_PMREQ; 468172827Smatteo } 469172827Smatteo mtx_init(&ch->mtx, "SIIS channel lock", NULL, MTX_DEF); 470172827Smatteo rid = ch->unit; 471172827Smatteo if (!(ch->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 472172827Smatteo &rid, RF_ACTIVE))) 473172827Smatteo return (ENXIO); 474172827Smatteo siis_dmainit(dev); 475172827Smatteo siis_slotsalloc(dev); 476172827Smatteo siis_ch_init(dev); 477172827Smatteo mtx_lock(&ch->mtx); 478172827Smatteo rid = ATA_IRQ_RID; 479172827Smatteo if (!(ch->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 480172827Smatteo &rid, RF_SHAREABLE | RF_ACTIVE))) { 481172827Smatteo bus_release_resource(dev, SYS_RES_MEMORY, ch->unit, ch->r_mem); 482172827Smatteo device_printf(dev, "Unable to map interrupt\n"); 483172827Smatteo return (ENXIO); 484172827Smatteo } 485172827Smatteo if ((bus_setup_intr(dev, ch->r_irq, ATA_INTR_FLAGS, NULL, 486172827Smatteo siis_ch_intr_locked, dev, &ch->ih))) { 487172827Smatteo device_printf(dev, "Unable to setup interrupt\n"); 488172827Smatteo error = ENXIO; 489172827Smatteo goto err1; 490172827Smatteo } 491172827Smatteo /* Create the device queue for our SIM. */ 492172827Smatteo devq = cam_simq_alloc(SIIS_MAX_SLOTS); 493172827Smatteo if (devq == NULL) { 494172827Smatteo device_printf(dev, "Unable to allocate simq\n"); 495172827Smatteo error = ENOMEM; 496172827Smatteo goto err1; 497172827Smatteo } 498172827Smatteo /* Construct SIM entry */ 499172827Smatteo ch->sim = cam_sim_alloc(siisaction, siispoll, "siisch", ch, 500172827Smatteo device_get_unit(dev), &ch->mtx, 2, SIIS_MAX_SLOTS, devq); 501172827Smatteo if (ch->sim == NULL) { 502172827Smatteo device_printf(dev, "unable to allocate sim\n"); 503172827Smatteo error = ENOMEM; 504172827Smatteo goto err2; 505172827Smatteo } 506172827Smatteo if (xpt_bus_register(ch->sim, dev, 0) != CAM_SUCCESS) { 507172827Smatteo device_printf(dev, "unable to register xpt bus\n"); 508172827Smatteo error = ENXIO; 509172827Smatteo goto err2; 510172827Smatteo } 511172827Smatteo if (xpt_create_path(&ch->path, /*periph*/NULL, cam_sim_path(ch->sim), 512172827Smatteo CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 513172827Smatteo device_printf(dev, "unable to create path\n"); 514172827Smatteo error = ENXIO; 515172827Smatteo goto err3; 516172827Smatteo } 517172827Smatteo mtx_unlock(&ch->mtx); 518172827Smatteo return (0); 519172827Smatteo 520172827Smatteoerr3: 521172827Smatteo xpt_bus_deregister(cam_sim_path(ch->sim)); 522172827Smatteoerr2: 523172827Smatteo cam_sim_free(ch->sim, /*free_devq*/TRUE); 524172827Smatteoerr1: 525172827Smatteo bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ch->r_irq); 526172827Smatteo bus_release_resource(dev, SYS_RES_MEMORY, ch->unit, ch->r_mem); 527172827Smatteo mtx_unlock(&ch->mtx); 528172827Smatteo return (error); 529172827Smatteo} 530172827Smatteo 531172827Smatteostatic int 532172827Smatteosiis_ch_detach(device_t dev) 533172827Smatteo{ 534172827Smatteo struct siis_channel *ch = device_get_softc(dev); 535172827Smatteo 536172827Smatteo mtx_lock(&ch->mtx); 537172827Smatteo xpt_async(AC_LOST_DEVICE, ch->path, NULL); 538172827Smatteo xpt_free_path(ch->path); 539172827Smatteo xpt_bus_deregister(cam_sim_path(ch->sim)); 540172827Smatteo cam_sim_free(ch->sim, /*free_devq*/TRUE); 541172827Smatteo mtx_unlock(&ch->mtx); 542172827Smatteo 543172827Smatteo bus_teardown_intr(dev, ch->r_irq, ch->ih); 544172827Smatteo bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ch->r_irq); 545172827Smatteo 546172827Smatteo siis_ch_deinit(dev); 547172827Smatteo siis_slotsfree(dev); 548172827Smatteo siis_dmafini(dev); 549172827Smatteo 550172827Smatteo bus_release_resource(dev, SYS_RES_MEMORY, ch->unit, ch->r_mem); 551172827Smatteo mtx_destroy(&ch->mtx); 552172827Smatteo return (0); 553172827Smatteo} 554172827Smatteo 555172827Smatteostatic int 556172827Smatteosiis_ch_init(device_t dev) 557172827Smatteo{ 558172827Smatteo struct siis_channel *ch = device_get_softc(dev); 559172827Smatteo 560172827Smatteo /* Get port out of reset state. */ 561172827Smatteo ATA_OUTL(ch->r_mem, SIIS_P_CTLCLR, SIIS_P_CTL_PORT_RESET); 562172827Smatteo ATA_OUTL(ch->r_mem, SIIS_P_CTLCLR, SIIS_P_CTL_32BIT); 563172827Smatteo if (ch->pm_present) 564172827Smatteo ATA_OUTL(ch->r_mem, SIIS_P_CTLSET, SIIS_P_CTL_PME); 565172827Smatteo else 566172827Smatteo ATA_OUTL(ch->r_mem, SIIS_P_CTLCLR, SIIS_P_CTL_PME); 567172827Smatteo /* Enable port interrupts */ 568172827Smatteo ATA_OUTL(ch->r_mem, SIIS_P_IESET, SIIS_P_IX_ENABLED); 569172827Smatteo return (0); 570172827Smatteo} 571172827Smatteo 572172827Smatteostatic int 573172827Smatteosiis_ch_deinit(device_t dev) 574172827Smatteo{ 575172827Smatteo struct siis_channel *ch = device_get_softc(dev); 576172827Smatteo 577172827Smatteo /* Put port into reset state. */ 578172827Smatteo ATA_OUTL(ch->r_mem, SIIS_P_CTLSET, SIIS_P_CTL_PORT_RESET); 579172827Smatteo return (0); 580172827Smatteo} 581172827Smatteo 582172827Smatteostatic int 583172827Smatteosiis_ch_suspend(device_t dev) 584172827Smatteo{ 585172827Smatteo struct siis_channel *ch = device_get_softc(dev); 586172827Smatteo 587172827Smatteo mtx_lock(&ch->mtx); 588172827Smatteo xpt_freeze_simq(ch->sim, 1); 589172827Smatteo while (ch->oslots) 590172827Smatteo msleep(ch, &ch->mtx, PRIBIO, "siissusp", hz/100); 591172827Smatteo siis_ch_deinit(dev); 592172827Smatteo mtx_unlock(&ch->mtx); 593172827Smatteo return (0); 594172827Smatteo} 595172827Smatteo 596172827Smatteostatic int 597172827Smatteosiis_ch_resume(device_t dev) 598172827Smatteo{ 599172827Smatteo struct siis_channel *ch = device_get_softc(dev); 600172827Smatteo 601172827Smatteo mtx_lock(&ch->mtx); 602172827Smatteo siis_ch_init(dev); 603172827Smatteo siis_reset(dev); 604172827Smatteo xpt_release_simq(ch->sim, TRUE); 605172827Smatteo mtx_unlock(&ch->mtx); 606172827Smatteo return (0); 607172827Smatteo} 608172827Smatteo 609172827Smatteodevclass_t siisch_devclass; 610172827Smatteostatic device_method_t siisch_methods[] = { 611172827Smatteo DEVMETHOD(device_probe, siis_ch_probe), 612172827Smatteo DEVMETHOD(device_attach, siis_ch_attach), 613172827Smatteo DEVMETHOD(device_detach, siis_ch_detach), 614172827Smatteo DEVMETHOD(device_suspend, siis_ch_suspend), 615172827Smatteo DEVMETHOD(device_resume, siis_ch_resume), 616172827Smatteo { 0, 0 } 617172827Smatteo}; 618172827Smatteostatic driver_t siisch_driver = { 619172827Smatteo "siisch", 620172827Smatteo siisch_methods, 621172827Smatteo sizeof(struct siis_channel) 622172827Smatteo}; 623172827SmatteoDRIVER_MODULE(siisch, siis, siisch_driver, siis_devclass, 0, 0); 624172827Smatteo 625172827Smatteostruct siis_dc_cb_args { 626172827Smatteo bus_addr_t maddr; 627172827Smatteo int error; 628172827Smatteo}; 629172827Smatteo 630172827Smatteostatic void 631172827Smatteosiis_dmainit(device_t dev) 632172827Smatteo{ 633172827Smatteo struct siis_channel *ch = device_get_softc(dev); 634172827Smatteo struct siis_dc_cb_args dcba; 635172827Smatteo 636172827Smatteo /* Command area. */ 637172827Smatteo if (bus_dma_tag_create(bus_get_dma_tag(dev), 1024, 0, 638172827Smatteo BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 639172827Smatteo NULL, NULL, SIIS_WORK_SIZE, 1, SIIS_WORK_SIZE, 640172827Smatteo 0, NULL, NULL, &ch->dma.work_tag)) 641172827Smatteo goto error; 642172827Smatteo if (bus_dmamem_alloc(ch->dma.work_tag, (void **)&ch->dma.work, 0, 643172827Smatteo &ch->dma.work_map)) 644172827Smatteo goto error; 645172827Smatteo if (bus_dmamap_load(ch->dma.work_tag, ch->dma.work_map, ch->dma.work, 646172827Smatteo SIIS_WORK_SIZE, siis_dmasetupc_cb, &dcba, 0) || dcba.error) { 647172827Smatteo bus_dmamem_free(ch->dma.work_tag, ch->dma.work, ch->dma.work_map); 648172827Smatteo goto error; 649172827Smatteo } 650172827Smatteo ch->dma.work_bus = dcba.maddr; 651172827Smatteo /* Data area. */ 652172827Smatteo if (bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, 653172827Smatteo BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 654172827Smatteo NULL, NULL, 655172827Smatteo SIIS_SG_ENTRIES * PAGE_SIZE * SIIS_MAX_SLOTS, 656172827Smatteo SIIS_SG_ENTRIES, 0xFFFFFFFF, 657172827Smatteo 0, busdma_lock_mutex, &ch->mtx, &ch->dma.data_tag)) { 658172827Smatteo goto error; 659172827Smatteo } 660172827Smatteo return; 661172827Smatteo 662172827Smatteoerror: 663172827Smatteo device_printf(dev, "WARNING - DMA initialization failed\n"); 664172827Smatteo siis_dmafini(dev); 665172827Smatteo} 666172827Smatteo 667172827Smatteostatic void 668172827Smatteosiis_dmasetupc_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) 669172827Smatteo{ 670172827Smatteo struct siis_dc_cb_args *dcba = (struct siis_dc_cb_args *)xsc; 671172827Smatteo 672172827Smatteo if (!(dcba->error = error)) 673172827Smatteo dcba->maddr = segs[0].ds_addr; 674172827Smatteo} 675172827Smatteo 676172827Smatteostatic void 677172827Smatteosiis_dmafini(device_t dev) 678172827Smatteo{ 679172827Smatteo struct siis_channel *ch = device_get_softc(dev); 680172827Smatteo 681172827Smatteo if (ch->dma.data_tag) { 682172827Smatteo bus_dma_tag_destroy(ch->dma.data_tag); 683172827Smatteo ch->dma.data_tag = NULL; 684172827Smatteo } 685172827Smatteo if (ch->dma.work_bus) { 686172827Smatteo bus_dmamap_unload(ch->dma.work_tag, ch->dma.work_map); 687172827Smatteo bus_dmamem_free(ch->dma.work_tag, ch->dma.work, ch->dma.work_map); 688172827Smatteo ch->dma.work_bus = 0; 689172827Smatteo ch->dma.work_map = NULL; 690172827Smatteo ch->dma.work = NULL; 691172827Smatteo } 692172827Smatteo if (ch->dma.work_tag) { 693172827Smatteo bus_dma_tag_destroy(ch->dma.work_tag); 694172827Smatteo ch->dma.work_tag = NULL; 695172827Smatteo } 696172827Smatteo} 697172827Smatteo 698172827Smatteostatic void 6991558Srgrimessiis_slotsalloc(device_t dev) 7001558Srgrimes{ 70137663Scharnier struct siis_channel *ch = device_get_softc(dev); 70237663Scharnier int i; 70337663Scharnier 70437663Scharnier /* Alloc and setup command/dma slots */ 705126572Sbms bzero(ch->slot, sizeof(ch->slot)); 706172827Smatteo for (i = 0; i < SIIS_MAX_SLOTS; i++) { 70737663Scharnier struct siis_slot *slot = &ch->slot[i]; 70837663Scharnier 70937663Scharnier slot->dev = dev; 7101558Srgrimes slot->slot = i; 7111558Srgrimes slot->state = SIIS_SLOT_EMPTY; 7121558Srgrimes slot->ccb = NULL; 7131558Srgrimes callout_init_mtx(&slot->timeout, &ch->mtx, 0); 7141558Srgrimes 7151558Srgrimes if (bus_dmamap_create(ch->dma.data_tag, 0, &slot->dma.data_map)) 7161558Srgrimes device_printf(ch->dev, "FAILURE - create data_map\n"); 7171558Srgrimes } 7181558Srgrimes} 7191558Srgrimes 7209336Sdfrstatic void 7211558Srgrimessiis_slotsfree(device_t dev) 7221558Srgrimes{ 72374462Salfred struct siis_channel *ch = device_get_softc(dev); 72474462Salfred int i; 72574462Salfred 7269336Sdfr /* Free all dma slots */ 72723681Speter for (i = 0; i < SIIS_MAX_SLOTS; i++) { 72828911Sguido struct siis_slot *slot = &ch->slot[i]; 7299336Sdfr 7301558Srgrimes callout_drain(&slot->timeout); 7319336Sdfr if (slot->dma.data_map) { 7329336Sdfr bus_dmamap_destroy(ch->dma.data_tag, slot->dma.data_map); 73374462Salfred slot->dma.data_map = NULL; 73474462Salfred } 73574462Salfred } 73675635Siedowse} 73774462Salfred 73874462Salfredstatic void 73975635Siedowsesiis_notify_events(device_t dev) 74074462Salfred{ 74174462Salfred struct siis_channel *ch = device_get_softc(dev); 74274462Salfred struct cam_path *dpath; 74374462Salfred u_int32_t status; 74474462Salfred int i; 74574462Salfred 74674462Salfred if (ch->quirks & SIIS_Q_SNTF) { 74774462Salfred status = ATA_INL(ch->r_mem, SIIS_P_SNTF); 74874462Salfred ATA_OUTL(ch->r_mem, SIIS_P_SNTF, status); 7491558Srgrimes } else { 7501558Srgrimes /* 751121556Speter * Without SNTF we have no idea which device sent notification. 75237663Scharnier * If PMP is connected, assume it, else - device. 7531558Srgrimes */ 7541558Srgrimes status = (ch->pm_present) ? 0x8000 : 0x0001; 7559336Sdfr } 75631656Sguido if (bootverbose) 75731656Sguido device_printf(dev, "SNTF 0x%04x\n", status); 75874462Salfred for (i = 0; i < 16; i++) { 7591558Srgrimes if ((status & (1 << i)) == 0) 7601558Srgrimes continue; 7611558Srgrimes if (xpt_create_path(&dpath, NULL, 762121556Speter xpt_path_path_id(ch->path), i, 0) == CAM_REQ_CMP) { 76331656Sguido xpt_async(AC_SCSI_AEN, dpath, NULL); 76474462Salfred xpt_free_path(dpath); 7651558Srgrimes } 7661558Srgrimes } 7671558Srgrimes 7681558Srgrimes} 7691558Srgrimes 7701558Srgrimesstatic void 7719336Sdfrsiis_phy_check_events(device_t dev) 7729336Sdfr{ 7731558Srgrimes struct siis_channel *ch = device_get_softc(dev); 77451968Salfred 7751558Srgrimes /* If we have a connection event, deal with it */ 7769336Sdfr if (ch->pm_level == 0) { 77774462Salfred u_int32_t status = ATA_INL(ch->r_mem, SIIS_P_SSTS); 7781558Srgrimes union ccb *ccb; 7791558Srgrimes 78031656Sguido if (bootverbose) { 78137663Scharnier if (((status & ATA_SS_DET_MASK) == ATA_SS_DET_PHY_ONLINE) && 78274462Salfred ((status & ATA_SS_SPD_MASK) != ATA_SS_SPD_NO_SPEED) && 7831558Srgrimes ((status & ATA_SS_IPM_MASK) == ATA_SS_IPM_ACTIVE)) { 78437663Scharnier device_printf(dev, "CONNECT requested\n"); 78528911Sguido } else 7861558Srgrimes device_printf(dev, "DISCONNECT requested\n"); 7871558Srgrimes } 7881558Srgrimes siis_reset(dev); 7899336Sdfr if ((ccb = xpt_alloc_ccb_nowait()) == NULL) 7901558Srgrimes return; 7919336Sdfr if (xpt_create_path(&ccb->ccb_h.path, NULL, 7929336Sdfr cam_sim_path(ch->sim), 7931558Srgrimes CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 79474462Salfred xpt_free_ccb(ccb); 79574462Salfred return; 79674462Salfred } 79728911Sguido xpt_rescan(ccb); 798121556Speter } 79928911Sguido} 80037663Scharnier 80128911Sguidostatic void 80228911Sguidosiis_ch_intr_locked(void *data) 80328911Sguido{ 8049336Sdfr device_t dev = (device_t)data; 8059336Sdfr struct siis_channel *ch = device_get_softc(dev); 8069336Sdfr 8079336Sdfr mtx_lock(&ch->mtx); 8089336Sdfr siis_ch_intr(data); 8091558Srgrimes mtx_unlock(&ch->mtx); 81023681Speter} 8119336Sdfr 8121558Srgrimesstatic void 81337663Scharniersiis_ch_intr(void *data) 814121556Speter{ 8151558Srgrimes device_t dev = (device_t)data; 81637663Scharnier struct siis_channel *ch = device_get_softc(dev); 8179336Sdfr uint32_t istatus, sstatus, ctx, estatus, ok, err = 0; 8181558Srgrimes enum siis_err_type et; 8191558Srgrimes int i, ccs, port, tslots; 820121556Speter 821121556Speter mtx_assert(&ch->mtx, MA_OWNED); 82237663Scharnier /* Read command statuses. */ 82374462Salfred sstatus = ATA_INL(ch->r_mem, SIIS_P_SS); 82474462Salfred ok = ch->rslots & ~sstatus; 8251558Srgrimes /* Complete all successfull commands. */ 82674462Salfred for (i = 0; i < SIIS_MAX_SLOTS; i++) { 8271558Srgrimes if ((ok >> i) & 1) 82837663Scharnier siis_end_transaction(&ch->slot[i], SIIS_ERR_NONE); 829121767Speter } 83031656Sguido /* Do we have any other events? */ 83131656Sguido if ((sstatus & SIIS_P_SS_ATTN) == 0) 83274462Salfred return; 83331656Sguido /* Read and clear interrupt statuses. */ 8341558Srgrimes istatus = ATA_INL(ch->r_mem, SIIS_P_IS) & 83531656Sguido (0xFFFF & ~SIIS_P_IX_COMMCOMP); 83631656Sguido ATA_OUTL(ch->r_mem, SIIS_P_IS, istatus); 83774462Salfred /* Process PHY events */ 83831656Sguido if (istatus & SIIS_P_IX_PHYRDYCHG) 83928911Sguido siis_phy_check_events(dev); 840121556Speter /* Process NOTIFY events */ 841121556Speter if (istatus & SIIS_P_IX_SDBN) 84237663Scharnier siis_notify_events(dev); 8439336Sdfr /* Process command errors */ 8441558Srgrimes if (istatus & SIIS_P_IX_COMMERR) { 8451558Srgrimes estatus = ATA_INL(ch->r_mem, SIIS_P_CMDERR); 846121556Speter ctx = ATA_INL(ch->r_mem, SIIS_P_CTX); 84737663Scharnier ccs = (ctx & SIIS_P_CTX_SLOT) >> SIIS_P_CTX_SLOT_SHIFT; 848121767Speter port = (ctx & SIIS_P_CTX_PMP) >> SIIS_P_CTX_PMP_SHIFT; 84931656Sguido err = ch->rslots & sstatus; 85031656Sguido//device_printf(dev, "%s ERROR ss %08x is %08x rs %08x es %d act %d port %d serr %08x\n", 85174462Salfred// __func__, sstatus, istatus, ch->rslots, estatus, ccs, port, 8521558Srgrimes// ATA_INL(ch->r_mem, SIIS_P_SERR)); 8531558Srgrimes 8549336Sdfr if (!ch->readlog && !ch->recovery) { 85531656Sguido xpt_freeze_simq(ch->sim, ch->numrslots); 85631656Sguido ch->recovery = 1; 85774462Salfred } 8581558Srgrimes if (ch->frozen) { 8591558Srgrimes union ccb *fccb = ch->frozen; 8601558Srgrimes ch->frozen = NULL; 861121556Speter fccb->ccb_h.status &= ~CAM_STATUS_MASK; 86231656Sguido fccb->ccb_h.status |= CAM_REQUEUE_REQ | CAM_RELEASE_SIMQ; 86374462Salfred if (!(fccb->ccb_h.status & CAM_DEV_QFRZN)) { 8641558Srgrimes xpt_freeze_devq(fccb->ccb_h.path, 1); 8651558Srgrimes fccb->ccb_h.status |= CAM_DEV_QFRZN; 8661558Srgrimes } 86751968Salfred xpt_done(fccb); 86851968Salfred } 86951968Salfred if (estatus == SIIS_P_CMDERR_DEV || 87074462Salfred estatus == SIIS_P_CMDERR_SDB || 87151968Salfred estatus == SIIS_P_CMDERR_DATAFIS) { 872121556Speter tslots = ch->numtslots[port]; 87337663Scharnier for (i = 0; i < SIIS_MAX_SLOTS; i++) { 87474462Salfred /* XXX: requests in loading state. */ 87575635Siedowse if (((ch->rslots >> i) & 1) == 0) 87675635Siedowse continue; 877121767Speter if (ch->slot[i].ccb->ccb_h.target_id != port) 87831656Sguido continue; 87931656Sguido if (tslots == 0) { 88074462Salfred /* Untagged operation. */ 8811558Srgrimes if (i == ccs) 8821558Srgrimes et = SIIS_ERR_TFE; 8839336Sdfr else 88431656Sguido et = SIIS_ERR_INNOCENT; 88531656Sguido } else { 88674462Salfred /* Tagged operation. */ 8871558Srgrimes et = SIIS_ERR_NCQ; 8881558Srgrimes } 8891558Srgrimes siis_end_transaction(&ch->slot[i], et); 890121556Speter } 89137663Scharnier /* 89274462Salfred * We can't reinit port if there are some other 89375635Siedowse * commands active, use resume to complete them. 89475635Siedowse */ 895121767Speter if (ch->rslots != 0) 89631656Sguido ATA_OUTL(ch->r_mem, SIIS_P_CTLSET, SIIS_P_CTL_RESUME); 89731656Sguido } else { 89874462Salfred if (estatus == SIIS_P_CMDERR_SENDFIS || 8991558Srgrimes estatus == SIIS_P_CMDERR_INCSTATE || 9001558Srgrimes estatus == SIIS_P_CMDERR_PPE || 901121556Speter estatus == SIIS_P_CMDERR_SERVICE) { 902121556Speter et = SIIS_ERR_SATA; 903121556Speter } else 904100117Salfred et = SIIS_ERR_INVALID; 905121767Speter for (i = 0; i < SIIS_MAX_SLOTS; i++) { 90631656Sguido /* XXX: requests in loading state. */ 90731656Sguido if (((ch->rslots >> i) & 1) == 0) 90874462Salfred continue; 9091558Srgrimes siis_end_transaction(&ch->slot[i], et); 9101558Srgrimes } 9111558Srgrimes } 9121558Srgrimes } 9131558Srgrimes} 9141558Srgrimes 9151558Srgrimes/* Must be called with channel locked. */ 9161558Srgrimesstatic int 9171558Srgrimessiis_check_collision(device_t dev, union ccb *ccb) 9181558Srgrimes{ 9191558Srgrimes struct siis_channel *ch = device_get_softc(dev); 9201558Srgrimes 9211558Srgrimes mtx_assert(&ch->mtx, MA_OWNED); 9221558Srgrimes if ((ccb->ccb_h.func_code == XPT_ATA_IO) && 9231558Srgrimes (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA)) { 9241558Srgrimes /* Tagged command while we have no supported tag free. */ 9251558Srgrimes if (((~ch->oslots) & (0x7fffffff >> (31 - 9261558Srgrimes ch->curr[ccb->ccb_h.target_id].tags))) == 0) 9271558Srgrimes return (1); 9289336Sdfr } 9291558Srgrimes if ((ccb->ccb_h.func_code == XPT_ATA_IO) && 9301558Srgrimes (ccb->ataio.cmd.flags & (CAM_ATAIO_CONTROL | CAM_ATAIO_NEEDRESULT))) { 9319336Sdfr /* Atomic command while anything active. */ 9321558Srgrimes if (ch->numrslots != 0) 9339336Sdfr return (1); 9341558Srgrimes } 93592806Sobrien /* We have some atomic command running. */ 9369336Sdfr if (ch->aslots != 0) 9371558Srgrimes return (1); 9381558Srgrimes return (0); 9391558Srgrimes} 9409336Sdfr 9419336Sdfr/* Must be called with channel locked. */ 9429336Sdfrstatic void 9439336Sdfrsiis_begin_transaction(device_t dev, union ccb *ccb) 9449336Sdfr{ 9459336Sdfr struct siis_channel *ch = device_get_softc(dev); 9469336Sdfr struct siis_slot *slot; 9479336Sdfr int tag, tags; 9489336Sdfr 94983653Speter mtx_assert(&ch->mtx, MA_OWNED); 9509336Sdfr /* Choose empty slot. */ 9519336Sdfr tags = SIIS_MAX_SLOTS; 9529336Sdfr if ((ccb->ccb_h.func_code == XPT_ATA_IO) && 9539336Sdfr (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA)) 9549336Sdfr tags = ch->curr[ccb->ccb_h.target_id].tags; 9559336Sdfr tag = fls((~ch->oslots) & (0x7fffffff >> (31 - tags))) - 1; 9561558Srgrimes /* Occupy chosen slot. */ 9571558Srgrimes slot = &ch->slot[tag]; 9581558Srgrimes slot->ccb = ccb; 9591558Srgrimes /* Update channel stats. */ 9601558Srgrimes ch->oslots |= (1 << slot->slot); 9611558Srgrimes ch->numrslots++; 9621558Srgrimes if ((ccb->ccb_h.func_code == XPT_ATA_IO) && 9631558Srgrimes (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA)) { 9641558Srgrimes ch->numtslots[ccb->ccb_h.target_id]++; 9651558Srgrimes } 9661558Srgrimes if ((ccb->ccb_h.func_code == XPT_ATA_IO) && 9671558Srgrimes (ccb->ataio.cmd.flags & (CAM_ATAIO_CONTROL | CAM_ATAIO_NEEDRESULT))) 9681558Srgrimes ch->aslots |= (1 << slot->slot); 9691558Srgrimes slot->dma.nsegs = 0; 9701558Srgrimes /* If request moves data, setup and load SG list */ 9711558Srgrimes if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 9721558Srgrimes void *buf; 9731558Srgrimes bus_size_t size; 9741558Srgrimes 9751558Srgrimes slot->state = SIIS_SLOT_LOADING; 9761558Srgrimes if (ccb->ccb_h.func_code == XPT_ATA_IO) { 9771558Srgrimes buf = ccb->ataio.data_ptr; 9781558Srgrimes size = ccb->ataio.dxfer_len; 9791558Srgrimes } else { 9801558Srgrimes buf = ccb->csio.data_ptr; 9811558Srgrimes size = ccb->csio.dxfer_len; 9821558Srgrimes } 9831558Srgrimes bus_dmamap_load(ch->dma.data_tag, slot->dma.data_map, 9841558Srgrimes buf, size, siis_dmasetprd, slot, 0); 9851558Srgrimes } else 9861558Srgrimes siis_execute_transaction(slot); 9871558Srgrimes} 9881558Srgrimes 989100117Salfred/* Locked by busdma engine. */ 9901558Srgrimesstatic void 9911558Srgrimessiis_dmasetprd(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 992100117Salfred{ 9931558Srgrimes struct siis_slot *slot = arg; 9941558Srgrimes struct siis_channel *ch = device_get_softc(slot->dev); 9951558Srgrimes struct siis_cmd *ctp; 9969336Sdfr struct siis_dma_prd *prd; 9979336Sdfr int i; 9981558Srgrimes 9999336Sdfr mtx_assert(&ch->mtx, MA_OWNED); 10009336Sdfr if (error) { 10019336Sdfr device_printf(slot->dev, "DMA load error\n"); 10021558Srgrimes if (!ch->readlog) 10031558Srgrimes xpt_freeze_simq(ch->sim, 1); 10041558Srgrimes siis_end_transaction(slot, SIIS_ERR_INVALID); 1005100117Salfred return; 1006100117Salfred } 10071558Srgrimes KASSERT(nsegs <= SIIS_SG_ENTRIES, ("too many DMA segment entries\n")); 10081558Srgrimes /* Get a piece of the workspace for this request */ 10091558Srgrimes ctp = (struct siis_cmd *) 1010100117Salfred (ch->dma.work + SIIS_CT_OFFSET + (SIIS_CT_SIZE * slot->slot)); 10111558Srgrimes /* Fill S/G table */ 10121558Srgrimes if (slot->ccb->ccb_h.func_code == XPT_ATA_IO) 10131558Srgrimes prd = &ctp->u.ata.prd[0]; 10149336Sdfr else 10151558Srgrimes prd = &ctp->u.atapi.prd[0]; 10161558Srgrimes for (i = 0; i < nsegs; i++) { 10171558Srgrimes prd[i].dba = htole64(segs[i].ds_addr); 10181558Srgrimes prd[i].dbc = htole32(segs[i].ds_len); 10199336Sdfr prd[i].control = 0; 10201558Srgrimes } 10211558Srgrimes prd[nsegs - 1].control = htole32(SIIS_PRD_TRM); 10221558Srgrimes slot->dma.nsegs = nsegs; 10231558Srgrimes bus_dmamap_sync(ch->dma.data_tag, slot->dma.data_map, 10241558Srgrimes ((slot->ccb->ccb_h.flags & CAM_DIR_IN) ? 10251558Srgrimes BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE)); 10261558Srgrimes siis_execute_transaction(slot); 10271558Srgrimes} 1028100117Salfred 10291558Srgrimes/* Must be called with channel locked. */ 10301558Srgrimesstatic void 10311558Srgrimessiis_execute_transaction(struct siis_slot *slot) 10321558Srgrimes{ 1033100117Salfred device_t dev = slot->dev; 10341558Srgrimes struct siis_channel *ch = device_get_softc(dev); 10351558Srgrimes struct siis_cmd *ctp; 10361558Srgrimes union ccb *ccb = slot->ccb; 10371558Srgrimes u_int64_t prb_bus; 10381558Srgrimes 10391558Srgrimes mtx_assert(&ch->mtx, MA_OWNED); 10401558Srgrimes /* Get a piece of the workspace for this request */ 10411558Srgrimes ctp = (struct siis_cmd *) 10421558Srgrimes (ch->dma.work + SIIS_CT_OFFSET + (SIIS_CT_SIZE * slot->slot)); 1043100117Salfred ctp->control = 0; 10441558Srgrimes ctp->protocol_override = 0; 10451558Srgrimes ctp->transfer_count = 0; 10461558Srgrimes /* Special handling for Soft Reset command. */ 10471558Srgrimes if (ccb->ccb_h.func_code == XPT_ATA_IO) { 10481558Srgrimes if (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) { 10491558Srgrimes ctp->control |= htole16(SIIS_PRB_SOFT_RESET); 10501558Srgrimes } else { 10511558Srgrimes ctp->control |= htole16(SIIS_PRB_PROTOCOL_OVERRIDE); 10521558Srgrimes if (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA) { 10531558Srgrimes ctp->protocol_override |= 1054100117Salfred htole16(SIIS_PRB_PROTO_NCQ); 1055100117Salfred } 1056100117Salfred if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1057100117Salfred ctp->protocol_override |= 1058100117Salfred htole16(SIIS_PRB_PROTO_READ); 1059100117Salfred } else 1060100117Salfred if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { 10611558Srgrimes ctp->protocol_override |= 10621558Srgrimes htole16(SIIS_PRB_PROTO_WRITE); 10631558Srgrimes } 10641558Srgrimes } 10651558Srgrimes } else if (ccb->ccb_h.func_code == XPT_SCSI_IO) { 10661558Srgrimes if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 10671558Srgrimes ctp->control |= htole16(SIIS_PRB_PACKET_READ); 106874462Salfred else 10698871Srgrimes if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 10701558Srgrimes ctp->control |= htole16(SIIS_PRB_PACKET_WRITE); 10711558Srgrimes } 10721558Srgrimes /* Special handling for Soft Reset command. */ 10731558Srgrimes if ((ccb->ccb_h.func_code == XPT_ATA_IO) && 10741558Srgrimes (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) && 10751558Srgrimes (ccb->ataio.cmd.control & ATA_A_RESET)) { 10768871Srgrimes /* Kick controller into sane state */ 10771558Srgrimes siis_portinit(dev); 10781558Srgrimes } 10791558Srgrimes /* Setup the FIS for this request */ 10801558Srgrimes if (!siis_setup_fis(dev, ctp, ccb, slot->slot)) { 10811558Srgrimes device_printf(ch->dev, "Setting up SATA FIS failed\n"); 10821558Srgrimes if (!ch->readlog) 10831558Srgrimes xpt_freeze_simq(ch->sim, 1); 10841558Srgrimes siis_end_transaction(slot, SIIS_ERR_INVALID); 10851558Srgrimes return; 10861558Srgrimes } 10871558Srgrimes bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, 10881558Srgrimes BUS_DMASYNC_PREWRITE); 1089100117Salfred /* Issue command to the controller. */ 10901558Srgrimes slot->state = SIIS_SLOT_RUNNING; 10911558Srgrimes ch->rslots |= (1 << slot->slot); 10921558Srgrimes prb_bus = ch->dma.work_bus + 10931558Srgrimes SIIS_CT_OFFSET + (SIIS_CT_SIZE * slot->slot); 10941558Srgrimes ATA_OUTL(ch->r_mem, SIIS_P_CACTL(slot->slot), prb_bus); 1095100117Salfred ATA_OUTL(ch->r_mem, SIIS_P_CACTH(slot->slot), prb_bus >> 32); 1096100117Salfred /* Start command execution timeout */ 1097100117Salfred callout_reset(&slot->timeout, (int)ccb->ccb_h.timeout * hz / 1000, 1098100117Salfred (timeout_t*)siis_timeout, slot); 1099100117Salfred return; 1100100117Salfred} 1101100117Salfred 1102100117Salfred/* Must be called with channel locked. */ 1103100117Salfredstatic void 1104100117Salfredsiis_process_timeout(device_t dev) 1105100117Salfred{ 1106100117Salfred struct siis_channel *ch = device_get_softc(dev); 1107100117Salfred int i; 1108100117Salfred 1109100117Salfred mtx_assert(&ch->mtx, MA_OWNED); 1110100117Salfred if (!ch->readlog && !ch->recovery) { 1111100117Salfred xpt_freeze_simq(ch->sim, ch->numrslots); 1112100117Salfred ch->recovery = 1; 111396622Siedowse } 111496622Siedowse /* Handle the rest of commands. */ 11151558Srgrimes for (i = 0; i < SIIS_MAX_SLOTS; i++) { 11161558Srgrimes /* Do we have a running request on slot? */ 11171558Srgrimes if (ch->slot[i].state < SIIS_SLOT_RUNNING) 1118166440Spjd continue; 11191558Srgrimes siis_end_transaction(&ch->slot[i], SIIS_ERR_TIMEOUT); 1120166440Spjd } 1121166440Spjd} 11221558Srgrimes 11231558Srgrimes/* Must be called with channel locked. */ 11241558Srgrimesstatic void 11251558Srgrimessiis_rearm_timeout(device_t dev) 11261558Srgrimes{ 1127166440Spjd struct siis_channel *ch = device_get_softc(dev); 112872650Sgreen int i; 11291558Srgrimes 1130166440Spjd mtx_assert(&ch->mtx, MA_OWNED); 11311558Srgrimes for (i = 0; i < SIIS_MAX_SLOTS; i++) { 11321558Srgrimes struct siis_slot *slot = &ch->slot[i]; 11331558Srgrimes 11341558Srgrimes /* Do we have a running request on slot? */ 113537663Scharnier if (slot->state < SIIS_SLOT_RUNNING) 11361558Srgrimes continue; 11371558Srgrimes if ((ch->toslots & (1 << i)) == 0) 11381558Srgrimes continue; 11391558Srgrimes callout_reset(&slot->timeout, 11401558Srgrimes (int)slot->ccb->ccb_h.timeout * hz / 1000, 11411558Srgrimes (timeout_t*)siis_timeout, slot); 11421558Srgrimes } 11431558Srgrimes} 11441558Srgrimes 11451558Srgrimes/* Locked by callout mechanism. */ 11461558Srgrimesstatic void 11471558Srgrimessiis_timeout(struct siis_slot *slot) 11481558Srgrimes{ 11491558Srgrimes device_t dev = slot->dev; 11501558Srgrimes struct siis_channel *ch = device_get_softc(dev); 11511558Srgrimes 11521558Srgrimes mtx_assert(&ch->mtx, MA_OWNED); 11531558Srgrimes /* Check for stale timeout. */ 11541558Srgrimes if (slot->state < SIIS_SLOT_RUNNING) 11551558Srgrimes return; 11561558Srgrimes device_printf(dev, "Timeout on slot %d\n", slot->slot); 11571558Srgrimes device_printf(dev, "%s is %08x ss %08x rs %08x es %08x sts %08x serr %08x\n", 11581558Srgrimes __func__, ATA_INL(ch->r_mem, SIIS_P_IS), 11591558Srgrimes ATA_INL(ch->r_mem, SIIS_P_SS), ch->rslots, 11601558Srgrimes ATA_INL(ch->r_mem, SIIS_P_CMDERR), ATA_INL(ch->r_mem, SIIS_P_STS), 11611558Srgrimes ATA_INL(ch->r_mem, SIIS_P_SERR)); 11621558Srgrimes 11631558Srgrimes if (ch->toslots == 0) 11641558Srgrimes xpt_freeze_simq(ch->sim, 1); 11651558Srgrimes ch->toslots |= (1 << slot->slot); 11661558Srgrimes if ((ch->rslots & ~ch->toslots) == 0) 116737663Scharnier siis_process_timeout(dev); 11681558Srgrimes else 11691558Srgrimes device_printf(dev, " ... waiting for slots %08x\n", 11701558Srgrimes ch->rslots & ~ch->toslots); 11711558Srgrimes} 11721558Srgrimes 11731558Srgrimes/* Must be called with channel locked. */ 11741558Srgrimesstatic void 11751558Srgrimessiis_end_transaction(struct siis_slot *slot, enum siis_err_type et) 11761558Srgrimes{ 11771558Srgrimes device_t dev = slot->dev; 11781558Srgrimes struct siis_channel *ch = device_get_softc(dev); 11791558Srgrimes union ccb *ccb = slot->ccb; 118037663Scharnier 11811558Srgrimes mtx_assert(&ch->mtx, MA_OWNED); 11821558Srgrimes bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, 11831558Srgrimes BUS_DMASYNC_POSTWRITE); 11841558Srgrimes /* Read result registers to the result struct 11851558Srgrimes * May be incorrect if several commands finished same time, 11861558Srgrimes * so read only when sure or have to. 11871558Srgrimes */ 11881558Srgrimes if (ccb->ccb_h.func_code == XPT_ATA_IO) { 11891558Srgrimes struct ata_res *res = &ccb->ataio.res; 11901558Srgrimes if ((et == SIIS_ERR_TFE) || 11911558Srgrimes (ccb->ataio.cmd.flags & CAM_ATAIO_NEEDRESULT)) { 11921558Srgrimes int offs = SIIS_P_LRAM_SLOT(slot->slot) + 8; 11931558Srgrimes 11941558Srgrimes res->status = ATA_INB(ch->r_mem, offs + 2); 11951558Srgrimes res->error = ATA_INB(ch->r_mem, offs + 3); 11961558Srgrimes res->lba_low = ATA_INB(ch->r_mem, offs + 4); 11971558Srgrimes res->lba_mid = ATA_INB(ch->r_mem, offs + 5); 11981558Srgrimes res->lba_high = ATA_INB(ch->r_mem, offs + 6); 11991558Srgrimes res->device = ATA_INB(ch->r_mem, offs + 7); 12001558Srgrimes res->lba_low_exp = ATA_INB(ch->r_mem, offs + 8); 12011558Srgrimes res->lba_mid_exp = ATA_INB(ch->r_mem, offs + 9); 12021558Srgrimes res->lba_high_exp = ATA_INB(ch->r_mem, offs + 10); 12031558Srgrimes res->sector_count = ATA_INB(ch->r_mem, offs + 12); 12041558Srgrimes res->sector_count_exp = ATA_INB(ch->r_mem, offs + 13); 12051558Srgrimes } else 12061558Srgrimes bzero(res, sizeof(*res)); 120774462Salfred } 120874462Salfred if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 120974462Salfred bus_dmamap_sync(ch->dma.data_tag, slot->dma.data_map, 12101558Srgrimes (ccb->ccb_h.flags & CAM_DIR_IN) ? 121137663Scharnier BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 12121558Srgrimes bus_dmamap_unload(ch->dma.data_tag, slot->dma.data_map); 12131558Srgrimes } 12141558Srgrimes /* Set proper result status. */ 12151558Srgrimes if (et != SIIS_ERR_NONE || ch->recovery) { 12161558Srgrimes ch->eslots |= (1 << slot->slot); 12171558Srgrimes ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 12181558Srgrimes } 12191558Srgrimes /* In case of error, freeze device for proper recovery. */ 12201558Srgrimes if (et != SIIS_ERR_NONE && 12211558Srgrimes !(ccb->ccb_h.status & CAM_DEV_QFRZN)) { 12221558Srgrimes xpt_freeze_devq(ccb->ccb_h.path, 1); 12231558Srgrimes ccb->ccb_h.status |= CAM_DEV_QFRZN; 12241558Srgrimes } 12251558Srgrimes ccb->ccb_h.status &= ~CAM_STATUS_MASK; 12261558Srgrimes switch (et) { 12271558Srgrimes case SIIS_ERR_NONE: 12281558Srgrimes ccb->ccb_h.status |= CAM_REQ_CMP; 12291558Srgrimes if (ccb->ccb_h.func_code == XPT_SCSI_IO) 12301558Srgrimes ccb->csio.scsi_status = SCSI_STATUS_OK; 12311558Srgrimes break; 12321558Srgrimes case SIIS_ERR_INVALID: 12331558Srgrimes ch->fatalerr = 1; 12341558Srgrimes ccb->ccb_h.status |= CAM_REQ_INVALID; 12351558Srgrimes break; 12361558Srgrimes case SIIS_ERR_INNOCENT: 12371558Srgrimes ccb->ccb_h.status |= CAM_REQUEUE_REQ; 12381558Srgrimes break; 12391558Srgrimes case SIIS_ERR_TFE: 12401558Srgrimes case SIIS_ERR_NCQ: 12411558Srgrimes if (ccb->ccb_h.func_code == XPT_SCSI_IO) { 12421558Srgrimes ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 12431558Srgrimes ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; 12441558Srgrimes } else { 12451558Srgrimes ccb->ccb_h.status |= CAM_ATA_STATUS_ERROR; 124637003Sjoerg } 124737663Scharnier break; 124837663Scharnier case SIIS_ERR_SATA: 124937004Sjoerg ch->fatalerr = 1; 125037003Sjoerg ccb->ccb_h.status |= CAM_UNCOR_PARITY; 125137663Scharnier break; 125237663Scharnier case SIIS_ERR_TIMEOUT: 125329317Sjlemon ch->fatalerr = 1; 12541558Srgrimes ccb->ccb_h.status |= CAM_CMD_TIMEOUT; 12557401Swpaul break; 125637663Scharnier default: 125729317Sjlemon ccb->ccb_h.status |= CAM_REQ_CMP_ERR; 12581558Srgrimes } 12591558Srgrimes /* Free slot. */ 12601558Srgrimes ch->oslots &= ~(1 << slot->slot); 12611558Srgrimes ch->rslots &= ~(1 << slot->slot); 12621558Srgrimes ch->aslots &= ~(1 << slot->slot); 12631558Srgrimes if (et != SIIS_ERR_TIMEOUT) { 12641558Srgrimes if (ch->toslots == (1 << slot->slot)) 12651558Srgrimes xpt_release_simq(ch->sim, TRUE); 12661558Srgrimes ch->toslots &= ~(1 << slot->slot); 12671558Srgrimes } 12681558Srgrimes slot->state = SIIS_SLOT_EMPTY; 12691558Srgrimes slot->ccb = NULL; 12701558Srgrimes /* Update channel stats. */ 12711558Srgrimes ch->numrslots--; 12721558Srgrimes if ((ccb->ccb_h.func_code == XPT_ATA_IO) && 127375641Siedowse (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA)) { 12741558Srgrimes ch->numtslots[ccb->ccb_h.target_id]--; 127537663Scharnier } 12761558Srgrimes /* If it was our READ LOG command - process it. */ 12771558Srgrimes if (ch->readlog) { 12781558Srgrimes siis_process_read_log(dev, ccb); 12791558Srgrimes /* If it was NCQ command error, put result on hold. */ 12801558Srgrimes } else if (et == SIIS_ERR_NCQ) { 12811558Srgrimes ch->hold[slot->slot] = ccb; 128275801Siedowse ch->numhslots++; 12831558Srgrimes } else 12841558Srgrimes xpt_done(ccb); 128529317Sjlemon /* Unfreeze frozen command. */ 128674462Salfred if (ch->frozen && !siis_check_collision(dev, ch->frozen)) { 128774462Salfred union ccb *fccb = ch->frozen; 128829317Sjlemon ch->frozen = NULL; 128929317Sjlemon siis_begin_transaction(dev, fccb); 129029317Sjlemon xpt_release_simq(ch->sim, TRUE); 129129317Sjlemon } 129274462Salfred /* If we have no other active commands, ... */ 129329317Sjlemon if (ch->rslots == 0) { 129429317Sjlemon /* if there were timeouts or fatal error - reset port. */ 129529317Sjlemon if (ch->toslots != 0 || ch->fatalerr) { 129629317Sjlemon siis_reset(dev); 129729317Sjlemon } else { 12981558Srgrimes /* if we have slots in error, we can reinit port. */ 12991558Srgrimes if (ch->eslots != 0) 13001558Srgrimes siis_portinit(dev); 13011558Srgrimes /* if there commands on hold, we can do READ LOG. */ 13021558Srgrimes if (!ch->readlog && ch->numhslots) 13031558Srgrimes siis_issue_read_log(dev); 13041558Srgrimes } 13051558Srgrimes /* If all the reset of commands are in timeout - abort them. */ 13061558Srgrimes } else if ((ch->rslots & ~ch->toslots) == 0 && 130775635Siedowse et != SIIS_ERR_TIMEOUT) 130875635Siedowse siis_rearm_timeout(dev); 130975635Siedowse} 131075635Siedowse 131175635Siedowsestatic void 13121558Srgrimessiis_issue_read_log(device_t dev) 13131558Srgrimes{ 13141558Srgrimes struct siis_channel *ch = device_get_softc(dev); 13151558Srgrimes union ccb *ccb; 13161558Srgrimes struct ccb_ataio *ataio; 13171558Srgrimes int i; 13189336Sdfr 13191558Srgrimes /* Find some holden command. */ 13201558Srgrimes for (i = 0; i < SIIS_MAX_SLOTS; i++) { 13211558Srgrimes if (ch->hold[i]) 13221558Srgrimes break; 13239336Sdfr } 13241558Srgrimes if (i == SIIS_MAX_SLOTS) 13251558Srgrimes return; 13261558Srgrimes ch->readlog = 1; 13271558Srgrimes ccb = xpt_alloc_ccb_nowait(); 13281558Srgrimes if (ccb == NULL) { 13291558Srgrimes device_printf(dev, "Unable allocate READ LOG command"); 13301558Srgrimes return; /* XXX */ 13311558Srgrimes } 13321558Srgrimes ccb->ccb_h = ch->hold[i]->ccb_h; /* Reuse old header. */ 13331558Srgrimes ccb->ccb_h.func_code = XPT_ATA_IO; 13341558Srgrimes ccb->ccb_h.flags = CAM_DIR_IN; 13351558Srgrimes ccb->ccb_h.timeout = 1000; /* 1s should be enough. */ 13361558Srgrimes ataio = &ccb->ataio; 13371558Srgrimes ataio->data_ptr = malloc(512, M_SIIS, M_NOWAIT); 13381558Srgrimes if (ataio->data_ptr == NULL) { 13391558Srgrimes device_printf(dev, "Unable allocate memory for READ LOG command"); 13401558Srgrimes return; /* XXX */ 13411558Srgrimes } 13421558Srgrimes ataio->dxfer_len = 512; 13431558Srgrimes bzero(&ataio->cmd, sizeof(ataio->cmd)); 13441558Srgrimes ataio->cmd.flags = CAM_ATAIO_48BIT; 13451558Srgrimes ataio->cmd.command = 0x2F; /* READ LOG EXT */ 13461558Srgrimes ataio->cmd.sector_count = 1; 13471558Srgrimes ataio->cmd.sector_count_exp = 0; 13481558Srgrimes ataio->cmd.lba_low = 0x10; 13491558Srgrimes ataio->cmd.lba_mid = 0; 13501558Srgrimes ataio->cmd.lba_mid_exp = 0; 13511558Srgrimes siis_begin_transaction(dev, ccb); 1352166440Spjd} 1353166440Spjd 1354166440Spjdstatic void 1355166440Spjdsiis_process_read_log(device_t dev, union ccb *ccb) 1356166440Spjd{ 1357166440Spjd struct siis_channel *ch = device_get_softc(dev); 1358166440Spjd uint8_t *data; 1359166440Spjd struct ata_res *res; 1360166440Spjd int i; 1361166440Spjd 1362166440Spjd ch->readlog = 0; 1363166440Spjd data = ccb->ataio.data_ptr; 1364166440Spjd if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP && 1365166440Spjd (data[0] & 0x80) == 0) { 1366166440Spjd for (i = 0; i < SIIS_MAX_SLOTS; i++) { 1367168684Spjd if (!ch->hold[i]) 1368166440Spjd continue; 1369166440Spjd if (ch->hold[i]->ccb_h.target_id != ccb->ccb_h.target_id) 1370166440Spjd continue; 1371166440Spjd if ((data[0] & 0x1F) == i) { 1372166440Spjd res = &ch->hold[i]->ataio.res; 1373166440Spjd res->status = data[2]; 1374166440Spjd res->error = data[3]; 1375166440Spjd res->lba_low = data[4]; 1376166440Spjd res->lba_mid = data[5]; 1377166440Spjd res->lba_high = data[6]; 1378166440Spjd res->device = data[7]; 1379166440Spjd res->lba_low_exp = data[8]; 1380166440Spjd res->lba_mid_exp = data[9]; 1381166440Spjd res->lba_high_exp = data[10]; 1382166440Spjd res->sector_count = data[12]; 1383166440Spjd res->sector_count_exp = data[13]; 1384166440Spjd } else { 1385166440Spjd ch->hold[i]->ccb_h.status &= ~CAM_STATUS_MASK; 1386166440Spjd ch->hold[i]->ccb_h.status |= CAM_REQUEUE_REQ; 1387166440Spjd } 1388166440Spjd xpt_done(ch->hold[i]); 1389166440Spjd ch->hold[i] = NULL; 1390166440Spjd ch->numhslots--; 1391166440Spjd } 1392166440Spjd } else { 1393166440Spjd if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 1394166440Spjd device_printf(dev, "Error while READ LOG EXT\n"); 1395166440Spjd else if ((data[0] & 0x80) == 0) { 1396166440Spjd device_printf(dev, "Non-queued command error in READ LOG EXT\n"); 1397166440Spjd } 1398166440Spjd for (i = 0; i < SIIS_MAX_SLOTS; i++) { 1399166440Spjd if (!ch->hold[i]) 1400166440Spjd continue; 1401166440Spjd if (ch->hold[i]->ccb_h.target_id != ccb->ccb_h.target_id) 1402166440Spjd continue; 1403166440Spjd xpt_done(ch->hold[i]); 1404166440Spjd ch->hold[i] = NULL; 1405166440Spjd ch->numhslots--; 1406166440Spjd } 1407166440Spjd } 1408166440Spjd free(ccb->ataio.data_ptr, M_SIIS); 1409166440Spjd xpt_free_ccb(ccb); 1410166440Spjd} 1411166440Spjd 1412166440Spjdstatic void 1413166440Spjdsiis_portinit(device_t dev) 1414166440Spjd{ 1415166440Spjd struct siis_channel *ch = device_get_softc(dev); 1416166440Spjd int i; 1417166440Spjd 1418166440Spjd ch->eslots = 0; 1419166440Spjd ch->recovery = 0; 1420166440Spjd ATA_OUTL(ch->r_mem, SIIS_P_CTLCLR, SIIS_P_CTL_RESUME); 1421166440Spjd for (i = 0; i < 16; i++) { 1422166440Spjd ATA_OUTL(ch->r_mem, SIIS_P_PMPSTS(i), 0), 1423166440Spjd ATA_OUTL(ch->r_mem, SIIS_P_PMPQACT(i), 0); 1424166440Spjd } 1425166440Spjd ATA_OUTL(ch->r_mem, SIIS_P_CTLSET, SIIS_P_CTL_PORT_INIT); 1426166440Spjd siis_wait_ready(dev, 1000); 1427166440Spjd} 1428166440Spjd 1429166440Spjdstatic int 1430166440Spjdsiis_devreset(device_t dev) 1431166440Spjd{ 1432166440Spjd struct siis_channel *ch = device_get_softc(dev); 1433166440Spjd int timeout = 0; 1434166440Spjd uint32_t val; 1435166440Spjd 1436166440Spjd ATA_OUTL(ch->r_mem, SIIS_P_CTLSET, SIIS_P_CTL_DEV_RESET); 1437166440Spjd while (((val = ATA_INL(ch->r_mem, SIIS_P_STS)) & 1438166440Spjd SIIS_P_CTL_DEV_RESET) != 0) { 1439166440Spjd DELAY(1000); 1440166440Spjd if (timeout++ > 100) { 1441166440Spjd device_printf(dev, "device reset stuck (timeout %dms) " 1442166440Spjd "status = %08x\n", timeout, val); 1443166440Spjd return (EBUSY); 1444166440Spjd } 1445166440Spjd } 1446166440Spjd return (0); 1447166440Spjd} 1448166440Spjd 1449166440Spjdstatic int 1450166440Spjdsiis_wait_ready(device_t dev, int t) 1451166440Spjd{ 1452166440Spjd struct siis_channel *ch = device_get_softc(dev); 1453166440Spjd int timeout = 0; 1454166440Spjd uint32_t val; 1455166440Spjd 1456166440Spjd while (((val = ATA_INL(ch->r_mem, SIIS_P_STS)) & 1457166440Spjd SIIS_P_CTL_READY) == 0) { 1458166440Spjd DELAY(1000); 1459166440Spjd if (timeout++ > t) { 1460166440Spjd device_printf(dev, "port is not ready (timeout %dms) " 1461166440Spjd "status = %08x\n", t, val); 1462166440Spjd return (EBUSY); 1463166440Spjd } 1464166440Spjd } 1465166440Spjd return (0); 1466166440Spjd} 1467166440Spjd 1468166440Spjdstatic void 1469166440Spjdsiis_reset(device_t dev) 1470168684Spjd{ 1471166440Spjd struct siis_channel *ch = device_get_softc(dev); 1472166440Spjd int i, retry = 0, sata_rev; 1473166440Spjd uint32_t val; 1474166440Spjd 1475168684Spjd xpt_freeze_simq(ch->sim, 1); 1476168684Spjd if (bootverbose) 1477166440Spjd device_printf(dev, "SIIS reset...\n"); 1478166440Spjd if (!ch->readlog && !ch->recovery) 1479166440Spjd xpt_freeze_simq(ch->sim, ch->numrslots); 1480168684Spjd /* Requeue frozen command. */ 1481166440Spjd if (ch->frozen) { 1482168684Spjd union ccb *fccb = ch->frozen; 1483168684Spjd ch->frozen = NULL; 1484168684Spjd fccb->ccb_h.status &= ~CAM_STATUS_MASK; 1485168684Spjd fccb->ccb_h.status |= CAM_REQUEUE_REQ | CAM_RELEASE_SIMQ; 1486166440Spjd if (!(fccb->ccb_h.status & CAM_DEV_QFRZN)) { 1487166440Spjd xpt_freeze_devq(fccb->ccb_h.path, 1); 1488166440Spjd fccb->ccb_h.status |= CAM_DEV_QFRZN; 14891558Srgrimes } 14901558Srgrimes xpt_done(fccb); 14911558Srgrimes } 14921558Srgrimes /* Requeue all running commands. */ 14931558Srgrimes for (i = 0; i < SIIS_MAX_SLOTS; i++) { 14941558Srgrimes /* Do we have a running request on slot? */ 14951558Srgrimes if (ch->slot[i].state < SIIS_SLOT_RUNNING) 14961558Srgrimes continue; 14971558Srgrimes /* XXX; Commands in loading state. */ 14981558Srgrimes siis_end_transaction(&ch->slot[i], SIIS_ERR_INNOCENT); 149923681Speter } 15001558Srgrimes /* Finish all holden commands as-is. */ 15011558Srgrimes for (i = 0; i < SIIS_MAX_SLOTS; i++) { 15021558Srgrimes if (!ch->hold[i]) 15031558Srgrimes continue; 15041558Srgrimes xpt_done(ch->hold[i]); 15051558Srgrimes ch->hold[i] = NULL; 15061558Srgrimes ch->numhslots--; 15071558Srgrimes } 15081558Srgrimes if (ch->toslots != 0) 15091558Srgrimes xpt_release_simq(ch->sim, TRUE); 15101558Srgrimes ch->eslots = 0; 15111558Srgrimes ch->recovery = 0; 15121558Srgrimes ch->toslots = 0; 15131558Srgrimes ch->fatalerr = 0; 151423681Speter /* Disable port interrupts */ 15151558Srgrimes ATA_OUTL(ch->r_mem, SIIS_P_IECLR, 0x0000FFFF); 15161558Srgrimes /* Set speed limit. */ 15171558Srgrimes sata_rev = ch->user[ch->pm_present ? 15 : 0].revision; 15181558Srgrimes if (sata_rev == 1) 15191558Srgrimes val = ATA_SC_SPD_SPEED_GEN1; 15201558Srgrimes else if (sata_rev == 2) 15211558Srgrimes val = ATA_SC_SPD_SPEED_GEN2; 15221558Srgrimes else if (sata_rev == 3) 15231558Srgrimes val = ATA_SC_SPD_SPEED_GEN3; 15241558Srgrimes else 15251558Srgrimes val = 0; 15261558Srgrimes ATA_OUTL(ch->r_mem, SIIS_P_SCTL, 15271558Srgrimes ATA_SC_DET_IDLE | val | ((ch->pm_level > 0) ? 0 : 1528100336Sjoerg (ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER))); 1529100336Sjoergretry: 15301558Srgrimes siis_devreset(dev); 15311558Srgrimes /* Reset and reconnect PHY, */ 15321558Srgrimes if (!siis_sata_connect(ch)) { 15331558Srgrimes ch->devices = 0; 15341558Srgrimes /* Enable port interrupts */ 15351558Srgrimes ATA_OUTL(ch->r_mem, SIIS_P_IESET, SIIS_P_IX_ENABLED); 15361558Srgrimes if (bootverbose) 15371558Srgrimes device_printf(dev, 15381558Srgrimes "SIIS reset done: phy reset found no device\n"); 15391558Srgrimes /* Tell the XPT about the event */ 15401558Srgrimes xpt_async(AC_BUS_RESET, ch->path, NULL); 15411558Srgrimes xpt_release_simq(ch->sim, TRUE); 15421558Srgrimes return; 15431558Srgrimes } 15441558Srgrimes /* Wait for clearing busy status. */ 15451558Srgrimes if (siis_wait_ready(dev, 10000)) { 15461558Srgrimes device_printf(dev, "device ready timeout\n"); 15471558Srgrimes if (!retry) { 15481558Srgrimes device_printf(dev, "trying full port reset ...\n"); 15491558Srgrimes /* Get port to the reset state. */ 15501558Srgrimes ATA_OUTL(ch->r_mem, SIIS_P_CTLSET, SIIS_P_CTL_PORT_RESET); 15511558Srgrimes DELAY(10000); 15521558Srgrimes /* Get port out of reset state. */ 15531558Srgrimes ATA_OUTL(ch->r_mem, SIIS_P_CTLCLR, SIIS_P_CTL_PORT_RESET); 15541558Srgrimes ATA_OUTL(ch->r_mem, SIIS_P_CTLCLR, SIIS_P_CTL_32BIT); 15551558Srgrimes if (ch->pm_present) 15561558Srgrimes ATA_OUTL(ch->r_mem, SIIS_P_CTLSET, SIIS_P_CTL_PME); 15571558Srgrimes else 15581558Srgrimes ATA_OUTL(ch->r_mem, SIIS_P_CTLCLR, SIIS_P_CTL_PME); 15591558Srgrimes siis_wait_ready(dev, 5000); 15601558Srgrimes retry = 1; 15611558Srgrimes goto retry; 15621558Srgrimes } 15631558Srgrimes } 15641558Srgrimes ch->devices = 1; 15651558Srgrimes /* Enable port interrupts */ 15661558Srgrimes ATA_OUTL(ch->r_mem, SIIS_P_IS, 0xFFFFFFFF); 15671558Srgrimes ATA_OUTL(ch->r_mem, SIIS_P_IESET, SIIS_P_IX_ENABLED); 15681558Srgrimes if (bootverbose) 15691558Srgrimes device_printf(dev, "SIIS reset done: devices=%08x\n", ch->devices); 157037663Scharnier /* Tell the XPT about the event */ 157137663Scharnier xpt_async(AC_BUS_RESET, ch->path, NULL); 15721558Srgrimes xpt_release_simq(ch->sim, TRUE); 15731558Srgrimes} 15741558Srgrimes 15751558Srgrimesstatic int 15761558Srgrimessiis_setup_fis(device_t dev, struct siis_cmd *ctp, union ccb *ccb, int tag) 15771558Srgrimes{ 15781558Srgrimes struct siis_channel *ch = device_get_softc(dev); 15791558Srgrimes u_int8_t *fis = &ctp->fis[0]; 15801558Srgrimes 15811558Srgrimes bzero(fis, 24); 15821558Srgrimes fis[0] = 0x27; /* host to device */ 15831558Srgrimes fis[1] = (ccb->ccb_h.target_id & 0x0f); 15841558Srgrimes if (ccb->ccb_h.func_code == XPT_SCSI_IO) { 15851558Srgrimes fis[1] |= 0x80; 15869336Sdfr fis[2] = ATA_PACKET_CMD; 15871558Srgrimes if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE && 15881558Srgrimes ch->curr[ccb->ccb_h.target_id].mode >= ATA_DMA) 15891558Srgrimes fis[3] = ATA_F_DMA; 15909336Sdfr else { 15911558Srgrimes fis[5] = ccb->csio.dxfer_len; 15921558Srgrimes fis[6] = ccb->csio.dxfer_len >> 8; 15931558Srgrimes } 15941558Srgrimes fis[7] = ATA_D_LBA; 15959336Sdfr fis[15] = ATA_A_4BIT; 15961558Srgrimes bzero(ctp->u.atapi.ccb, 16); 15971558Srgrimes bcopy((ccb->ccb_h.flags & CAM_CDB_POINTER) ? 15981558Srgrimes ccb->csio.cdb_io.cdb_ptr : ccb->csio.cdb_io.cdb_bytes, 15991558Srgrimes ctp->u.atapi.ccb, ccb->csio.cdb_len); 16009336Sdfr } else if ((ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) == 0) { 16011558Srgrimes fis[1] |= 0x80; 16029336Sdfr fis[2] = ccb->ataio.cmd.command; 16031558Srgrimes fis[3] = ccb->ataio.cmd.features; 16041558Srgrimes fis[4] = ccb->ataio.cmd.lba_low; 16051558Srgrimes fis[5] = ccb->ataio.cmd.lba_mid; 16061558Srgrimes fis[6] = ccb->ataio.cmd.lba_high; 16071558Srgrimes fis[7] = ccb->ataio.cmd.device; 16081558Srgrimes fis[8] = ccb->ataio.cmd.lba_low_exp; 16091558Srgrimes fis[9] = ccb->ataio.cmd.lba_mid_exp; 16101558Srgrimes fis[10] = ccb->ataio.cmd.lba_high_exp; 16111558Srgrimes fis[11] = ccb->ataio.cmd.features_exp; 161237663Scharnier if (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA) { 16131558Srgrimes fis[12] = tag << 3; 16141558Srgrimes fis[13] = 0; 16151558Srgrimes } else { 16169336Sdfr fis[12] = ccb->ataio.cmd.sector_count; 16171558Srgrimes fis[13] = ccb->ataio.cmd.sector_count_exp; 16181558Srgrimes } 16191558Srgrimes fis[15] = ATA_A_4BIT; 16201558Srgrimes } else { 16211558Srgrimes /* Soft reset. */ 16221558Srgrimes } 16231558Srgrimes return (20); 16241558Srgrimes} 16251558Srgrimes 16261558Srgrimesstatic int 16279336Sdfrsiis_sata_connect(struct siis_channel *ch) 16281558Srgrimes{ 16291558Srgrimes u_int32_t status; 16301558Srgrimes int timeout; 16319336Sdfr 16321558Srgrimes /* Wait up to 100ms for "connect well" */ 16331558Srgrimes for (timeout = 0; timeout < 100 ; timeout++) { 16341558Srgrimes status = ATA_INL(ch->r_mem, SIIS_P_SSTS); 16351558Srgrimes if (((status & ATA_SS_DET_MASK) == ATA_SS_DET_PHY_ONLINE) && 16361558Srgrimes ((status & ATA_SS_SPD_MASK) != ATA_SS_SPD_NO_SPEED) && 16371558Srgrimes ((status & ATA_SS_IPM_MASK) == ATA_SS_IPM_ACTIVE)) 16381558Srgrimes break; 16391558Srgrimes DELAY(1000); 16401558Srgrimes } 16419336Sdfr if (timeout >= 100) { 16421558Srgrimes if (bootverbose) { 16431558Srgrimes device_printf(ch->dev, "SATA connect timeout status=%08x\n", 16449336Sdfr status); 16451558Srgrimes } 16461558Srgrimes return (0); 16471558Srgrimes } 16481558Srgrimes if (bootverbose) { 16491558Srgrimes device_printf(ch->dev, "SATA connect time=%dms status=%08x\n", 16501558Srgrimes timeout, status); 16511558Srgrimes } 16521558Srgrimes /* Clear SATA error register */ 16531558Srgrimes ATA_OUTL(ch->r_mem, SIIS_P_SERR, 0xffffffff); 16541558Srgrimes return (1); 16551558Srgrimes} 16561558Srgrimes 16571558Srgrimesstatic int 16581558Srgrimessiis_check_ids(device_t dev, union ccb *ccb) 16591558Srgrimes{ 16601558Srgrimes 16611558Srgrimes if (ccb->ccb_h.target_id > 15) { 16621558Srgrimes ccb->ccb_h.status = CAM_TID_INVALID; 16631558Srgrimes xpt_done(ccb); 16641558Srgrimes return (-1); 16659336Sdfr } 16661558Srgrimes if (ccb->ccb_h.target_lun != 0) { 16679336Sdfr ccb->ccb_h.status = CAM_LUN_INVALID; 16681558Srgrimes xpt_done(ccb); 16691558Srgrimes return (-1); 16701558Srgrimes } 16711558Srgrimes return (0); 16721558Srgrimes} 16731558Srgrimes 167474462Salfredstatic void 16751558Srgrimessiisaction(struct cam_sim *sim, union ccb *ccb) 167674462Salfred{ 16771558Srgrimes device_t dev; 16781558Srgrimes struct siis_channel *ch; 16791558Srgrimes 16801558Srgrimes CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("siisaction func_code=%x\n", 168174462Salfred ccb->ccb_h.func_code)); 16821558Srgrimes 168374462Salfred ch = (struct siis_channel *)cam_sim_softc(sim); 16841558Srgrimes dev = ch->dev; 168574462Salfred mtx_assert(&ch->mtx, MA_OWNED); 16861558Srgrimes switch (ccb->ccb_h.func_code) { 16871558Srgrimes /* Common cases first */ 16881558Srgrimes case XPT_ATA_IO: /* Execute the requested I/O operation */ 16891558Srgrimes case XPT_SCSI_IO: 16901558Srgrimes if (siis_check_ids(dev, ccb)) 16911558Srgrimes return; 16921558Srgrimes if (ch->devices == 0 || 16931558Srgrimes (ch->pm_present == 0 && 16941558Srgrimes ccb->ccb_h.target_id > 0 && ccb->ccb_h.target_id < 15)) { 16951558Srgrimes ccb->ccb_h.status = CAM_SEL_TIMEOUT; 16969336Sdfr break; 16971558Srgrimes } 169874462Salfred /* Check for command collision. */ 16991558Srgrimes if (siis_check_collision(dev, ccb)) { 17009336Sdfr /* Freeze command. */ 17011558Srgrimes ch->frozen = ccb; 17021558Srgrimes /* We have only one frozen slot, so freeze simq also. */ 17031558Srgrimes xpt_freeze_simq(ch->sim, 1); 170474462Salfred return; 17051558Srgrimes } 17061558Srgrimes siis_begin_transaction(dev, ccb); 17071558Srgrimes return; 17089336Sdfr case XPT_EN_LUN: /* Enable LUN as a target */ 17091558Srgrimes case XPT_TARGET_IO: /* Execute target I/O request */ 17101558Srgrimes case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 17111558Srgrimes case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 17121558Srgrimes case XPT_ABORT: /* Abort the specified CCB */ 17131558Srgrimes /* XXX Implement */ 171474462Salfred ccb->ccb_h.status = CAM_REQ_INVALID; 171574462Salfred break; 171675801Siedowse case XPT_SET_TRAN_SETTINGS: 171774462Salfred { 171874462Salfred struct ccb_trans_settings *cts = &ccb->cts; 171974462Salfred struct siis_device *d; 172074462Salfred 17219336Sdfr if (siis_check_ids(dev, ccb)) 172275801Siedowse return; 17231558Srgrimes if (cts->type == CTS_TYPE_CURRENT_SETTINGS) 172475801Siedowse d = &ch->curr[ccb->ccb_h.target_id]; 172575801Siedowse else 172675801Siedowse d = &ch->user[ccb->ccb_h.target_id]; 172775801Siedowse if (cts->xport_specific.sata.valid & CTS_SATA_VALID_REVISION) 172874462Salfred d->revision = cts->xport_specific.sata.revision; 172974462Salfred if (cts->xport_specific.sata.valid & CTS_SATA_VALID_MODE) 173074462Salfred d->mode = cts->xport_specific.sata.mode; 173175801Siedowse if (cts->xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT) 173275801Siedowse d->bytecount = min(8192, cts->xport_specific.sata.bytecount); 17331558Srgrimes if (cts->xport_specific.sata.valid & CTS_SATA_VALID_TAGS) 17341558Srgrimes d->tags = min(SIIS_MAX_SLOTS, cts->xport_specific.sata.tags); 17351558Srgrimes if (cts->xport_specific.sata.valid & CTS_SATA_VALID_PM) { 17361558Srgrimes ch->pm_present = cts->xport_specific.sata.pm_present; 17371558Srgrimes if (ch->pm_present) 17381558Srgrimes ATA_OUTL(ch->r_mem, SIIS_P_CTLSET, SIIS_P_CTL_PME); 17391558Srgrimes else 17401558Srgrimes ATA_OUTL(ch->r_mem, SIIS_P_CTLCLR, SIIS_P_CTL_PME); 17411558Srgrimes } 17421558Srgrimes if (cts->xport_specific.sata.valid & CTS_SATA_VALID_TAGS) 17431558Srgrimes d->atapi = cts->xport_specific.sata.atapi; 17441558Srgrimes if (cts->xport_specific.sata.valid & CTS_SATA_VALID_CAPS) 174574462Salfred d->caps = cts->xport_specific.sata.caps; 17461558Srgrimes ccb->ccb_h.status = CAM_REQ_CMP; 17479336Sdfr break; 17481558Srgrimes } 17491558Srgrimes case XPT_GET_TRAN_SETTINGS: 17501558Srgrimes /* Get default/user set transfer settings for the target */ 17511558Srgrimes { 17529336Sdfr struct ccb_trans_settings *cts = &ccb->cts; 17531558Srgrimes struct siis_device *d; 17541558Srgrimes uint32_t status; 17551558Srgrimes 17561558Srgrimes if (siis_check_ids(dev, ccb)) 17571558Srgrimes return; 17581558Srgrimes if (cts->type == CTS_TYPE_CURRENT_SETTINGS) 17591558Srgrimes d = &ch->curr[ccb->ccb_h.target_id]; 17601558Srgrimes else 17611558Srgrimes d = &ch->user[ccb->ccb_h.target_id]; 17621558Srgrimes cts->protocol = PROTO_ATA; 17631558Srgrimes cts->protocol_version = PROTO_VERSION_UNSPECIFIED; 17641558Srgrimes cts->transport = XPORT_SATA; 17651558Srgrimes cts->transport_version = XPORT_VERSION_UNSPECIFIED; 17661558Srgrimes cts->proto_specific.valid = 0; 17671558Srgrimes cts->xport_specific.sata.valid = 0; 17681558Srgrimes if (cts->type == CTS_TYPE_CURRENT_SETTINGS && 17691558Srgrimes (ccb->ccb_h.target_id == 15 || 17701558Srgrimes (ccb->ccb_h.target_id == 0 && !ch->pm_present))) { 17711558Srgrimes status = ATA_INL(ch->r_mem, SIIS_P_SSTS) & ATA_SS_SPD_MASK; 17721558Srgrimes if (status & 0x0f0) { 17731558Srgrimes cts->xport_specific.sata.revision = 17741558Srgrimes (status & 0x0f0) >> 4; 17751558Srgrimes cts->xport_specific.sata.valid |= 17761558Srgrimes CTS_SATA_VALID_REVISION; 17771558Srgrimes } 17781558Srgrimes cts->xport_specific.sata.caps = d->caps & CTS_SATA_CAPS_D; 17791558Srgrimes if (ch->pm_level) 17801558Srgrimes cts->xport_specific.sata.caps |= CTS_SATA_CAPS_H_PMREQ; 17811558Srgrimes cts->xport_specific.sata.caps &= 17821558Srgrimes ch->user[ccb->ccb_h.target_id].caps; 17831558Srgrimes cts->xport_specific.sata.valid |= CTS_SATA_VALID_CAPS; 17841558Srgrimes } else { 17851558Srgrimes cts->xport_specific.sata.revision = d->revision; 17861558Srgrimes cts->xport_specific.sata.valid |= CTS_SATA_VALID_REVISION; 17871558Srgrimes cts->xport_specific.sata.caps = d->caps; 178872650Sgreen cts->xport_specific.sata.valid |= CTS_SATA_VALID_CAPS; 17891558Srgrimes } 17901558Srgrimes cts->xport_specific.sata.mode = d->mode; 17911558Srgrimes cts->xport_specific.sata.valid |= CTS_SATA_VALID_MODE; 17921558Srgrimes cts->xport_specific.sata.bytecount = d->bytecount; 17931558Srgrimes cts->xport_specific.sata.valid |= CTS_SATA_VALID_BYTECOUNT; 179451968Salfred cts->xport_specific.sata.pm_present = ch->pm_present; 17951558Srgrimes cts->xport_specific.sata.valid |= CTS_SATA_VALID_PM; 17961558Srgrimes cts->xport_specific.sata.tags = d->tags; 17971558Srgrimes cts->xport_specific.sata.valid |= CTS_SATA_VALID_TAGS; 17981558Srgrimes cts->xport_specific.sata.atapi = d->atapi; 17991558Srgrimes cts->xport_specific.sata.valid |= CTS_SATA_VALID_ATAPI; 18001558Srgrimes ccb->ccb_h.status = CAM_REQ_CMP; 18011558Srgrimes break; 18021558Srgrimes } 180337663Scharnier case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 18041558Srgrimes case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 180537663Scharnier siis_reset(dev); 18061558Srgrimes ccb->ccb_h.status = CAM_REQ_CMP; 18071558Srgrimes break; 180837663Scharnier case XPT_TERM_IO: /* Terminate the I/O process */ 18091558Srgrimes /* XXX Implement */ 18101558Srgrimes ccb->ccb_h.status = CAM_REQ_INVALID; 18111558Srgrimes break; 18121558Srgrimes case XPT_PATH_INQ: /* Path routing inquiry */ 18131558Srgrimes { 18141558Srgrimes struct ccb_pathinq *cpi = &ccb->cpi; 18151558Srgrimes 18161558Srgrimes cpi->version_num = 1; /* XXX??? */ 18171558Srgrimes cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE; 18181558Srgrimes cpi->hba_inquiry |= PI_SATAPM; 18191558Srgrimes cpi->target_sprt = 0; 18201558Srgrimes cpi->hba_misc = PIM_SEQSCAN; 18211558Srgrimes cpi->hba_eng_cnt = 0; 18221558Srgrimes cpi->max_target = 15; 18231558Srgrimes cpi->max_lun = 0; 18241558Srgrimes cpi->initiator_id = 0; 18251558Srgrimes cpi->bus_id = cam_sim_bus(sim); 18261558Srgrimes cpi->base_transfer_speed = 150000; 18271558Srgrimes strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 18281558Srgrimes strncpy(cpi->hba_vid, "SIIS", HBA_IDLEN); 18291558Srgrimes strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 18301558Srgrimes cpi->unit_number = cam_sim_unit(sim); 18311558Srgrimes cpi->transport = XPORT_SATA; 18321558Srgrimes cpi->transport_version = XPORT_VERSION_UNSPECIFIED; 18331558Srgrimes cpi->protocol = PROTO_ATA; 18341558Srgrimes cpi->protocol_version = PROTO_VERSION_UNSPECIFIED; 183575801Siedowse cpi->ccb_h.status = CAM_REQ_CMP; 18361558Srgrimes cpi->maxio = MAXPHYS; 183737663Scharnier break; 18381558Srgrimes } 18391558Srgrimes default: 18401558Srgrimes ccb->ccb_h.status = CAM_REQ_INVALID; 18411558Srgrimes break; 18421558Srgrimes } 18431558Srgrimes xpt_done(ccb); 184474462Salfred} 184574462Salfred 184674462Salfredstatic void 184774462Salfredsiispoll(struct cam_sim *sim) 184874462Salfred{ 18491558Srgrimes struct siis_channel *ch = (struct siis_channel *)cam_sim_softc(sim); 185037663Scharnier 18511558Srgrimes siis_ch_intr(ch->dev); 18521558Srgrimes} 185337663Scharnier