drivers/scsi/qla4xxx/ql4_83xx.c

Source file repositories/reference/linux-study-clean/drivers/scsi/qla4xxx/ql4_83xx.c

File Facts

System
Linux kernel
Corpus path
drivers/scsi/qla4xxx/ql4_83xx.c
Extension
.c
Size
44290 bytes
Lines
1585
Domain
Driver Families
Bucket
drivers/scsi
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct device_info {
	int func_num;
	int device_type;
	int port_num;
};

int qla4_83xx_can_perform_reset(struct scsi_qla_host *ha)
{
	uint32_t drv_active;
	uint32_t dev_part, dev_part1, dev_part2;
	int i;
	struct device_info device_map[16];
	int func_nibble;
	int nibble;
	int nic_present = 0;
	int iscsi_present = 0;
	int iscsi_func_low = 0;

	/* Use the dev_partition register to determine the PCI function number
	 * and then check drv_active register to see which driver is loaded */
	dev_part1 = qla4_83xx_rd_reg(ha,
				     ha->reg_tbl[QLA8XXX_CRB_DEV_PART_INFO]);
	dev_part2 = qla4_83xx_rd_reg(ha, QLA83XX_CRB_DEV_PART_INFO2);
	drv_active = qla4_83xx_rd_reg(ha, ha->reg_tbl[QLA8XXX_CRB_DRV_ACTIVE]);

	/* Each function has 4 bits in dev_partition Info register,
	 * Lower 2 bits - device type, Upper 2 bits - physical port number */
	dev_part = dev_part1;
	for (i = nibble = 0; i <= 15; i++, nibble++) {
		func_nibble = dev_part & (0xF << (nibble * 4));
		func_nibble >>= (nibble * 4);
		device_map[i].func_num = i;
		device_map[i].device_type = func_nibble & 0x3;
		device_map[i].port_num = func_nibble & 0xC;

		if (device_map[i].device_type == NIC_CLASS) {
			if (drv_active & (1 << device_map[i].func_num)) {
				nic_present++;
				break;
			}
		} else if (device_map[i].device_type == ISCSI_CLASS) {
			if (drv_active & (1 << device_map[i].func_num)) {
				if (!iscsi_present ||
				iscsi_func_low > device_map[i].func_num)
					iscsi_func_low = device_map[i].func_num;

				iscsi_present++;
			}
		}

		/* For function_num[8..15] get info from dev_part2 register */
		if (nibble == 7) {
			nibble = 0;
			dev_part = dev_part2;
		}
	}

	/* NIC, iSCSI and FCOE are the Reset owners based on order, NIC gets
	 * precedence over iSCSI and FCOE and iSCSI over FCOE, based on drivers
	 * present. */
	if (!nic_present && (ha->func_num == iscsi_func_low)) {
		DEBUG2(ql4_printk(KERN_INFO, ha,
				  "%s: can reset - NIC not present and lower iSCSI function is %d\n",
				  __func__, ha->func_num));
		return 1;
	}

	return 0;
}

/**
 * qla4_83xx_need_reset_handler - Code to start reset sequence
 * @ha: pointer to adapter structure
 *
 * Note: IDC lock must be held upon entry
 **/
void qla4_83xx_need_reset_handler(struct scsi_qla_host *ha)
{
	uint32_t dev_state, drv_state, drv_active;
	unsigned long reset_timeout, dev_init_timeout;

	ql4_printk(KERN_INFO, ha, "%s: Performing ISP error recovery\n",
		   __func__);

	if (!test_bit(AF_8XXX_RST_OWNER, &ha->flags)) {
		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: reset acknowledged\n",
				  __func__));
		qla4_8xxx_set_rst_ready(ha);

		/* Non-reset owners ACK Reset and wait for device INIT state

Annotation

Implementation Notes