diff options
-rw-r--r-- | drivers/scsi/aic7xxx/Kconfig.aic7xxx | 1 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aic7xxx_osm.c | 261 |
2 files changed, 262 insertions, 0 deletions
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx index 8398e0dd481..ac8de03c9fa 100644 --- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx +++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx @@ -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 diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 35d6de5a4c9..6b6ee0a52a4 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -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); |