diff options
Diffstat (limited to 'drivers/scsi/aic7xxx/aic7xxx_osm.c')
-rw-r--r-- | drivers/scsi/aic7xxx/aic7xxx_osm.c | 247 |
1 files changed, 37 insertions, 210 deletions
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index b89094d..687f19e 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -136,10 +136,6 @@ static struct scsi_transport_template *ahc_linux_transport_template = NULL; #include <linux/blkdev.h> /* For block_size() */ #include <linux/delay.h> /* For ssleep/msleep */ -/* - * Lock protecting manipulation of the ahc softc list. - */ -spinlock_t ahc_list_spinlock; /* * Set this to the delay in seconds after SCSI bus reset. @@ -292,25 +288,6 @@ ahc_print_path(struct ahc_softc *ahc, struct scb *scb) static uint32_t aic7xxx_no_reset; /* - * Certain PCI motherboards will scan PCI devices from highest to lowest, - * others scan from lowest to highest, and they tend to do all kinds of - * strange things when they come into contact with PCI bridge chips. The - * net result of all this is that the PCI card that is actually used to boot - * the machine is very hard to detect. Most motherboards go from lowest - * PCI slot number to highest, and the first SCSI controller found is the - * one you boot from. The only exceptions to this are when a controller - * has its BIOS disabled. So, we by default sort all of our SCSI controllers - * from lowest PCI slot number to highest PCI slot number. We also force - * all controllers with their BIOS disabled to the end of the list. This - * works on *almost* all computers. Where it doesn't work, we have this - * option. Setting this option to non-0 will reverse the order of the sort - * to highest first, then lowest, but will still leave cards with their BIOS - * disabled at the very end. That should fix everyone up unless there are - * really strange cirumstances. - */ -static uint32_t aic7xxx_reverse_scan; - -/* * Should we force EXTENDED translation on a controller. * 0 == Use whatever is in the SEEPROM or default to off * 1 == Use whatever is in the SEEPROM or default to on @@ -338,13 +315,6 @@ static uint32_t aic7xxx_pci_parity = ~0; uint32_t aic7xxx_allow_memio = ~0; /* - * aic7xxx_detect() has been run, so register all device arrivals - * immediately with the system rather than deferring to the sorted - * attachment performed by aic7xxx_detect(). - */ -int aic7xxx_detect_complete; - -/* * So that we can set how long each device is given as a selection timeout. * The table of values goes like this: * 0 - 256ms @@ -423,7 +393,9 @@ static int ahc_linux_run_command(struct ahc_softc*, static void ahc_linux_setup_tag_info_global(char *p); static aic_option_callback_t ahc_linux_setup_tag_info; static int aic7xxx_setup(char *s); -static int ahc_linux_next_unit(void); + +static int ahc_linux_unit; + /********************************* Inlines ************************************/ static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*); @@ -476,48 +448,6 @@ ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb, } /* - * Try to detect an Adaptec 7XXX controller. - */ -static int -ahc_linux_detect(struct scsi_host_template *template) -{ - struct ahc_softc *ahc; - int found = 0; - - /* - * If we've been passed any parameters, process them now. - */ - if (aic7xxx) - aic7xxx_setup(aic7xxx); - - template->proc_name = "aic7xxx"; - - /* - * Initialize our softc list lock prior to - * probing for any adapters. - */ - ahc_list_lockinit(); - - found = ahc_linux_pci_init(); - if (!ahc_linux_eisa_init()) - found++; - - /* - * Register with the SCSI layer all - * controllers we've found. - */ - TAILQ_FOREACH(ahc, &ahc_tailq, links) { - - if (ahc_linux_register_host(ahc, template) == 0) - found++; - } - - aic7xxx_detect_complete++; - - return (found); -} - -/* * Return a string describing the driver. */ static const char * @@ -848,6 +778,7 @@ ahc_linux_bus_reset(struct scsi_cmnd *cmd) struct scsi_host_template aic7xxx_driver_template = { .module = THIS_MODULE, .name = "aic7xxx", + .proc_name = "aic7xxx", .proc_info = ahc_linux_proc_info, .info = ahc_linux_info, .queuecommand = ahc_linux_queue, @@ -959,99 +890,6 @@ ahc_dmamap_unload(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map) return (0); } -/********************* Platform Dependent Functions ***************************/ -/* - * Compare "left hand" softc with "right hand" softc, returning: - * < 0 - lahc has a lower priority than rahc - * 0 - Softcs are equal - * > 0 - lahc has a higher priority than rahc - */ -int -ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc) -{ - int value; - int rvalue; - int lvalue; - - /* - * Under Linux, cards are ordered as follows: - * 1) VLB/EISA BIOS enabled devices sorted by BIOS address. - * 2) PCI devices with BIOS enabled sorted by bus/slot/func. - * 3) All remaining VLB/EISA devices sorted by ioport. - * 4) All remaining PCI devices sorted by bus/slot/func. - */ - value = (lahc->flags & AHC_BIOS_ENABLED) - - (rahc->flags & AHC_BIOS_ENABLED); - if (value != 0) - /* Controllers with BIOS enabled have a *higher* priority */ - return (value); - - /* - * Same BIOS setting, now sort based on bus type. - * EISA and VL controllers sort together. EISA/VL - * have higher priority than PCI. - */ - rvalue = (rahc->chip & AHC_BUS_MASK); - if (rvalue == AHC_VL) - rvalue = AHC_EISA; - lvalue = (lahc->chip & AHC_BUS_MASK); - if (lvalue == AHC_VL) - lvalue = AHC_EISA; - value = rvalue - lvalue; - if (value != 0) - return (value); - - /* Still equal. Sort by BIOS address, ioport, or bus/slot/func. */ - switch (rvalue) { -#ifdef CONFIG_PCI - case AHC_PCI: - { - char primary_channel; - - if (aic7xxx_reverse_scan != 0) - value = ahc_get_pci_bus(lahc->dev_softc) - - ahc_get_pci_bus(rahc->dev_softc); - else - value = ahc_get_pci_bus(rahc->dev_softc) - - ahc_get_pci_bus(lahc->dev_softc); - if (value != 0) - break; - if (aic7xxx_reverse_scan != 0) - value = ahc_get_pci_slot(lahc->dev_softc) - - ahc_get_pci_slot(rahc->dev_softc); - else - value = ahc_get_pci_slot(rahc->dev_softc) - - ahc_get_pci_slot(lahc->dev_softc); - if (value != 0) - break; - /* - * On multi-function devices, the user can choose - * to have function 1 probed before function 0. - * Give whichever channel is the primary channel - * the highest priority. - */ - primary_channel = (lahc->flags & AHC_PRIMARY_CHANNEL) + 'A'; - value = -1; - if (lahc->channel == primary_channel) - value = 1; - break; - } -#endif - case AHC_EISA: - if ((rahc->flags & AHC_BIOS_ENABLED) != 0) { - value = rahc->platform_data->bios_address - - lahc->platform_data->bios_address; - } else { - value = rahc->bsh.ioport - - lahc->bsh.ioport; - } - break; - default: - panic("ahc_softc_sort: invalid bus type"); - } - return (value); -} - static void ahc_linux_setup_tag_info_global(char *p) { @@ -1103,7 +941,6 @@ aic7xxx_setup(char *s) #ifdef AHC_DEBUG { "debug", &ahc_debug }, #endif - { "reverse_scan", &aic7xxx_reverse_scan }, { "periodic_otag", &aic7xxx_periodic_otag }, { "pci_parity", &aic7xxx_pci_parity }, { "seltime", &aic7xxx_seltime }, @@ -1178,7 +1015,7 @@ ahc_linux_register_host(struct ahc_softc *ahc, struct scsi_host_template *templa host->max_lun = AHC_NUM_LUNS; host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0; host->sg_tablesize = AHC_NSEG; - ahc_set_unit(ahc, ahc_linux_next_unit()); + ahc_set_unit(ahc, ahc_linux_unit++); sprintf(buf, "scsi%d", host->host_no); new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); if (new_name != NULL) { @@ -1207,29 +1044,6 @@ ahc_linux_get_memsize(void) } /* - * Find the smallest available unit number to use - * for a new device. We don't just use a static - * count to handle the "repeated hot-(un)plug" - * scenario. - */ -static int -ahc_linux_next_unit(void) -{ - struct ahc_softc *ahc; - int unit; - - unit = 0; -retry: - TAILQ_FOREACH(ahc, &ahc_tailq, links) { - if (ahc->unit == unit) { - unit++; - goto retry; - } - } - return (unit); -} - -/* * Place the SCSI bus into a known state by either resetting it, * or forcing transfer negotiations on the next command to any * target. @@ -1450,14 +1264,12 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, } switch ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED))) { case AHC_DEV_Q_BASIC: - scsi_adjust_queue_depth(sdev, - MSG_SIMPLE_TASK, - dev->openings + dev->active); + scsi_set_tag_type(sdev, MSG_SIMPLE_TAG); + scsi_activate_tcq(sdev, dev->openings + dev->active); break; case AHC_DEV_Q_TAGGED: - scsi_adjust_queue_depth(sdev, - MSG_ORDERED_TASK, - dev->openings + dev->active); + scsi_set_tag_type(sdev, MSG_ORDERED_TAG); + scsi_activate_tcq(sdev, dev->openings + dev->active); break; default: /* @@ -1466,9 +1278,7 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, * serially on the controller/device. This should * remove some latency. */ - scsi_adjust_queue_depth(sdev, - /*NON-TAGGED*/0, - /*queue depth*/2); + scsi_deactivate_tcq(sdev, 2); break; } } @@ -1821,9 +1631,9 @@ ahc_send_async(struct ahc_softc *ahc, char channel, spi_period(starget) = tinfo->curr.period; spi_width(starget) = tinfo->curr.width; spi_offset(starget) = tinfo->curr.offset; - spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ; - spi_qas(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ; - spi_iu(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ; + spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ ? 1 : 0; + spi_qas(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ ? 1 : 0; + spi_iu(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ ? 1 : 0; spi_display_xfer_agreement(starget); break; } @@ -2615,12 +2425,14 @@ static void ahc_linux_set_dt(struct scsi_target *starget, int dt) unsigned int ppr_options = tinfo->goal.ppr_options & ~MSG_EXT_PPR_DT_REQ; unsigned int period = tinfo->goal.period; + unsigned int width = tinfo->goal.width; unsigned long flags; struct ahc_syncrate *syncrate; if (dt) { - period = 9; /* 12.5ns is the only period valid for DT */ ppr_options |= MSG_EXT_PPR_DT_REQ; + if (!width) + ahc_linux_set_width(starget, 1); } else if (period == 9) period = 10; /* if resetting DT, period must be >= 25ns */ @@ -2633,6 +2445,11 @@ static void ahc_linux_set_dt(struct scsi_target *starget, int dt) ahc_unlock(ahc, &flags); } +#if 0 +/* FIXME: This code claims to support IU and QAS. However, the actual + * sequencer code and aic7xxx_core have no support for these parameters and + * will get into a bad state if they're negotiated. Do not enable this + * unless you know what you're doing */ static void ahc_linux_set_qas(struct scsi_target *starget, int qas) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); @@ -2688,6 +2505,7 @@ static void ahc_linux_set_iu(struct scsi_target *starget, int iu) ppr_options, AHC_TRANS_GOAL, FALSE); ahc_unlock(ahc, &flags); } +#endif static struct spi_function_template ahc_linux_transport_functions = { .set_offset = ahc_linux_set_offset, @@ -2698,10 +2516,12 @@ static struct spi_function_template ahc_linux_transport_functions = { .show_width = 1, .set_dt = ahc_linux_set_dt, .show_dt = 1, +#if 0 .set_iu = ahc_linux_set_iu, .show_iu = 1, .set_qas = ahc_linux_set_qas, .show_qas = 1, +#endif }; @@ -2709,18 +2529,25 @@ static struct spi_function_template ahc_linux_transport_functions = { static int __init ahc_linux_init(void) { - ahc_linux_transport_template = spi_attach_transport(&ahc_linux_transport_functions); + /* + * If we've been passed any parameters, process them now. + */ + if (aic7xxx) + aic7xxx_setup(aic7xxx); + + ahc_linux_transport_template = + spi_attach_transport(&ahc_linux_transport_functions); if (!ahc_linux_transport_template) return -ENODEV; + scsi_transport_reserve_target(ahc_linux_transport_template, sizeof(struct ahc_linux_target)); scsi_transport_reserve_device(ahc_linux_transport_template, sizeof(struct ahc_linux_device)); - if (ahc_linux_detect(&aic7xxx_driver_template)) - return 0; - spi_release_transport(ahc_linux_transport_template); - ahc_linux_exit(); - return -ENODEV; + + ahc_linux_pci_init(); + ahc_linux_eisa_init(); + return 0; } static void |