| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * PS3 Disk Storage Driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2007 Sony Computer Entertainment Inc. |
|---|
| 5 | 6 | * Copyright 2007 Sony Corp. |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 8 | | - * under the terms of the GNU General Public License as published |
|---|
| 9 | | - * by the Free Software Foundation; version 2 of the License. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, but |
|---|
| 12 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 14 | | - * General Public License for more details. |
|---|
| 15 | | - * |
|---|
| 16 | | - * You should have received a copy of the GNU General Public License along |
|---|
| 17 | | - * with this program; if not, write to the Free Software Foundation, Inc., |
|---|
| 18 | | - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|---|
| 19 | 7 | */ |
|---|
| 20 | 8 | |
|---|
| 21 | 9 | #include <linux/ata.h> |
|---|
| 22 | | -#include <linux/blkdev.h> |
|---|
| 10 | +#include <linux/blk-mq.h> |
|---|
| 23 | 11 | #include <linux/slab.h> |
|---|
| 24 | 12 | #include <linux/module.h> |
|---|
| 25 | 13 | |
|---|
| .. | .. |
|---|
| 42 | 30 | struct ps3disk_private { |
|---|
| 43 | 31 | spinlock_t lock; /* Request queue spinlock */ |
|---|
| 44 | 32 | struct request_queue *queue; |
|---|
| 33 | + struct blk_mq_tag_set tag_set; |
|---|
| 45 | 34 | struct gendisk *gendisk; |
|---|
| 46 | 35 | unsigned int blocking_factor; |
|---|
| 47 | 36 | struct request *req; |
|---|
| .. | .. |
|---|
| 101 | 90 | |
|---|
| 102 | 91 | rq_for_each_segment(bvec, req, iter) { |
|---|
| 103 | 92 | unsigned long flags; |
|---|
| 104 | | - dev_dbg(&dev->sbd.core, "%s:%u: bio %u: %u sectors from %lu\n", |
|---|
| 93 | + dev_dbg(&dev->sbd.core, "%s:%u: bio %u: %u sectors from %llu\n", |
|---|
| 105 | 94 | __func__, __LINE__, i, bio_sectors(iter.bio), |
|---|
| 106 | 95 | iter.bio->bi_iter.bi_sector); |
|---|
| 107 | 96 | |
|---|
| .. | .. |
|---|
| 118 | 107 | } |
|---|
| 119 | 108 | } |
|---|
| 120 | 109 | |
|---|
| 121 | | -static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, |
|---|
| 122 | | - struct request *req) |
|---|
| 110 | +static blk_status_t ps3disk_submit_request_sg(struct ps3_storage_device *dev, |
|---|
| 111 | + struct request *req) |
|---|
| 123 | 112 | { |
|---|
| 124 | 113 | struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); |
|---|
| 125 | 114 | int write = rq_data_dir(req), res; |
|---|
| .. | .. |
|---|
| 158 | 147 | if (res) { |
|---|
| 159 | 148 | dev_err(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__, |
|---|
| 160 | 149 | __LINE__, op, res); |
|---|
| 161 | | - __blk_end_request_all(req, BLK_STS_IOERR); |
|---|
| 162 | | - return 0; |
|---|
| 150 | + return BLK_STS_IOERR; |
|---|
| 163 | 151 | } |
|---|
| 164 | 152 | |
|---|
| 165 | 153 | priv->req = req; |
|---|
| 166 | | - return 1; |
|---|
| 154 | + return BLK_STS_OK; |
|---|
| 167 | 155 | } |
|---|
| 168 | 156 | |
|---|
| 169 | | -static int ps3disk_submit_flush_request(struct ps3_storage_device *dev, |
|---|
| 170 | | - struct request *req) |
|---|
| 157 | +static blk_status_t ps3disk_submit_flush_request(struct ps3_storage_device *dev, |
|---|
| 158 | + struct request *req) |
|---|
| 171 | 159 | { |
|---|
| 172 | 160 | struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); |
|---|
| 173 | 161 | u64 res; |
|---|
| .. | .. |
|---|
| 180 | 168 | if (res) { |
|---|
| 181 | 169 | dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%llx\n", |
|---|
| 182 | 170 | __func__, __LINE__, res); |
|---|
| 183 | | - __blk_end_request_all(req, BLK_STS_IOERR); |
|---|
| 184 | | - return 0; |
|---|
| 171 | + return BLK_STS_IOERR; |
|---|
| 185 | 172 | } |
|---|
| 186 | 173 | |
|---|
| 187 | 174 | priv->req = req; |
|---|
| 188 | | - return 1; |
|---|
| 175 | + return BLK_STS_OK; |
|---|
| 189 | 176 | } |
|---|
| 190 | 177 | |
|---|
| 191 | | -static void ps3disk_do_request(struct ps3_storage_device *dev, |
|---|
| 192 | | - struct request_queue *q) |
|---|
| 178 | +static blk_status_t ps3disk_do_request(struct ps3_storage_device *dev, |
|---|
| 179 | + struct request *req) |
|---|
| 193 | 180 | { |
|---|
| 194 | | - struct request *req; |
|---|
| 195 | | - |
|---|
| 196 | 181 | dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__); |
|---|
| 197 | 182 | |
|---|
| 198 | | - while ((req = blk_fetch_request(q))) { |
|---|
| 199 | | - switch (req_op(req)) { |
|---|
| 200 | | - case REQ_OP_FLUSH: |
|---|
| 201 | | - if (ps3disk_submit_flush_request(dev, req)) |
|---|
| 202 | | - return; |
|---|
| 203 | | - break; |
|---|
| 204 | | - case REQ_OP_READ: |
|---|
| 205 | | - case REQ_OP_WRITE: |
|---|
| 206 | | - if (ps3disk_submit_request_sg(dev, req)) |
|---|
| 207 | | - return; |
|---|
| 208 | | - break; |
|---|
| 209 | | - default: |
|---|
| 210 | | - blk_dump_rq_flags(req, DEVICE_NAME " bad request"); |
|---|
| 211 | | - __blk_end_request_all(req, BLK_STS_IOERR); |
|---|
| 212 | | - } |
|---|
| 183 | + switch (req_op(req)) { |
|---|
| 184 | + case REQ_OP_FLUSH: |
|---|
| 185 | + return ps3disk_submit_flush_request(dev, req); |
|---|
| 186 | + case REQ_OP_READ: |
|---|
| 187 | + case REQ_OP_WRITE: |
|---|
| 188 | + return ps3disk_submit_request_sg(dev, req); |
|---|
| 189 | + default: |
|---|
| 190 | + blk_dump_rq_flags(req, DEVICE_NAME " bad request"); |
|---|
| 191 | + return BLK_STS_IOERR; |
|---|
| 213 | 192 | } |
|---|
| 214 | 193 | } |
|---|
| 215 | 194 | |
|---|
| 216 | | -static void ps3disk_request(struct request_queue *q) |
|---|
| 195 | +static blk_status_t ps3disk_queue_rq(struct blk_mq_hw_ctx *hctx, |
|---|
| 196 | + const struct blk_mq_queue_data *bd) |
|---|
| 217 | 197 | { |
|---|
| 198 | + struct request_queue *q = hctx->queue; |
|---|
| 218 | 199 | struct ps3_storage_device *dev = q->queuedata; |
|---|
| 219 | 200 | struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); |
|---|
| 201 | + blk_status_t ret; |
|---|
| 220 | 202 | |
|---|
| 221 | | - if (priv->req) { |
|---|
| 222 | | - dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__); |
|---|
| 223 | | - return; |
|---|
| 224 | | - } |
|---|
| 203 | + blk_mq_start_request(bd->rq); |
|---|
| 225 | 204 | |
|---|
| 226 | | - ps3disk_do_request(dev, q); |
|---|
| 205 | + spin_lock_irq(&priv->lock); |
|---|
| 206 | + ret = ps3disk_do_request(dev, bd->rq); |
|---|
| 207 | + spin_unlock_irq(&priv->lock); |
|---|
| 208 | + |
|---|
| 209 | + return ret; |
|---|
| 227 | 210 | } |
|---|
| 228 | 211 | |
|---|
| 229 | 212 | static irqreturn_t ps3disk_interrupt(int irq, void *data) |
|---|
| .. | .. |
|---|
| 280 | 263 | } |
|---|
| 281 | 264 | |
|---|
| 282 | 265 | spin_lock(&priv->lock); |
|---|
| 283 | | - __blk_end_request_all(req, error); |
|---|
| 284 | 266 | priv->req = NULL; |
|---|
| 285 | | - ps3disk_do_request(dev, priv->queue); |
|---|
| 267 | + blk_mq_end_request(req, error); |
|---|
| 286 | 268 | spin_unlock(&priv->lock); |
|---|
| 287 | 269 | |
|---|
| 270 | + blk_mq_run_hw_queues(priv->queue, true); |
|---|
| 288 | 271 | return IRQ_HANDLED; |
|---|
| 289 | 272 | } |
|---|
| 290 | 273 | |
|---|
| .. | .. |
|---|
| 404 | 387 | |
|---|
| 405 | 388 | static DEFINE_MUTEX(ps3disk_mask_mutex); |
|---|
| 406 | 389 | |
|---|
| 390 | +static const struct blk_mq_ops ps3disk_mq_ops = { |
|---|
| 391 | + .queue_rq = ps3disk_queue_rq, |
|---|
| 392 | +}; |
|---|
| 393 | + |
|---|
| 407 | 394 | static int ps3disk_probe(struct ps3_system_bus_device *_dev) |
|---|
| 408 | 395 | { |
|---|
| 409 | 396 | struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); |
|---|
| .. | .. |
|---|
| 454 | 441 | |
|---|
| 455 | 442 | ps3disk_identify(dev); |
|---|
| 456 | 443 | |
|---|
| 457 | | - queue = blk_init_queue(ps3disk_request, &priv->lock); |
|---|
| 458 | | - if (!queue) { |
|---|
| 459 | | - dev_err(&dev->sbd.core, "%s:%u: blk_init_queue failed\n", |
|---|
| 444 | + queue = blk_mq_init_sq_queue(&priv->tag_set, &ps3disk_mq_ops, 1, |
|---|
| 445 | + BLK_MQ_F_SHOULD_MERGE); |
|---|
| 446 | + if (IS_ERR(queue)) { |
|---|
| 447 | + dev_err(&dev->sbd.core, "%s:%u: blk_mq_init_queue failed\n", |
|---|
| 460 | 448 | __func__, __LINE__); |
|---|
| 461 | | - error = -ENOMEM; |
|---|
| 449 | + error = PTR_ERR(queue); |
|---|
| 462 | 450 | goto fail_teardown; |
|---|
| 463 | 451 | } |
|---|
| 464 | 452 | |
|---|
| .. | .. |
|---|
| 495 | 483 | dev->regions[dev->region_idx].size*priv->blocking_factor); |
|---|
| 496 | 484 | |
|---|
| 497 | 485 | dev_info(&dev->sbd.core, |
|---|
| 498 | | - "%s is a %s (%llu MiB total, %lu MiB for OtherOS)\n", |
|---|
| 486 | + "%s is a %s (%llu MiB total, %llu MiB for OtherOS)\n", |
|---|
| 499 | 487 | gendisk->disk_name, priv->model, priv->raw_capacity >> 11, |
|---|
| 500 | 488 | get_capacity(gendisk) >> 11); |
|---|
| 501 | 489 | |
|---|
| 502 | | - device_add_disk(&dev->sbd.core, gendisk); |
|---|
| 490 | + device_add_disk(&dev->sbd.core, gendisk, NULL); |
|---|
| 503 | 491 | return 0; |
|---|
| 504 | 492 | |
|---|
| 505 | 493 | fail_cleanup_queue: |
|---|
| 506 | 494 | blk_cleanup_queue(queue); |
|---|
| 495 | + blk_mq_free_tag_set(&priv->tag_set); |
|---|
| 507 | 496 | fail_teardown: |
|---|
| 508 | 497 | ps3stor_teardown(dev); |
|---|
| 509 | 498 | fail_free_bounce: |
|---|
| .. | .. |
|---|
| 529 | 518 | mutex_unlock(&ps3disk_mask_mutex); |
|---|
| 530 | 519 | del_gendisk(priv->gendisk); |
|---|
| 531 | 520 | blk_cleanup_queue(priv->queue); |
|---|
| 521 | + blk_mq_free_tag_set(&priv->tag_set); |
|---|
| 532 | 522 | put_disk(priv->gendisk); |
|---|
| 533 | 523 | dev_notice(&dev->sbd.core, "Synchronizing disk cache\n"); |
|---|
| 534 | 524 | ps3disk_sync_cache(dev); |
|---|