Advertisement
deaphroat

ps3disk

Oct 4th, 2012
153
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 16.15 KB | None | 0 0
  1. 1/*
  2. 2 * PS3 Disk Storage Driver
  3. 3 *
  4. 4 * Copyright (C) 2007 Sony Computer Entertainment Inc.
  5. 5 * Copyright 2007 Sony Corp.
  6. 6 *
  7. 7 * This program is free software; you can redistribute it and/or modify it
  8. 8 * under the terms of the GNU General Public License as published
  9. 9 * by the Free Software Foundation; version 2 of the License.
  10. 10 *
  11. 11 * This program is distributed in the hope that it will be useful, but
  12. 12 * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14. 14 * General Public License for more details.
  15. 15 *
  16. 16 * You should have received a copy of the GNU General Public License along
  17. 17 * with this program; if not, write to the Free Software Foundation, Inc.,
  18. 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. 19 */
  20. 20
  21. 21#include <linux/ata.h>
  22. 22#include <linux/blkdev.h>
  23. 23#include <linux/slab.h>
  24. 24#include <linux/module.h>
  25. 25
  26. 26#include <asm/lv1call.h>
  27. 27#include <asm/ps3stor.h>
  28. 28#include <asm/firmware.h>
  29. 29
  30. 30
  31. 31#define DEVICE_NAME       "ps3disk"
  32. 32
  33. 33#define BOUNCE_SIZE       (64*1024)
  34. 34
  35. 35#define PS3DISK_MAX_DISKS 16
  36. 36#define PS3DISK_MINORS        16
  37. 37
  38. 38
  39. 39#define PS3DISK_NAME      "ps3d%c"
  40. 40
  41. 41
  42. 42struct ps3disk_private {
  43. 43  spinlock_t lock;        /* Request queue spinlock */
  44. 44  struct request_queue *queue;
  45. 45  struct gendisk *gendisk;
  46. 46  unsigned int blocking_factor;
  47. 47  struct request *req;
  48. 48  u64 raw_capacity;
  49. 49  unsigned char model[ATA_ID_PROD_LEN+1];
  50. 50};
  51. 51
  52. 52
  53. 53#define LV1_STORAGE_SEND_ATA_COMMAND  (2)
  54. 54#define LV1_STORAGE_ATA_HDDOUT        (0x23)
  55. 55
  56. 56struct lv1_ata_cmnd_block {
  57. 57  u16 features;
  58. 58  u16 sector_count;
  59. 59  u16 LBA_low;
  60. 60  u16 LBA_mid;
  61. 61  u16 LBA_high;
  62. 62  u8  device;
  63. 63  u8  command;
  64. 64  u32 is_ext;
  65. 65  u32 proto;
  66. 66  u32 in_out;
  67. 67  u32 size;
  68. 68  u64 buffer;
  69. 69  u32 arglen;
  70. 70};
  71. 71
  72. 72enum lv1_ata_proto {
  73. 73  NON_DATA_PROTO     = 0,
  74. 74  PIO_DATA_IN_PROTO  = 1,
  75. 75  PIO_DATA_OUT_PROTO = 2,
  76. 76  DMA_PROTO = 3
  77. 77};
  78. 78
  79. 79enum lv1_ata_in_out {
  80. 80  DIR_WRITE = 0,          /* memory -> device */
  81. 81  DIR_READ = 1            /* device -> memory */
  82. 82};
  83. 83
  84. 84static int ps3disk_major;
  85. 85
  86. 86
  87. 87static const struct block_device_operations ps3disk_fops = {
  88. 88  .owner      = THIS_MODULE,
  89. 89};
  90. 90
  91. 91
  92. 92static void ps3disk_scatter_gather(struct ps3_storage_device *dev,
  93. 93                 struct request *req, int gather)
  94. 94{
  95. 95  unsigned int offset = 0;
  96. 96  struct req_iterator iter;
  97. 97  struct bio_vec *bvec;
  98. 98  unsigned int i = 0;
  99. 99  size_t size;
  100. 100 void *buf;
  101. 101
  102. 102 rq_for_each_segment(bvec, req, iter) {
  103. 103     unsigned long flags;
  104. 104     dev_dbg(&dev->sbd.core,
  105. 105         "%s:%u: bio %u: %u segs %u sectors from %lu\n",
  106. 106         __func__, __LINE__, i, bio_segments(iter.bio),
  107. 107         bio_sectors(iter.bio), iter.bio->bi_sector);
  108. 108
  109. 109     size = bvec->bv_len;
  110. 110     buf = bvec_kmap_irq(bvec, &flags);
  111. 111     if (gather)
  112. 112         memcpy(dev->bounce_buf+offset, buf, size);
  113. 113     else
  114. 114         memcpy(buf, dev->bounce_buf+offset, size);
  115. 115     offset += size;
  116. 116     flush_kernel_dcache_page(bvec->bv_page);
  117. 117     bvec_kunmap_irq(buf, &flags);
  118. 118     i++;
  119. 119 }
  120. 120}
  121. 121
  122. 122static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
  123. 123                  struct request *req)
  124. 124{
  125. 125 struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
  126. 126 int write = rq_data_dir(req), res;
  127. 127 const char *op = write ? "write" : "read";
  128. 128 u64 start_sector, sectors;
  129. 129 unsigned int region_id = dev->regions[dev->region_idx].id;
  130. 130
  131. 131#ifdef DEBUG
  132. 132 unsigned int n = 0;
  133. 133 struct bio_vec *bv;
  134. 134 struct req_iterator iter;
  135. 135
  136. 136 rq_for_each_segment(bv, req, iter)
  137. 137     n++;
  138. 138 dev_dbg(&dev->sbd.core,
  139. 139     "%s:%u: %s req has %u bvecs for %u sectors\n",
  140. 140     __func__, __LINE__, op, n, blk_rq_sectors(req));
  141. 141#endif
  142. 142
  143. 143 start_sector = blk_rq_pos(req) * priv->blocking_factor;
  144. 144 sectors = blk_rq_sectors(req) * priv->blocking_factor;
  145. 145 dev_dbg(&dev->sbd.core, "%s:%u: %s %llu sectors starting at %llu\n",
  146. 146     __func__, __LINE__, op, sectors, start_sector);
  147. 147
  148. 148 if (write) {
  149. 149     ps3disk_scatter_gather(dev, req, 1);
  150. 150
  151. 151     res = lv1_storage_write(dev->sbd.dev_id, region_id,
  152. 152                 start_sector, sectors, 0,
  153. 153                 dev->bounce_lpar, &dev->tag);
  154. 154 } else {
  155. 155     res = lv1_storage_read(dev->sbd.dev_id, region_id,
  156. 156                    start_sector, sectors, 0,
  157. 157                    dev->bounce_lpar, &dev->tag);
  158. 158 }
  159. 159 if (res) {
  160. 160     dev_err(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__,
  161. 161         __LINE__, op, res);
  162. 162     __blk_end_request_all(req, -EIO);
  163. 163     return 0;
  164. 164 }
  165. 165
  166. 166 priv->req = req;
  167. 167 return 1;
  168. 168}
  169. 169
  170. 170static int ps3disk_submit_flush_request(struct ps3_storage_device *dev,
  171. 171                 struct request *req)
  172. 172{
  173. 173 struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
  174. 174 u64 res;
  175. 175
  176. 176 dev_dbg(&dev->sbd.core, "%s:%u: flush request\n", __func__, __LINE__);
  177. 177
  178. 178 res = lv1_storage_send_device_command(dev->sbd.dev_id,
  179. 179                       LV1_STORAGE_ATA_HDDOUT, 0, 0, 0,
  180. 180                       0, &dev->tag);
  181. 181 if (res) {
  182. 182     dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%llx\n",
  183. 183         __func__, __LINE__, res);
  184. 184     __blk_end_request_all(req, -EIO);
  185. 185     return 0;
  186. 186 }
  187. 187
  188. 188 priv->req = req;
  189. 189 return 1;
  190. 190}
  191. 191
  192. 192static void ps3disk_do_request(struct ps3_storage_device *dev,
  193. 193                struct request_queue *q)
  194. 194{
  195. 195 struct request *req;
  196. 196
  197. 197 dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
  198. 198
  199. 199 while ((req = blk_fetch_request(q))) {
  200. 200     if (req->cmd_flags & REQ_FLUSH) {
  201. 201         if (ps3disk_submit_flush_request(dev, req))
  202. 202             break;
  203. 203     } else if (req->cmd_type == REQ_TYPE_FS) {
  204. 204         if (ps3disk_submit_request_sg(dev, req))
  205. 205             break;
  206. 206     } else {
  207. 207         blk_dump_rq_flags(req, DEVICE_NAME " bad request");
  208. 208         __blk_end_request_all(req, -EIO);
  209. 209         continue;
  210. 210     }
  211. 211 }
  212. 212}
  213. 213
  214. 214static void ps3disk_request(struct request_queue *q)
  215. 215{
  216. 216 struct ps3_storage_device *dev = q->queuedata;
  217. 217 struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
  218. 218
  219. 219 if (priv->req) {
  220. 220     dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__);
  221. 221     return;
  222. 222 }
  223. 223
  224. 224 ps3disk_do_request(dev, q);
  225. 225}
  226. 226
  227. 227static irqreturn_t ps3disk_interrupt(int irq, void *data)
  228. 228{
  229. 229 struct ps3_storage_device *dev = data;
  230. 230 struct ps3disk_private *priv;
  231. 231 struct request *req;
  232. 232 int res, read, error;
  233. 233 u64 tag, status;
  234. 234 const char *op;
  235. 235
  236. 236 res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
  237. 237
  238. 238 if (tag != dev->tag)
  239. 239     dev_err(&dev->sbd.core,
  240. 240         "%s:%u: tag mismatch, got %llx, expected %llx\n",
  241. 241         __func__, __LINE__, tag, dev->tag);
  242. 242
  243. 243 if (res) {
  244. 244     dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%llx\n",
  245. 245         __func__, __LINE__, res, status);
  246. 246     return IRQ_HANDLED;
  247. 247 }
  248. 248
  249. 249 priv = ps3_system_bus_get_drvdata(&dev->sbd);
  250. 250 req = priv->req;
  251. 251 if (!req) {
  252. 252     dev_dbg(&dev->sbd.core,
  253. 253         "%s:%u non-block layer request completed\n", __func__,
  254. 254         __LINE__);
  255. 255     dev->lv1_status = status;
  256. 256     complete(&dev->done);
  257. 257     return IRQ_HANDLED;
  258. 258 }
  259. 259
  260. 260 if (req->cmd_flags & REQ_FLUSH) {
  261. 261     read = 0;
  262. 262     op = "flush";
  263. 263 } else {
  264. 264     read = !rq_data_dir(req);
  265. 265     op = read ? "read" : "write";
  266. 266 }
  267. 267 if (status) {
  268. 268     dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__,
  269. 269         __LINE__, op, status);
  270. 270     error = -EIO;
  271. 271 } else {
  272. 272     dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__,
  273. 273         __LINE__, op);
  274. 274     error = 0;
  275. 275     if (read)
  276. 276         ps3disk_scatter_gather(dev, req, 0);
  277. 277 }
  278. 278
  279. 279 spin_lock(&priv->lock);
  280. 280 __blk_end_request_all(req, error);
  281. 281 priv->req = NULL;
  282. 282 ps3disk_do_request(dev, priv->queue);
  283. 283 spin_unlock(&priv->lock);
  284. 284
  285. 285 return IRQ_HANDLED;
  286. 286}
  287. 287
  288. 288static int ps3disk_sync_cache(struct ps3_storage_device *dev)
  289. 289{
  290. 290 u64 res;
  291. 291
  292. 292 dev_dbg(&dev->sbd.core, "%s:%u: sync cache\n", __func__, __LINE__);
  293. 293
  294. 294 res = ps3stor_send_command(dev, LV1_STORAGE_ATA_HDDOUT, 0, 0, 0, 0);
  295. 295 if (res) {
  296. 296     dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%llx\n",
  297. 297         __func__, __LINE__, res);
  298. 298     return -EIO;
  299. 299 }
  300. 300 return 0;
  301. 301}
  302. 302
  303. 303
  304. 304/* ATA helpers copied from drivers/ata/libata-core.c */
  305. 305
  306. 306static void swap_buf_le16(u16 *buf, unsigned int buf_words)
  307. 307{
  308. 308#ifdef __BIG_ENDIAN
  309. 309 unsigned int i;
  310. 310
  311. 311 for (i = 0; i < buf_words; i++)
  312. 312     buf[i] = le16_to_cpu(buf[i]);
  313. 313#endif /* __BIG_ENDIAN */
  314. 314}
  315. 315
  316. 316static u64 ata_id_n_sectors(const u16 *id)
  317. 317{
  318. 318 if (ata_id_has_lba(id)) {
  319. 319     if (ata_id_has_lba48(id))
  320. 320         return ata_id_u64(id, 100);
  321. 321     else
  322. 322         return ata_id_u32(id, 60);
  323. 323 } else {
  324. 324     if (ata_id_current_chs_valid(id))
  325. 325         return ata_id_u32(id, 57);
  326. 326     else
  327. 327         return id[1] * id[3] * id[6];
  328. 328 }
  329. 329}
  330. 330
  331. 331static void ata_id_string(const u16 *id, unsigned char *s, unsigned int ofs,
  332. 332           unsigned int len)
  333. 333{
  334. 334 unsigned int c;
  335. 335
  336. 336 while (len > 0) {
  337. 337     c = id[ofs] >> 8;
  338. 338     *s = c;
  339. 339     s++;
  340. 340
  341. 341     c = id[ofs] & 0xff;
  342. 342     *s = c;
  343. 343     s++;
  344. 344
  345. 345     ofs++;
  346. 346     len -= 2;
  347. 347 }
  348. 348}
  349. 349
  350. 350static void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs,
  351. 351             unsigned int len)
  352. 352{
  353. 353 unsigned char *p;
  354. 354
  355. 355 WARN_ON(!(len & 1));
  356. 356
  357. 357 ata_id_string(id, s, ofs, len - 1);
  358. 358
  359. 359 p = s + strnlen(s, len - 1);
  360. 360 while (p > s && p[-1] == ' ')
  361. 361     p--;
  362. 362 *p = '\0';
  363. 363}
  364. 364
  365. 365static int ps3disk_identify(struct ps3_storage_device *dev)
  366. 366{
  367. 367 struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
  368. 368 struct lv1_ata_cmnd_block ata_cmnd;
  369. 369 u16 *id = dev->bounce_buf;
  370. 370 u64 res;
  371. 371
  372. 372 dev_dbg(&dev->sbd.core, "%s:%u: identify disk\n", __func__, __LINE__);
  373. 373
  374. 374 memset(&ata_cmnd, 0, sizeof(struct lv1_ata_cmnd_block));
  375. 375 ata_cmnd.command = ATA_CMD_ID_ATA;
  376. 376 ata_cmnd.sector_count = 1;
  377. 377 ata_cmnd.size = ata_cmnd.arglen = ATA_ID_WORDS * 2;
  378. 378 ata_cmnd.buffer = dev->bounce_lpar;
  379. 379 ata_cmnd.proto = PIO_DATA_IN_PROTO;
  380. 380 ata_cmnd.in_out = DIR_READ;
  381. 381
  382. 382 res = ps3stor_send_command(dev, LV1_STORAGE_SEND_ATA_COMMAND,
  383. 383                ps3_mm_phys_to_lpar(__pa(&ata_cmnd)),
  384. 384                sizeof(ata_cmnd), ata_cmnd.buffer,
  385. 385                ata_cmnd.arglen);
  386. 386 if (res) {
  387. 387     dev_err(&dev->sbd.core, "%s:%u: identify disk failed 0x%llx\n",
  388. 388         __func__, __LINE__, res);
  389. 389     return -EIO;
  390. 390 }
  391. 391
  392. 392 swap_buf_le16(id, ATA_ID_WORDS);
  393. 393
  394. 394 /* All we're interested in are raw capacity and model name */
  395. 395 priv->raw_capacity = ata_id_n_sectors(id);
  396. 396 ata_id_c_string(id, priv->model, ATA_ID_PROD, sizeof(priv->model));
  397. 397 return 0;
  398. 398}
  399. 399
  400. 400static unsigned long ps3disk_mask;
  401. 401
  402. 402static DEFINE_MUTEX(ps3disk_mask_mutex);
  403. 403
  404. 404static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
  405. 405{
  406. 406 struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
  407. 407 struct ps3disk_private *priv;
  408. 408 int error;
  409. 409 unsigned int devidx;
  410. 410 struct request_queue *queue;
  411. 411 struct gendisk *gendisk;
  412. 412
  413. 413 if (dev->blk_size < 512) {
  414. 414     dev_err(&dev->sbd.core,
  415. 415         "%s:%u: cannot handle block size %llu\n", __func__,
  416. 416         __LINE__, dev->blk_size);
  417. 417     return -EINVAL;
  418. 418 }
  419. 419
  420. 420 BUILD_BUG_ON(PS3DISK_MAX_DISKS > BITS_PER_LONG);
  421. 421 mutex_lock(&ps3disk_mask_mutex);
  422. 422 devidx = find_first_zero_bit(&ps3disk_mask, PS3DISK_MAX_DISKS);
  423. 423 if (devidx >= PS3DISK_MAX_DISKS) {
  424. 424     dev_err(&dev->sbd.core, "%s:%u: Too many disks\n", __func__,
  425. 425         __LINE__);
  426. 426     mutex_unlock(&ps3disk_mask_mutex);
  427. 427     return -ENOSPC;
  428. 428 }
  429. 429 __set_bit(devidx, &ps3disk_mask);
  430. 430 mutex_unlock(&ps3disk_mask_mutex);
  431. 431
  432. 432 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  433. 433 if (!priv) {
  434. 434     error = -ENOMEM;
  435. 435     goto fail;
  436. 436 }
  437. 437
  438. 438 ps3_system_bus_set_drvdata(_dev, priv);
  439. 439 spin_lock_init(&priv->lock);
  440. 440
  441. 441 dev->bounce_size = BOUNCE_SIZE;
  442. 442 dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA);
  443. 443 if (!dev->bounce_buf) {
  444. 444     error = -ENOMEM;
  445. 445     goto fail_free_priv;
  446. 446 }
  447. 447
  448. 448 error = ps3stor_setup(dev, ps3disk_interrupt);
  449. 449 if (error)
  450. 450     goto fail_free_bounce;
  451. 451
  452. 452 ps3disk_identify(dev);
  453. 453
  454. 454 queue = blk_init_queue(ps3disk_request, &priv->lock);
  455. 455 if (!queue) {
  456. 456     dev_err(&dev->sbd.core, "%s:%u: blk_init_queue failed\n",
  457. 457         __func__, __LINE__);
  458. 458     error = -ENOMEM;
  459. 459     goto fail_teardown;
  460. 460 }
  461. 461
  462. 462 priv->queue = queue;
  463. 463 queue->queuedata = dev;
  464. 464
  465. 465 blk_queue_bounce_limit(queue, BLK_BOUNCE_HIGH);
  466. 466
  467. 467 blk_queue_max_hw_sectors(queue, dev->bounce_size >> 9);
  468. 468 blk_queue_segment_boundary(queue, -1UL);
  469. 469 blk_queue_dma_alignment(queue, dev->blk_size-1);
  470. 470 blk_queue_logical_block_size(queue, dev->blk_size);
  471. 471
  472. 472 blk_queue_flush(queue, REQ_FLUSH);
  473. 473
  474. 474 blk_queue_max_segments(queue, -1);
  475. 475 blk_queue_max_segment_size(queue, dev->bounce_size);
  476. 476
  477. 477 gendisk = alloc_disk(PS3DISK_MINORS);
  478. 478 if (!gendisk) {
  479. 479     dev_err(&dev->sbd.core, "%s:%u: alloc_disk failed\n", __func__,
  480. 480         __LINE__);
  481. 481     error = -ENOMEM;
  482. 482     goto fail_cleanup_queue;
  483. 483 }
  484. 484
  485. 485 priv->gendisk = gendisk;
  486. 486 gendisk->major = ps3disk_major;
  487. 487 gendisk->first_minor = devidx * PS3DISK_MINORS;
  488. 488 gendisk->fops = &ps3disk_fops;
  489. 489 gendisk->queue = queue;
  490. 490 gendisk->private_data = dev;
  491. 491 gendisk->driverfs_dev = &dev->sbd.core;
  492. 492 snprintf(gendisk->disk_name, sizeof(gendisk->disk_name), PS3DISK_NAME,
  493. 493      devidx+'a');
  494. 494 priv->blocking_factor = dev->blk_size >> 9;
  495. 495 set_capacity(gendisk,
  496. 496          dev->regions[dev->region_idx].size*priv->blocking_factor);
  497. 497
  498. 498 dev_info(&dev->sbd.core,
  499. 499      "%s is a %s (%llu MiB total, %lu MiB for OtherOS)\n",
  500. 500      gendisk->disk_name, priv->model, priv->raw_capacity >> 11,
  501. 501      get_capacity(gendisk) >> 11);
  502. 502
  503. 503 add_disk(gendisk);
  504. 504 return 0;
  505. 505
  506. 506fail_cleanup_queue:
  507. 507 blk_cleanup_queue(queue);
  508. 508fail_teardown:
  509. 509 ps3stor_teardown(dev);
  510. 510fail_free_bounce:
  511. 511 kfree(dev->bounce_buf);
  512. 512fail_free_priv:
  513. 513 kfree(priv);
  514. 514 ps3_system_bus_set_drvdata(_dev, NULL);
  515. 515fail:
  516. 516 mutex_lock(&ps3disk_mask_mutex);
  517. 517 __clear_bit(devidx, &ps3disk_mask);
  518. 518 mutex_unlock(&ps3disk_mask_mutex);
  519. 519 return error;
  520. 520}
  521. 521
  522. 522static int ps3disk_remove(struct ps3_system_bus_device *_dev)
  523. 523{
  524. 524 struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
  525. 525 struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
  526. 526
  527. 527 mutex_lock(&ps3disk_mask_mutex);
  528. 528 __clear_bit(MINOR(disk_devt(priv->gendisk)) / PS3DISK_MINORS,
  529. 529         &ps3disk_mask);
  530. 530 mutex_unlock(&ps3disk_mask_mutex);
  531. 531 del_gendisk(priv->gendisk);
  532. 532 blk_cleanup_queue(priv->queue);
  533. 533 put_disk(priv->gendisk);
  534. 534 dev_notice(&dev->sbd.core, "Synchronizing disk cache\n");
  535. 535 ps3disk_sync_cache(dev);
  536. 536 ps3stor_teardown(dev);
  537. 537 kfree(dev->bounce_buf);
  538. 538 kfree(priv);
  539. 539 ps3_system_bus_set_drvdata(_dev, NULL);
  540. 540 return 0;
  541. 541}
  542. 542
  543. 543static struct ps3_system_bus_driver ps3disk = {
  544. 544 .match_id   = PS3_MATCH_ID_STOR_DISK,
  545. 545 .core.name  = DEVICE_NAME,
  546. 546 .core.owner = THIS_MODULE,
  547. 547 .probe      = ps3disk_probe,
  548. 548 .remove     = ps3disk_remove,
  549. 549 .shutdown   = ps3disk_remove,
  550. 550};
  551. 551
  552. 552
  553. 553static int __init ps3disk_init(void)
  554. 554{
  555. 555 int error;
  556. 556
  557. 557 if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
  558. 558     return -ENODEV;
  559. 559
  560. 560 error = register_blkdev(0, DEVICE_NAME);
  561. 561 if (error <= 0) {
  562. 562     printk(KERN_ERR "%s:%u: register_blkdev failed %d\n", __func__,
  563. 563            __LINE__, error);
  564. 564     return error;
  565. 565 }
  566. 566 ps3disk_major = error;
  567. 567
  568. 568 pr_info("%s:%u: registered block device major %d\n", __func__,
  569. 569     __LINE__, ps3disk_major);
  570. 570
  571. 571 error = ps3_system_bus_driver_register(&ps3disk);
  572. 572 if (error)
  573. 573     unregister_blkdev(ps3disk_major, DEVICE_NAME);
  574. 574
  575. 575 return error;
  576. 576}
  577. 577
  578. 578static void __exit ps3disk_exit(void)
  579. 579{
  580. 580 ps3_system_bus_driver_unregister(&ps3disk);
  581. 581 unregister_blkdev(ps3disk_major, DEVICE_NAME);
  582. 582}
  583. 583
  584. 584module_init(ps3disk_init);
  585. 585module_exit(ps3disk_exit);
  586. 586
  587. 587MODULE_LICENSE("GPL");
  588. 588MODULE_DESCRIPTION("PS3 Disk Storage Driver");
  589. 589MODULE_AUTHOR("Sony Corporation");
  590. 590MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_DISK);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement