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