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 + -
显示快捷键?