Enscript Output

extractedLnx/linux-2.5.9/drivers/scsi/aic7xxx_old.c_aic7xxx_detect.c

int
aic7xxx_detect(Scsi_Host_Template *template)
{
  struct aic7xxx_host *temp_p = NULL;
  struct aic7xxx_host *current_p = NULL;
  struct aic7xxx_host *list_p = NULL;
  int found = 0;
#if defined(__i386__) || defined(__alpha__)
  ahc_flag_type flags = 0;
  int type;
#endif
  unsigned char sxfrctl1;
#if defined(__i386__) || defined(__alpha__)
  unsigned char hcntrl, hostconf;
  unsigned int slot, base;
#endif

#ifdef MODULE
  /*
   * If we are called as a module, the aic7xxx pointer may not be null
   * and it would point to our bootup string, just like on the lilo
   * command line.  IF not NULL, then process this config string with
   * aic7xxx_setup
   */
  if(aic7xxx)
    aic7xxx_setup(aic7xxx);
  if(dummy_buffer[0] != 'P')
    printk(KERN_WARNING "aic7xxx: Please read the file /usr/src/linux/drivers"
      "/scsi/README.aic7xxx\n"
      "aic7xxx: to see the proper way to specify options to the aic7xxx "
      "module\n"
      "aic7xxx: Specifically, don't use any commas when passing arguments to\n"
      "aic7xxx: insmod or else it might trash certain memory areas.\n");
#endif

  template->proc_name = "aic7xxx";
  template->sg_tablesize = AIC7XXX_MAX_SG;


#ifdef CONFIG_PCI
  /*
   * PCI-bus probe.
   */
  if (pci_present())
  {
    struct
    {
      unsigned short      vendor_id;
      unsigned short      device_id;
      ahc_chip            chip;
      ahc_flag_type       flags;
      ahc_feature         features;
      int                 board_name_index;
      unsigned short      seeprom_size;
      unsigned short      seeprom_type;
    } const aic_pdevs[] = {
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7810, AHC_NONE,
       AHC_FNONE, AHC_FENONE,                                1,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AHC_AIC7850,
       AHC_PAGESCBS, AHC_AIC7850_FE,                         5,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850,
       AHC_PAGESCBS, AHC_AIC7850_FE,                         6,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7821, AHC_AIC7860,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
       AHC_AIC7860_FE,                                       7,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_3860, AHC_AIC7860,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
       AHC_AIC7860_FE,                                       7,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
       AHC_AIC7860_FE,                                       7,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
       AHC_AIC7860_FE,                                       7,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MOTHERBOARD,
       AHC_AIC7860_FE,                                       7,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AHC_AIC7860,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
       AHC_AIC7860_FE,                                       8,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AHC_AIC7870,
       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD,
       AHC_AIC7870_FE,                                       9,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AHC_AIC7870,
       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE,     10,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AHC_AIC7870,
       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
       AHC_AIC7870_FE,                                      11,
       32, C56_66 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AHC_AIC7870,
       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
       AHC_AIC7870_FE,                                      12,
       32, C56_66 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AHC_AIC7870,
       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE,     13,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AHC_AIC7880,
       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD,
       AHC_AIC7880_FE,                                      14,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AHC_AIC7880,
       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     15,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AHC_AIC7880,
       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
       AHC_AIC7880_FE,                                      16,
       32, C56_66 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AHC_AIC7880,
       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
       AHC_AIC7880_FE,                                      17,
       32, C56_66 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_AIC7880,
       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7885, AHC_AIC7880,
       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7886, AHC_AIC7880,
       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880,
       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE | AHC_NEW_AUTOTERM, 19,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880,
       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
       AHC_AIC7895_FE,                                      20,
       32, C56_66 },
      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890, AHC_AIC7890,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
       AHC_AIC7890_FE,                                      21,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890B, AHC_AIC7890,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
       AHC_AIC7890_FE,                                      21,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2930U2, AHC_AIC7890,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
       AHC_AIC7890_FE,                                      22,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
       AHC_AIC7890_FE,                                      23,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
       AHC_AIC7896_FE,                                      24,
       32, C56_66 },
      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
       AHC_AIC7896_FE,                                      25,
       32, C56_66 },
      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
       AHC_AIC7896_FE,                                      26,
       32, C56_66 },
      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_NO_STPWEN,
       AHC_AIC7860_FE,                                      27,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
       AHC_AIC7892_FE,                                      28,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892B, AHC_AIC7892,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
       AHC_AIC7892_FE,                                      28,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892D, AHC_AIC7892,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
       AHC_AIC7892_FE,                                      28,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892P, AHC_AIC7892,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
       AHC_AIC7892_FE,                                      28,
       32, C46 },
      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899A, AHC_AIC7899,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
       AHC_AIC7899_FE,                                      29,
       32, C56_66 },
      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899B, AHC_AIC7899,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
       AHC_AIC7899_FE,                                      29,
       32, C56_66 },
      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899D, AHC_AIC7899,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
       AHC_AIC7899_FE,                                      29,
       32, C56_66 },
      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899P, AHC_AIC7899,
       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
       AHC_AIC7899_FE,                                      29,
       32, C56_66 },
    };

    unsigned short command;
    unsigned int  devconfig, i, oldverbose;
    struct pci_dev *pdev = NULL;

    for (i = 0; i < NUMBER(aic_pdevs); i++)
    {
      pdev = NULL;
      while ((pdev = pci_find_device(aic_pdevs[i].vendor_id,
                                     aic_pdevs[i].device_id,
                                     pdev))) {
	if (pci_enable_device(pdev))
		continue;
        if ( i == 0 ) /* We found one, but it's the 7810 RAID cont. */
        {
          if (aic7xxx_verbose & (VERBOSE_PROBE|VERBOSE_PROBE2))
          {
            printk(KERN_INFO "aic7xxx: The 7810 RAID controller is not "
              "supported by\n");
            printk(KERN_INFO "         this driver, we are ignoring it.\n");
          }
        }
        else if ( (temp_p = kmalloc(sizeof(struct aic7xxx_host),
                                    GFP_ATOMIC)) != NULL )
        {
          memset(temp_p, 0, sizeof(struct aic7xxx_host));
          temp_p->chip = aic_pdevs[i].chip | AHC_PCI;
          temp_p->flags = aic_pdevs[i].flags;
          temp_p->features = aic_pdevs[i].features;
          temp_p->board_name_index = aic_pdevs[i].board_name_index;
          temp_p->sc_size = aic_pdevs[i].seeprom_size;
          temp_p->sc_type = aic_pdevs[i].seeprom_type;

          /*
           * Read sundry information from PCI BIOS.
           */
          temp_p->irq = pdev->irq;
          temp_p->pdev = pdev;
          temp_p->pci_bus = pdev->bus->number;
          temp_p->pci_device_fn = pdev->devfn;
          temp_p->base = pci_resource_start(pdev, 0);
          temp_p->mbase = pci_resource_start(pdev, 1);
          current_p = list_p;
	  while(current_p && temp_p)
	  {
	    if ( ((current_p->pci_bus == temp_p->pci_bus) &&
	          (current_p->pci_device_fn == temp_p->pci_device_fn)) ||
                 (temp_p->base && (current_p->base == temp_p->base)) ||
                 (temp_p->mbase && (current_p->mbase == temp_p->mbase)) )
	    {
              /* duplicate PCI entry, skip it */
	      kfree(temp_p);
	      temp_p = NULL;
	    }
	    current_p = current_p->next;
	  }
	  if ( temp_p == NULL )
            continue;
          if (aic7xxx_verbose & VERBOSE_PROBE2)
            printk("aic7xxx: <%s> at PCI %d/%d\n", 
              board_names[aic_pdevs[i].board_name_index],
              PCI_SLOT(pdev->devfn),
              PCI_FUNC(pdev->devfn));
          pci_read_config_word(pdev, PCI_COMMAND, &command);
          if (aic7xxx_verbose & VERBOSE_PROBE2)
          {
            printk("aic7xxx: Initial PCI_COMMAND value was 0x%x\n",
              (int)command);
          }
#ifdef AIC7XXX_STRICT_PCI_SETUP
          command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
            PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
#else
          command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
#endif
          command &= ~PCI_COMMAND_INVALIDATE;
          if (aic7xxx_pci_parity == 0)
            command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
          pci_write_config_word(pdev, PCI_COMMAND, command);
#ifdef AIC7XXX_STRICT_PCI_SETUP
          pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
          if (aic7xxx_verbose & VERBOSE_PROBE2)
          {
            printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig);
          }
          devconfig |= 0x80000040;
          pci_write_config_dword(pdev, DEVCONFIG, devconfig);
#endif /* AIC7XXX_STRICT_PCI_SETUP */

          if(temp_p->base && check_region(temp_p->base, MAXREG - MINREG))
          {
            printk("aic7xxx: <%s> at PCI %d/%d/%d\n", 
              board_names[aic_pdevs[i].board_name_index],
              temp_p->pci_bus,
              PCI_SLOT(temp_p->pci_device_fn),
              PCI_FUNC(temp_p->pci_device_fn));
            printk("aic7xxx: I/O ports already in use, ignoring.\n");
            kfree(temp_p);
            temp_p = NULL;
            continue;
          }

          temp_p->unpause = INTEN;
          temp_p->pause = temp_p->unpause | PAUSE;
          if ( ((temp_p->base == 0) &&
                (temp_p->mbase == 0)) ||
               (temp_p->irq == 0) )
          {
            printk("aic7xxx: <%s> at PCI %d/%d/%d\n", 
              board_names[aic_pdevs[i].board_name_index],
              temp_p->pci_bus,
              PCI_SLOT(temp_p->pci_device_fn),
              PCI_FUNC(temp_p->pci_device_fn));
            printk("aic7xxx: Controller disabled by BIOS, ignoring.\n");
            kfree(temp_p);
            temp_p = NULL;
            continue;
          }

#ifdef MMAPIO
          if ( !(temp_p->base) || !(temp_p->flags & AHC_MULTI_CHANNEL) ||
               ((temp_p->chip != (AHC_AIC7870 | AHC_PCI)) &&
                (temp_p->chip != (AHC_AIC7880 | AHC_PCI))) )
          {
            unsigned long page_offset, base;

            base = temp_p->mbase & PAGE_MASK;
            page_offset = temp_p->mbase - base;
            temp_p->maddr = ioremap_nocache(base, page_offset + 256);
            if(temp_p->maddr)
            {
              temp_p->maddr += page_offset;
              /*
               * We need to check the I/O with the MMAPed address.  Some machines
               * simply fail to work with MMAPed I/O and certain controllers.
               */
              if(aic_inb(temp_p, HCNTRL) == 0xff)
              {
                /*
                 * OK.....we failed our test....go back to programmed I/O
                 */
                printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", 
                  board_names[aic_pdevs[i].board_name_index],
                  temp_p->pci_bus,
                  PCI_SLOT(temp_p->pci_device_fn),
                  PCI_FUNC(temp_p->pci_device_fn));
                printk(KERN_INFO "aic7xxx: MMAPed I/O failed, reverting to "
                                 "Programmed I/O.\n");
                iounmap((void *) (((unsigned long) temp_p->maddr) & PAGE_MASK));
                temp_p->maddr = 0;
                if(temp_p->base == 0)
                {
                  printk("aic7xxx: <%s> at PCI %d/%d/%d\n", 
                    board_names[aic_pdevs[i].board_name_index],
                    temp_p->pci_bus,
                    PCI_SLOT(temp_p->pci_device_fn),
                    PCI_FUNC(temp_p->pci_device_fn));
                  printk("aic7xxx: Controller disabled by BIOS, ignoring.\n");
                  kfree(temp_p);
                  temp_p = NULL;
                  continue;
                }
              }
            }
          }
#endif

          /*
           * Lock out other contenders for our i/o space.
           */
          if(temp_p->base)
            request_region(temp_p->base, MAXREG - MINREG, "aic7xxx");

          /*
           * We HAVE to make sure the first pause_sequencer() and all other
           * subsequent I/O that isn't PCI config space I/O takes place
           * after the MMAPed I/O region is configured and tested.  The
           * problem is the PowerPC architecture that doesn't support
           * programmed I/O at all, so we have to have the MMAP I/O set up
           * for this pause to even work on those machines.
           */
          pause_sequencer(temp_p);

          /*
           * Clear out any pending PCI error status messages.  Also set
           * verbose to 0 so that we don't emit strange PCI error messages
           * while cleaning out the current status bits.
           */
          oldverbose = aic7xxx_verbose;
          aic7xxx_verbose = 0;
          aic7xxx_pci_intr(temp_p);
          aic7xxx_verbose = oldverbose;

          temp_p->bios_address = 0;

          /*
           * Remember how the card was setup in case there is no seeprom.
           */
          if (temp_p->features & AHC_ULTRA2)
            temp_p->scsi_id = aic_inb(temp_p, SCSIID_ULTRA2) & OID;
          else
            temp_p->scsi_id = aic_inb(temp_p, SCSIID) & OID;
          /*
           * Get current termination setting
           */
          sxfrctl1 = aic_inb(temp_p, SXFRCTL1);

          if (aic7xxx_chip_reset(temp_p) == -1)
          {
            release_region(temp_p->base, MAXREG - MINREG);
            kfree(temp_p);
            temp_p = NULL;
            continue;
          }
          /*
           * Very quickly put the term setting back into the register since
           * the chip reset may cause odd things to happen.  This is to keep
           * LVD busses with lots of drives from draining the power out of
           * the diffsense line before we get around to running the
           * configure_termination() function.  Also restore the STPWLEVEL
           * bit of DEVCONFIG
           */
          aic_outb(temp_p, sxfrctl1, SXFRCTL1);
          pci_write_config_dword(temp_p->pdev, DEVCONFIG, devconfig);
          sxfrctl1 &= STPWEN;

          /*
           * We need to set the CHNL? assignments before loading the SEEPROM
           * The 3940 and 3985 cards (original stuff, not any of the later
           * stuff) are 7870 and 7880 class chips.  The Ultra2 stuff falls
           * under 7896 and 7897.  The 7895 is in a class by itself :)
           */
          switch (temp_p->chip & AHC_CHIPID_MASK)
          {
            case AHC_AIC7870: /* 3840 / 3985 */
            case AHC_AIC7880: /* 3840 UW / 3985 UW */
              if(temp_p->flags & AHC_MULTI_CHANNEL)
              {
                switch(PCI_SLOT(temp_p->pci_device_fn))
                {
                  case 5:
                    temp_p->flags |= AHC_CHNLB;
                    break;
                  case 8:
                    temp_p->flags |= AHC_CHNLB;
                    break;
                  case 12:
                    temp_p->flags |= AHC_CHNLC;
                    break;
                  default:
                    break;
                }
              }
              break;

            case AHC_AIC7895: /* 7895 */
            case AHC_AIC7896: /* 7896/7 */
            case AHC_AIC7899: /* 7899 */
              if (PCI_FUNC(pdev->devfn) != 0)
              {
                temp_p->flags |= AHC_CHNLB;
              }
              /*
               * The 7895 is the only chipset that sets the SCBSIZE32 param
               * in the DEVCONFIG register.  The Ultra2 chipsets use
               * the DSCOMMAND0 register instead.
               */
              if ((temp_p->chip & AHC_CHIPID_MASK) == AHC_AIC7895)
              {
                pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
                devconfig |= SCBSIZE32;
                pci_write_config_dword(pdev, DEVCONFIG, devconfig);
              }
              break;
            default:
              break;
          }

          /*
           * Loading of the SEEPROM needs to come after we've set the flags
           * to indicate possible CHNLB and CHNLC assigments.  Otherwise,
           * on 394x and 398x cards we'll end up reading the wrong settings
           * for channels B and C
           */
          switch (temp_p->chip & AHC_CHIPID_MASK)
          {
            case AHC_AIC7892:
            case AHC_AIC7899:
              aic_outb(temp_p, 0, SCAMCTL);
              /*
               * Switch to the alt mode of the chip...
               */
              aic_outb(temp_p, aic_inb(temp_p, SFUNCT) | ALT_MODE, SFUNCT);
              /*
               * Set our options...the last two items set our CRC after x byte
	       * count in target mode...
               */
              aic_outb(temp_p, AUTO_MSGOUT_DE | DIS_MSGIN_DUALEDGE, OPTIONMODE);
	      aic_outb(temp_p, 0x00, 0x0b);
	      aic_outb(temp_p, 0x10, 0x0a);
              /*
               * switch back to normal mode...
               */
              aic_outb(temp_p, aic_inb(temp_p, SFUNCT) & ~ALT_MODE, SFUNCT);
              aic_outb(temp_p, CRCVALCHKEN | CRCENDCHKEN | CRCREQCHKEN |
			       TARGCRCENDEN | TARGCRCCNTEN,
                       CRCCONTROL1);
              aic_outb(temp_p, ((aic_inb(temp_p, DSCOMMAND0) | USCBSIZE32 |
                                 MPARCKEN | CIOPARCKEN | CACHETHEN) & 
                               ~DPARCKEN), DSCOMMAND0);
              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
              break;
            case AHC_AIC7890:
            case AHC_AIC7896:
              aic_outb(temp_p, 0, SCAMCTL);
              aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
                                CACHETHEN | MPARCKEN | USCBSIZE32 |
                                CIOPARCKEN) & ~DPARCKEN, DSCOMMAND0);
              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
              break;
            case AHC_AIC7850:
            case AHC_AIC7860:
              /*
               * Set the DSCOMMAND0 register on these cards different from
               * on the 789x cards.  Also, read the SEEPROM as well.
               */
              aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
                                CACHETHEN | MPARCKEN) & ~DPARCKEN,
                       DSCOMMAND0);
              /* FALLTHROUGH */
            default:
              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
              break;
            case AHC_AIC7880:
              /*
               * Check the rev of the chipset before we change DSCOMMAND0
               */
              pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
              if ((devconfig & 0xff) >= 1)
              {
                aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
                                  CACHETHEN | MPARCKEN) & ~DPARCKEN,
                         DSCOMMAND0);
              }
              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
              break;
          }
          

          /*
           * and then we need another switch based on the type in order to
           * make sure the channel B primary flag is set properly on 7895
           * controllers....Arrrgggghhh!!!  We also have to catch the fact
           * that when you disable the BIOS on the 7895 on the Intel DK440LX
           * motherboard, and possibly others, it only sets the BIOS disabled
           * bit on the A channel...I think I'm starting to lean towards
           * going postal....
           */
          switch(temp_p->chip & AHC_CHIPID_MASK)
          {
            case AHC_AIC7895:
            case AHC_AIC7896:
            case AHC_AIC7899:
              current_p = list_p;
              while(current_p != NULL)
              {
                if ( (current_p->pci_bus == temp_p->pci_bus) &&
                     (PCI_SLOT(current_p->pci_device_fn) ==
                      PCI_SLOT(temp_p->pci_device_fn)) )
                {
                  if ( PCI_FUNC(current_p->pci_device_fn) == 0 )
                  {
                    temp_p->flags |= 
                      (current_p->flags & AHC_CHANNEL_B_PRIMARY);
                    temp_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS);
                    temp_p->flags |=
                      (current_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS));
                  }
                  else
                  {
                    current_p->flags |=
                      (temp_p->flags & AHC_CHANNEL_B_PRIMARY);
                    current_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS);
                    current_p->flags |=
                      (temp_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS));
                  }
                }
                current_p = current_p->next;
              }
              break;
            default:
              break;
          }

          /*
           * We only support external SCB RAM on the 7895/6/7 chipsets.
           * We could support it on the 7890/1 easy enough, but I don't
           * know of any 7890/1 based cards that have it.  I do know
           * of 7895/6/7 cards that have it and they work properly.
           */
          switch(temp_p->chip & AHC_CHIPID_MASK)
          {
            default:
              break;
            case AHC_AIC7895:
            case AHC_AIC7896:
            case AHC_AIC7899:
              pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
              if (temp_p->features & AHC_ULTRA2)
              {
                if ( (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2) &&
                     (aic7xxx_scbram) )
                {
                  aic_outb(temp_p,
                           aic_inb(temp_p, DSCOMMAND0) & ~SCBRAMSEL_ULTRA2,
                           DSCOMMAND0);
                  temp_p->flags |= AHC_EXTERNAL_SRAM;
                  devconfig |= EXTSCBPEN;
                }
                else if (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2)
                {
                  printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", 
                    board_names[aic_pdevs[i].board_name_index],
                    temp_p->pci_bus,
                    PCI_SLOT(temp_p->pci_device_fn),
                    PCI_FUNC(temp_p->pci_device_fn));
                  printk("aic7xxx: external SCB RAM detected, "
                         "but not enabled\n");
                }
              }
              else
              {
                if ((devconfig & RAMPSM) && (aic7xxx_scbram))
                {
                  devconfig &= ~SCBRAMSEL;
                  devconfig |= EXTSCBPEN;
                  temp_p->flags |= AHC_EXTERNAL_SRAM;
                }
                else if (devconfig & RAMPSM)
                {
                  printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", 
                    board_names[aic_pdevs[i].board_name_index],
                    temp_p->pci_bus,
                    PCI_SLOT(temp_p->pci_device_fn),
                    PCI_FUNC(temp_p->pci_device_fn));
                  printk("aic7xxx: external SCB RAM detected, "
                         "but not enabled\n");
                }
              }
              pci_write_config_dword(pdev, DEVCONFIG, devconfig);
              if ( (temp_p->flags & AHC_EXTERNAL_SRAM) &&
                   (temp_p->flags & AHC_CHNLB) )
                aic_outb(temp_p, 1, CCSCBBADDR);
              break;
          }

          /*
           * Take the LED out of diagnostic mode
           */
          aic_outb(temp_p, 
            (aic_inb(temp_p, SBLKCTL) & ~(DIAGLEDEN | DIAGLEDON)),
            SBLKCTL);

          /*
           * We don't know where this is set in the SEEPROM or by the
           * BIOS, so we default to 100%.  On Ultra2 controllers, use 75%
           * instead.
           */
          if (temp_p->features & AHC_ULTRA2)
          {
            aic_outb(temp_p, RD_DFTHRSH_MAX | WR_DFTHRSH_MAX, DFF_THRSH);
          }
          else
          {
            aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
          }

          /*
           * Call our function to fixup any bugs that exist on this chipset.
           * This may muck with PCI settings and other device settings, so
           * make sure it's after all the other PCI and device register
           * tweaks so it can back out bad settings on specific broken cards.
           */
          aic7xxx_configure_bugs(temp_p);

          if ( list_p == NULL )
          {
            list_p = current_p = temp_p;
          }
          else
          {
            current_p = list_p;
            while(current_p->next != NULL)
              current_p = current_p->next;
            current_p->next = temp_p;
          }
          temp_p->next = NULL;
          found++;
        }  /* Found an Adaptec PCI device. */
        else /* Well, we found one, but we couldn't get any memory */
        {
          printk("aic7xxx: Found <%s>\n", 
            board_names[aic_pdevs[i].board_name_index]);
          printk(KERN_INFO "aic7xxx: Unable to allocate device memory, "
            "skipping.\n");
        }
      } /* while(pdev=....) */
    } /* for PCI_DEVICES */
  } /* PCI BIOS present */
#endif /* CONFIG_PCI */

#if defined(__i386__) || defined(__alpha__)
  /*
   * EISA/VL-bus card signature probe.
   */
  slot = MINSLOT;
  while ( (slot <= MAXSLOT) && 
         !(aic7xxx_no_probe) )
  {
    base = SLOTBASE(slot) + MINREG;

    if (check_region(base, MAXREG - MINREG))
    {
      /*
       * Some other driver has staked a
       * claim to this i/o region already.
       */
      slot++;
      continue; /* back to the beginning of the for loop */
    }
    flags = 0;
    type = aic7xxx_probe(slot, base + AHC_HID0, &flags);
    if (type == -1)
    {
      slot++;
      continue;
    }
    temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC);
    if (temp_p == NULL)
    {
      printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
      slot++;
      continue; /* back to the beginning of the while loop */
    }
    /*
     * Lock out other contenders for our i/o space.
     */
    request_region(base, MAXREG - MINREG, "aic7xxx");

    /*
     * Pause the card preserving the IRQ type.  Allow the operator
     * to override the IRQ trigger.
     */
    if (aic7xxx_irq_trigger == 1)
      hcntrl = IRQMS;  /* Level */
    else if (aic7xxx_irq_trigger == 0)
      hcntrl = 0;  /* Edge */
    else
      hcntrl = inb(base + HCNTRL) & IRQMS;  /* Default */
    memset(temp_p, 0, sizeof(struct aic7xxx_host));
    temp_p->unpause = hcntrl | INTEN;
    temp_p->pause = hcntrl | PAUSE | INTEN;
    temp_p->base = base;
    temp_p->mbase = 0;
    temp_p->maddr = 0;
    temp_p->pci_bus = 0;
    temp_p->pci_device_fn = slot;
    aic_outb(temp_p, hcntrl | PAUSE, HCNTRL);
    while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
    if (aic7xxx_chip_reset(temp_p) == -1)
      temp_p->irq = 0;
    else
      temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F;
    temp_p->flags |= AHC_PAGESCBS;

    switch (temp_p->irq)
    {
      case 9:
      case 10:
      case 11:
      case 12:
      case 14:
      case 15:
        break;

      default:
        printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
          "level %d, ignoring.\n", temp_p->irq);
        kfree(temp_p);
        release_region(base, MAXREG - MINREG);
        slot++;
        continue; /* back to the beginning of the while loop */
    }

    /*
     * We are commited now, everything has been checked and this card
     * has been found, now we just set it up
     */

    /*
     * Insert our new struct into the list at the end
     */
    if (list_p == NULL)
    {
      list_p = current_p = temp_p;
    }
    else
    {
      current_p = list_p;
      while (current_p->next != NULL)
        current_p = current_p->next;
      current_p->next = temp_p;
    }

    switch (type)
    {
      case 0:
        temp_p->board_name_index = 2;
        if (aic7xxx_verbose & VERBOSE_PROBE2)
          printk("aic7xxx: <%s> at EISA %d\n",
               board_names[2], slot);
        /* FALLTHROUGH */
      case 1:
      {
        temp_p->chip = AHC_AIC7770 | AHC_EISA;
        temp_p->features |= AHC_AIC7770_FE;
        temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL);

        /*
         * Get the primary channel information.  Right now we don't
         * do anything with this, but someday we will be able to inform
         * the mid-level SCSI code which channel is primary.
         */
        if (temp_p->board_name_index == 0)
        {
          temp_p->board_name_index = 3;
          if (aic7xxx_verbose & VERBOSE_PROBE2)
            printk("aic7xxx: <%s> at EISA %d\n",
                 board_names[3], slot);
        }
        if (temp_p->bios_control & CHANNEL_B_PRIMARY)
        {
          temp_p->flags |= AHC_CHANNEL_B_PRIMARY;
        }

        if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED)
        {
          temp_p->flags &= ~AHC_BIOS_ENABLED;
        }
        else
        {
          temp_p->flags &= ~AHC_USEDEFAULTS;
          temp_p->flags |= AHC_BIOS_ENABLED;
          if ( (temp_p->bios_control & 0x20) == 0 )
          {
            temp_p->bios_address = 0xcc000;
            temp_p->bios_address += (0x4000 * (temp_p->bios_control & 0x07));
          }
          else
          {
            temp_p->bios_address = 0xd0000;
            temp_p->bios_address += (0x8000 * (temp_p->bios_control & 0x06));
          }
        }
        temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8;
        temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1);
        if (temp_p->features & AHC_WIDE)
        {
          temp_p->scsi_id = temp_p->adapter_control & HWSCSIID;
          temp_p->scsi_id_b = temp_p->scsi_id;
        }
        else
        {
          temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID;
          temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID;
        }
        aic7xxx_load_seeprom(temp_p, &sxfrctl1);
        break;
      }

      case 2:
      case 3:
        temp_p->chip = AHC_AIC7770 | AHC_VL;
        temp_p->features |= AHC_AIC7770_FE;
        if (type == 2)
          temp_p->flags |= AHC_BIOS_ENABLED;
        else
          temp_p->flags &= ~AHC_BIOS_ENABLED;
        if (aic_inb(temp_p, SCSICONF) & TERM_ENB)
          sxfrctl1 = STPWEN;
        aic7xxx_load_seeprom(temp_p, &sxfrctl1);
        temp_p->board_name_index = 4;
        if (aic7xxx_verbose & VERBOSE_PROBE2)
          printk("aic7xxx: <%s> at VLB %d\n",
               board_names[2], slot);
        switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL )
        {
          case 0x00:
            temp_p->bios_address = 0xe0000;
            break;
          case 0x20:
            temp_p->bios_address = 0xc8000;
            break;
          case 0x40:
            temp_p->bios_address = 0xd0000;
            break;
          case 0x60:
            temp_p->bios_address = 0xd8000;
            break;
          default:
            break; /* can't get here */
        }
        break;

      default:  /* Won't get here. */
        break;
    }
    if (aic7xxx_verbose & VERBOSE_PROBE2)
    {
      printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n",
        (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base,
        temp_p->irq,
        (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered");
      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
             (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis");
    }

    /*
     * All the 7770 based chipsets have this bug
     */
    temp_p->bugs |= AHC_BUG_TMODE_WIDEODD;

    /*
     * Set the FIFO threshold and the bus off time.
     */
    hostconf = aic_inb(temp_p, HOSTCONF);
    aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD);
    aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME);
    slot++;
    found++;
  }

#endif /* defined(__i386__) || defined(__alpha__) */

  /*
   * Now, we re-order the probed devices by BIOS address and BUS class.
   * In general, we follow this algorithm to make the adapters show up
   * in the same order under linux that the computer finds them.
   *  1: All VLB/EISA cards with BIOS_ENABLED first, according to BIOS
   *     address, going from lowest to highest.
   *  2: All PCI controllers with BIOS_ENABLED next, according to BIOS
   *     address, going from lowest to highest.
   *  3: Remaining VLB/EISA controllers going in slot order.
   *  4: Remaining PCI controllers, going in PCI device order (reversable)
   */

  {
    struct aic7xxx_host *sort_list[4] = { NULL, NULL, NULL, NULL };
    struct aic7xxx_host *vlb, *pci;
    struct aic7xxx_host *prev_p;
    struct aic7xxx_host *p;
    unsigned char left;

    prev_p = vlb = pci = NULL;

    temp_p = list_p;
    while (temp_p != NULL)
    {
      switch(temp_p->chip & ~AHC_CHIPID_MASK)
      {
        case AHC_EISA:
        case AHC_VL:
        {
          p = temp_p;
          if (p->flags & AHC_BIOS_ENABLED)
            vlb = sort_list[0];
          else
            vlb = sort_list[2];

          if (vlb == NULL)
          {
            vlb = temp_p;
            temp_p = temp_p->next;
            vlb->next = NULL;
          }
          else
          {
            current_p = vlb;
            prev_p = NULL;
            while ( (current_p != NULL) &&
                    (current_p->bios_address < temp_p->bios_address))
            {
              prev_p = current_p;
              current_p = current_p->next;
            }
            if (prev_p != NULL)
            {
              prev_p->next = temp_p;
              temp_p = temp_p->next;
              prev_p->next->next = current_p;
            }
            else
            {
              vlb = temp_p;
              temp_p = temp_p->next;
              vlb->next = current_p;
            }
          }
          
          if (p->flags & AHC_BIOS_ENABLED)
            sort_list[0] = vlb;
          else
            sort_list[2] = vlb;
          
          break;
        }
        default:  /* All PCI controllers fall through to default */
        {

          p = temp_p;
          if (p->flags & AHC_BIOS_ENABLED) 
            pci = sort_list[1];
          else
            pci = sort_list[3];

          if (pci == NULL)
          {
            pci = temp_p;
            temp_p = temp_p->next;
            pci->next = NULL;
          }
          else
          {
            current_p = pci;
            prev_p = NULL;
            if (!aic7xxx_reverse_scan)
            {
              while ( (current_p != NULL) &&
                      ( (PCI_SLOT(current_p->pci_device_fn) |
                        (current_p->pci_bus << 8)) < 
                        (PCI_SLOT(temp_p->pci_device_fn) |
                        (temp_p->pci_bus << 8)) ) )
              {
                prev_p = current_p;
                current_p = current_p->next;
              }
            }
            else
            {
              while ( (current_p != NULL) &&
                      ( (PCI_SLOT(current_p->pci_device_fn) |
                        (current_p->pci_bus << 8)) > 
                        (PCI_SLOT(temp_p->pci_device_fn) |
                        (temp_p->pci_bus << 8)) ) )
              {
                prev_p = current_p;
                current_p = current_p->next;
              }
            }
            /*
             * Are we dealing with a 7895/6/7/9 where we need to sort the
             * channels as well, if so, the bios_address values should
             * be the same
             */
            if ( (current_p) && (temp_p->flags & AHC_MULTI_CHANNEL) &&
                 (temp_p->pci_bus == current_p->pci_bus) &&
                 (PCI_SLOT(temp_p->pci_device_fn) ==
                  PCI_SLOT(current_p->pci_device_fn)) )
            {
              if (temp_p->flags & AHC_CHNLB)
              {
                if ( !(temp_p->flags & AHC_CHANNEL_B_PRIMARY) )
                {
                  prev_p = current_p;
                  current_p = current_p->next;
                }
              }
              else
              {
                if (temp_p->flags & AHC_CHANNEL_B_PRIMARY)
                {
                  prev_p = current_p;
                  current_p = current_p->next;
                }
              }
            }
            if (prev_p != NULL)
            {
              prev_p->next = temp_p;
              temp_p = temp_p->next;
              prev_p->next->next = current_p;
            }
            else
            {
              pci = temp_p;
              temp_p = temp_p->next;
              pci->next = current_p;
            }
          }

          if (p->flags & AHC_BIOS_ENABLED)
            sort_list[1] = pci;
          else
            sort_list[3] = pci;

          break;
        }
      }  /* End of switch(temp_p->type) */
    } /* End of while (temp_p != NULL) */
    /*
     * At this point, the cards have been broken into 4 sorted lists, now
     * we run through the lists in order and register each controller
     */
    {
      int i;
      
      left = found;
      for (i=0; i<NUMBER(sort_list); i++)
      {
        temp_p = sort_list[i];
        while(temp_p != NULL)
        {
          template->name = board_names[temp_p->board_name_index];
          p = aic7xxx_alloc(template, temp_p);
          if (p != NULL)
          {
            p->instance = found - left;
            if (aic7xxx_register(template, p, (--left)) == 0)
            {
              found--;
              aic7xxx_release(p->host);
              scsi_unregister(p->host);
            }
            else if (aic7xxx_dump_card)
            {
              pause_sequencer(p);
              aic7xxx_print_card(p);
              aic7xxx_print_scratch_ram(p);
              unpause_sequencer(p, TRUE);
            }
          }
          current_p = temp_p;
          temp_p = (struct aic7xxx_host *)temp_p->next;
          kfree(current_p);
        }
      }
    }
  }
  return (found);
}

Generated by GNU enscript 1.6.4.