Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 92d161c3 authored by James Bottomley's avatar James Bottomley Committed by James Bottomley
Browse files

aic7xxx: add support for the SPI transport class



This is just a simplistic patch to export all of the
aic7xxx internal transport parameters via the SPI
transport class.  It doesn't actually alter the way the
driver works at all.

Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 7aaef27b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
config SCSI_AIC7XXX
	tristate "Adaptec AIC7xxx Fast -> U160 support (New Driver)"
	depends on (PCI || EISA) && SCSI
	select SCSI_SPI_ATTRS
	---help---
	This driver supports all of Adaptec's Fast through Ultra 160 PCI
	based SCSI controllers as well as the aic7770 based EISA and VLB
+261 −0
Original line number Diff line number Diff line
@@ -122,6 +122,10 @@
#include "aic7xxx_osm.h"
#include "aic7xxx_inline.h"
#include <scsi/scsicam.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_spi.h>

static struct scsi_transport_template *ahc_linux_transport_template = NULL;

/*
 * Include aiclib.c as part of our
@@ -1728,6 +1732,8 @@ ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template)
	ahc_linux_start_dv(ahc);
	ahc_unlock(ahc, &s);

	host->transportt = ahc_linux_transport_template;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
	scsi_add_host(host, (ahc->dev_softc ? &ahc->dev_softc->dev : NULL)); /* XXX handle failure */
	scsi_scan_host(host);
@@ -4990,13 +4996,267 @@ ahc_platform_dump_card_state(struct ahc_softc *ahc)

static void ahc_linux_exit(void);

static void ahc_linux_get_period(struct scsi_target *starget)
{
	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
	struct ahc_tmode_tstate *tstate;
	struct ahc_initiator_tinfo *tinfo 
		= ahc_fetch_transinfo(ahc,
				      starget->channel + 'A',
				      shost->this_id, starget->id, &tstate);
	spi_period(starget) = tinfo->curr.period;
}

static void ahc_linux_set_period(struct scsi_target *starget, int period)
{
	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
	struct ahc_tmode_tstate *tstate;
	struct ahc_initiator_tinfo *tinfo 
		= ahc_fetch_transinfo(ahc,
				      starget->channel + 'A',
				      shost->this_id, starget->id, &tstate);
	struct ahc_devinfo devinfo;
	unsigned int ppr_options = tinfo->curr.ppr_options;
	unsigned long flags;
	unsigned long offset = tinfo->curr.offset;
	struct ahc_syncrate *syncrate;

	if (offset == 0)
		offset = MAX_OFFSET;

	ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
			    starget->channel + 'A', ROLE_INITIATOR);
	syncrate = ahc_find_syncrate(ahc, &period, &ppr_options, AHC_SYNCRATE_DT);
	ahc_lock(ahc, &flags);
	ahc_set_syncrate(ahc, &devinfo, syncrate, period, offset,
			 ppr_options, AHC_TRANS_GOAL, FALSE);
	ahc_unlock(ahc, &flags);
}

static void ahc_linux_get_offset(struct scsi_target *starget)
{
	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
	struct ahc_tmode_tstate *tstate;
	struct ahc_initiator_tinfo *tinfo 
		= ahc_fetch_transinfo(ahc,
				      starget->channel + 'A',
				      shost->this_id, starget->id, &tstate);
	spi_offset(starget) = tinfo->curr.offset;
}

static void ahc_linux_set_offset(struct scsi_target *starget, int offset)
{
	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
	struct ahc_tmode_tstate *tstate;
	struct ahc_initiator_tinfo *tinfo 
		= ahc_fetch_transinfo(ahc,
				      starget->channel + 'A',
				      shost->this_id, starget->id, &tstate);
	struct ahc_devinfo devinfo;
	unsigned int ppr_options = 0;
	unsigned int period = 0;
	unsigned long flags;
	struct ahc_syncrate *syncrate = NULL;

	ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
			    starget->channel + 'A', ROLE_INITIATOR);
	if (offset != 0) {
		syncrate = ahc_find_syncrate(ahc, &period, &ppr_options, AHC_SYNCRATE_DT);
		period = tinfo->curr.period;
		ppr_options = tinfo->curr.ppr_options;
	}
	ahc_lock(ahc, &flags);
	ahc_set_syncrate(ahc, &devinfo, syncrate, period, offset,
			 ppr_options, AHC_TRANS_GOAL, FALSE);
	ahc_unlock(ahc, &flags);
}

static void ahc_linux_get_width(struct scsi_target *starget)
{
	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
	struct ahc_tmode_tstate *tstate;
	struct ahc_initiator_tinfo *tinfo 
		= ahc_fetch_transinfo(ahc,
				      starget->channel + 'A',
				      shost->this_id, starget->id, &tstate);
	spi_width(starget) = tinfo->curr.width;
}

static void ahc_linux_set_width(struct scsi_target *starget, int width)
{
	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
	struct ahc_devinfo devinfo;
	unsigned long flags;

	ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
			    starget->channel + 'A', ROLE_INITIATOR);
	ahc_lock(ahc, &flags);
	ahc_set_width(ahc, &devinfo, width, AHC_TRANS_GOAL, FALSE);
	ahc_unlock(ahc, &flags);
}

static void ahc_linux_get_dt(struct scsi_target *starget)
{
	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
	struct ahc_tmode_tstate *tstate;
	struct ahc_initiator_tinfo *tinfo 
		= ahc_fetch_transinfo(ahc,
				      starget->channel + 'A',
				      shost->this_id, starget->id, &tstate);
	spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ;
}

static void ahc_linux_set_dt(struct scsi_target *starget, int dt)
{
	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
	struct ahc_tmode_tstate *tstate;
	struct ahc_initiator_tinfo *tinfo 
		= ahc_fetch_transinfo(ahc,
				      starget->channel + 'A',
				      shost->this_id, starget->id, &tstate);
	struct ahc_devinfo devinfo;
	unsigned int ppr_options = tinfo->curr.ppr_options
		& ~MSG_EXT_PPR_DT_REQ;
	unsigned int period = tinfo->curr.period;
	unsigned long flags;
	struct ahc_syncrate *syncrate;

	ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
			    starget->channel + 'A', ROLE_INITIATOR);
	syncrate = ahc_find_syncrate(ahc, &period, &ppr_options,
				     dt ? AHC_SYNCRATE_DT : AHC_SYNCRATE_ULTRA2);
	ahc_lock(ahc, &flags);
	ahc_set_syncrate(ahc, &devinfo, syncrate, period, tinfo->curr.offset,
			 ppr_options, AHC_TRANS_GOAL, FALSE);
	ahc_unlock(ahc, &flags);
}

static void ahc_linux_get_qas(struct scsi_target *starget)
{
	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
	struct ahc_tmode_tstate *tstate;
	struct ahc_initiator_tinfo *tinfo 
		= ahc_fetch_transinfo(ahc,
				      starget->channel + 'A',
				      shost->this_id, starget->id, &tstate);
	spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ;
}

static void ahc_linux_set_qas(struct scsi_target *starget, int qas)
{
	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
	struct ahc_tmode_tstate *tstate;
	struct ahc_initiator_tinfo *tinfo 
		= ahc_fetch_transinfo(ahc,
				      starget->channel + 'A',
				      shost->this_id, starget->id, &tstate);
	struct ahc_devinfo devinfo;
	unsigned int ppr_options = tinfo->curr.ppr_options
		& ~MSG_EXT_PPR_QAS_REQ;
	unsigned int period = tinfo->curr.period;
	unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
	unsigned long flags;
	struct ahc_syncrate *syncrate;

	if (qas)
		ppr_options |= MSG_EXT_PPR_QAS_REQ;

	ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
			    starget->channel + 'A', ROLE_INITIATOR);
	syncrate = ahc_find_syncrate(ahc, &period, &ppr_options,
				     dt ? AHC_SYNCRATE_DT : AHC_SYNCRATE_ULTRA2);
	ahc_lock(ahc, &flags);
	ahc_set_syncrate(ahc, &devinfo, syncrate, period, tinfo->curr.offset,
			 ppr_options, AHC_TRANS_GOAL, FALSE);
	ahc_unlock(ahc, &flags);
}

static void ahc_linux_get_iu(struct scsi_target *starget)
{
	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
	struct ahc_tmode_tstate *tstate;
	struct ahc_initiator_tinfo *tinfo 
		= ahc_fetch_transinfo(ahc,
				      starget->channel + 'A',
				      shost->this_id, starget->id, &tstate);
	spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ;
}

static void ahc_linux_set_iu(struct scsi_target *starget, int iu)
{
	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
	struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
	struct ahc_tmode_tstate *tstate;
	struct ahc_initiator_tinfo *tinfo 
		= ahc_fetch_transinfo(ahc,
				      starget->channel + 'A',
				      shost->this_id, starget->id, &tstate);
	struct ahc_devinfo devinfo;
	unsigned int ppr_options = tinfo->curr.ppr_options
		& ~MSG_EXT_PPR_IU_REQ;
	unsigned int period = tinfo->curr.period;
	unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
	unsigned long flags;
	struct ahc_syncrate *syncrate;

	if (iu)
		ppr_options |= MSG_EXT_PPR_IU_REQ;

	ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
			    starget->channel + 'A', ROLE_INITIATOR);
	syncrate = ahc_find_syncrate(ahc, &period, &ppr_options,
				     dt ? AHC_SYNCRATE_DT : AHC_SYNCRATE_ULTRA2);
	ahc_lock(ahc, &flags);
	ahc_set_syncrate(ahc, &devinfo, syncrate, period, tinfo->curr.offset,
			 ppr_options, AHC_TRANS_GOAL, FALSE);
	ahc_unlock(ahc, &flags);
}

static struct spi_function_template ahc_linux_transport_functions = {
	.get_offset	= ahc_linux_get_offset,
	.set_offset	= ahc_linux_set_offset,
	.show_offset	= 1,
	.get_period	= ahc_linux_get_period,
	.set_period	= ahc_linux_set_period,
	.show_period	= 1,
	.get_width	= ahc_linux_get_width,
	.set_width	= ahc_linux_set_width,
	.show_width	= 1,
	.get_dt		= ahc_linux_get_dt,
	.set_dt		= ahc_linux_set_dt,
	.show_dt	= 1,
	.get_iu		= ahc_linux_get_iu,
	.set_iu		= ahc_linux_set_iu,
	.show_iu	= 1,
	.get_qas	= ahc_linux_get_qas,
	.set_qas	= ahc_linux_set_qas,
	.show_qas	= 1,
};



static int __init
ahc_linux_init(void)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
	ahc_linux_transport_template = spi_attach_transport(&ahc_linux_transport_functions);
	if (!ahc_linux_transport_template)
		return -ENODEV;
	int rc = ahc_linux_detect(&aic7xxx_driver_template);
	if (rc)
		return rc;
	spi_release_transport(ahc_linux_transport_template);
	ahc_linux_exit();
	return -ENODEV;
#else
@@ -5037,6 +5297,7 @@ ahc_linux_exit(void)
#endif
	ahc_linux_pci_exit();
	ahc_linux_eisa_exit();
	spi_release_transport(ahc_linux_transport_template);
}

module_init(ahc_linux_init);