static int advansys_board_found()

in advansys.c [10706:11145]


static int advansys_board_found(struct Scsi_Host *shost, unsigned int iop,
				int bus_type)
{
	struct pci_dev *pdev;
	struct asc_board *boardp = shost_priv(shost);
	ASC_DVC_VAR *asc_dvc_varp = NULL;
	ADV_DVC_VAR *adv_dvc_varp = NULL;
	int share_irq, warn_code, ret;

	pdev = (bus_type == ASC_IS_PCI) ? to_pci_dev(boardp->dev) : NULL;

	if (ASC_NARROW_BOARD(boardp)) {
		ASC_DBG(1, "narrow board\n");
		asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
		asc_dvc_varp->bus_type = bus_type;
		asc_dvc_varp->drv_ptr = boardp;
		asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
		asc_dvc_varp->iop_base = iop;
	} else {
#ifdef CONFIG_PCI
		adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
		adv_dvc_varp->drv_ptr = boardp;
		adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
		if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
			ASC_DBG(1, "wide board ASC-3550\n");
			adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
		} else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
			ASC_DBG(1, "wide board ASC-38C0800\n");
			adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
		} else {
			ASC_DBG(1, "wide board ASC-38C1600\n");
			adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
		}

		boardp->asc_n_io_port = pci_resource_len(pdev, 1);
		boardp->ioremap_addr = pci_ioremap_bar(pdev, 1);
		if (!boardp->ioremap_addr) {
			shost_printk(KERN_ERR, shost, "ioremap(%lx, %d) "
					"returned NULL\n",
					(long)pci_resource_start(pdev, 1),
					boardp->asc_n_io_port);
			ret = -ENODEV;
			goto err_shost;
		}
		adv_dvc_varp->iop_base = (AdvPortAddr)boardp->ioremap_addr;
		ASC_DBG(1, "iop_base: 0x%p\n", adv_dvc_varp->iop_base);

		/*
		 * Even though it isn't used to access wide boards, other
		 * than for the debug line below, save I/O Port address so
		 * that it can be reported.
		 */
		boardp->ioport = iop;

		ASC_DBG(1, "iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
				(ushort)inp(iop + 1), (ushort)inpw(iop));
#endif /* CONFIG_PCI */
	}

	if (ASC_NARROW_BOARD(boardp)) {
		/*
		 * Set the board bus type and PCI IRQ before
		 * calling AscInitGetConfig().
		 */
		switch (asc_dvc_varp->bus_type) {
#ifdef CONFIG_ISA
		case ASC_IS_VL:
			share_irq = 0;
			break;
		case ASC_IS_EISA:
			share_irq = IRQF_SHARED;
			break;
#endif /* CONFIG_ISA */
#ifdef CONFIG_PCI
		case ASC_IS_PCI:
			share_irq = IRQF_SHARED;
			break;
#endif /* CONFIG_PCI */
		default:
			shost_printk(KERN_ERR, shost, "unknown adapter type: "
					"%d\n", asc_dvc_varp->bus_type);
			share_irq = 0;
			break;
		}

		/*
		 * NOTE: AscInitGetConfig() may change the board's
		 * bus_type value. The bus_type value should no
		 * longer be used. If the bus_type field must be
		 * referenced only use the bit-wise AND operator "&".
		 */
		ASC_DBG(2, "AscInitGetConfig()\n");
		ret = AscInitGetConfig(shost) ? -ENODEV : 0;
	} else {
#ifdef CONFIG_PCI
		/*
		 * For Wide boards set PCI information before calling
		 * AdvInitGetConfig().
		 */
		share_irq = IRQF_SHARED;
		ASC_DBG(2, "AdvInitGetConfig()\n");

		ret = AdvInitGetConfig(pdev, shost) ? -ENODEV : 0;
#else
		share_irq = 0;
		ret = -ENODEV;
#endif /* CONFIG_PCI */
	}

	if (ret)
		goto err_unmap;

	/*
	 * Save the EEPROM configuration so that it can be displayed
	 * from /proc/scsi/advansys/[0...].
	 */
	if (ASC_NARROW_BOARD(boardp)) {

		ASCEEP_CONFIG *ep;

		/*
		 * Set the adapter's target id bit in the 'init_tidmask' field.
		 */
		boardp->init_tidmask |=
		    ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);

		/*
		 * Save EEPROM settings for the board.
		 */
		ep = &boardp->eep_config.asc_eep;

		ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
		ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
		ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
		ASC_EEP_SET_DMA_SPD(ep, ASC_DEF_ISA_DMA_SPEED);
		ep->start_motor = asc_dvc_varp->start_motor;
		ep->cntl = asc_dvc_varp->dvc_cntl;
		ep->no_scam = asc_dvc_varp->no_scam;
		ep->max_total_qng = asc_dvc_varp->max_total_qng;
		ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
		/* 'max_tag_qng' is set to the same value for every device. */
		ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
		ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
		ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
		ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
		ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
		ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
		ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];

		/*
		 * Modify board configuration.
		 */
		ASC_DBG(2, "AscInitSetConfig()\n");
		ret = AscInitSetConfig(pdev, shost) ? -ENODEV : 0;
		if (ret)
			goto err_unmap;
	} else {
		ADVEEP_3550_CONFIG *ep_3550;
		ADVEEP_38C0800_CONFIG *ep_38C0800;
		ADVEEP_38C1600_CONFIG *ep_38C1600;

		/*
		 * Save Wide EEP Configuration Information.
		 */
		if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
			ep_3550 = &boardp->eep_config.adv_3550_eep;

			ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
			ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
			ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
			ep_3550->termination = adv_dvc_varp->cfg->termination;
			ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
			ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
			ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
			ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
			ep_3550->ultra_able = adv_dvc_varp->ultra_able;
			ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
			ep_3550->start_motor = adv_dvc_varp->start_motor;
			ep_3550->scsi_reset_delay =
			    adv_dvc_varp->scsi_reset_wait;
			ep_3550->serial_number_word1 =
			    adv_dvc_varp->cfg->serial1;
			ep_3550->serial_number_word2 =
			    adv_dvc_varp->cfg->serial2;
			ep_3550->serial_number_word3 =
			    adv_dvc_varp->cfg->serial3;
		} else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
			ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;

			ep_38C0800->adapter_scsi_id =
			    adv_dvc_varp->chip_scsi_id;
			ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
			ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
			ep_38C0800->termination_lvd =
			    adv_dvc_varp->cfg->termination;
			ep_38C0800->disc_enable =
			    adv_dvc_varp->cfg->disc_enable;
			ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
			ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
			ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
			ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
			ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
			ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
			ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
			ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
			ep_38C0800->start_motor = adv_dvc_varp->start_motor;
			ep_38C0800->scsi_reset_delay =
			    adv_dvc_varp->scsi_reset_wait;
			ep_38C0800->serial_number_word1 =
			    adv_dvc_varp->cfg->serial1;
			ep_38C0800->serial_number_word2 =
			    adv_dvc_varp->cfg->serial2;
			ep_38C0800->serial_number_word3 =
			    adv_dvc_varp->cfg->serial3;
		} else {
			ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;

			ep_38C1600->adapter_scsi_id =
			    adv_dvc_varp->chip_scsi_id;
			ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
			ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
			ep_38C1600->termination_lvd =
			    adv_dvc_varp->cfg->termination;
			ep_38C1600->disc_enable =
			    adv_dvc_varp->cfg->disc_enable;
			ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
			ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
			ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
			ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
			ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
			ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
			ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
			ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
			ep_38C1600->start_motor = adv_dvc_varp->start_motor;
			ep_38C1600->scsi_reset_delay =
			    adv_dvc_varp->scsi_reset_wait;
			ep_38C1600->serial_number_word1 =
			    adv_dvc_varp->cfg->serial1;
			ep_38C1600->serial_number_word2 =
			    adv_dvc_varp->cfg->serial2;
			ep_38C1600->serial_number_word3 =
			    adv_dvc_varp->cfg->serial3;
		}

		/*
		 * Set the adapter's target id bit in the 'init_tidmask' field.
		 */
		boardp->init_tidmask |=
		    ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
	}

	/*
	 * Channels are numbered beginning with 0. For AdvanSys one host
	 * structure supports one channel. Multi-channel boards have a
	 * separate host structure for each channel.
	 */
	shost->max_channel = 0;
	if (ASC_NARROW_BOARD(boardp)) {
		shost->max_id = ASC_MAX_TID + 1;
		shost->max_lun = ASC_MAX_LUN + 1;
		shost->max_cmd_len = ASC_MAX_CDB_LEN;

		shost->io_port = asc_dvc_varp->iop_base;
		boardp->asc_n_io_port = ASC_IOADR_GAP;
		shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;

		/* Set maximum number of queues the adapter can handle. */
		shost->can_queue = asc_dvc_varp->max_total_qng;
	} else {
		shost->max_id = ADV_MAX_TID + 1;
		shost->max_lun = ADV_MAX_LUN + 1;
		shost->max_cmd_len = ADV_MAX_CDB_LEN;

		/*
		 * Save the I/O Port address and length even though
		 * I/O ports are not used to access Wide boards.
		 * Instead the Wide boards are accessed with
		 * PCI Memory Mapped I/O.
		 */
		shost->io_port = iop;

		shost->this_id = adv_dvc_varp->chip_scsi_id;

		/* Set maximum number of queues the adapter can handle. */
		shost->can_queue = adv_dvc_varp->max_host_qng;
	}

	/*
	 * Set the maximum number of scatter-gather elements the
	 * adapter can handle.
	 */
	if (ASC_NARROW_BOARD(boardp)) {
		/*
		 * Allow two commands with 'sg_tablesize' scatter-gather
		 * elements to be executed simultaneously. This value is
		 * the theoretical hardware limit. It may be decreased
		 * below.
		 */
		shost->sg_tablesize =
		    (((asc_dvc_varp->max_total_qng - 2) / 2) *
		     ASC_SG_LIST_PER_Q) + 1;
	} else {
		shost->sg_tablesize = ADV_MAX_SG_LIST;
	}

	/*
	 * The value of 'sg_tablesize' can not exceed the SCSI
	 * mid-level driver definition of SG_ALL. SG_ALL also
	 * must not be exceeded, because it is used to define the
	 * size of the scatter-gather table in 'struct asc_sg_head'.
	 */
	if (shost->sg_tablesize > SG_ALL) {
		shost->sg_tablesize = SG_ALL;
	}

	ASC_DBG(1, "sg_tablesize: %d\n", shost->sg_tablesize);

	/* BIOS start address. */
	if (ASC_NARROW_BOARD(boardp)) {
		shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base,
						    asc_dvc_varp->bus_type);
	} else {
		/*
		 * Fill-in BIOS board variables. The Wide BIOS saves
		 * information in LRAM that is used by the driver.
		 */
		AdvReadWordLram(adv_dvc_varp->iop_base,
				BIOS_SIGNATURE, boardp->bios_signature);
		AdvReadWordLram(adv_dvc_varp->iop_base,
				BIOS_VERSION, boardp->bios_version);
		AdvReadWordLram(adv_dvc_varp->iop_base,
				BIOS_CODESEG, boardp->bios_codeseg);
		AdvReadWordLram(adv_dvc_varp->iop_base,
				BIOS_CODELEN, boardp->bios_codelen);

		ASC_DBG(1, "bios_signature 0x%x, bios_version 0x%x\n",
			 boardp->bios_signature, boardp->bios_version);

		ASC_DBG(1, "bios_codeseg 0x%x, bios_codelen 0x%x\n",
			 boardp->bios_codeseg, boardp->bios_codelen);

		/*
		 * If the BIOS saved a valid signature, then fill in
		 * the BIOS code segment base address.
		 */
		if (boardp->bios_signature == 0x55AA) {
			/*
			 * Convert x86 realmode code segment to a linear
			 * address by shifting left 4.
			 */
			shost->base = ((ulong)boardp->bios_codeseg << 4);
		} else {
			shost->base = 0;
		}
	}

	/*
	 * Register Board Resources - I/O Port, DMA, IRQ
	 */

	/* Register DMA Channel for Narrow boards. */
	shost->dma_channel = NO_ISA_DMA;	/* Default to no ISA DMA. */

	/* Register IRQ Number. */
	ASC_DBG(2, "request_irq(%d, %p)\n", boardp->irq, shost);

	ret = request_irq(boardp->irq, advansys_interrupt, share_irq,
			  DRV_NAME, shost);

	if (ret) {
		if (ret == -EBUSY) {
			shost_printk(KERN_ERR, shost, "request_irq(): IRQ 0x%x "
					"already in use\n", boardp->irq);
		} else if (ret == -EINVAL) {
			shost_printk(KERN_ERR, shost, "request_irq(): IRQ 0x%x "
					"not valid\n", boardp->irq);
		} else {
			shost_printk(KERN_ERR, shost, "request_irq(): IRQ 0x%x "
					"failed with %d\n", boardp->irq, ret);
		}
		goto err_unmap;
	}

	/*
	 * Initialize board RISC chip and enable interrupts.
	 */
	if (ASC_NARROW_BOARD(boardp)) {
		ASC_DBG(2, "AscInitAsc1000Driver()\n");

		asc_dvc_varp->overrun_buf = kzalloc(ASC_OVERRUN_BSIZE, GFP_KERNEL);
		if (!asc_dvc_varp->overrun_buf) {
			ret = -ENOMEM;
			goto err_free_irq;
		}
		warn_code = AscInitAsc1000Driver(asc_dvc_varp);

		if (warn_code || asc_dvc_varp->err_code) {
			shost_printk(KERN_ERR, shost, "error: init_state 0x%x, "
					"warn 0x%x, error 0x%x\n",
					asc_dvc_varp->init_state, warn_code,
					asc_dvc_varp->err_code);
			if (!asc_dvc_varp->overrun_dma) {
				ret = -ENODEV;
				goto err_free_mem;
			}
		}
	} else {
		if (advansys_wide_init_chip(shost)) {
			ret = -ENODEV;
			goto err_free_mem;
		}
	}

	ASC_DBG_PRT_SCSI_HOST(2, shost);

	ret = scsi_add_host(shost, boardp->dev);
	if (ret)
		goto err_free_mem;

	scsi_scan_host(shost);
	return 0;

 err_free_mem:
	if (ASC_NARROW_BOARD(boardp)) {
		if (asc_dvc_varp->overrun_dma)
			dma_unmap_single(boardp->dev, asc_dvc_varp->overrun_dma,
					 ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE);
		kfree(asc_dvc_varp->overrun_buf);
	} else
		advansys_wide_free_mem(boardp);
 err_free_irq:
	free_irq(boardp->irq, shost);
 err_unmap:
	if (boardp->ioremap_addr)
		iounmap(boardp->ioremap_addr);
#ifdef CONFIG_PCI
 err_shost:
#endif
	return ret;
}