ipr.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,336 行 · 第 1/5 页

C
2,336
字号
	ipr_cmd = list_entry(ioa_cfg->free_q.next, struct ipr_cmnd, queue);	list_del(&ipr_cmd->queue);	ipr_init_ipr_cmnd(ipr_cmd);	return ipr_cmd;}/** * ipr_unmap_sglist - Unmap scatterlist if mapped * @ioa_cfg:	ioa config struct * @ipr_cmd:	ipr command struct * * Return value: * 	nothing **/static void ipr_unmap_sglist(struct ipr_ioa_cfg *ioa_cfg,			     struct ipr_cmnd *ipr_cmd){	struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;	if (ipr_cmd->dma_use_sg) {		if (scsi_cmd->use_sg > 0) {			pci_unmap_sg(ioa_cfg->pdev, scsi_cmd->request_buffer,				     scsi_cmd->use_sg,				     scsi_cmd->sc_data_direction);		} else {			pci_unmap_single(ioa_cfg->pdev, ipr_cmd->dma_handle,					 scsi_cmd->request_bufflen,					 scsi_cmd->sc_data_direction);		}	}}/** * ipr_mask_and_clear_interrupts - Mask all and clear specified interrupts * @ioa_cfg:	ioa config struct * @clr_ints:     interrupts to clear * * This function masks all interrupts on the adapter, then clears the * interrupts specified in the mask * * Return value: * 	none **/static void ipr_mask_and_clear_interrupts(struct ipr_ioa_cfg *ioa_cfg,					  u32 clr_ints){	volatile u32 int_reg;	/* Stop new interrupts */	ioa_cfg->allow_interrupts = 0;	/* Set interrupt mask to stop all new interrupts */	writel(~0, ioa_cfg->regs.set_interrupt_mask_reg);	/* Clear any pending interrupts */	writel(clr_ints, ioa_cfg->regs.clr_interrupt_reg);	int_reg = readl(ioa_cfg->regs.sense_interrupt_reg);}/** * ipr_save_pcix_cmd_reg - Save PCI-X command register * @ioa_cfg:	ioa config struct * * Return value: * 	0 on success / -EIO on failure **/static int ipr_save_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg){	int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX);	if (pcix_cmd_reg == 0) {		dev_err(&ioa_cfg->pdev->dev, "Failed to save PCI-X command register\n");		return -EIO;	}	if (pci_read_config_word(ioa_cfg->pdev, pcix_cmd_reg,				 &ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) {		dev_err(&ioa_cfg->pdev->dev, "Failed to save PCI-X command register\n");		return -EIO;	}	ioa_cfg->saved_pcix_cmd_reg |= PCI_X_CMD_DPERR_E | PCI_X_CMD_ERO;	return 0;}/** * ipr_set_pcix_cmd_reg - Setup PCI-X command register * @ioa_cfg:	ioa config struct * * Return value: * 	0 on success / -EIO on failure **/static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg){	int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX);	if (pcix_cmd_reg) {		if (pci_write_config_word(ioa_cfg->pdev, pcix_cmd_reg,					  ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) {			dev_err(&ioa_cfg->pdev->dev, "Failed to setup PCI-X command register\n");			return -EIO;		}	} else {		dev_err(&ioa_cfg->pdev->dev,			"Failed to setup PCI-X command register\n");		return -EIO;	}	return 0;}/** * ipr_scsi_eh_done - mid-layer done function for aborted ops * @ipr_cmd:	ipr command struct * * This function is invoked by the interrupt handler for * ops generated by the SCSI mid-layer which are being aborted. * * Return value: * 	none **/static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd){	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;	struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;	scsi_cmd->result |= (DID_ERROR << 16);	ipr_unmap_sglist(ioa_cfg, ipr_cmd);	scsi_cmd->scsi_done(scsi_cmd);	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);}/** * ipr_fail_all_ops - Fails all outstanding ops. * @ioa_cfg:	ioa config struct * * This function fails all outstanding ops. * * Return value: * 	none **/static void ipr_fail_all_ops(struct ipr_ioa_cfg *ioa_cfg){	struct ipr_cmnd *ipr_cmd, *temp;	ENTER;	list_for_each_entry_safe(ipr_cmd, temp, &ioa_cfg->pending_q, queue) {		list_del(&ipr_cmd->queue);		ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_IOA_WAS_RESET);		ipr_cmd->ioasa.ilid = cpu_to_be32(IPR_DRIVER_ILID);		if (ipr_cmd->scsi_cmd)			ipr_cmd->done = ipr_scsi_eh_done;		ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, IPR_IOASC_IOA_WAS_RESET);		del_timer(&ipr_cmd->timer);		ipr_cmd->done(ipr_cmd);	}	LEAVE;}/** * ipr_do_req -  Send driver initiated requests. * @ipr_cmd:		ipr command struct * @done:			done function * @timeout_func:	timeout function * @timeout:		timeout value * * This function sends the specified command to the adapter with the * timeout given. The done function is invoked on command completion. * * Return value: * 	none **/static void ipr_do_req(struct ipr_cmnd *ipr_cmd,		       void (*done) (struct ipr_cmnd *),		       void (*timeout_func) (struct ipr_cmnd *), u32 timeout){	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;	list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);	ipr_cmd->done = done;	ipr_cmd->timer.data = (unsigned long) ipr_cmd;	ipr_cmd->timer.expires = jiffies + timeout;	ipr_cmd->timer.function = (void (*)(unsigned long))timeout_func;	add_timer(&ipr_cmd->timer);	ipr_trc_hook(ipr_cmd, IPR_TRACE_START, 0);	mb();	writel(be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr),	       ioa_cfg->regs.ioarrin_reg);}/** * ipr_internal_cmd_done - Op done function for an internally generated op. * @ipr_cmd:	ipr command struct * * This function is the op done function for an internally generated, * blocking op. It simply wakes the sleeping thread. * * Return value: * 	none **/static void ipr_internal_cmd_done(struct ipr_cmnd *ipr_cmd){	if (ipr_cmd->sibling)		ipr_cmd->sibling = NULL;	else		complete(&ipr_cmd->completion);}/** * ipr_send_blocking_cmd - Send command and sleep on its completion. * @ipr_cmd:	ipr command struct * @timeout_func:	function to invoke if command times out * @timeout:	timeout * * Return value: * 	none **/static void ipr_send_blocking_cmd(struct ipr_cmnd *ipr_cmd,				  void (*timeout_func) (struct ipr_cmnd *ipr_cmd),				  u32 timeout){	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;	init_completion(&ipr_cmd->completion);	ipr_do_req(ipr_cmd, ipr_internal_cmd_done, timeout_func, timeout);	spin_unlock_irq(ioa_cfg->host->host_lock);	wait_for_completion(&ipr_cmd->completion);	spin_lock_irq(ioa_cfg->host->host_lock);}/** * ipr_send_hcam - Send an HCAM to the adapter. * @ioa_cfg:	ioa config struct * @type:		HCAM type * @hostrcb:	hostrcb struct * * This function will send a Host Controlled Async command to the adapter. * If HCAMs are currently not allowed to be issued to the adapter, it will * place the hostrcb on the free queue. * * Return value: * 	none **/static void ipr_send_hcam(struct ipr_ioa_cfg *ioa_cfg, u8 type,			  struct ipr_hostrcb *hostrcb){	struct ipr_cmnd *ipr_cmd;	struct ipr_ioarcb *ioarcb;	if (ioa_cfg->allow_cmds) {		ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);		list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);		list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_pending_q);		ipr_cmd->u.hostrcb = hostrcb;		ioarcb = &ipr_cmd->ioarcb;		ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);		ioarcb->cmd_pkt.request_type = IPR_RQTYPE_HCAM;		ioarcb->cmd_pkt.cdb[0] = IPR_HOST_CONTROLLED_ASYNC;		ioarcb->cmd_pkt.cdb[1] = type;		ioarcb->cmd_pkt.cdb[7] = (sizeof(hostrcb->hcam) >> 8) & 0xff;		ioarcb->cmd_pkt.cdb[8] = sizeof(hostrcb->hcam) & 0xff;		ioarcb->read_data_transfer_length = cpu_to_be32(sizeof(hostrcb->hcam));		ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));		ipr_cmd->ioadl[0].flags_and_data_len =			cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | sizeof(hostrcb->hcam));		ipr_cmd->ioadl[0].address = cpu_to_be32(hostrcb->hostrcb_dma);		if (type == IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE)			ipr_cmd->done = ipr_process_ccn;		else			ipr_cmd->done = ipr_process_error;		ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_IOA_RES_ADDR);		mb();		writel(be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr),		       ioa_cfg->regs.ioarrin_reg);	} else {		list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q);	}}/** * ipr_init_res_entry - Initialize a resource entry struct. * @res:	resource entry struct * * Return value: * 	none **/static void ipr_init_res_entry(struct ipr_resource_entry *res){	res->needs_sync_complete = 1;	res->in_erp = 0;	res->add_to_ml = 0;	res->del_from_ml = 0;	res->resetting_device = 0;	res->tcq_active = 0;	res->qdepth = IPR_MAX_CMD_PER_LUN;	res->sdev = NULL;}/** * ipr_handle_config_change - Handle a config change from the adapter * @ioa_cfg:	ioa config struct * @hostrcb:	hostrcb * * Return value: * 	none **/static void ipr_handle_config_change(struct ipr_ioa_cfg *ioa_cfg,			      struct ipr_hostrcb *hostrcb){	struct ipr_resource_entry *res = NULL;	struct ipr_config_table_entry *cfgte;	u32 is_ndn = 1;	cfgte = &hostrcb->hcam.u.ccn.cfgte;	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {		if (!memcmp(&res->cfgte.res_addr, &cfgte->res_addr,			    sizeof(cfgte->res_addr))) {			is_ndn = 0;			break;		}	}	if (is_ndn) {		if (list_empty(&ioa_cfg->free_res_q)) {			ipr_send_hcam(ioa_cfg,				      IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE,				      hostrcb);			return;		}		res = list_entry(ioa_cfg->free_res_q.next,				 struct ipr_resource_entry, queue);		list_del(&res->queue);		ipr_init_res_entry(res);		list_add_tail(&res->queue, &ioa_cfg->used_res_q);	}	memcpy(&res->cfgte, cfgte, sizeof(struct ipr_config_table_entry));	if (hostrcb->hcam.notify_type == IPR_HOST_RCB_NOTIF_TYPE_REM_ENTRY) {		if (res->sdev) {			res->sdev->hostdata = NULL;			res->del_from_ml = 1;			if (ioa_cfg->allow_ml_add_del)				schedule_work(&ioa_cfg->work_q);		} else			list_move_tail(&res->queue, &ioa_cfg->free_res_q);	} else if (!res->sdev) {		res->add_to_ml = 1;		if (ioa_cfg->allow_ml_add_del)			schedule_work(&ioa_cfg->work_q);	}	ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb);}/** * ipr_process_ccn - Op done function for a CCN. * @ipr_cmd:	ipr command struct * * This function is the op done function for a configuration * change notification host controlled async from the adapter. * * Return value: * 	none **/static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd){	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;	struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;	u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);	list_del(&hostrcb->queue);	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);	if (ioasc) {		if (ioasc != IPR_IOASC_IOA_WAS_RESET)			dev_err(&ioa_cfg->pdev->dev,				"Host RCB failed with IOASC: 0x%08X\n", ioasc);		ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb);	} else {		ipr_handle_config_change(ioa_cfg, hostrcb);	}}/** * ipr_log_vpd - Log the passed VPD to the error log. * @vpids:			vendor/product id struct * @serial_num:		serial number string * * Return value: * 	none **/static void ipr_log_vpd(struct ipr_std_inq_vpids *vpids, u8 *serial_num){	char buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN		    + IPR_SERIAL_NUM_LEN];	memcpy(buffer, vpids->vendor_id, IPR_VENDOR_ID_LEN);	memcpy(buffer + IPR_VENDOR_ID_LEN, vpids->product_id,	       IPR_PROD_ID_LEN);	buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN] = '\0';	ipr_err("Vendor/Product ID: %s\n", buffer);	memcpy(buffer, serial_num, IPR_SERIAL_NUM_LEN);	buffer[IPR_SERIAL_NUM_LEN] = '\0';	ipr_err("    Serial Number: %s\n", buffer);}/** * ipr_log_cache_error - Log a cache error. * @ioa_cfg:	ioa config struct * @hostrcb:	hostrcb struct * * Return value: * 	none **/static void ipr_log_cache_error(struct ipr_ioa_cfg *ioa_cfg,				struct ipr_hostrcb *hostrcb){	struct ipr_hostrcb_type_02_error *error =		&hostrcb->hcam.u.error.u.type_02_error;	ipr_err("-----Current Configuration-----\n");	ipr_err("Cache Directory Card Information:\n");	ipr_log_vpd(&error->ioa_vpids, error->ioa_sn);	ipr_err("Adapter Card Information:\n");	ipr_log_vpd(&error->cfc_vpids, error->cfc_sn);	ipr_err("-----Expected Configuration-----\n");	ipr_err("Cache Directory Card Information:\n");	ipr_log_vpd(&error->ioa_last_attached_to_cfc_vpids,		    error->ioa_last_attached_to_cfc_sn);	ipr_err("Adapter Card Information:\n");	ipr_log_vpd(&error->cfc_last_attached_to_ioa_vpids,		    error->cfc_last_attached_to_ioa_sn);	ipr_err("Additional IOA Data: %08X %08X %08X\n",		     be32_to_cpu(error->ioa_data[0]),		     be32_to_cpu(error->ioa_data[1]),		     be32_to_cpu(error->ioa_data[2]));}/** * ipr_log_config_error - Log a configuration error. * @ioa_cfg:	ioa config struct * @hostrcb:	hostrcb struct

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?