ipr.c

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

C
2,336
字号
			spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);			goto restart;		}	}	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);	LEAVE;}#ifdef CONFIG_SCSI_IPR_TRACE/** * ipr_read_trace - Dump the adapter trace * @kobj:		kobject struct * @buf:		buffer * @off:		offset * @count:		buffer size * * Return value: *	number of bytes printed to buffer **/static ssize_t ipr_read_trace(struct kobject *kobj, char *buf,			      loff_t off, size_t count){	struct class_device *cdev = container_of(kobj,struct class_device,kobj);	struct Scsi_Host *shost = class_to_shost(cdev);	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;	unsigned long lock_flags = 0;	int size = IPR_TRACE_SIZE;	char *src = (char *)ioa_cfg->trace;	if (off > size)		return 0;	if (off + count > size) {		size -= off;		count = size;	}	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);	memcpy(buf, &src[off], count);	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);	return count;}static struct bin_attribute ipr_trace_attr = {	.attr =	{		.name = "trace",		.mode = S_IRUGO,	},	.size = 0,	.read = ipr_read_trace,};#endif/** * ipr_show_fw_version - Show the firmware version * @class_dev:	class device struct * @buf:		buffer * * Return value: *	number of bytes printed to buffer **/static ssize_t ipr_show_fw_version(struct class_device *class_dev, char *buf){	struct Scsi_Host *shost = class_to_shost(class_dev);	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;	struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data;	unsigned long lock_flags = 0;	int len;	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);	len = snprintf(buf, PAGE_SIZE, "%02X%02X%02X%02X\n",		       ucode_vpd->major_release, ucode_vpd->card_type,		       ucode_vpd->minor_release[0],		       ucode_vpd->minor_release[1]);	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);	return len;}static struct class_device_attribute ipr_fw_version_attr = {	.attr = {		.name =		"fw_version",		.mode =		S_IRUGO,	},	.show = ipr_show_fw_version,};/** * ipr_show_log_level - Show the adapter's error logging level * @class_dev:	class device struct * @buf:		buffer * * Return value: * 	number of bytes printed to buffer **/static ssize_t ipr_show_log_level(struct class_device *class_dev, char *buf){	struct Scsi_Host *shost = class_to_shost(class_dev);	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;	unsigned long lock_flags = 0;	int len;	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);	len = snprintf(buf, PAGE_SIZE, "%d\n", ioa_cfg->log_level);	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);	return len;}/** * ipr_store_log_level - Change the adapter's error logging level * @class_dev:	class device struct * @buf:		buffer * * Return value: * 	number of bytes printed to buffer **/static ssize_t ipr_store_log_level(struct class_device *class_dev,				   const char *buf, size_t count){	struct Scsi_Host *shost = class_to_shost(class_dev);	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;	unsigned long lock_flags = 0;	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);	ioa_cfg->log_level = simple_strtoul(buf, NULL, 10);	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);	return strlen(buf);}static struct class_device_attribute ipr_log_level_attr = {	.attr = {		.name =		"log_level",		.mode =		S_IRUGO | S_IWUSR,	},	.show = ipr_show_log_level,	.store = ipr_store_log_level};/** * ipr_store_diagnostics - IOA Diagnostics interface * @class_dev:	class_device struct * @buf:		buffer * @count:		buffer size * * This function will reset the adapter and wait a reasonable * amount of time for any errors that the adapter might log. * * Return value: * 	count on success / other on failure **/static ssize_t ipr_store_diagnostics(struct class_device *class_dev,				     const char *buf, size_t count){	struct Scsi_Host *shost = class_to_shost(class_dev);	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;	unsigned long lock_flags = 0;	int rc = count;	if (!capable(CAP_SYS_ADMIN))		return -EACCES;	wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);	ioa_cfg->errors_logged = 0;	ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL);	if (ioa_cfg->in_reset_reload) {		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);		wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);		/* Wait for a second for any errors to be logged */		msleep(1000);	} else {		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);		return -EIO;	}	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);	if (ioa_cfg->in_reset_reload || ioa_cfg->errors_logged)		rc = -EIO;	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);	return rc;}static struct class_device_attribute ipr_diagnostics_attr = {	.attr = {		.name =		"run_diagnostics",		.mode =		S_IWUSR,	},	.store = ipr_store_diagnostics};/** * ipr_store_reset_adapter - Reset the adapter * @class_dev:	class_device struct * @buf:		buffer * @count:		buffer size * * This function will reset the adapter. * * Return value: * 	count on success / other on failure **/static ssize_t ipr_store_reset_adapter(struct class_device *class_dev,				       const char *buf, size_t count){	struct Scsi_Host *shost = class_to_shost(class_dev);	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;	unsigned long lock_flags;	int result = count;	if (!capable(CAP_SYS_ADMIN))		return -EACCES;	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);	if (!ioa_cfg->in_reset_reload)		ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL);	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);	wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);	return result;}static struct class_device_attribute ipr_ioa_reset_attr = {	.attr = {		.name =		"reset_host",		.mode =		S_IWUSR,	},	.store = ipr_store_reset_adapter};/** * ipr_alloc_ucode_buffer - Allocates a microcode download buffer * @buf_len:		buffer length * * Allocates a DMA'able buffer in chunks and assembles a scatter/gather * list to use for microcode download * * Return value: * 	pointer to sglist / NULL on failure **/static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len){	int sg_size, order, bsize_elem, num_elem, i, j;	struct ipr_sglist *sglist;	struct scatterlist *scatterlist;	struct page *page;	/* Get the minimum size per scatter/gather element */	sg_size = buf_len / (IPR_MAX_SGLIST - 1);	/* Get the actual size per element */	order = get_order(sg_size);	/* Determine the actual number of bytes per element */	bsize_elem = PAGE_SIZE * (1 << order);	/* Determine the actual number of sg entries needed */	if (buf_len % bsize_elem)		num_elem = (buf_len / bsize_elem) + 1;	else		num_elem = buf_len / bsize_elem;	/* Allocate a scatter/gather list for the DMA */	sglist = kmalloc(sizeof(struct ipr_sglist) +			 (sizeof(struct scatterlist) * (num_elem - 1)),			 GFP_KERNEL);	if (sglist == NULL) {		ipr_trace;		return NULL;	}	memset(sglist, 0, sizeof(struct ipr_sglist) +	       (sizeof(struct scatterlist) * (num_elem - 1)));	scatterlist = sglist->scatterlist;	sglist->order = order;	sglist->num_sg = num_elem;	/* Allocate a bunch of sg elements */	for (i = 0; i < num_elem; i++) {		page = alloc_pages(GFP_KERNEL, order);		if (!page) {			ipr_trace;			/* Free up what we already allocated */			for (j = i - 1; j >= 0; j--)				__free_pages(scatterlist[j].page, order);			kfree(sglist);			return NULL;		}		scatterlist[i].page = page;	}	return sglist;}/** * ipr_free_ucode_buffer - Frees a microcode download buffer * @p_dnld:		scatter/gather list pointer * * Free a DMA'able ucode download buffer previously allocated with * ipr_alloc_ucode_buffer * * Return value: * 	nothing **/static void ipr_free_ucode_buffer(struct ipr_sglist *sglist){	int i;	for (i = 0; i < sglist->num_sg; i++)		__free_pages(sglist->scatterlist[i].page, sglist->order);	kfree(sglist);}/** * ipr_copy_ucode_buffer - Copy user buffer to kernel buffer * @sglist:		scatter/gather list pointer * @buffer:		buffer pointer * @len:		buffer length * * Copy a microcode image from a user buffer into a buffer allocated by * ipr_alloc_ucode_buffer * * Return value: * 	0 on success / other on failure **/static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist,				 u8 *buffer, u32 len){	int bsize_elem, i, result = 0;	struct scatterlist *scatterlist;	void *kaddr;	/* Determine the actual number of bytes per element */	bsize_elem = PAGE_SIZE * (1 << sglist->order);	scatterlist = sglist->scatterlist;	for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) {		kaddr = kmap(scatterlist[i].page);		memcpy(kaddr, buffer, bsize_elem);		kunmap(scatterlist[i].page);		scatterlist[i].length = bsize_elem;		if (result != 0) {			ipr_trace;			return result;		}	}	if (len % bsize_elem) {		kaddr = kmap(scatterlist[i].page);		memcpy(kaddr, buffer, len % bsize_elem);		kunmap(scatterlist[i].page);		scatterlist[i].length = len % bsize_elem;	}	sglist->buffer_len = len;	return result;}/** * ipr_map_ucode_buffer - Map a microcode download buffer * @ipr_cmd:	ipr command struct * @sglist:		scatter/gather list * @len:		total length of download buffer * * Maps a microcode download scatter/gather list for DMA and * builds the IOADL. * * Return value: * 	0 on success / -EIO on failure **/static int ipr_map_ucode_buffer(struct ipr_cmnd *ipr_cmd,				struct ipr_sglist *sglist, int len){	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;	struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;	struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;	struct scatterlist *scatterlist = sglist->scatterlist;	int i;	ipr_cmd->dma_use_sg = pci_map_sg(ioa_cfg->pdev, scatterlist,					 sglist->num_sg, DMA_TO_DEVICE);	ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;	ioarcb->write_data_transfer_length = cpu_to_be32(len);	ioarcb->write_ioadl_len =		cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);	for (i = 0; i < ipr_cmd->dma_use_sg; i++) {		ioadl[i].flags_and_data_len =			cpu_to_be32(IPR_IOADL_FLAGS_WRITE | sg_dma_len(&scatterlist[i]));		ioadl[i].address =			cpu_to_be32(sg_dma_address(&scatterlist[i]));	}	if (likely(ipr_cmd->dma_use_sg)) {		ioadl[i-1].flags_and_data_len |=			cpu_to_be32(IPR_IOADL_FLAGS_LAST);	}	else {		dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n");		return -EIO;	}	return 0;}/** * ipr_store_update_fw - Update the firmware on the adapter * @class_dev:	class_device struct * @buf:		buffer * @count:		buffer size * * This function will update the firmware on the adapter. * * Return value: * 	count on success / other on failure **/static ssize_t ipr_store_update_fw(struct class_device *class_dev,				       const char *buf, size_t count){	struct Scsi_Host *shost = class_to_shost(class_dev);	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;	struct ipr_ucode_image_header *image_hdr;	const struct firmware *fw_entry;	struct ipr_sglist *sglist;	unsigned long lock_flags;	char fname[100];	char *src;	int len, result, dnld_size;	if (!capable(CAP_SYS_ADMIN))		return -EACCES;	len = snprintf(fname, 99, "%s", buf);	fname[len-1] = '\0';	if(request_firmware(&fw_entry, fname, &ioa_cfg->pdev->dev)) {		dev_err(&ioa_cfg->pdev->dev, "Firmware file %s not found\n", fname);		return -EIO;	}	image_hdr = (struct ipr_ucode_image_header *)fw_entry->data;	if (be32_to_cpu(image_hdr->header_length) > fw_entry->size ||	    (ioa_cfg->vpd_cbs->page3_data.card_type &&	     ioa_cfg->vpd_cbs->page3_data.card_type != image_hdr->card_type)) {		dev_err(&ioa_cfg->pdev->dev, "Invalid microcode buffer\n");		release_firmware(fw_entry);		return -EINVAL;	}	src = (u8 *)image_hdr + be32_to_cpu(image_hdr->header_length);	dnld_size = fw_entry->size - be32_to_cpu(image_hdr->header_le

⌨️ 快捷键说明

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