18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PS3 BD/DVD/CD-ROM Storage Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2007 Sony Computer Entertainment Inc. 68c2ecf20Sopenharmony_ci * Copyright 2007 Sony Corp. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/cdrom.h> 108c2ecf20Sopenharmony_ci#include <linux/highmem.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 158c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 168c2ecf20Sopenharmony_ci#include <scsi/scsi_dbg.h> 178c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 188c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 198c2ecf20Sopenharmony_ci#include <scsi/scsi_eh.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <asm/lv1call.h> 228c2ecf20Sopenharmony_ci#include <asm/ps3stor.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define DEVICE_NAME "ps3rom" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define BOUNCE_SIZE (64*1024) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define PS3ROM_MAX_SECTORS (BOUNCE_SIZE >> 9) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistruct ps3rom_private { 338c2ecf20Sopenharmony_ci struct ps3_storage_device *dev; 348c2ecf20Sopenharmony_ci struct scsi_cmnd *curr_cmd; 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define LV1_STORAGE_SEND_ATAPI_COMMAND (1) 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistruct lv1_atapi_cmnd_block { 418c2ecf20Sopenharmony_ci u8 pkt[32]; /* packet command block */ 428c2ecf20Sopenharmony_ci u32 pktlen; /* should be 12 for ATAPI 8020 */ 438c2ecf20Sopenharmony_ci u32 blocks; 448c2ecf20Sopenharmony_ci u32 block_size; 458c2ecf20Sopenharmony_ci u32 proto; /* transfer mode */ 468c2ecf20Sopenharmony_ci u32 in_out; /* transfer direction */ 478c2ecf20Sopenharmony_ci u64 buffer; /* parameter except command block */ 488c2ecf20Sopenharmony_ci u32 arglen; /* length above */ 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cienum lv1_atapi_proto { 528c2ecf20Sopenharmony_ci NON_DATA_PROTO = 0, 538c2ecf20Sopenharmony_ci PIO_DATA_IN_PROTO = 1, 548c2ecf20Sopenharmony_ci PIO_DATA_OUT_PROTO = 2, 558c2ecf20Sopenharmony_ci DMA_PROTO = 3 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cienum lv1_atapi_in_out { 598c2ecf20Sopenharmony_ci DIR_WRITE = 0, /* memory -> device */ 608c2ecf20Sopenharmony_ci DIR_READ = 1 /* device -> memory */ 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic int ps3rom_slave_configure(struct scsi_device *scsi_dev) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct ps3rom_private *priv = shost_priv(scsi_dev->host); 678c2ecf20Sopenharmony_ci struct ps3_storage_device *dev = priv->dev; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci dev_dbg(&dev->sbd.core, "%s:%u: id %u, lun %llu, channel %u\n", __func__, 708c2ecf20Sopenharmony_ci __LINE__, scsi_dev->id, scsi_dev->lun, scsi_dev->channel); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* 738c2ecf20Sopenharmony_ci * ATAPI SFF8020 devices use MODE_SENSE_10, 748c2ecf20Sopenharmony_ci * so we can prohibit MODE_SENSE_6 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_ci scsi_dev->use_10_for_ms = 1; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* we don't support {READ,WRITE}_6 */ 798c2ecf20Sopenharmony_ci scsi_dev->use_10_for_rw = 1; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci return 0; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int ps3rom_atapi_request(struct ps3_storage_device *dev, 858c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct lv1_atapi_cmnd_block atapi_cmnd; 888c2ecf20Sopenharmony_ci unsigned char opcode = cmd->cmnd[0]; 898c2ecf20Sopenharmony_ci int res; 908c2ecf20Sopenharmony_ci u64 lpar; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci dev_dbg(&dev->sbd.core, "%s:%u: send ATAPI command 0x%02x\n", __func__, 938c2ecf20Sopenharmony_ci __LINE__, opcode); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci memset(&atapi_cmnd, 0, sizeof(struct lv1_atapi_cmnd_block)); 968c2ecf20Sopenharmony_ci memcpy(&atapi_cmnd.pkt, cmd->cmnd, 12); 978c2ecf20Sopenharmony_ci atapi_cmnd.pktlen = 12; 988c2ecf20Sopenharmony_ci atapi_cmnd.block_size = 1; /* transfer size is block_size * blocks */ 998c2ecf20Sopenharmony_ci atapi_cmnd.blocks = atapi_cmnd.arglen = scsi_bufflen(cmd); 1008c2ecf20Sopenharmony_ci atapi_cmnd.buffer = dev->bounce_lpar; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci switch (cmd->sc_data_direction) { 1038c2ecf20Sopenharmony_ci case DMA_FROM_DEVICE: 1048c2ecf20Sopenharmony_ci if (scsi_bufflen(cmd) >= CD_FRAMESIZE) 1058c2ecf20Sopenharmony_ci atapi_cmnd.proto = DMA_PROTO; 1068c2ecf20Sopenharmony_ci else 1078c2ecf20Sopenharmony_ci atapi_cmnd.proto = PIO_DATA_IN_PROTO; 1088c2ecf20Sopenharmony_ci atapi_cmnd.in_out = DIR_READ; 1098c2ecf20Sopenharmony_ci break; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci case DMA_TO_DEVICE: 1128c2ecf20Sopenharmony_ci if (scsi_bufflen(cmd) >= CD_FRAMESIZE) 1138c2ecf20Sopenharmony_ci atapi_cmnd.proto = DMA_PROTO; 1148c2ecf20Sopenharmony_ci else 1158c2ecf20Sopenharmony_ci atapi_cmnd.proto = PIO_DATA_OUT_PROTO; 1168c2ecf20Sopenharmony_ci atapi_cmnd.in_out = DIR_WRITE; 1178c2ecf20Sopenharmony_ci scsi_sg_copy_to_buffer(cmd, dev->bounce_buf, dev->bounce_size); 1188c2ecf20Sopenharmony_ci break; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci default: 1218c2ecf20Sopenharmony_ci atapi_cmnd.proto = NON_DATA_PROTO; 1228c2ecf20Sopenharmony_ci break; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci lpar = ps3_mm_phys_to_lpar(__pa(&atapi_cmnd)); 1268c2ecf20Sopenharmony_ci res = lv1_storage_send_device_command(dev->sbd.dev_id, 1278c2ecf20Sopenharmony_ci LV1_STORAGE_SEND_ATAPI_COMMAND, 1288c2ecf20Sopenharmony_ci lpar, sizeof(atapi_cmnd), 1298c2ecf20Sopenharmony_ci atapi_cmnd.buffer, 1308c2ecf20Sopenharmony_ci atapi_cmnd.arglen, &dev->tag); 1318c2ecf20Sopenharmony_ci if (res == LV1_DENIED_BY_POLICY) { 1328c2ecf20Sopenharmony_ci dev_dbg(&dev->sbd.core, 1338c2ecf20Sopenharmony_ci "%s:%u: ATAPI command 0x%02x denied by policy\n", 1348c2ecf20Sopenharmony_ci __func__, __LINE__, opcode); 1358c2ecf20Sopenharmony_ci return DID_ERROR << 16; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (res) { 1398c2ecf20Sopenharmony_ci dev_err(&dev->sbd.core, 1408c2ecf20Sopenharmony_ci "%s:%u: ATAPI command 0x%02x failed %d\n", __func__, 1418c2ecf20Sopenharmony_ci __LINE__, opcode, res); 1428c2ecf20Sopenharmony_ci return DID_ERROR << 16; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return 0; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic inline unsigned int srb10_lba(const struct scsi_cmnd *cmd) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci return cmd->cmnd[2] << 24 | cmd->cmnd[3] << 16 | cmd->cmnd[4] << 8 | 1518c2ecf20Sopenharmony_ci cmd->cmnd[5]; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic inline unsigned int srb10_len(const struct scsi_cmnd *cmd) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci return cmd->cmnd[7] << 8 | cmd->cmnd[8]; 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic int ps3rom_read_request(struct ps3_storage_device *dev, 1608c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd, u32 start_sector, 1618c2ecf20Sopenharmony_ci u32 sectors) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci int res; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci dev_dbg(&dev->sbd.core, "%s:%u: read %u sectors starting at %u\n", 1668c2ecf20Sopenharmony_ci __func__, __LINE__, sectors, start_sector); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci res = lv1_storage_read(dev->sbd.dev_id, 1698c2ecf20Sopenharmony_ci dev->regions[dev->region_idx].id, start_sector, 1708c2ecf20Sopenharmony_ci sectors, 0, dev->bounce_lpar, &dev->tag); 1718c2ecf20Sopenharmony_ci if (res) { 1728c2ecf20Sopenharmony_ci dev_err(&dev->sbd.core, "%s:%u: read failed %d\n", __func__, 1738c2ecf20Sopenharmony_ci __LINE__, res); 1748c2ecf20Sopenharmony_ci return DID_ERROR << 16; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic int ps3rom_write_request(struct ps3_storage_device *dev, 1818c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd, u32 start_sector, 1828c2ecf20Sopenharmony_ci u32 sectors) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci int res; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci dev_dbg(&dev->sbd.core, "%s:%u: write %u sectors starting at %u\n", 1878c2ecf20Sopenharmony_ci __func__, __LINE__, sectors, start_sector); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci scsi_sg_copy_to_buffer(cmd, dev->bounce_buf, dev->bounce_size); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci res = lv1_storage_write(dev->sbd.dev_id, 1928c2ecf20Sopenharmony_ci dev->regions[dev->region_idx].id, start_sector, 1938c2ecf20Sopenharmony_ci sectors, 0, dev->bounce_lpar, &dev->tag); 1948c2ecf20Sopenharmony_ci if (res) { 1958c2ecf20Sopenharmony_ci dev_err(&dev->sbd.core, "%s:%u: write failed %d\n", __func__, 1968c2ecf20Sopenharmony_ci __LINE__, res); 1978c2ecf20Sopenharmony_ci return DID_ERROR << 16; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci return 0; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic int ps3rom_queuecommand_lck(struct scsi_cmnd *cmd, 2048c2ecf20Sopenharmony_ci void (*done)(struct scsi_cmnd *)) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci struct ps3rom_private *priv = shost_priv(cmd->device->host); 2078c2ecf20Sopenharmony_ci struct ps3_storage_device *dev = priv->dev; 2088c2ecf20Sopenharmony_ci unsigned char opcode; 2098c2ecf20Sopenharmony_ci int res; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci priv->curr_cmd = cmd; 2128c2ecf20Sopenharmony_ci cmd->scsi_done = done; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci opcode = cmd->cmnd[0]; 2158c2ecf20Sopenharmony_ci /* 2168c2ecf20Sopenharmony_ci * While we can submit READ/WRITE SCSI commands as ATAPI commands, 2178c2ecf20Sopenharmony_ci * it's recommended for various reasons (performance, error handling, 2188c2ecf20Sopenharmony_ci * ...) to use lv1_storage_{read,write}() instead 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ci switch (opcode) { 2218c2ecf20Sopenharmony_ci case READ_10: 2228c2ecf20Sopenharmony_ci res = ps3rom_read_request(dev, cmd, srb10_lba(cmd), 2238c2ecf20Sopenharmony_ci srb10_len(cmd)); 2248c2ecf20Sopenharmony_ci break; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci case WRITE_10: 2278c2ecf20Sopenharmony_ci res = ps3rom_write_request(dev, cmd, srb10_lba(cmd), 2288c2ecf20Sopenharmony_ci srb10_len(cmd)); 2298c2ecf20Sopenharmony_ci break; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci default: 2328c2ecf20Sopenharmony_ci res = ps3rom_atapi_request(dev, cmd); 2338c2ecf20Sopenharmony_ci break; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (res) { 2378c2ecf20Sopenharmony_ci memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); 2388c2ecf20Sopenharmony_ci cmd->result = res; 2398c2ecf20Sopenharmony_ci cmd->sense_buffer[0] = 0x70; 2408c2ecf20Sopenharmony_ci cmd->sense_buffer[2] = ILLEGAL_REQUEST; 2418c2ecf20Sopenharmony_ci priv->curr_cmd = NULL; 2428c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci return 0; 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(ps3rom_queuecommand) 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int decode_lv1_status(u64 status, unsigned char *sense_key, 2518c2ecf20Sopenharmony_ci unsigned char *asc, unsigned char *ascq) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci if (((status >> 24) & 0xff) != SAM_STAT_CHECK_CONDITION) 2548c2ecf20Sopenharmony_ci return -1; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci *sense_key = (status >> 16) & 0xff; 2578c2ecf20Sopenharmony_ci *asc = (status >> 8) & 0xff; 2588c2ecf20Sopenharmony_ci *ascq = status & 0xff; 2598c2ecf20Sopenharmony_ci return 0; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic irqreturn_t ps3rom_interrupt(int irq, void *data) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct ps3_storage_device *dev = data; 2658c2ecf20Sopenharmony_ci struct Scsi_Host *host; 2668c2ecf20Sopenharmony_ci struct ps3rom_private *priv; 2678c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 2688c2ecf20Sopenharmony_ci int res; 2698c2ecf20Sopenharmony_ci u64 tag, status; 2708c2ecf20Sopenharmony_ci unsigned char sense_key, asc, ascq; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status); 2738c2ecf20Sopenharmony_ci /* 2748c2ecf20Sopenharmony_ci * status = -1 may mean that ATAPI transport completed OK, but 2758c2ecf20Sopenharmony_ci * ATAPI command itself resulted CHECK CONDITION 2768c2ecf20Sopenharmony_ci * so, upper layer should issue REQUEST_SENSE to check the sense data 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (tag != dev->tag) 2808c2ecf20Sopenharmony_ci dev_err(&dev->sbd.core, 2818c2ecf20Sopenharmony_ci "%s:%u: tag mismatch, got %llx, expected %llx\n", 2828c2ecf20Sopenharmony_ci __func__, __LINE__, tag, dev->tag); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (res) { 2858c2ecf20Sopenharmony_ci dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%llx\n", 2868c2ecf20Sopenharmony_ci __func__, __LINE__, res, status); 2878c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci host = ps3_system_bus_get_drvdata(&dev->sbd); 2918c2ecf20Sopenharmony_ci priv = shost_priv(host); 2928c2ecf20Sopenharmony_ci cmd = priv->curr_cmd; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (!status) { 2958c2ecf20Sopenharmony_ci /* OK, completed */ 2968c2ecf20Sopenharmony_ci if (cmd->sc_data_direction == DMA_FROM_DEVICE) { 2978c2ecf20Sopenharmony_ci int len; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci len = scsi_sg_copy_from_buffer(cmd, 3008c2ecf20Sopenharmony_ci dev->bounce_buf, 3018c2ecf20Sopenharmony_ci dev->bounce_size); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci scsi_set_resid(cmd, scsi_bufflen(cmd) - len); 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci cmd->result = DID_OK << 16; 3068c2ecf20Sopenharmony_ci goto done; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (cmd->cmnd[0] == REQUEST_SENSE) { 3108c2ecf20Sopenharmony_ci /* SCSI spec says request sense should never get error */ 3118c2ecf20Sopenharmony_ci dev_err(&dev->sbd.core, "%s:%u: end error without autosense\n", 3128c2ecf20Sopenharmony_ci __func__, __LINE__); 3138c2ecf20Sopenharmony_ci cmd->result = DID_ERROR << 16 | SAM_STAT_CHECK_CONDITION; 3148c2ecf20Sopenharmony_ci goto done; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (decode_lv1_status(status, &sense_key, &asc, &ascq)) { 3188c2ecf20Sopenharmony_ci cmd->result = DID_ERROR << 16; 3198c2ecf20Sopenharmony_ci goto done; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci scsi_build_sense_buffer(0, cmd->sense_buffer, sense_key, asc, ascq); 3238c2ecf20Sopenharmony_ci cmd->result = SAM_STAT_CHECK_CONDITION; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cidone: 3268c2ecf20Sopenharmony_ci priv->curr_cmd = NULL; 3278c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 3288c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic struct scsi_host_template ps3rom_host_template = { 3328c2ecf20Sopenharmony_ci .name = DEVICE_NAME, 3338c2ecf20Sopenharmony_ci .slave_configure = ps3rom_slave_configure, 3348c2ecf20Sopenharmony_ci .queuecommand = ps3rom_queuecommand, 3358c2ecf20Sopenharmony_ci .can_queue = 1, 3368c2ecf20Sopenharmony_ci .this_id = 7, 3378c2ecf20Sopenharmony_ci .sg_tablesize = SG_ALL, 3388c2ecf20Sopenharmony_ci .emulated = 1, /* only sg driver uses this */ 3398c2ecf20Sopenharmony_ci .max_sectors = PS3ROM_MAX_SECTORS, 3408c2ecf20Sopenharmony_ci .module = THIS_MODULE, 3418c2ecf20Sopenharmony_ci}; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic int ps3rom_probe(struct ps3_system_bus_device *_dev) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); 3478c2ecf20Sopenharmony_ci int error; 3488c2ecf20Sopenharmony_ci struct Scsi_Host *host; 3498c2ecf20Sopenharmony_ci struct ps3rom_private *priv; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (dev->blk_size != CD_FRAMESIZE) { 3528c2ecf20Sopenharmony_ci dev_err(&dev->sbd.core, 3538c2ecf20Sopenharmony_ci "%s:%u: cannot handle block size %llu\n", __func__, 3548c2ecf20Sopenharmony_ci __LINE__, dev->blk_size); 3558c2ecf20Sopenharmony_ci return -EINVAL; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci dev->bounce_size = BOUNCE_SIZE; 3598c2ecf20Sopenharmony_ci dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA); 3608c2ecf20Sopenharmony_ci if (!dev->bounce_buf) 3618c2ecf20Sopenharmony_ci return -ENOMEM; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci error = ps3stor_setup(dev, ps3rom_interrupt); 3648c2ecf20Sopenharmony_ci if (error) 3658c2ecf20Sopenharmony_ci goto fail_free_bounce; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci host = scsi_host_alloc(&ps3rom_host_template, 3688c2ecf20Sopenharmony_ci sizeof(struct ps3rom_private)); 3698c2ecf20Sopenharmony_ci if (!host) { 3708c2ecf20Sopenharmony_ci dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed\n", 3718c2ecf20Sopenharmony_ci __func__, __LINE__); 3728c2ecf20Sopenharmony_ci error = -ENOMEM; 3738c2ecf20Sopenharmony_ci goto fail_teardown; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci priv = shost_priv(host); 3778c2ecf20Sopenharmony_ci ps3_system_bus_set_drvdata(&dev->sbd, host); 3788c2ecf20Sopenharmony_ci priv->dev = dev; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* One device/LUN per SCSI bus */ 3818c2ecf20Sopenharmony_ci host->max_id = 1; 3828c2ecf20Sopenharmony_ci host->max_lun = 1; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci error = scsi_add_host(host, &dev->sbd.core); 3858c2ecf20Sopenharmony_ci if (error) { 3868c2ecf20Sopenharmony_ci dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed %d\n", 3878c2ecf20Sopenharmony_ci __func__, __LINE__, error); 3888c2ecf20Sopenharmony_ci error = -ENODEV; 3898c2ecf20Sopenharmony_ci goto fail_host_put; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci scsi_scan_host(host); 3938c2ecf20Sopenharmony_ci return 0; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cifail_host_put: 3968c2ecf20Sopenharmony_ci scsi_host_put(host); 3978c2ecf20Sopenharmony_ci ps3_system_bus_set_drvdata(&dev->sbd, NULL); 3988c2ecf20Sopenharmony_cifail_teardown: 3998c2ecf20Sopenharmony_ci ps3stor_teardown(dev); 4008c2ecf20Sopenharmony_cifail_free_bounce: 4018c2ecf20Sopenharmony_ci kfree(dev->bounce_buf); 4028c2ecf20Sopenharmony_ci return error; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic int ps3rom_remove(struct ps3_system_bus_device *_dev) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); 4088c2ecf20Sopenharmony_ci struct Scsi_Host *host = ps3_system_bus_get_drvdata(&dev->sbd); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci scsi_remove_host(host); 4118c2ecf20Sopenharmony_ci ps3stor_teardown(dev); 4128c2ecf20Sopenharmony_ci scsi_host_put(host); 4138c2ecf20Sopenharmony_ci ps3_system_bus_set_drvdata(&dev->sbd, NULL); 4148c2ecf20Sopenharmony_ci kfree(dev->bounce_buf); 4158c2ecf20Sopenharmony_ci return 0; 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic struct ps3_system_bus_driver ps3rom = { 4198c2ecf20Sopenharmony_ci .match_id = PS3_MATCH_ID_STOR_ROM, 4208c2ecf20Sopenharmony_ci .core.name = DEVICE_NAME, 4218c2ecf20Sopenharmony_ci .core.owner = THIS_MODULE, 4228c2ecf20Sopenharmony_ci .probe = ps3rom_probe, 4238c2ecf20Sopenharmony_ci .remove = ps3rom_remove 4248c2ecf20Sopenharmony_ci}; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic int __init ps3rom_init(void) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci return ps3_system_bus_driver_register(&ps3rom); 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic void __exit ps3rom_exit(void) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci ps3_system_bus_driver_unregister(&ps3rom); 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cimodule_init(ps3rom_init); 4388c2ecf20Sopenharmony_cimodule_exit(ps3rom_exit); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 4418c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PS3 BD/DVD/CD-ROM Storage Driver"); 4428c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sony Corporation"); 4438c2ecf20Sopenharmony_ciMODULE_ALIAS(PS3_MODULE_ALIAS_STOR_ROM); 444