int ps3_alloc_vuart_irq(void* virt_addr_bmp, unsigned int *virq) { int result; unsigned long outlet; unsigned long lpar_addr; BUG_ON(!is_kernel_addr((unsigned long)virt_addr_bmp)); lpar_addr = ps3_mm_phys_to_lpar(__pa(virt_addr_bmp)); result = lv1_configure_virtual_uart_irq(lpar_addr, &outlet); if (result) { pr_debug("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n", __func__, __LINE__, ps3_result(result)); return result; } *virq = irq_create_mapping(NULL, outlet); pr_debug("%s:%d: outlet %lu, virq %u\n", __func__, __LINE__, outlet, *virq); return 0; }
static long ps3_hpte_insert(unsigned long hpte_group, unsigned long vpn, unsigned long pa, unsigned long rflags, unsigned long vflags, int psize, int apsize, int ssize) { int result; u64 hpte_v, hpte_r; u64 inserted_index; u64 evicted_v, evicted_r; u64 hpte_v_array[4], hpte_rs; unsigned long flags; long ret = -1; /* * lv1_insert_htab_entry() will search for victim * entry in both primary and secondary pte group */ vflags &= ~HPTE_V_SECONDARY; hpte_v = hpte_encode_v(vpn, psize, apsize, ssize) | vflags | HPTE_V_VALID; hpte_r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize, apsize) | rflags; spin_lock_irqsave(&ps3_htab_lock, flags); /* talk hvc to replace entries BOLTED == 0 */ result = lv1_insert_htab_entry(PS3_LPAR_VAS_ID_CURRENT, hpte_group, hpte_v, hpte_r, HPTE_V_BOLTED, 0, &inserted_index, &evicted_v, &evicted_r); if (result) { /* all entries bolted !*/ pr_info("%s:result=%s vpn=%lx pa=%lx ix=%lx v=%llx r=%llx\n", __func__, ps3_result(result), vpn, pa, hpte_group, hpte_v, hpte_r); BUG(); } /* * see if the entry is inserted into secondary pteg */ result = lv1_read_htab_entries(PS3_LPAR_VAS_ID_CURRENT, inserted_index & ~0x3UL, &hpte_v_array[0], &hpte_v_array[1], &hpte_v_array[2], &hpte_v_array[3], &hpte_rs); BUG_ON(result); if (hpte_v_array[inserted_index % 4] & HPTE_V_SECONDARY) ret = (inserted_index & 7) | (1 << 3); else ret = inserted_index & 7; spin_unlock_irqrestore(&ps3_htab_lock, flags); return ret; }
int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp, unsigned int *virq) { int result; u64 outlet; u64 lpar_addr; BUG_ON(!is_kernel_addr((u64)virt_addr_bmp)); lpar_addr = ps3_mm_phys_to_lpar(__pa(virt_addr_bmp)); result = lv1_configure_virtual_uart_irq(lpar_addr, &outlet); if (result) { pr_debug("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n", __func__, __LINE__, ps3_result(result)); return result; } result = ps3_irq_plug_setup(cpu, outlet, virq); BUG_ON(result); return result; }
static int ps3_probe_thread(void *data) { struct ps3_notification_device dev; int res; unsigned int irq; u64 lpar; void *buf; struct ps3_notify_cmd *notify_cmd; struct ps3_notify_event *notify_event; pr_debug(" -> %s:%u: kthread started\n", __func__, __LINE__); buf = kzalloc(512, GFP_KERNEL); if (!buf) return -ENOMEM; lpar = ps3_mm_phys_to_lpar(__pa(buf)); notify_cmd = buf; notify_event = buf; /* dummy system bus device */ dev.sbd.bus_id = (u64)data; dev.sbd.dev_id = PS3_NOTIFICATION_DEV_ID; dev.sbd.interrupt_id = PS3_NOTIFICATION_INTERRUPT_ID; res = lv1_open_device(dev.sbd.bus_id, dev.sbd.dev_id, 0); if (res) { pr_err("%s:%u: lv1_open_device failed %s\n", __func__, __LINE__, ps3_result(res)); goto fail_free; } res = ps3_sb_event_receive_port_setup(&dev.sbd, PS3_BINDING_CPU_ANY, &irq); if (res) { pr_err("%s:%u: ps3_sb_event_receive_port_setup failed %d\n", __func__, __LINE__, res); goto fail_close_device; } spin_lock_init(&dev.lock); res = request_irq(irq, ps3_notification_interrupt, 0, "ps3_notification", &dev); if (res) { pr_err("%s:%u: request_irq failed %d\n", __func__, __LINE__, res); goto fail_sb_event_receive_port_destroy; } /* Setup and write the request for device notification. */ notify_cmd->operation_code = 0; /* must be zero */ notify_cmd->event_mask = 1UL << notify_region_probe; res = ps3_notification_read_write(&dev, lpar, 1); if (res) goto fail_free_irq; /* Loop here processing the requested notification events. */ do { try_to_freeze(); memset(notify_event, 0, sizeof(*notify_event)); res = ps3_notification_read_write(&dev, lpar, 0); if (res) break; pr_debug("%s:%u: notify event type 0x%llx bus id %llu dev id %llu" " type %llu port %llu\n", __func__, __LINE__, notify_event->event_type, notify_event->bus_id, notify_event->dev_id, notify_event->dev_type, notify_event->dev_port); if (notify_event->event_type != notify_region_probe || notify_event->bus_id != dev.sbd.bus_id) { pr_warning("%s:%u: bad notify_event: event %llu, " "dev_id %llu, dev_type %llu\n", __func__, __LINE__, notify_event->event_type, notify_event->dev_id, notify_event->dev_type); continue; } ps3_find_and_add_device(dev.sbd.bus_id, notify_event->dev_id); } while (!kthread_should_stop()); fail_free_irq: free_irq(irq, &dev); fail_sb_event_receive_port_destroy: ps3_sb_event_receive_port_destroy(&dev.sbd, irq); fail_close_device: lv1_close_device(dev.sbd.bus_id, dev.sbd.dev_id); fail_free: kfree(buf); probe_task = NULL; pr_debug(" <- %s:%u: kthread finished\n", __func__, __LINE__); return 0; }
static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) { struct ps3vram_priv *priv; int status; u64 ddr_lpar; u64 ctrl_lpar; u64 info_lpar; u64 reports_lpar; u64 ddr_size; u64 reports_size; int ret = -ENOMEM; char *rest; ret = -EIO; ps3vram_mtd.priv = kzalloc(sizeof(struct ps3vram_priv), GFP_KERNEL); if (!ps3vram_mtd.priv) goto out; priv = ps3vram_mtd.priv; mutex_init(&priv->lock); priv->dev = &dev->core; /* Allocate XDR buffer (1MiB aligned) */ priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL, get_order(XDR_BUF_SIZE)); if (priv->xdr_buf == NULL) { dev_dbg(&dev->core, "%s:%d: could not allocate XDR buffer\n", __func__, __LINE__); ret = -ENOMEM; goto out_free_priv; } /* Put FIFO at begginning of XDR buffer */ priv->fifo_base = (u32 *) (priv->xdr_buf + FIFO_OFFSET); priv->fifo_ptr = priv->fifo_base; /* XXX: Need to open GPU, in case ps3fb or snd_ps3 aren't loaded */ if (ps3_open_hv_device(dev)) { dev_err(&dev->core, "%s:%d: ps3_open_hv_device failed\n", __func__, __LINE__); ret = -EAGAIN; goto out_close_gpu; } /* Request memory */ status = -1; ddr_size = memparse(size, &rest); if (*rest == '-') ddr_size -= ps3fb_videomemory.size; ddr_size = ALIGN(ddr_size, 1024*1024); if (ddr_size <= 0) { dev_err(&dev->core, "%s:%d: specified size is too small\n", __func__, __LINE__); ret = -EINVAL; goto out_close_gpu; } while (ddr_size > 0) { status = lv1_gpu_memory_allocate(ddr_size, 0, 0, 0, 0, &priv->memory_handle, &ddr_lpar); if (!status) break; ddr_size -= 1024*1024; } if (status || ddr_size <= 0) { dev_err(&dev->core, "%s:%d: lv1_gpu_memory_allocate failed\n", __func__, __LINE__); ret = -ENOMEM; goto out_free_xdr_buf; } /* Request context */ status = lv1_gpu_context_allocate(priv->memory_handle, 0, &priv->context_handle, &ctrl_lpar, &info_lpar, &reports_lpar, &reports_size); if (status) { dev_err(&dev->core, "%s:%d: lv1_gpu_context_allocate failed\n", __func__, __LINE__); ret = -ENOMEM; goto out_free_memory; } /* Map XDR buffer to RSX */ status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)), XDR_BUF_SIZE, 0); if (status) { dev_err(&dev->core, "%s:%d: lv1_gpu_context_iomap failed\n", __func__, __LINE__); ret = -ENOMEM; goto out_free_context; } priv->ddr_base = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE); if (!priv->ddr_base) { dev_err(&dev->core, "%s:%d: ioremap failed\n", __func__, __LINE__); ret = -ENOMEM; goto out_free_context; } priv->ctrl = ioremap(ctrl_lpar, 64 * 1024); if (!priv->ctrl) { dev_err(&dev->core, "%s:%d: ioremap failed\n", __func__, __LINE__); ret = -ENOMEM; goto out_unmap_vram; } priv->reports = ioremap(reports_lpar, reports_size); if (!priv->reports) { dev_err(&dev->core, "%s:%d: ioremap failed\n", __func__, __LINE__); ret = -ENOMEM; goto out_unmap_ctrl; } mutex_lock(&ps3_gpu_mutex); ps3vram_init_ring(&ps3vram_mtd); mutex_unlock(&ps3_gpu_mutex); ps3vram_mtd.name = "ps3vram"; ps3vram_mtd.size = ddr_size; ps3vram_mtd.flags = MTD_CAP_RAM; ps3vram_mtd.erase = ps3vram_erase; ps3vram_mtd.point = NULL; ps3vram_mtd.unpoint = NULL; ps3vram_mtd.read = ps3vram_read; ps3vram_mtd.write = ps3vram_write; ps3vram_mtd.owner = THIS_MODULE; ps3vram_mtd.type = MTD_RAM; ps3vram_mtd.erasesize = CACHE_PAGE_SIZE; ps3vram_mtd.writesize = 1; ps3vram_bind(&ps3vram_mtd); mutex_lock(&ps3_gpu_mutex); ret = ps3vram_wait_ring(&ps3vram_mtd, 100); mutex_unlock(&ps3_gpu_mutex); if (ret < 0) { dev_err(&dev->core, "%s:%d: failed to initialize channels\n", __func__, __LINE__); ret = -ETIMEDOUT; goto out_unmap_reports; } ps3vram_cache_init(&ps3vram_mtd); if (add_mtd_device(&ps3vram_mtd)) { dev_err(&dev->core, "%s:%d: add_mtd_device failed\n", __func__, __LINE__); ret = -EAGAIN; goto out_cache_cleanup; } dev_info(&dev->core, "reserved %u MiB of gpu memory\n", (unsigned int)(ddr_size / 1024 / 1024)); return 0; out_cache_cleanup: ps3vram_cache_cleanup(&ps3vram_mtd); out_unmap_reports: iounmap(priv->reports); out_unmap_ctrl: iounmap(priv->ctrl); out_unmap_vram: iounmap(priv->ddr_base); out_free_context: lv1_gpu_context_free(priv->context_handle); out_free_memory: lv1_gpu_memory_free(priv->memory_handle); out_close_gpu: ps3_close_hv_device(dev); out_free_xdr_buf: free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); out_free_priv: kfree(ps3vram_mtd.priv); ps3vram_mtd.priv = NULL; out: return ret; }
/** * ps3stor_setup - Setup a storage device before use * @dev: Pointer to a struct ps3_storage_device * @handler: Pointer to an interrupt handler * * Returns 0 for success, or an error code */ int ps3stor_setup(struct ps3_storage_device *dev, irq_handler_t handler) { int error, res, alignment; enum ps3_dma_page_size page_size; error = ps3_open_hv_device(&dev->sbd); if (error) { dev_err(&dev->sbd.core, "%s:%u: ps3_open_hv_device failed %d\n", __func__, __LINE__, error); goto fail; } error = ps3_sb_event_receive_port_setup(&dev->sbd, PS3_BINDING_CPU_ANY, &dev->irq); if (error) { dev_err(&dev->sbd.core, "%s:%u: ps3_sb_event_receive_port_setup failed %d\n", __func__, __LINE__, error); goto fail_close_device; } error = request_irq(dev->irq, handler, IRQF_DISABLED, dev->sbd.core.driver->name, dev); if (error) { dev_err(&dev->sbd.core, "%s:%u: request_irq failed %d\n", __func__, __LINE__, error); goto fail_sb_event_receive_port_destroy; } alignment = min(__ffs(dev->bounce_size), __ffs((unsigned long)dev->bounce_buf)); if (alignment < 12) { dev_err(&dev->sbd.core, "%s:%u: bounce buffer not aligned (%lx at 0x%p)\n", __func__, __LINE__, dev->bounce_size, dev->bounce_buf); error = -EINVAL; goto fail_free_irq; } else if (alignment < 16) page_size = PS3_DMA_4K; else page_size = PS3_DMA_64K; dev->sbd.d_region = &dev->dma_region; ps3_dma_region_init(&dev->sbd, &dev->dma_region, page_size, PS3_DMA_OTHER, dev->bounce_buf, dev->bounce_size); res = ps3_dma_region_create(&dev->dma_region); if (res) { dev_err(&dev->sbd.core, "%s:%u: cannot create DMA region\n", __func__, __LINE__); error = -ENOMEM; goto fail_free_irq; } dev->bounce_lpar = ps3_mm_phys_to_lpar(__pa(dev->bounce_buf)); dev->bounce_dma = dma_map_single(&dev->sbd.core, dev->bounce_buf, dev->bounce_size, DMA_BIDIRECTIONAL); if (!dev->bounce_dma) { dev_err(&dev->sbd.core, "%s:%u: map DMA region failed\n", __func__, __LINE__); error = -ENODEV; goto fail_free_dma; } error = ps3stor_probe_access(dev); if (error) { dev_err(&dev->sbd.core, "%s:%u: No accessible regions found\n", __func__, __LINE__); goto fail_unmap_dma; } return 0; fail_unmap_dma: dma_unmap_single(&dev->sbd.core, dev->bounce_dma, dev->bounce_size, DMA_BIDIRECTIONAL); fail_free_dma: ps3_dma_region_free(&dev->dma_region); fail_free_irq: free_irq(dev->irq, dev); fail_sb_event_receive_port_destroy: ps3_sb_event_receive_port_destroy(&dev->sbd, dev->irq); fail_close_device: ps3_close_hv_device(&dev->sbd); fail: return error; }
static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo) { int error = -ENODEV; int result; const u64 notification_dev_id = (u64)-1LL; const unsigned int timeout = HZ; u64 lpar; u64 tag; void *buf; enum ps3_notify_type { notify_device_ready = 0, notify_region_probe = 1, notify_region_update = 2, }; struct { u64 operation_code; /* must be zero */ u64 event_mask; /* OR of 1UL << enum ps3_notify_type */ } *notify_cmd; struct { u64 event_type; /* enum ps3_notify_type */ u64 bus_id; u64 dev_id; u64 dev_type; u64 dev_port; } *notify_event; pr_debug(" -> %s:%u: (%u:%u:%u)\n", __func__, __LINE__, repo->bus_id, repo->dev_id, repo->dev_type); buf = kzalloc(512, GFP_KERNEL); if (!buf) return -ENOMEM; lpar = ps3_mm_phys_to_lpar(__pa(buf)); notify_cmd = buf; notify_event = buf; result = lv1_open_device(repo->bus_id, notification_dev_id, 0); if (result) { printk(KERN_ERR "%s:%u: lv1_open_device %s\n", __func__, __LINE__, ps3_result(result)); goto fail_free; } /* Setup and write the request for device notification. */ notify_cmd->operation_code = 0; /* must be zero */ notify_cmd->event_mask = 1UL << notify_region_probe; result = lv1_storage_write(notification_dev_id, 0, 0, 1, 0, lpar, &tag); if (result) { printk(KERN_ERR "%s:%u: write failed %s\n", __func__, __LINE__, ps3_result(result)); goto fail_close; } /* Wait for the write completion */ result = ps3stor_wait_for_completion(notification_dev_id, tag, timeout); if (result) { printk(KERN_ERR "%s:%u: write not completed %s\n", __func__, __LINE__, ps3_result(result)); goto fail_close; } /* Loop here processing the requested notification events. */ while (1) { memset(notify_event, 0, sizeof(*notify_event)); result = lv1_storage_read(notification_dev_id, 0, 0, 1, 0, lpar, &tag); if (result) { printk(KERN_ERR "%s:%u: write failed %s\n", __func__, __LINE__, ps3_result(result)); break; } result = ps3stor_wait_for_completion(notification_dev_id, tag, timeout); if (result) { printk(KERN_ERR "%s:%u: read not completed %s\n", __func__, __LINE__, ps3_result(result)); break; } pr_debug("%s:%d: notify event (%u:%u:%u): event_type 0x%lx, " "port %lu\n", __func__, __LINE__, repo->bus_index, repo->dev_index, repo->dev_type, notify_event->event_type, notify_event->dev_port); if (notify_event->event_type != notify_region_probe || notify_event->bus_id != repo->bus_id) { pr_debug("%s:%u: bad notify_event: event %lu, " "dev_id %lu, dev_type %lu\n", __func__, __LINE__, notify_event->event_type, notify_event->dev_id, notify_event->dev_type); break; } if (notify_event->dev_id == repo->dev_id && notify_event->dev_type == repo->dev_type) { pr_debug("%s:%u: device ready (%u:%u:%u)\n", __func__, __LINE__, repo->bus_index, repo->dev_index, repo->dev_type); error = 0; break; } if (notify_event->dev_id == repo->dev_id && notify_event->dev_type == PS3_DEV_TYPE_NOACCESS) { pr_debug("%s:%u: no access: dev_id %u\n", __func__, __LINE__, repo->dev_id); break; } } fail_close: lv1_close_device(repo->bus_id, notification_dev_id); fail_free: kfree(buf); pr_debug(" <- %s:%u\n", __func__, __LINE__); return error; }
int ps3_lpm_open(enum ps3_lpm_tb_type tb_type, void *tb_cache, u64 tb_cache_size) { int result; u64 tb_size; BUG_ON(!lpm_priv); BUG_ON(tb_type != PS3_LPM_TB_TYPE_NONE && tb_type != PS3_LPM_TB_TYPE_INTERNAL); if (tb_type == PS3_LPM_TB_TYPE_NONE && tb_cache) dev_dbg(sbd_core(), "%s:%u: bad in vals\n", __func__, __LINE__); if (!atomic_add_unless(&lpm_priv->open, 1, 1)) { dev_dbg(sbd_core(), "%s:%u: busy\n", __func__, __LINE__); return -EBUSY; } if (tb_type == PS3_LPM_TB_TYPE_NONE) { lpm_priv->tb_cache_size = 0; lpm_priv->tb_cache_internal = NULL; lpm_priv->tb_cache = NULL; } else if (tb_cache) { if (tb_cache != (void *)_ALIGN_UP((unsigned long)tb_cache, 128) || tb_cache_size != _ALIGN_UP(tb_cache_size, 128)) { dev_err(sbd_core(), "%s:%u: unaligned tb_cache\n", __func__, __LINE__); result = -EINVAL; goto fail_align; } lpm_priv->tb_cache_size = tb_cache_size; lpm_priv->tb_cache_internal = NULL; lpm_priv->tb_cache = tb_cache; } else { lpm_priv->tb_cache_size = PS3_LPM_DEFAULT_TB_CACHE_SIZE; lpm_priv->tb_cache_internal = kzalloc( lpm_priv->tb_cache_size + 127, GFP_KERNEL); if (!lpm_priv->tb_cache_internal) { dev_err(sbd_core(), "%s:%u: alloc internal tb_cache " "failed\n", __func__, __LINE__); result = -ENOMEM; goto fail_malloc; } lpm_priv->tb_cache = (void *)_ALIGN_UP( (unsigned long)lpm_priv->tb_cache_internal, 128); } result = lv1_construct_lpm(lpm_priv->node_id, tb_type, 0, 0, ps3_mm_phys_to_lpar(__pa(lpm_priv->tb_cache)), lpm_priv->tb_cache_size, &lpm_priv->lpm_id, &lpm_priv->outlet_id, &tb_size); if (result) { dev_err(sbd_core(), "%s:%u: lv1_construct_lpm failed: %s\n", __func__, __LINE__, ps3_result(result)); result = -EINVAL; goto fail_construct; } lpm_priv->shadow.pm_control = PS3_LPM_SHADOW_REG_INIT; lpm_priv->shadow.pm_start_stop = PS3_LPM_SHADOW_REG_INIT; lpm_priv->shadow.group_control = PS3_LPM_SHADOW_REG_INIT; lpm_priv->shadow.debug_bus_control = PS3_LPM_SHADOW_REG_INIT; dev_dbg(sbd_core(), "%s:%u: lpm_id 0x%llx, outlet_id 0x%llx, " "tb_size 0x%llx\n", __func__, __LINE__, lpm_priv->lpm_id, lpm_priv->outlet_id, tb_size); return 0; fail_construct: kfree(lpm_priv->tb_cache_internal); lpm_priv->tb_cache_internal = NULL; fail_malloc: fail_align: atomic_dec(&lpm_priv->open); return result; }
/** * ps3_gelic_driver_probe - add a device to the control of this driver */ static int ps3_gelic_driver_probe (struct ps3_system_bus_device *dev) { struct gelic_net_card *card = gelic_net_alloc_card(); int result; if (!card) { dev_info(&dev->core, "gelic_net_alloc_card failed\n"); result = -ENOMEM; goto fail_alloc_card; } ps3_system_bus_set_driver_data(dev, card); card->dev = dev; result = ps3_open_hv_device(dev); if (result) { dev_dbg(&dev->core, "ps3_open_hv_device failed\n"); goto fail_open; } result = ps3_dma_region_create(dev->d_region); if (result) { dev_dbg(&dev->core, "ps3_dma_region_create failed(%d)\n", result); BUG_ON("check region type"); goto fail_dma_region; } result = lv1_net_set_interrupt_status_indicator(bus_id(card), dev_id(card), ps3_mm_phys_to_lpar(__pa(&card->irq_status)), 0); if (result) { dev_dbg(&dev->core, "lv1_net_set_interrupt_status_indicator failed: %s\n", ps3_result(result)); result = -EIO; goto fail_status_indicator; } result = gelic_net_setup_netdev(card); if (result) { dev_dbg(&dev->core, "%s:%d: ps3_dma_region_create failed: " "(%d)\n", __func__, __LINE__, result); goto fail_setup_netdev; } return 0; fail_setup_netdev: lv1_net_set_interrupt_status_indicator(bus_id(card), bus_id(card), 0 , 0); fail_status_indicator: ps3_dma_region_free(dev->d_region); fail_dma_region: ps3_close_hv_device(dev); fail_open: ps3_system_bus_set_driver_data(dev, NULL); free_netdev(card->netdev); fail_alloc_card: return result; }
static int ps3rom_atapi_request(struct ps3_storage_device *dev, struct scsi_cmnd *cmd) { struct lv1_atapi_cmnd_block atapi_cmnd; unsigned char opcode = cmd->cmnd[0]; int res; u64 lpar; dev_dbg(&dev->sbd.core, "%s:%u: send ATAPI command 0x%02x\n", __func__, __LINE__, opcode); memset(&atapi_cmnd, 0, sizeof(struct lv1_atapi_cmnd_block)); memcpy(&atapi_cmnd.pkt, cmd->cmnd, 12); atapi_cmnd.pktlen = 12; atapi_cmnd.block_size = 1; /* transfer size is block_size * blocks */ atapi_cmnd.blocks = atapi_cmnd.arglen = scsi_bufflen(cmd); atapi_cmnd.buffer = dev->bounce_lpar; switch (cmd->sc_data_direction) { case DMA_FROM_DEVICE: if (scsi_bufflen(cmd) >= CD_FRAMESIZE) atapi_cmnd.proto = DMA_PROTO; else atapi_cmnd.proto = PIO_DATA_IN_PROTO; atapi_cmnd.in_out = DIR_READ; break; case DMA_TO_DEVICE: if (scsi_bufflen(cmd) >= CD_FRAMESIZE) atapi_cmnd.proto = DMA_PROTO; else atapi_cmnd.proto = PIO_DATA_OUT_PROTO; atapi_cmnd.in_out = DIR_WRITE; scsi_sg_copy_to_buffer(cmd, dev->bounce_buf, dev->bounce_size); break; default: atapi_cmnd.proto = NON_DATA_PROTO; break; } lpar = ps3_mm_phys_to_lpar(__pa(&atapi_cmnd)); res = lv1_storage_send_device_command(dev->sbd.dev_id, LV1_STORAGE_SEND_ATAPI_COMMAND, lpar, sizeof(atapi_cmnd), atapi_cmnd.buffer, atapi_cmnd.arglen, &dev->tag); if (res == LV1_DENIED_BY_POLICY) { dev_dbg(&dev->sbd.core, "%s:%u: ATAPI command 0x%02x denied by policy\n", __func__, __LINE__, opcode); return DID_ERROR << 16; } if (res) { dev_err(&dev->sbd.core, "%s:%u: ATAPI command 0x%02x failed %d\n", __func__, __LINE__, opcode, res); return DID_ERROR << 16; } return 0; }
static long ps3encdec_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct ps3_storage_device *dev = ps3encdec_dev; struct ps3encdec_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); void __user *argp = (void __user *) arg; int res = -EFAULT; mutex_lock(&priv->mutex); pr_debug("%s:%d cmd %x\n", __func__, __LINE__, cmd); switch (cmd) { case PS3ENCDEC_IOCTL_DO_REQUEST: { struct ps3encdec_ioctl_do_request do_request; void *cmdbuf; u64 cmdbuf_lpar; if (copy_from_user(&do_request, argp, sizeof(do_request))) { pr_debug("%s:%d: copy_from_user failed\n", __func__, __LINE__); res = -EFAULT; break; } BUG_ON(do_request.respbuf_size > BOUNCE_SIZE); pr_debug("%s:%d: cmd (%llx) cmdbuf_size (%lld) respbuf_size (%lld)\n", __func__, __LINE__, do_request.cmd, do_request.cmdbuf_size, do_request.respbuf_size); cmdbuf = kmalloc(do_request.cmdbuf_size, GFP_KERNEL); if (!cmdbuf) { pr_debug("%s:%d: kmalloc failed\n", __func__, __LINE__); res = -ENOMEM; break; } if (copy_from_user(cmdbuf, (const void __user *) do_request.cmdbuf, do_request.cmdbuf_size)) { pr_debug("%s:%d: copy_from_user failed\n", __func__, __LINE__); res = -EFAULT; goto kfree_cmdbuf; } cmdbuf_lpar = ps3_mm_phys_to_lpar(__pa(cmdbuf)); res = ps3stor_send_command(dev, do_request.cmd, cmdbuf_lpar, do_request.cmdbuf_size, dev->bounce_lpar, do_request.respbuf_size); if (res) { pr_debug("%s:%d: ps3stor_send_command failed (%d)\n", __func__, __LINE__, res); res = -EFAULT; goto kfree_cmdbuf; } if (copy_to_user((void __user *) do_request.respbuf, dev->bounce_buf, do_request.respbuf_size)) { pr_debug("%s:%d: copy_to_user failed\n", __func__, __LINE__); res = -EFAULT; goto kfree_cmdbuf; } res = 0; kfree_cmdbuf: kfree(cmdbuf); break; } } mutex_unlock(&priv->mutex); return res; }