|
@@ -122,6 +122,10 @@
|
|
#include "aic7xxx_osm.h"
|
|
#include "aic7xxx_osm.h"
|
|
#include "aic7xxx_inline.h"
|
|
#include "aic7xxx_inline.h"
|
|
#include <scsi/scsicam.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
|
|
* 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_linux_start_dv(ahc);
|
|
ahc_unlock(ahc, &s);
|
|
ahc_unlock(ahc, &s);
|
|
|
|
|
|
|
|
+ host->transportt = ahc_linux_transport_template;
|
|
|
|
+
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
|
|
#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_add_host(host, (ahc->dev_softc ? &ahc->dev_softc->dev : NULL)); /* XXX handle failure */
|
|
scsi_scan_host(host);
|
|
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_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
|
|
static int __init
|
|
ahc_linux_init(void)
|
|
ahc_linux_init(void)
|
|
{
|
|
{
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
|
|
#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);
|
|
int rc = ahc_linux_detect(&aic7xxx_driver_template);
|
|
if (rc)
|
|
if (rc)
|
|
return rc;
|
|
return rc;
|
|
|
|
+ spi_release_transport(ahc_linux_transport_template);
|
|
ahc_linux_exit();
|
|
ahc_linux_exit();
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
#else
|
|
#else
|
|
@@ -5037,6 +5297,7 @@ ahc_linux_exit(void)
|
|
#endif
|
|
#endif
|
|
ahc_linux_pci_exit();
|
|
ahc_linux_pci_exit();
|
|
ahc_linux_eisa_exit();
|
|
ahc_linux_eisa_exit();
|
|
|
|
+ spi_release_transport(ahc_linux_transport_template);
|
|
}
|
|
}
|
|
|
|
|
|
module_init(ahc_linux_init);
|
|
module_init(ahc_linux_init);
|