static bool __init blogic_rdconfig()

in BusLogic.c [1232:1685]


static bool __init blogic_rdconfig(struct blogic_adapter *adapter)
{
	struct blogic_board_id id;
	struct blogic_config config;
	struct blogic_setup_info setupinfo;
	struct blogic_ext_setup ext_setupinfo;
	unsigned char model[5];
	unsigned char fw_ver_digit3;
	unsigned char fw_ver_letter;
	struct blogic_adapter_info adapter_info;
	struct blogic_fetch_localram fetch_localram;
	struct blogic_autoscsi autoscsi;
	union blogic_geo_reg georeg;
	unsigned char req_replylen;
	unsigned char *tgt, ch;
	int tgt_id, i;
	/*
	   Configuration Information for FlashPoint Host Adapters is
	   provided in the fpoint_info structure by the FlashPoint
	   SCCB Manager's Probe Function. Initialize fields in the
	   Host Adapter structure from the fpoint_info structure.
	 */
	if (blogic_flashpoint_type(adapter)) {
		struct fpoint_info *fpinfo = &adapter->fpinfo;
		tgt = adapter->model;
		*tgt++ = 'B';
		*tgt++ = 'T';
		*tgt++ = '-';
		for (i = 0; i < sizeof(fpinfo->model); i++)
			*tgt++ = fpinfo->model[i];
		*tgt++ = '\0';
		strcpy(adapter->fw_ver, FLASHPOINT_FW_VER);
		adapter->scsi_id = fpinfo->scsi_id;
		adapter->ext_trans_enable = fpinfo->ext_trans_enable;
		adapter->parity = fpinfo->parity;
		adapter->reset_enabled = !fpinfo->softreset;
		adapter->level_int = true;
		adapter->wide = fpinfo->wide;
		adapter->differential = false;
		adapter->scam = true;
		adapter->ultra = true;
		adapter->ext_lun = true;
		adapter->terminfo_valid = true;
		adapter->low_term = fpinfo->low_term;
		adapter->high_term = fpinfo->high_term;
		adapter->scam_enabled = fpinfo->scam_enabled;
		adapter->scam_lev2 = fpinfo->scam_lev2;
		adapter->drvr_sglimit = BLOGIC_SG_LIMIT;
		adapter->maxdev = (adapter->wide ? 16 : 8);
		adapter->maxlun = 32;
		adapter->initccbs = 4 * BLOGIC_CCB_GRP_ALLOCSIZE;
		adapter->inc_ccbs = BLOGIC_CCB_GRP_ALLOCSIZE;
		adapter->drvr_qdepth = 255;
		adapter->adapter_qdepth = adapter->drvr_qdepth;
		adapter->sync_ok = fpinfo->sync_ok;
		adapter->fast_ok = fpinfo->fast_ok;
		adapter->ultra_ok = fpinfo->ultra_ok;
		adapter->wide_ok = fpinfo->wide_ok;
		adapter->discon_ok = fpinfo->discon_ok;
		adapter->tagq_ok = 0xFFFF;
		goto common;
	}
	/*
	   Issue the Inquire Board ID command.
	 */
	if (blogic_cmd(adapter, BLOGIC_GET_BOARD_ID, NULL, 0, &id,
				sizeof(id)) != sizeof(id))
		return blogic_failure(adapter, "INQUIRE BOARD ID");
	/*
	   Issue the Inquire Configuration command.
	 */
	if (blogic_cmd(adapter, BLOGIC_INQ_CONFIG, NULL, 0, &config,
				sizeof(config))
	    != sizeof(config))
		return blogic_failure(adapter, "INQUIRE CONFIGURATION");
	/*
	   Issue the Inquire Setup Information command.
	 */
	req_replylen = sizeof(setupinfo);
	if (blogic_cmd(adapter, BLOGIC_INQ_SETUPINFO, &req_replylen,
				sizeof(req_replylen), &setupinfo,
				sizeof(setupinfo)) != sizeof(setupinfo))
		return blogic_failure(adapter, "INQUIRE SETUP INFORMATION");
	/*
	   Issue the Inquire Extended Setup Information command.
	 */
	req_replylen = sizeof(ext_setupinfo);
	if (blogic_cmd(adapter, BLOGIC_INQ_EXTSETUP, &req_replylen,
				sizeof(req_replylen), &ext_setupinfo,
				sizeof(ext_setupinfo)) != sizeof(ext_setupinfo))
		return blogic_failure(adapter,
					"INQUIRE EXTENDED SETUP INFORMATION");
	/*
	   Issue the Inquire Firmware Version 3rd Digit command.
	 */
	fw_ver_digit3 = '\0';
	if (id.fw_ver_digit1 > '0')
		if (blogic_cmd(adapter, BLOGIC_INQ_FWVER_D3, NULL, 0,
				&fw_ver_digit3,
				sizeof(fw_ver_digit3)) != sizeof(fw_ver_digit3))
			return blogic_failure(adapter,
						"INQUIRE FIRMWARE 3RD DIGIT");
	/*
	   Issue the Inquire Host Adapter Model Number command.
	 */
	if (ext_setupinfo.bus_type == 'A' && id.fw_ver_digit1 == '2')
		/* BusLogic BT-542B ISA 2.xx */
		strcpy(model, "542B");
	else if (ext_setupinfo.bus_type == 'E' && id.fw_ver_digit1 == '2' &&
			(id.fw_ver_digit2 <= '1' || (id.fw_ver_digit2 == '2' &&
						     fw_ver_digit3 == '0')))
		/* BusLogic BT-742A EISA 2.1x or 2.20 */
		strcpy(model, "742A");
	else if (ext_setupinfo.bus_type == 'E' && id.fw_ver_digit1 == '0')
		/* AMI FastDisk EISA Series 441 0.x */
		strcpy(model, "747A");
	else {
		req_replylen = sizeof(model);
		if (blogic_cmd(adapter, BLOGIC_INQ_MODELNO, &req_replylen,
					sizeof(req_replylen), &model,
					sizeof(model)) != sizeof(model))
			return blogic_failure(adapter,
					"INQUIRE HOST ADAPTER MODEL NUMBER");
	}
	/*
	   BusLogic MultiMaster Host Adapters can be identified by their
	   model number and the major version number of their firmware
	   as follows:

	   5.xx       BusLogic "W" Series Host Adapters:
	   BT-948/958/958D
	   4.xx       BusLogic "C" Series Host Adapters:
	   BT-946C/956C/956CD/747C/757C/757CD/445C/545C/540CF
	   3.xx       BusLogic "S" Series Host Adapters:
	   BT-747S/747D/757S/757D/445S/545S/542D
	   BT-542B/742A (revision H)
	   2.xx       BusLogic "A" Series Host Adapters:
	   BT-542B/742A (revision G and below)
	   0.xx       AMI FastDisk VLB/EISA BusLogic Clone Host Adapter
	 */
	/*
	   Save the Model Name and Host Adapter Name in the Host Adapter
	   structure.
	 */
	tgt = adapter->model;
	*tgt++ = 'B';
	*tgt++ = 'T';
	*tgt++ = '-';
	for (i = 0; i < sizeof(model); i++) {
		ch = model[i];
		if (ch == ' ' || ch == '\0')
			break;
		*tgt++ = ch;
	}
	*tgt++ = '\0';
	/*
	   Save the Firmware Version in the Host Adapter structure.
	 */
	tgt = adapter->fw_ver;
	*tgt++ = id.fw_ver_digit1;
	*tgt++ = '.';
	*tgt++ = id.fw_ver_digit2;
	if (fw_ver_digit3 != ' ' && fw_ver_digit3 != '\0')
		*tgt++ = fw_ver_digit3;
	*tgt = '\0';
	/*
	   Issue the Inquire Firmware Version Letter command.
	 */
	if (strcmp(adapter->fw_ver, "3.3") >= 0) {
		if (blogic_cmd(adapter, BLOGIC_INQ_FWVER_LETTER, NULL, 0,
				&fw_ver_letter,
				sizeof(fw_ver_letter)) != sizeof(fw_ver_letter))
			return blogic_failure(adapter,
					"INQUIRE FIRMWARE VERSION LETTER");
		if (fw_ver_letter != ' ' && fw_ver_letter != '\0')
			*tgt++ = fw_ver_letter;
		*tgt = '\0';
	}
	/*
	   Save the Host Adapter SCSI ID in the Host Adapter structure.
	 */
	adapter->scsi_id = config.id;
	/*
	   Determine the Bus Type and save it in the Host Adapter structure,
	   determine and save the IRQ Channel if necessary, and determine
	   and save the DMA Channel for ISA Host Adapters.
	 */
	adapter->adapter_bus_type =
			blogic_adater_bus_types[adapter->model[3] - '4'];
	if (adapter->irq_ch == 0) {
		if (config.irq_ch9)
			adapter->irq_ch = 9;
		else if (config.irq_ch10)
			adapter->irq_ch = 10;
		else if (config.irq_ch11)
			adapter->irq_ch = 11;
		else if (config.irq_ch12)
			adapter->irq_ch = 12;
		else if (config.irq_ch14)
			adapter->irq_ch = 14;
		else if (config.irq_ch15)
			adapter->irq_ch = 15;
	}
	/*
	   Determine whether Extended Translation is enabled and save it in
	   the Host Adapter structure.
	 */
	georeg.all = blogic_rdgeom(adapter);
	adapter->ext_trans_enable = georeg.gr.ext_trans_enable;
	/*
	   Save the Scatter Gather Limits, Level Sensitive Interrupt flag, Wide
	   SCSI flag, Differential SCSI flag, SCAM Supported flag, and
	   Ultra SCSI flag in the Host Adapter structure.
	 */
	adapter->adapter_sglimit = ext_setupinfo.sg_limit;
	adapter->drvr_sglimit = adapter->adapter_sglimit;
	if (adapter->adapter_sglimit > BLOGIC_SG_LIMIT)
		adapter->drvr_sglimit = BLOGIC_SG_LIMIT;
	if (ext_setupinfo.misc.level_int)
		adapter->level_int = true;
	adapter->wide = ext_setupinfo.wide;
	adapter->differential = ext_setupinfo.differential;
	adapter->scam = ext_setupinfo.scam;
	adapter->ultra = ext_setupinfo.ultra;
	/*
	   Determine whether Extended LUN Format CCBs are supported and save the
	   information in the Host Adapter structure.
	 */
	if (adapter->fw_ver[0] == '5' || (adapter->fw_ver[0] == '4' &&
				adapter->wide))
		adapter->ext_lun = true;
	/*
	   Issue the Inquire PCI Host Adapter Information command to read the
	   Termination Information from "W" series MultiMaster Host Adapters.
	 */
	if (adapter->fw_ver[0] == '5') {
		if (blogic_cmd(adapter, BLOGIC_INQ_PCI_INFO, NULL, 0,
				&adapter_info,
				sizeof(adapter_info)) != sizeof(adapter_info))
			return blogic_failure(adapter,
					"INQUIRE PCI HOST ADAPTER INFORMATION");
		/*
		   Save the Termination Information in the Host Adapter
		   structure.
		 */
		if (adapter_info.genericinfo_valid) {
			adapter->terminfo_valid = true;
			adapter->low_term = adapter_info.low_term;
			adapter->high_term = adapter_info.high_term;
		}
	}
	/*
	   Issue the Fetch Host Adapter Local RAM command to read the
	   AutoSCSI data from "W" and "C" series MultiMaster Host Adapters.
	 */
	if (adapter->fw_ver[0] >= '4') {
		fetch_localram.offset = BLOGIC_AUTOSCSI_BASE;
		fetch_localram.count = sizeof(autoscsi);
		if (blogic_cmd(adapter, BLOGIC_FETCH_LOCALRAM, &fetch_localram,
					sizeof(fetch_localram), &autoscsi,
					sizeof(autoscsi)) != sizeof(autoscsi))
			return blogic_failure(adapter,
						"FETCH HOST ADAPTER LOCAL RAM");
		/*
		   Save the Parity Checking Enabled, Bus Reset Enabled,
		   and Termination Information in the Host Adapter structure.
		 */
		adapter->parity = autoscsi.parity;
		adapter->reset_enabled = autoscsi.reset_enabled;
		if (adapter->fw_ver[0] == '4') {
			adapter->terminfo_valid = true;
			adapter->low_term = autoscsi.low_term;
			adapter->high_term = autoscsi.high_term;
		}
		/*
		   Save the Wide Permitted, Fast Permitted, Synchronous
		   Permitted, Disconnect Permitted, Ultra Permitted, and
		   SCAM Information in the Host Adapter structure.
		 */
		adapter->wide_ok = autoscsi.wide_ok;
		adapter->fast_ok = autoscsi.fast_ok;
		adapter->sync_ok = autoscsi.sync_ok;
		adapter->discon_ok = autoscsi.discon_ok;
		if (adapter->ultra)
			adapter->ultra_ok = autoscsi.ultra_ok;
		if (adapter->scam) {
			adapter->scam_enabled = autoscsi.scam_enabled;
			adapter->scam_lev2 = autoscsi.scam_lev2;
		}
	}
	/*
	   Initialize fields in the Host Adapter structure for "S" and "A"
	   series MultiMaster Host Adapters.
	 */
	if (adapter->fw_ver[0] < '4') {
		if (setupinfo.sync) {
			adapter->sync_ok = 0xFF;
			if (adapter->adapter_bus_type == BLOGIC_EISA_BUS) {
				if (ext_setupinfo.misc.fast_on_eisa)
					adapter->fast_ok = 0xFF;
				if (strcmp(adapter->model, "BT-757") == 0)
					adapter->wide_ok = 0xFF;
			}
		}
		adapter->discon_ok = 0xFF;
		adapter->parity = setupinfo.parity;
		adapter->reset_enabled = true;
	}
	/*
	   Determine the maximum number of Target IDs and Logical Units
	   supported by this driver for Wide and Narrow Host Adapters.
	 */
	adapter->maxdev = (adapter->wide ? 16 : 8);
	adapter->maxlun = (adapter->ext_lun ? 32 : 8);
	/*
	   Select appropriate values for the Mailbox Count, Driver Queue Depth,
	   Initial CCBs, and Incremental CCBs variables based on whether
	   or not Strict Round Robin Mode is supported.  If Strict Round
	   Robin Mode is supported, then there is no performance degradation
	   in using the maximum possible number of Outgoing and Incoming
	   Mailboxes and allowing the Tagged and Untagged Queue Depths to
	   determine the actual utilization.  If Strict Round Robin Mode is
	   not supported, then the Host Adapter must scan all the Outgoing
	   Mailboxes whenever an Outgoing Mailbox entry is made, which can
	   cause a substantial performance penalty.  The host adapters
	   actually have room to store the following number of CCBs
	   internally; that is, they can internally queue and manage this
	   many active commands on the SCSI bus simultaneously.  Performance
	   measurements demonstrate that the Driver Queue Depth should be
	   set to the Mailbox Count, rather than the Host Adapter Queue
	   Depth (internal CCB capacity), as it is more efficient to have the
	   queued commands waiting in Outgoing Mailboxes if necessary than
	   to block the process in the higher levels of the SCSI Subsystem.

	   192          BT-948/958/958D
	   100          BT-946C/956C/956CD/747C/757C/757CD/445C
	   50   BT-545C/540CF
	   30   BT-747S/747D/757S/757D/445S/545S/542D/542B/742A
	 */
	if (adapter->fw_ver[0] == '5')
		adapter->adapter_qdepth = 192;
	else if (adapter->fw_ver[0] == '4')
		adapter->adapter_qdepth = 100;
	else
		adapter->adapter_qdepth = 30;
	if (strcmp(adapter->fw_ver, "3.31") >= 0) {
		adapter->strict_rr = true;
		adapter->mbox_count = BLOGIC_MAX_MAILBOX;
	} else {
		adapter->strict_rr = false;
		adapter->mbox_count = 32;
	}
	adapter->drvr_qdepth = adapter->mbox_count;
	adapter->initccbs = 4 * BLOGIC_CCB_GRP_ALLOCSIZE;
	adapter->inc_ccbs = BLOGIC_CCB_GRP_ALLOCSIZE;
	/*
	   Tagged Queuing support is available and operates properly on
	   all "W" series MultiMaster Host Adapters, on "C" series
	   MultiMaster Host Adapters with firmware version 4.22 and above,
	   and on "S" series MultiMaster Host Adapters with firmware version
	   3.35 and above.
	 */
	adapter->tagq_ok = 0;
	switch (adapter->fw_ver[0]) {
	case '5':
		adapter->tagq_ok = 0xFFFF;
		break;
	case '4':
		if (strcmp(adapter->fw_ver, "4.22") >= 0)
			adapter->tagq_ok = 0xFFFF;
		break;
	case '3':
		if (strcmp(adapter->fw_ver, "3.35") >= 0)
			adapter->tagq_ok = 0xFFFF;
		break;
	}
	/*
	   Determine the Host Adapter BIOS Address if the BIOS is enabled and
	   save it in the Host Adapter structure.  The BIOS is disabled if the
	   bios_addr is 0.
	 */
	adapter->bios_addr = ext_setupinfo.bios_addr << 12;
	/*
	   BusLogic BT-445S Host Adapters prior to board revision E have a
	   hardware bug whereby when the BIOS is enabled, transfers to/from
	   the same address range the BIOS occupies modulo 16MB are handled
	   incorrectly.  Only properly functioning BT-445S Host Adapters
	   have firmware version 3.37.
	 */
	if (adapter->bios_addr > 0 &&
	    strcmp(adapter->model, "BT-445S") == 0 &&
	    strcmp(adapter->fw_ver, "3.37") < 0)
		return blogic_failure(adapter, "Too old firmware");
	/*
	   Initialize parameters common to MultiMaster and FlashPoint
	   Host Adapters.
	 */
common:
	/*
	   Initialize the Host Adapter Full Model Name from the Model Name.
	 */
	strcpy(adapter->full_model, "BusLogic ");
	strcat(adapter->full_model, adapter->model);
	/*
	   Select an appropriate value for the Tagged Queue Depth either from a
	   BusLogic Driver Options specification, or based on whether this Host
	   Adapter requires that ISA Bounce Buffers be used.  The Tagged Queue
	   Depth is left at 0 for automatic determination in
	   BusLogic_SelectQueueDepths. Initialize the Untagged Queue Depth.
	 */
	for (tgt_id = 0; tgt_id < BLOGIC_MAXDEV; tgt_id++) {
		unsigned char qdepth = 0;
		if (adapter->drvr_opts != NULL &&
				adapter->drvr_opts->qdepth[tgt_id] > 0)
			qdepth = adapter->drvr_opts->qdepth[tgt_id];
		adapter->qdepth[tgt_id] = qdepth;
	}
	adapter->untag_qdepth = BLOGIC_UNTAG_DEPTH;
	if (adapter->drvr_opts != NULL)
		adapter->common_qdepth = adapter->drvr_opts->common_qdepth;
	if (adapter->common_qdepth > 0 &&
			adapter->common_qdepth < adapter->untag_qdepth)
		adapter->untag_qdepth = adapter->common_qdepth;
	/*
	   Tagged Queuing is only allowed if Disconnect/Reconnect is permitted.
	   Therefore, mask the Tagged Queuing Permitted Default bits with the
	   Disconnect/Reconnect Permitted bits.
	 */
	adapter->tagq_ok &= adapter->discon_ok;
	/*
	   Combine the default Tagged Queuing Permitted bits with any
	   BusLogic Driver Options Tagged Queuing specification.
	 */
	if (adapter->drvr_opts != NULL)
		adapter->tagq_ok = (adapter->drvr_opts->tagq_ok &
				adapter->drvr_opts->tagq_ok_mask) |
			(adapter->tagq_ok & ~adapter->drvr_opts->tagq_ok_mask);

	/*
	   Select an appropriate value for Bus Settle Time either from a
	   BusLogic Driver Options specification, or from
	   BLOGIC_BUS_SETTLE_TIME.
	 */
	if (adapter->drvr_opts != NULL &&
			adapter->drvr_opts->bus_settle_time > 0)
		adapter->bus_settle_time = adapter->drvr_opts->bus_settle_time;
	else
		adapter->bus_settle_time = BLOGIC_BUS_SETTLE_TIME;
	/*
	   Indicate reading the Host Adapter Configuration completed
	   successfully.
	 */
	return true;
}