# --- T2-COPYRIGHT-NOTE-BEGIN --- # T2 SDE: architecture/powerpc64/package/*/0010-ps3stor-multiple-regions.patch # Copyright (C) 2019 - 2024 The T2 SDE Project # # This Copyright note is generated by scripts/Create-CopyPatch, # more information can be found in the files COPYING and README. # # This patch file is dual-licensed. It is available under the license the # patched project is licensed under, as long as it is an OpenSource license # as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms # of the GNU General Public License version 2 as used by the T2 SDE. # --- T2-COPYRIGHT-NOTE-END --- --- a/arch/powerpc/include/asm/ps3stor.h +++ b/arch/powerpc/include/asm/ps3stor.h @@ -18,6 +18,7 @@ struct ps3_storage_region { unsigned int id; u64 start; u64 size; + u64 flags; }; struct ps3_storage_device { @@ -38,7 +39,6 @@ struct ps3_storage_device { unsigned int num_regions; unsigned long accessible_regions; - unsigned int region_idx; /* first accessible region */ struct ps3_storage_region regions[]; /* Must be last */ }; @@ -50,8 +50,8 @@ static inline struct ps3_storage_device *to_ps3_storage_device(struct device *de extern int ps3stor_setup(struct ps3_storage_device *dev, irq_handler_t handler); extern void ps3stor_teardown(struct ps3_storage_device *dev); -extern u64 ps3stor_read_write_sectors(struct ps3_storage_device *dev, u64 lpar, - u64 start_sector, u64 sectors, +extern u64 ps3stor_read_write_sectors(struct ps3_storage_device *dev, u64 lpar, unsigned int region_idx, + u64 start_sector, u64 sectors, u64 flags, int write); extern u64 ps3stor_send_command(struct ps3_storage_device *dev, u64 cmd, u64 arg1, u64 arg2, u64 arg3, u64 arg4); --- a/drivers/block/ps3disk.c.orig 2024-07-15 00:43:32.000000000 +0200 +++ b/drivers/block/ps3disk.c 2024-08-18 23:23:40.324352412 +0200 @@ -2,6 +2,8 @@ /* * PS3 Disk Storage Driver * + * Copyright (C) 2018-2024 René Rebe + * Copyright (C) 2019 Emmanuel Nicolet * Copyright (C) 2007 Sony Computer Entertainment Inc. * Copyright 2007 Sony Corp. */ @@ -17,24 +19,22 @@ #define DEVICE_NAME "ps3disk" - #define BOUNCE_SIZE (64*1024) -#define PS3DISK_MAX_DISKS 16 +#define PS3DISK_MAX_NUM_REGS 8 #define PS3DISK_MINORS 16 - - #define PS3DISK_NAME "ps3d%c" struct ps3disk_private { spinlock_t lock; /* Request queue spinlock */ - struct blk_mq_tag_set tag_set; - struct gendisk *gendisk; unsigned int blocking_factor; struct request *req; u64 raw_capacity; unsigned char model[ATA_ID_PROD_LEN+1]; + struct blk_mq_tag_set tag_set[PS3DISK_MAX_NUM_REGS]; + struct gendisk *gendisk[PS3DISK_MAX_NUM_REGS]; + int next_queue; }; @@ -76,6 +76,13 @@ .owner = THIS_MODULE, }; +static unsigned int region_flags[] = +{ + 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; +module_param_array(region_flags, uint, NULL, S_IRUGO); +MODULE_PARM_DESC(region_flags, "Region flags"); + static void ps3disk_scatter_gather(struct ps3_storage_device *dev, struct request *req, int gather) @@ -89,6 +96,7 @@ memcpy_from_bvec(dev->bounce_buf + offset, &bvec); else memcpy_to_bvec(&bvec, dev->bounce_buf + offset); + offset += bvec.bv_len; } } @@ -99,7 +107,9 @@ int write = rq_data_dir(req), res; const char *op = write ? "write" : "read"; u64 start_sector, sectors; - unsigned int region_id = dev->regions[dev->region_idx].id; + unsigned int region_idx = MINOR(disk_devt(req->q->disk)) / PS3DISK_MINORS; + unsigned int region_id = dev->regions[region_idx].id; + unsigned int region_flags = dev->regions[region_idx].flags; #ifdef DEBUG unsigned int n = 0; @@ -122,11 +132,11 @@ ps3disk_scatter_gather(dev, req, 1); res = lv1_storage_write(dev->sbd.dev_id, region_id, - start_sector, sectors, 0, + start_sector, sectors, region_flags, dev->bounce_lpar, &dev->tag); } else { res = lv1_storage_read(dev->sbd.dev_id, region_id, - start_sector, sectors, 0, + start_sector, sectors, region_flags, dev->bounce_lpar, &dev->tag); } if (res) { @@ -185,9 +195,15 @@ struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); blk_status_t ret; + spin_lock_irq(&priv->lock); + if (priv->req) { + spin_unlock_irq(&priv->lock); + blk_mq_stop_hw_queue(hctx); + return BLK_STS_DEV_RESOURCE; + } + blk_mq_start_request(bd->rq); - spin_lock_irq(&priv->lock); ret = ps3disk_do_request(dev, bd->rq); spin_unlock_irq(&priv->lock); @@ -203,6 +219,8 @@ blk_status_t error; u64 tag, status; const char *op; + struct gendisk *gdq; + int last_queue; res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status); @@ -250,9 +268,22 @@ spin_lock(&priv->lock); priv->req = NULL; blk_mq_end_request(req, error); + + last_queue = priv->next_queue; + /* find and start the next possibly stopped queue */ + do { + gdq = priv->gendisk[priv->next_queue]; + priv->next_queue++; + if (priv->next_queue >= dev->num_regions) + priv->next_queue = 0; + + if (gdq && blk_mq_queue_stopped(gdq->queue)) { + blk_mq_start_stopped_hw_queues(gdq->queue, true); + break; + } + } while (last_queue != priv->next_queue); spin_unlock(&priv->lock); - blk_mq_run_hw_queues(priv->gendisk->queue, true); return IRQ_HANDLED; } @@ -368,10 +399,6 @@ return 0; } -static unsigned long ps3disk_mask; - -static DEFINE_MUTEX(ps3disk_mask_mutex); - static const struct blk_mq_ops ps3disk_mq_ops = { .queue_rq = ps3disk_queue_rq, }; @@ -381,7 +408,9 @@ struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); struct ps3disk_private *priv; int error; - unsigned int devidx; + unsigned int regidx, devidx; + + dev->bounce_size = BOUNCE_SIZE; struct queue_limits lim = { .logical_block_size = dev->blk_size, .max_hw_sectors = dev->bounce_size >> 9, @@ -393,6 +422,8 @@ struct request_queue *queue; struct gendisk *gendisk; + BUG_ON(dev->num_regions > PS3DISK_MAX_NUM_REGS); + if (dev->blk_size < 512) { dev_err(&dev->sbd.core, "%s:%u: cannot handle block size %llu\n", __func__, @@ -400,18 +431,6 @@ return -EINVAL; } - BUILD_BUG_ON(PS3DISK_MAX_DISKS > BITS_PER_LONG); - mutex_lock(&ps3disk_mask_mutex); - devidx = find_first_zero_bit(&ps3disk_mask, PS3DISK_MAX_DISKS); - if (devidx >= PS3DISK_MAX_DISKS) { - dev_err(&dev->sbd.core, "%s:%u: Too many disks\n", __func__, - __LINE__); - mutex_unlock(&ps3disk_mask_mutex); - return -ENOSPC; - } - __set_bit(devidx, &ps3disk_mask); - mutex_unlock(&ps3disk_mask_mutex); - priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { error = -ENOMEM; @@ -421,63 +440,71 @@ ps3_system_bus_set_drvdata(_dev, priv); spin_lock_init(&priv->lock); - dev->bounce_size = BOUNCE_SIZE; dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA); if (!dev->bounce_buf) { error = -ENOMEM; goto fail_free_priv; } + for (regidx = 0; regidx < dev->num_regions; regidx++) + dev->regions[regidx].flags = region_flags[regidx]; + error = ps3stor_setup(dev, ps3disk_interrupt); if (error) goto fail_free_bounce; ps3disk_identify(dev); - error = blk_mq_alloc_sq_tag_set(&priv->tag_set, &ps3disk_mq_ops, 1, - BLK_MQ_F_SHOULD_MERGE); - if (error) - goto fail_teardown; + for (devidx = 0; devidx < dev->num_regions; devidx++) { + if (test_bit(devidx, &dev->accessible_regions) == 0) + continue; + + error = blk_mq_alloc_sq_tag_set(&priv->tag_set[devidx], &ps3disk_mq_ops, 1, + BLK_MQ_F_SHOULD_MERGE); + if (error) + goto fail_teardown; + + gendisk = blk_mq_alloc_disk(&priv->tag_set[devidx], &lim, dev); + if (IS_ERR(gendisk)) { + dev_err(&dev->sbd.core, "%s:%u: blk_mq_alloc_disk failed\n", + __func__, __LINE__); + error = PTR_ERR(gendisk); + goto fail_teardown; + } + queue = gendisk->queue; + priv->gendisk[devidx] = gendisk; + + blk_queue_write_cache(queue, true, false); + + gendisk->major = ps3disk_major; + gendisk->minors = PS3DISK_MINORS; + gendisk->first_minor = devidx * PS3DISK_MINORS; + gendisk->fops = &ps3disk_fops; + gendisk->queue = queue; + gendisk->private_data = dev; + snprintf(gendisk->disk_name, sizeof(gendisk->disk_name), PS3DISK_NAME, + devidx+'a'); + priv->blocking_factor = dev->blk_size >> 9; + set_capacity(gendisk, + dev->regions[devidx].size*priv->blocking_factor); + + dev_info(&dev->sbd.core, + "%s is a %s (%llu MiB total, %llu MiB region)\n", + gendisk->disk_name, priv->model, priv->raw_capacity >> 11, + get_capacity(gendisk) >> 11); - gendisk = blk_mq_alloc_disk(&priv->tag_set, &lim, dev); - if (IS_ERR(gendisk)) { - dev_err(&dev->sbd.core, "%s:%u: blk_mq_alloc_disk failed\n", - __func__, __LINE__); - error = PTR_ERR(gendisk); - goto fail_free_tag_set; - } - - queue = gendisk->queue; - - blk_queue_write_cache(queue, true, false); - - priv->gendisk = gendisk; - gendisk->major = ps3disk_major; - gendisk->first_minor = devidx * PS3DISK_MINORS; - gendisk->minors = PS3DISK_MINORS; - gendisk->fops = &ps3disk_fops; - gendisk->private_data = dev; - snprintf(gendisk->disk_name, sizeof(gendisk->disk_name), PS3DISK_NAME, - devidx+'a'); - priv->blocking_factor = dev->blk_size >> 9; - set_capacity(gendisk, - dev->regions[dev->region_idx].size*priv->blocking_factor); - - dev_info(&dev->sbd.core, - "%s is a %s (%llu MiB total, %llu MiB for OtherOS)\n", - gendisk->disk_name, priv->model, priv->raw_capacity >> 11, - get_capacity(gendisk) >> 11); - - error = device_add_disk(&dev->sbd.core, gendisk, NULL); - if (error) - goto fail_cleanup_disk; + error = device_add_disk(&dev->sbd.core, gendisk, NULL); + } return 0; -fail_cleanup_disk: - put_disk(gendisk); -fail_free_tag_set: - blk_mq_free_tag_set(&priv->tag_set); fail_teardown: + for (devidx = 0; devidx < dev->num_regions; devidx++) { + if (priv->gendisk[devidx]) { + del_gendisk(priv->gendisk[devidx]); + put_disk(priv->gendisk[devidx]); + blk_mq_free_tag_set(&priv->tag_set[devidx]); + } + } ps3stor_teardown(dev); fail_free_bounce: kfree(dev->bounce_buf); @@ -485,9 +512,6 @@ kfree(priv); ps3_system_bus_set_drvdata(_dev, NULL); fail: - mutex_lock(&ps3disk_mask_mutex); - __clear_bit(devidx, &ps3disk_mask); - mutex_unlock(&ps3disk_mask_mutex); return error; } @@ -495,14 +519,15 @@ { struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + unsigned int devidx; + + for (devidx = 0; devidx < dev->num_regions; devidx++) { + if (priv->gendisk[devidx]) { + del_gendisk(priv->gendisk[devidx]); + put_disk(priv->gendisk[devidx]); + } + } - mutex_lock(&ps3disk_mask_mutex); - __clear_bit(MINOR(disk_devt(priv->gendisk)) / PS3DISK_MINORS, - &ps3disk_mask); - mutex_unlock(&ps3disk_mask_mutex); - del_gendisk(priv->gendisk); - put_disk(priv->gendisk); - blk_mq_free_tag_set(&priv->tag_set); dev_notice(&dev->sbd.core, "Synchronizing disk cache\n"); ps3disk_sync_cache(dev); ps3stor_teardown(dev); --- a/drivers/char/ps3flash.c +++ b/drivers/char/ps3flash.c @@ -34,9 +34,10 @@ u64 start_sector, int write) { struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + unsigned int region_idx = 0; u64 res = ps3stor_read_write_sectors(dev, dev->bounce_lpar, - start_sector, priv->chunk_sectors, - write); + region_idx, start_sector, + priv->chunk_sectors, 0, write); if (res) { dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__, __LINE__, write ? "write" : "read", res); @@ -86,8 +87,9 @@ static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin) { struct ps3_storage_device *dev = ps3flash_dev; + unsigned int region_idx = 0; return generic_file_llseek_size(file, offset, origin, MAX_LFS_FILESIZE, - dev->regions[dev->region_idx].size*dev->blk_size); + dev->regions[region_idx].size*dev->blk_size); } static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf, @@ -95,6 +97,7 @@ { struct ps3_storage_device *dev = ps3flash_dev; struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + unsigned int region_idx = 0; u64 size, sector, offset; int res; size_t remaining, n; @@ -104,7 +107,7 @@ "%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p\n", __func__, __LINE__, count, *pos, userbuf, kernelbuf); - size = dev->regions[dev->region_idx].size*dev->blk_size; + size = dev->regions[region_idx].size*dev->blk_size; if (*pos >= size || !count) return 0; @@ -164,6 +167,7 @@ { struct ps3_storage_device *dev = ps3flash_dev; struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + unsigned int region_idx = 0; u64 size, sector, offset; int res = 0; size_t remaining, n; @@ -173,7 +177,7 @@ "%s:%u: Writing %zu bytes at position %lld from U0x%p/K0x%p\n", __func__, __LINE__, count, *pos, userbuf, kernelbuf); - size = dev->regions[dev->region_idx].size*dev->blk_size; + size = dev->regions[region_idx].size*dev->blk_size; if (*pos >= size || !count) return 0; @@ -333,15 +337,16 @@ struct ps3flash_private *priv; int error; unsigned long tmp; + unsigned int region_idx = 0; - tmp = dev->regions[dev->region_idx].start*dev->blk_size; + tmp = dev->regions[region_idx].start*dev->blk_size; if (tmp % FLASH_BLOCK_SIZE) { dev_err(&dev->sbd.core, "%s:%u region start %lu is not aligned\n", __func__, __LINE__, tmp); return -EINVAL; } - tmp = dev->regions[dev->region_idx].size*dev->blk_size; + tmp = dev->regions[region_idx].size*dev->blk_size; if (tmp % FLASH_BLOCK_SIZE) { dev_err(&dev->sbd.core, "%s:%u region size %lu is not aligned\n", __func__, --- a/drivers/ps3/ps3stor_lib.c +++ b/drivers/ps3/ps3stor_lib.c @@ -90,9 +90,8 @@ static int ps3stor_probe_access(struct ps3_storage_device *dev) "%s:%u: checking accessibility of region %u\n", __func__, __LINE__, i); - dev->region_idx = i; - res = ps3stor_read_write_sectors(dev, dev->bounce_lpar, 0, 1, - 0); + res = ps3stor_read_write_sectors(dev, dev->bounce_lpar, i, 0, 1, + dev->regions[i].flags, 0); if (res) { dev_dbg(&dev->sbd.core, "%s:%u: read failed, " "region %u is not accessible\n", __func__, @@ -104,6 +103,10 @@ static int ps3stor_probe_access(struct ps3_storage_device *dev) __func__, __LINE__, i); set_bit(i, &dev->accessible_regions); + dev_info(&dev->sbd.core, + "accessible region %u start %llu size %llu\n", + i, dev->regions[i].start, dev->regions[i].size); + /* We can access at least one region */ error = 0; } @@ -113,14 +116,8 @@ static int ps3stor_probe_access(struct ps3_storage_device *dev) n = hweight_long(dev->accessible_regions); if (n > 1) dev_info(&dev->sbd.core, - "%s:%u: %lu accessible regions found. Only the first " - "one will be used\n", + "%s:%u: %lu accessible regions found\n", __func__, __LINE__, n); - dev->region_idx = __ffs(dev->accessible_regions); - dev_info(&dev->sbd.core, - "First accessible region has index %u start %llu size %llu\n", - dev->region_idx, dev->regions[dev->region_idx].start, - dev->regions[dev->region_idx].size); return 0; } @@ -254,17 +251,19 @@ EXPORT_SYMBOL_GPL(ps3stor_teardown); * ps3stor_read_write_sectors - read/write from/to a storage device * @dev: Pointer to a struct ps3_storage_device * @lpar: HV logical partition address + * @region_idx: Region index * @start_sector: First sector to read/write * @sectors: Number of sectors to read/write + * @flags: Flags * @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) +u64 ps3stor_read_write_sectors(struct ps3_storage_device *dev, u64 lpar, unsigned int region_idx, + u64 start_sector, u64 sectors, u64 flags, int write) { - unsigned int region_id = dev->regions[dev->region_idx].id; + unsigned int region_id = dev->regions[region_idx].id; const char *op = write ? "write" : "read"; int res; @@ -273,10 +272,10 @@ u64 ps3stor_read_write_sectors(struct ps3_storage_device *dev, u64 lpar, init_completion(&dev->done); res = write ? lv1_storage_write(dev->sbd.dev_id, region_id, - start_sector, sectors, 0, lpar, + start_sector, sectors, flags, lpar, &dev->tag) : lv1_storage_read(dev->sbd.dev_id, region_id, - start_sector, sectors, 0, lpar, + start_sector, sectors, flags, lpar, &dev->tag); if (res) { dev_dbg(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__, --- a/drivers/scsi/ps3rom.c +++ b/drivers/scsi/ps3rom.c @@ -61,6 +61,14 @@ enum lv1_atapi_in_out { }; +static unsigned int region_flags[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; +module_param_array(region_flags, uint, NULL, S_IRUGO); +MODULE_PARM_DESC(region_flags, "Region flags"); + + static int ps3rom_slave_configure(struct scsi_device *scsi_dev) { struct ps3rom_private *priv = shost_priv(scsi_dev->host); @@ -161,12 +169,13 @@ static int ps3rom_read_request(struct ps3_storage_device *dev, u32 sectors) { int res; + unsigned int region_idx = 0; 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, + dev->regions[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__, @@ -182,6 +191,7 @@ static int ps3rom_write_request(struct ps3_storage_device *dev, u32 sectors) { int res; + unsigned int region_idx = 0; dev_dbg(&dev->sbd.core, "%s:%u: write %u sectors starting at %u\n", __func__, __LINE__, sectors, start_sector); @@ -189,7 +199,7 @@ static int ps3rom_write_request(struct ps3_storage_device *dev, scsi_sg_copy_to_buffer(cmd, dev->bounce_buf, dev->bounce_size); res = lv1_storage_write(dev->sbd.dev_id, - dev->regions[dev->region_idx].id, start_sector, + dev->regions[region_idx].id, start_sector, sectors, 0, dev->bounce_lpar, &dev->tag); if (res) { dev_err(&dev->sbd.core, "%s:%u: write failed %d\n", __func__, @@ -345,6 +355,7 @@ static int ps3rom_probe(struct ps3_system_bus_device *_dev) { struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); int error; + unsigned int regidx; struct Scsi_Host *host; struct ps3rom_private *priv; @@ -360,6 +371,9 @@ static int ps3rom_probe(struct ps3_system_bus_device *_dev) if (!dev->bounce_buf) return -ENOMEM; + for (regidx = 0; regidx < dev->num_regions; regidx++) + dev->regions[regidx].flags = region_flags[regidx]; + error = ps3stor_setup(dev, ps3rom_interrupt); if (error) goto fail_free_bounce;