cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ps3rom.c (10588B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * PS3 BD/DVD/CD-ROM Storage Driver
      4 *
      5 * Copyright (C) 2007 Sony Computer Entertainment Inc.
      6 * Copyright 2007 Sony Corp.
      7 */
      8
      9#include <linux/cdrom.h>
     10#include <linux/highmem.h>
     11#include <linux/module.h>
     12#include <linux/slab.h>
     13
     14#include <scsi/scsi.h>
     15#include <scsi/scsi_cmnd.h>
     16#include <scsi/scsi_dbg.h>
     17#include <scsi/scsi_device.h>
     18#include <scsi/scsi_host.h>
     19#include <scsi/scsi_eh.h>
     20
     21#include <asm/lv1call.h>
     22#include <asm/ps3stor.h>
     23
     24
     25#define DEVICE_NAME			"ps3rom"
     26
     27#define BOUNCE_SIZE			(64*1024)
     28
     29#define PS3ROM_MAX_SECTORS		(BOUNCE_SIZE >> 9)
     30
     31
     32struct ps3rom_private {
     33	struct ps3_storage_device *dev;
     34	struct scsi_cmnd *curr_cmd;
     35};
     36
     37
     38#define LV1_STORAGE_SEND_ATAPI_COMMAND	(1)
     39
     40struct lv1_atapi_cmnd_block {
     41	u8	pkt[32];	/* packet command block           */
     42	u32	pktlen;		/* should be 12 for ATAPI 8020    */
     43	u32	blocks;
     44	u32	block_size;
     45	u32	proto;		/* transfer mode                  */
     46	u32	in_out;		/* transfer direction             */
     47	u64	buffer;		/* parameter except command block */
     48	u32	arglen;		/* length above                   */
     49};
     50
     51enum lv1_atapi_proto {
     52	NON_DATA_PROTO     = 0,
     53	PIO_DATA_IN_PROTO  = 1,
     54	PIO_DATA_OUT_PROTO = 2,
     55	DMA_PROTO = 3
     56};
     57
     58enum lv1_atapi_in_out {
     59	DIR_WRITE = 0,		/* memory -> device */
     60	DIR_READ = 1		/* device -> memory */
     61};
     62
     63
     64static int ps3rom_slave_configure(struct scsi_device *scsi_dev)
     65{
     66	struct ps3rom_private *priv = shost_priv(scsi_dev->host);
     67	struct ps3_storage_device *dev = priv->dev;
     68
     69	dev_dbg(&dev->sbd.core, "%s:%u: id %u, lun %llu, channel %u\n", __func__,
     70		__LINE__, scsi_dev->id, scsi_dev->lun, scsi_dev->channel);
     71
     72	/*
     73	 * ATAPI SFF8020 devices use MODE_SENSE_10,
     74	 * so we can prohibit MODE_SENSE_6
     75	 */
     76	scsi_dev->use_10_for_ms = 1;
     77
     78	/* we don't support {READ,WRITE}_6 */
     79	scsi_dev->use_10_for_rw = 1;
     80
     81	return 0;
     82}
     83
     84static int ps3rom_atapi_request(struct ps3_storage_device *dev,
     85				struct scsi_cmnd *cmd)
     86{
     87	struct lv1_atapi_cmnd_block atapi_cmnd;
     88	unsigned char opcode = cmd->cmnd[0];
     89	int res;
     90	u64 lpar;
     91
     92	dev_dbg(&dev->sbd.core, "%s:%u: send ATAPI command 0x%02x\n", __func__,
     93		__LINE__, opcode);
     94
     95	memset(&atapi_cmnd, 0, sizeof(struct lv1_atapi_cmnd_block));
     96	memcpy(&atapi_cmnd.pkt, cmd->cmnd, 12);
     97	atapi_cmnd.pktlen = 12;
     98	atapi_cmnd.block_size = 1; /* transfer size is block_size * blocks */
     99	atapi_cmnd.blocks = atapi_cmnd.arglen = scsi_bufflen(cmd);
    100	atapi_cmnd.buffer = dev->bounce_lpar;
    101
    102	switch (cmd->sc_data_direction) {
    103	case DMA_FROM_DEVICE:
    104		if (scsi_bufflen(cmd) >= CD_FRAMESIZE)
    105			atapi_cmnd.proto = DMA_PROTO;
    106		else
    107			atapi_cmnd.proto = PIO_DATA_IN_PROTO;
    108		atapi_cmnd.in_out = DIR_READ;
    109		break;
    110
    111	case DMA_TO_DEVICE:
    112		if (scsi_bufflen(cmd) >= CD_FRAMESIZE)
    113			atapi_cmnd.proto = DMA_PROTO;
    114		else
    115			atapi_cmnd.proto = PIO_DATA_OUT_PROTO;
    116		atapi_cmnd.in_out = DIR_WRITE;
    117		scsi_sg_copy_to_buffer(cmd, dev->bounce_buf, dev->bounce_size);
    118		break;
    119
    120	default:
    121		atapi_cmnd.proto = NON_DATA_PROTO;
    122		break;
    123	}
    124
    125	lpar = ps3_mm_phys_to_lpar(__pa(&atapi_cmnd));
    126	res = lv1_storage_send_device_command(dev->sbd.dev_id,
    127					      LV1_STORAGE_SEND_ATAPI_COMMAND,
    128					      lpar, sizeof(atapi_cmnd),
    129					      atapi_cmnd.buffer,
    130					      atapi_cmnd.arglen, &dev->tag);
    131	if (res == LV1_DENIED_BY_POLICY) {
    132		dev_dbg(&dev->sbd.core,
    133			"%s:%u: ATAPI command 0x%02x denied by policy\n",
    134			__func__, __LINE__, opcode);
    135		return DID_ERROR << 16;
    136	}
    137
    138	if (res) {
    139		dev_err(&dev->sbd.core,
    140			"%s:%u: ATAPI command 0x%02x failed %d\n", __func__,
    141			__LINE__, opcode, res);
    142		return DID_ERROR << 16;
    143	}
    144
    145	return 0;
    146}
    147
    148static inline unsigned int srb10_lba(const struct scsi_cmnd *cmd)
    149{
    150	return cmd->cmnd[2] << 24 | cmd->cmnd[3] << 16 | cmd->cmnd[4] << 8 |
    151	       cmd->cmnd[5];
    152}
    153
    154static inline unsigned int srb10_len(const struct scsi_cmnd *cmd)
    155{
    156	return cmd->cmnd[7] << 8 | cmd->cmnd[8];
    157}
    158
    159static int ps3rom_read_request(struct ps3_storage_device *dev,
    160			       struct scsi_cmnd *cmd, u32 start_sector,
    161			       u32 sectors)
    162{
    163	int res;
    164
    165	dev_dbg(&dev->sbd.core, "%s:%u: read %u sectors starting at %u\n",
    166		__func__, __LINE__, sectors, start_sector);
    167
    168	res = lv1_storage_read(dev->sbd.dev_id,
    169			       dev->regions[dev->region_idx].id, start_sector,
    170			       sectors, 0, dev->bounce_lpar, &dev->tag);
    171	if (res) {
    172		dev_err(&dev->sbd.core, "%s:%u: read failed %d\n", __func__,
    173			__LINE__, res);
    174		return DID_ERROR << 16;
    175	}
    176
    177	return 0;
    178}
    179
    180static int ps3rom_write_request(struct ps3_storage_device *dev,
    181				struct scsi_cmnd *cmd, u32 start_sector,
    182				u32 sectors)
    183{
    184	int res;
    185
    186	dev_dbg(&dev->sbd.core, "%s:%u: write %u sectors starting at %u\n",
    187		__func__, __LINE__, sectors, start_sector);
    188
    189	scsi_sg_copy_to_buffer(cmd, dev->bounce_buf, dev->bounce_size);
    190
    191	res = lv1_storage_write(dev->sbd.dev_id,
    192				dev->regions[dev->region_idx].id, start_sector,
    193				sectors, 0, dev->bounce_lpar, &dev->tag);
    194	if (res) {
    195		dev_err(&dev->sbd.core, "%s:%u: write failed %d\n", __func__,
    196			__LINE__, res);
    197		return DID_ERROR << 16;
    198	}
    199
    200	return 0;
    201}
    202
    203static int ps3rom_queuecommand_lck(struct scsi_cmnd *cmd)
    204{
    205	struct ps3rom_private *priv = shost_priv(cmd->device->host);
    206	struct ps3_storage_device *dev = priv->dev;
    207	unsigned char opcode;
    208	int res;
    209
    210	priv->curr_cmd = cmd;
    211
    212	opcode = cmd->cmnd[0];
    213	/*
    214	 * While we can submit READ/WRITE SCSI commands as ATAPI commands,
    215	 * it's recommended for various reasons (performance, error handling,
    216	 * ...) to use lv1_storage_{read,write}() instead
    217	 */
    218	switch (opcode) {
    219	case READ_10:
    220		res = ps3rom_read_request(dev, cmd, srb10_lba(cmd),
    221					  srb10_len(cmd));
    222		break;
    223
    224	case WRITE_10:
    225		res = ps3rom_write_request(dev, cmd, srb10_lba(cmd),
    226					   srb10_len(cmd));
    227		break;
    228
    229	default:
    230		res = ps3rom_atapi_request(dev, cmd);
    231		break;
    232	}
    233
    234	if (res) {
    235		scsi_build_sense(cmd, 0, ILLEGAL_REQUEST, 0, 0);
    236		cmd->result = res;
    237		priv->curr_cmd = NULL;
    238		scsi_done(cmd);
    239	}
    240
    241	return 0;
    242}
    243
    244static DEF_SCSI_QCMD(ps3rom_queuecommand)
    245
    246static int decode_lv1_status(u64 status, unsigned char *sense_key,
    247			     unsigned char *asc, unsigned char *ascq)
    248{
    249	if (((status >> 24) & 0xff) != SAM_STAT_CHECK_CONDITION)
    250		return -1;
    251
    252	*sense_key = (status >> 16) & 0xff;
    253	*asc       = (status >>  8) & 0xff;
    254	*ascq      =  status        & 0xff;
    255	return 0;
    256}
    257
    258static irqreturn_t ps3rom_interrupt(int irq, void *data)
    259{
    260	struct ps3_storage_device *dev = data;
    261	struct Scsi_Host *host;
    262	struct ps3rom_private *priv;
    263	struct scsi_cmnd *cmd;
    264	int res;
    265	u64 tag, status;
    266	unsigned char sense_key, asc, ascq;
    267
    268	res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
    269	/*
    270	 * status = -1 may mean that ATAPI transport completed OK, but
    271	 * ATAPI command itself resulted CHECK CONDITION
    272	 * so, upper layer should issue REQUEST_SENSE to check the sense data
    273	 */
    274
    275	if (tag != dev->tag)
    276		dev_err(&dev->sbd.core,
    277			"%s:%u: tag mismatch, got %llx, expected %llx\n",
    278			__func__, __LINE__, tag, dev->tag);
    279
    280	if (res) {
    281		dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%llx\n",
    282			__func__, __LINE__, res, status);
    283		return IRQ_HANDLED;
    284	}
    285
    286	host = ps3_system_bus_get_drvdata(&dev->sbd);
    287	priv = shost_priv(host);
    288	cmd = priv->curr_cmd;
    289
    290	if (!status) {
    291		/* OK, completed */
    292		if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
    293			int len;
    294
    295			len = scsi_sg_copy_from_buffer(cmd,
    296						       dev->bounce_buf,
    297						       dev->bounce_size);
    298
    299			scsi_set_resid(cmd, scsi_bufflen(cmd) - len);
    300		}
    301		cmd->result = DID_OK << 16;
    302		goto done;
    303	}
    304
    305	if (cmd->cmnd[0] == REQUEST_SENSE) {
    306		/* SCSI spec says request sense should never get error */
    307		dev_err(&dev->sbd.core, "%s:%u: end error without autosense\n",
    308			__func__, __LINE__);
    309		cmd->result = DID_ERROR << 16 | SAM_STAT_CHECK_CONDITION;
    310		goto done;
    311	}
    312
    313	if (decode_lv1_status(status, &sense_key, &asc, &ascq)) {
    314		cmd->result = DID_ERROR << 16;
    315		goto done;
    316	}
    317
    318	scsi_build_sense(cmd, 0, sense_key, asc, ascq);
    319
    320done:
    321	priv->curr_cmd = NULL;
    322	scsi_done(cmd);
    323	return IRQ_HANDLED;
    324}
    325
    326static struct scsi_host_template ps3rom_host_template = {
    327	.name =			DEVICE_NAME,
    328	.slave_configure =	ps3rom_slave_configure,
    329	.queuecommand =		ps3rom_queuecommand,
    330	.can_queue =		1,
    331	.this_id =		7,
    332	.sg_tablesize =		SG_ALL,
    333	.emulated =             1,		/* only sg driver uses this */
    334	.max_sectors =		PS3ROM_MAX_SECTORS,
    335	.module =		THIS_MODULE,
    336};
    337
    338
    339static int ps3rom_probe(struct ps3_system_bus_device *_dev)
    340{
    341	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
    342	int error;
    343	struct Scsi_Host *host;
    344	struct ps3rom_private *priv;
    345
    346	if (dev->blk_size != CD_FRAMESIZE) {
    347		dev_err(&dev->sbd.core,
    348			"%s:%u: cannot handle block size %llu\n", __func__,
    349			__LINE__, dev->blk_size);
    350		return -EINVAL;
    351	}
    352
    353	dev->bounce_size = BOUNCE_SIZE;
    354	dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA);
    355	if (!dev->bounce_buf)
    356		return -ENOMEM;
    357
    358	error = ps3stor_setup(dev, ps3rom_interrupt);
    359	if (error)
    360		goto fail_free_bounce;
    361
    362	host = scsi_host_alloc(&ps3rom_host_template,
    363			       sizeof(struct ps3rom_private));
    364	if (!host) {
    365		dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed\n",
    366			__func__, __LINE__);
    367		error = -ENOMEM;
    368		goto fail_teardown;
    369	}
    370
    371	priv = shost_priv(host);
    372	ps3_system_bus_set_drvdata(&dev->sbd, host);
    373	priv->dev = dev;
    374
    375	/* One device/LUN per SCSI bus */
    376	host->max_id = 1;
    377	host->max_lun = 1;
    378
    379	error = scsi_add_host(host, &dev->sbd.core);
    380	if (error) {
    381		dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed %d\n",
    382			__func__, __LINE__, error);
    383		error = -ENODEV;
    384		goto fail_host_put;
    385	}
    386
    387	scsi_scan_host(host);
    388	return 0;
    389
    390fail_host_put:
    391	scsi_host_put(host);
    392	ps3_system_bus_set_drvdata(&dev->sbd, NULL);
    393fail_teardown:
    394	ps3stor_teardown(dev);
    395fail_free_bounce:
    396	kfree(dev->bounce_buf);
    397	return error;
    398}
    399
    400static void ps3rom_remove(struct ps3_system_bus_device *_dev)
    401{
    402	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
    403	struct Scsi_Host *host = ps3_system_bus_get_drvdata(&dev->sbd);
    404
    405	scsi_remove_host(host);
    406	ps3stor_teardown(dev);
    407	scsi_host_put(host);
    408	ps3_system_bus_set_drvdata(&dev->sbd, NULL);
    409	kfree(dev->bounce_buf);
    410}
    411
    412static struct ps3_system_bus_driver ps3rom = {
    413	.match_id	= PS3_MATCH_ID_STOR_ROM,
    414	.core.name	= DEVICE_NAME,
    415	.core.owner	= THIS_MODULE,
    416	.probe		= ps3rom_probe,
    417	.remove		= ps3rom_remove
    418};
    419
    420
    421static int __init ps3rom_init(void)
    422{
    423	return ps3_system_bus_driver_register(&ps3rom);
    424}
    425
    426static void __exit ps3rom_exit(void)
    427{
    428	ps3_system_bus_driver_unregister(&ps3rom);
    429}
    430
    431module_init(ps3rom_init);
    432module_exit(ps3rom_exit);
    433
    434MODULE_LICENSE("GPL");
    435MODULE_DESCRIPTION("PS3 BD/DVD/CD-ROM Storage Driver");
    436MODULE_AUTHOR("Sony Corporation");
    437MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_ROM);