aic7xxx: add support for the SPI transport class
author <jejb@titanic.il.steeleye.com> <>
Sun, 17 Apr 2005 21:59:33 +0000 (16:59 -0500)
committerJames Bottomley <jejb@titanic>
Mon, 18 Apr 2005 18:52:02 +0000 (13:52 -0500)
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: James Bottomley <James.Bottomley@SteelEye.com>
drivers/scsi/aic7xxx/Kconfig.aic7xxx
drivers/scsi/aic7xxx/aic7xxx_osm.c

index 8398e0d..ac8de03 100644 (file)
@@ -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
index 35d6de5..6b6ee0a 100644 (file)
 #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);