/** * ps3stor_read_write_sectors - read/write from/to a storage device * @dev: Pointer to a struct ps3_storage_device * @lpar: HV logical partition address * @start_sector: First sector to read/write * @sectors: Number of sectors to read/write * @write: Flag indicating write (non-zero) or read (zero) * * Returns 0 for success, -1 in case of failure to submit the command, or * an LV1 status value in case of other errors */ u64 ps3stor_read_write_sectors(struct ps3_storage_device *dev, u64 lpar, u64 start_sector, u64 sectors, int write) { unsigned int region_id = dev->regions[dev->region_idx].id; const char *op = write ? "write" : "read"; int res; dev_dbg(&dev->sbd.core, "%s:%u: %s %lu sectors starting at %lu\n", __func__, __LINE__, op, sectors, start_sector); init_completion(&dev->done); res = write ? lv1_storage_write(dev->sbd.dev_id, region_id, start_sector, sectors, 0, lpar, &dev->tag) : lv1_storage_read(dev->sbd.dev_id, region_id, start_sector, sectors, 0, lpar, &dev->tag); if (res) { dev_dbg(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__, __LINE__, op, res); return -1; } wait_for_completion(&dev->done); if (dev->lv1_status) { dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__, __LINE__, op, dev->lv1_status); return dev->lv1_status; } dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__, __LINE__, op); return 0; }
int ps3stor_read_sectors(struct ps3_stordev *sd, int regidx, uint64_t start_sector, uint64_t sector_count, uint64_t flags, char *buf) { #define MIN(a, b) ((a) <= (b) ? (a) : (b)) #define BOUNCE_SECTORS (sizeof(dma_buf) / sd->sd_blksize) #define ASYNC_STATUS_POLL_PERIOD 100 /* microseconds */ struct ps3_storreg *reg = &sd->sd_regs[regidx]; uint64_t nleft, nread, nsectors; uint64_t tag, status; unsigned int timeout; int err = 0; nleft = sector_count; nread = 0; while (nleft) { nsectors = MIN(nleft, BOUNCE_SECTORS); err = lv1_storage_read(sd->sd_devid, reg->sr_id, start_sector + nread, nsectors, flags, (uint32_t)dma_buf, &tag); if (err) return err; timeout = 5000000; /* microseconds */ while (1) { if (timeout < ASYNC_STATUS_POLL_PERIOD) return ETIMEDOUT; err = lv1_storage_check_async_status(sd->sd_devid, tag, &status); if (!err && !status) break; delay(ASYNC_STATUS_POLL_PERIOD); timeout -= ASYNC_STATUS_POLL_PERIOD; } if (status != 0) return EIO; memcpy(buf + nread * sd->sd_blksize, (u_char *)dma_buf, nsectors * sd->sd_blksize); nread += nsectors; nleft -= nsectors; } return err; #undef MIN #undef BOUNCE_SECTORS #undef ASYNC_STATUS_POLL_PERIOD }
static int ps3rom_read_request(struct ps3_storage_device *dev, struct scsi_cmnd *cmd, u32 start_sector, u32 sectors) { int res; dev_dbg(&dev->sbd.core, "%s:%u: read %u sectors starting at %u\n", __func__, __LINE__, sectors, start_sector); res = lv1_storage_read(dev->sbd.dev_id, dev->regions[dev->region_idx].id, start_sector, sectors, 0, dev->bounce_lpar, &dev->tag); if (res) { dev_err(&dev->sbd.core, "%s:%u: read failed %d\n", __func__, __LINE__, res); return DID_ERROR << 16; } return 0; }
static int ps3_notification_read_write(struct ps3_notification_device *dev, u64 lpar, int write) { const char *op = write ? "write" : "read"; unsigned long flags; int res; init_completion(&dev->done); spin_lock_irqsave(&dev->lock, flags); res = write ? lv1_storage_write(dev->sbd.dev_id, 0, 0, 1, 0, lpar, &dev->tag) : lv1_storage_read(dev->sbd.dev_id, 0, 0, 1, 0, lpar, &dev->tag); spin_unlock_irqrestore(&dev->lock, flags); if (res) { pr_err("%s:%u: %s failed %d\n", __func__, __LINE__, op, res); return -EPERM; } pr_debug("%s:%u: notification %s issued\n", __func__, __LINE__, op); res = swait_event_interruptible(dev->done.wait, dev->done.done || kthread_should_stop()); if (kthread_should_stop()) res = -EINTR; if (res) { pr_debug("%s:%u: interrupted %s\n", __func__, __LINE__, op); return res; } if (dev->lv1_status) { pr_err("%s:%u: %s not completed, status 0x%llx\n", __func__, __LINE__, op, dev->lv1_status); return -EIO; } pr_debug("%s:%u: notification %s completed\n", __func__, __LINE__, op); return 0; }
int lv1_stor_wrapper_read(lv1_stor_wrapper_var *stor_var, u64 region_id, u64 start_sector, u64 num_sectors, u64 flags, void *data) { u64 tag, status; int result; result = lv1_storage_read(stor_var->dev_id, region_id, start_sector, num_sectors, flags, stor_var->dma_lpar_addr, &tag); if (result != 0) return result; for (;;) { result = lv1_storage_check_async_status(stor_var->dev_id, tag, &status); if (result != 0) continue; if (status == 0) break; } memcpy(data, stor_var->dma, stor_var->block_size * num_sectors); return 0; }
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; }