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