xref: /openbmc/linux/drivers/scsi/ps3rom.c (revision 6f039790)
19aea8cbfSGeert Uytterhoeven /*
29aea8cbfSGeert Uytterhoeven  * PS3 BD/DVD/CD-ROM Storage Driver
39aea8cbfSGeert Uytterhoeven  *
49aea8cbfSGeert Uytterhoeven  * Copyright (C) 2007 Sony Computer Entertainment Inc.
59aea8cbfSGeert Uytterhoeven  * Copyright 2007 Sony Corp.
69aea8cbfSGeert Uytterhoeven  *
79aea8cbfSGeert Uytterhoeven  * This program is free software; you can redistribute it and/or modify it
89aea8cbfSGeert Uytterhoeven  * under the terms of the GNU General Public License as published
99aea8cbfSGeert Uytterhoeven  * by the Free Software Foundation; version 2 of the License.
109aea8cbfSGeert Uytterhoeven  *
119aea8cbfSGeert Uytterhoeven  * This program is distributed in the hope that it will be useful, but
129aea8cbfSGeert Uytterhoeven  * WITHOUT ANY WARRANTY; without even the implied warranty of
139aea8cbfSGeert Uytterhoeven  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
149aea8cbfSGeert Uytterhoeven  * General Public License for more details.
159aea8cbfSGeert Uytterhoeven  *
169aea8cbfSGeert Uytterhoeven  * You should have received a copy of the GNU General Public License along
179aea8cbfSGeert Uytterhoeven  * with this program; if not, write to the Free Software Foundation, Inc.,
189aea8cbfSGeert Uytterhoeven  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
199aea8cbfSGeert Uytterhoeven  */
209aea8cbfSGeert Uytterhoeven 
219aea8cbfSGeert Uytterhoeven #include <linux/cdrom.h>
229aea8cbfSGeert Uytterhoeven #include <linux/highmem.h>
23acf3368fSPaul Gortmaker #include <linux/module.h>
245a0e3ad6STejun Heo #include <linux/slab.h>
259aea8cbfSGeert Uytterhoeven 
269aea8cbfSGeert Uytterhoeven #include <scsi/scsi.h>
279aea8cbfSGeert Uytterhoeven #include <scsi/scsi_cmnd.h>
289aea8cbfSGeert Uytterhoeven #include <scsi/scsi_dbg.h>
299aea8cbfSGeert Uytterhoeven #include <scsi/scsi_device.h>
309aea8cbfSGeert Uytterhoeven #include <scsi/scsi_host.h>
3153df8ba8SFUJITA Tomonori #include <scsi/scsi_eh.h>
329aea8cbfSGeert Uytterhoeven 
339aea8cbfSGeert Uytterhoeven #include <asm/lv1call.h>
349aea8cbfSGeert Uytterhoeven #include <asm/ps3stor.h>
359aea8cbfSGeert Uytterhoeven 
369aea8cbfSGeert Uytterhoeven 
379aea8cbfSGeert Uytterhoeven #define DEVICE_NAME			"ps3rom"
389aea8cbfSGeert Uytterhoeven 
399aea8cbfSGeert Uytterhoeven #define BOUNCE_SIZE			(64*1024)
409aea8cbfSGeert Uytterhoeven 
4151883b5eSAegis Lin #define PS3ROM_MAX_SECTORS		(BOUNCE_SIZE >> 9)
429aea8cbfSGeert Uytterhoeven 
439aea8cbfSGeert Uytterhoeven 
449aea8cbfSGeert Uytterhoeven struct ps3rom_private {
459aea8cbfSGeert Uytterhoeven 	struct ps3_storage_device *dev;
469aea8cbfSGeert Uytterhoeven 	struct scsi_cmnd *curr_cmd;
479aea8cbfSGeert Uytterhoeven };
489aea8cbfSGeert Uytterhoeven 
499aea8cbfSGeert Uytterhoeven 
509aea8cbfSGeert Uytterhoeven #define LV1_STORAGE_SEND_ATAPI_COMMAND	(1)
519aea8cbfSGeert Uytterhoeven 
529aea8cbfSGeert Uytterhoeven struct lv1_atapi_cmnd_block {
539aea8cbfSGeert Uytterhoeven 	u8	pkt[32];	/* packet command block           */
549aea8cbfSGeert Uytterhoeven 	u32	pktlen;		/* should be 12 for ATAPI 8020    */
559aea8cbfSGeert Uytterhoeven 	u32	blocks;
569aea8cbfSGeert Uytterhoeven 	u32	block_size;
579aea8cbfSGeert Uytterhoeven 	u32	proto;		/* transfer mode                  */
589aea8cbfSGeert Uytterhoeven 	u32	in_out;		/* transfer direction             */
599aea8cbfSGeert Uytterhoeven 	u64	buffer;		/* parameter except command block */
609aea8cbfSGeert Uytterhoeven 	u32	arglen;		/* length above                   */
619aea8cbfSGeert Uytterhoeven };
629aea8cbfSGeert Uytterhoeven 
639aea8cbfSGeert Uytterhoeven enum lv1_atapi_proto {
649aea8cbfSGeert Uytterhoeven 	NON_DATA_PROTO     = 0,
659aea8cbfSGeert Uytterhoeven 	PIO_DATA_IN_PROTO  = 1,
669aea8cbfSGeert Uytterhoeven 	PIO_DATA_OUT_PROTO = 2,
679aea8cbfSGeert Uytterhoeven 	DMA_PROTO = 3
689aea8cbfSGeert Uytterhoeven };
699aea8cbfSGeert Uytterhoeven 
709aea8cbfSGeert Uytterhoeven enum lv1_atapi_in_out {
719aea8cbfSGeert Uytterhoeven 	DIR_WRITE = 0,		/* memory -> device */
729aea8cbfSGeert Uytterhoeven 	DIR_READ = 1		/* device -> memory */
739aea8cbfSGeert Uytterhoeven };
749aea8cbfSGeert Uytterhoeven 
759aea8cbfSGeert Uytterhoeven 
769aea8cbfSGeert Uytterhoeven static int ps3rom_slave_configure(struct scsi_device *scsi_dev)
779aea8cbfSGeert Uytterhoeven {
789aea8cbfSGeert Uytterhoeven 	struct ps3rom_private *priv = shost_priv(scsi_dev->host);
799aea8cbfSGeert Uytterhoeven 	struct ps3_storage_device *dev = priv->dev;
809aea8cbfSGeert Uytterhoeven 
819aea8cbfSGeert Uytterhoeven 	dev_dbg(&dev->sbd.core, "%s:%u: id %u, lun %u, channel %u\n", __func__,
829aea8cbfSGeert Uytterhoeven 		__LINE__, scsi_dev->id, scsi_dev->lun, scsi_dev->channel);
839aea8cbfSGeert Uytterhoeven 
849aea8cbfSGeert Uytterhoeven 	/*
859aea8cbfSGeert Uytterhoeven 	 * ATAPI SFF8020 devices use MODE_SENSE_10,
869aea8cbfSGeert Uytterhoeven 	 * so we can prohibit MODE_SENSE_6
879aea8cbfSGeert Uytterhoeven 	 */
889aea8cbfSGeert Uytterhoeven 	scsi_dev->use_10_for_ms = 1;
899aea8cbfSGeert Uytterhoeven 
909aea8cbfSGeert Uytterhoeven 	/* we don't support {READ,WRITE}_6 */
919aea8cbfSGeert Uytterhoeven 	scsi_dev->use_10_for_rw = 1;
929aea8cbfSGeert Uytterhoeven 
939aea8cbfSGeert Uytterhoeven 	return 0;
949aea8cbfSGeert Uytterhoeven }
959aea8cbfSGeert Uytterhoeven 
969aea8cbfSGeert Uytterhoeven static int ps3rom_atapi_request(struct ps3_storage_device *dev,
979aea8cbfSGeert Uytterhoeven 				struct scsi_cmnd *cmd)
989aea8cbfSGeert Uytterhoeven {
999aea8cbfSGeert Uytterhoeven 	struct lv1_atapi_cmnd_block atapi_cmnd;
1009aea8cbfSGeert Uytterhoeven 	unsigned char opcode = cmd->cmnd[0];
1019aea8cbfSGeert Uytterhoeven 	int res;
1029aea8cbfSGeert Uytterhoeven 	u64 lpar;
1039aea8cbfSGeert Uytterhoeven 
1049aea8cbfSGeert Uytterhoeven 	dev_dbg(&dev->sbd.core, "%s:%u: send ATAPI command 0x%02x\n", __func__,
1059aea8cbfSGeert Uytterhoeven 		__LINE__, opcode);
1069aea8cbfSGeert Uytterhoeven 
1079aea8cbfSGeert Uytterhoeven 	memset(&atapi_cmnd, 0, sizeof(struct lv1_atapi_cmnd_block));
1089aea8cbfSGeert Uytterhoeven 	memcpy(&atapi_cmnd.pkt, cmd->cmnd, 12);
1099aea8cbfSGeert Uytterhoeven 	atapi_cmnd.pktlen = 12;
1109aea8cbfSGeert Uytterhoeven 	atapi_cmnd.block_size = 1; /* transfer size is block_size * blocks */
11135814740SFUJITA Tomonori 	atapi_cmnd.blocks = atapi_cmnd.arglen = scsi_bufflen(cmd);
1129aea8cbfSGeert Uytterhoeven 	atapi_cmnd.buffer = dev->bounce_lpar;
1139aea8cbfSGeert Uytterhoeven 
1149aea8cbfSGeert Uytterhoeven 	switch (cmd->sc_data_direction) {
1159aea8cbfSGeert Uytterhoeven 	case DMA_FROM_DEVICE:
11635814740SFUJITA Tomonori 		if (scsi_bufflen(cmd) >= CD_FRAMESIZE)
1179aea8cbfSGeert Uytterhoeven 			atapi_cmnd.proto = DMA_PROTO;
1189aea8cbfSGeert Uytterhoeven 		else
1199aea8cbfSGeert Uytterhoeven 			atapi_cmnd.proto = PIO_DATA_IN_PROTO;
1209aea8cbfSGeert Uytterhoeven 		atapi_cmnd.in_out = DIR_READ;
1219aea8cbfSGeert Uytterhoeven 		break;
1229aea8cbfSGeert Uytterhoeven 
1239aea8cbfSGeert Uytterhoeven 	case DMA_TO_DEVICE:
12435814740SFUJITA Tomonori 		if (scsi_bufflen(cmd) >= CD_FRAMESIZE)
1259aea8cbfSGeert Uytterhoeven 			atapi_cmnd.proto = DMA_PROTO;
1269aea8cbfSGeert Uytterhoeven 		else
1279aea8cbfSGeert Uytterhoeven 			atapi_cmnd.proto = PIO_DATA_OUT_PROTO;
1289aea8cbfSGeert Uytterhoeven 		atapi_cmnd.in_out = DIR_WRITE;
129944cf8b4SFUJITA Tomonori 		scsi_sg_copy_to_buffer(cmd, dev->bounce_buf, dev->bounce_size);
1309aea8cbfSGeert Uytterhoeven 		break;
1319aea8cbfSGeert Uytterhoeven 
1329aea8cbfSGeert Uytterhoeven 	default:
1339aea8cbfSGeert Uytterhoeven 		atapi_cmnd.proto = NON_DATA_PROTO;
1349aea8cbfSGeert Uytterhoeven 		break;
1359aea8cbfSGeert Uytterhoeven 	}
1369aea8cbfSGeert Uytterhoeven 
1379aea8cbfSGeert Uytterhoeven 	lpar = ps3_mm_phys_to_lpar(__pa(&atapi_cmnd));
1389aea8cbfSGeert Uytterhoeven 	res = lv1_storage_send_device_command(dev->sbd.dev_id,
1399aea8cbfSGeert Uytterhoeven 					      LV1_STORAGE_SEND_ATAPI_COMMAND,
1409aea8cbfSGeert Uytterhoeven 					      lpar, sizeof(atapi_cmnd),
1419aea8cbfSGeert Uytterhoeven 					      atapi_cmnd.buffer,
1429aea8cbfSGeert Uytterhoeven 					      atapi_cmnd.arglen, &dev->tag);
1439aea8cbfSGeert Uytterhoeven 	if (res == LV1_DENIED_BY_POLICY) {
1449aea8cbfSGeert Uytterhoeven 		dev_dbg(&dev->sbd.core,
1459aea8cbfSGeert Uytterhoeven 			"%s:%u: ATAPI command 0x%02x denied by policy\n",
1469aea8cbfSGeert Uytterhoeven 			__func__, __LINE__, opcode);
1479aea8cbfSGeert Uytterhoeven 		return DID_ERROR << 16;
1489aea8cbfSGeert Uytterhoeven 	}
1499aea8cbfSGeert Uytterhoeven 
1509aea8cbfSGeert Uytterhoeven 	if (res) {
1519aea8cbfSGeert Uytterhoeven 		dev_err(&dev->sbd.core,
1529aea8cbfSGeert Uytterhoeven 			"%s:%u: ATAPI command 0x%02x failed %d\n", __func__,
1539aea8cbfSGeert Uytterhoeven 			__LINE__, opcode, res);
1549aea8cbfSGeert Uytterhoeven 		return DID_ERROR << 16;
1559aea8cbfSGeert Uytterhoeven 	}
1569aea8cbfSGeert Uytterhoeven 
1579aea8cbfSGeert Uytterhoeven 	return 0;
1589aea8cbfSGeert Uytterhoeven }
1599aea8cbfSGeert Uytterhoeven 
1609aea8cbfSGeert Uytterhoeven static inline unsigned int srb10_lba(const struct scsi_cmnd *cmd)
1619aea8cbfSGeert Uytterhoeven {
1629aea8cbfSGeert Uytterhoeven 	return cmd->cmnd[2] << 24 | cmd->cmnd[3] << 16 | cmd->cmnd[4] << 8 |
1639aea8cbfSGeert Uytterhoeven 	       cmd->cmnd[5];
1649aea8cbfSGeert Uytterhoeven }
1659aea8cbfSGeert Uytterhoeven 
1669aea8cbfSGeert Uytterhoeven static inline unsigned int srb10_len(const struct scsi_cmnd *cmd)
1679aea8cbfSGeert Uytterhoeven {
1689aea8cbfSGeert Uytterhoeven 	return cmd->cmnd[7] << 8 | cmd->cmnd[8];
1699aea8cbfSGeert Uytterhoeven }
1709aea8cbfSGeert Uytterhoeven 
1719aea8cbfSGeert Uytterhoeven static int ps3rom_read_request(struct ps3_storage_device *dev,
1729aea8cbfSGeert Uytterhoeven 			       struct scsi_cmnd *cmd, u32 start_sector,
1739aea8cbfSGeert Uytterhoeven 			       u32 sectors)
1749aea8cbfSGeert Uytterhoeven {
1759aea8cbfSGeert Uytterhoeven 	int res;
1769aea8cbfSGeert Uytterhoeven 
1779aea8cbfSGeert Uytterhoeven 	dev_dbg(&dev->sbd.core, "%s:%u: read %u sectors starting at %u\n",
1789aea8cbfSGeert Uytterhoeven 		__func__, __LINE__, sectors, start_sector);
1799aea8cbfSGeert Uytterhoeven 
1809aea8cbfSGeert Uytterhoeven 	res = lv1_storage_read(dev->sbd.dev_id,
1819aea8cbfSGeert Uytterhoeven 			       dev->regions[dev->region_idx].id, start_sector,
1829aea8cbfSGeert Uytterhoeven 			       sectors, 0, dev->bounce_lpar, &dev->tag);
1839aea8cbfSGeert Uytterhoeven 	if (res) {
1849aea8cbfSGeert Uytterhoeven 		dev_err(&dev->sbd.core, "%s:%u: read failed %d\n", __func__,
1859aea8cbfSGeert Uytterhoeven 			__LINE__, res);
1869aea8cbfSGeert Uytterhoeven 		return DID_ERROR << 16;
1879aea8cbfSGeert Uytterhoeven 	}
1889aea8cbfSGeert Uytterhoeven 
1899aea8cbfSGeert Uytterhoeven 	return 0;
1909aea8cbfSGeert Uytterhoeven }
1919aea8cbfSGeert Uytterhoeven 
1929aea8cbfSGeert Uytterhoeven static int ps3rom_write_request(struct ps3_storage_device *dev,
1939aea8cbfSGeert Uytterhoeven 				struct scsi_cmnd *cmd, u32 start_sector,
1949aea8cbfSGeert Uytterhoeven 				u32 sectors)
1959aea8cbfSGeert Uytterhoeven {
1969aea8cbfSGeert Uytterhoeven 	int res;
1979aea8cbfSGeert Uytterhoeven 
1989aea8cbfSGeert Uytterhoeven 	dev_dbg(&dev->sbd.core, "%s:%u: write %u sectors starting at %u\n",
1999aea8cbfSGeert Uytterhoeven 		__func__, __LINE__, sectors, start_sector);
2009aea8cbfSGeert Uytterhoeven 
201944cf8b4SFUJITA Tomonori 	scsi_sg_copy_to_buffer(cmd, dev->bounce_buf, dev->bounce_size);
2029aea8cbfSGeert Uytterhoeven 
2039aea8cbfSGeert Uytterhoeven 	res = lv1_storage_write(dev->sbd.dev_id,
2049aea8cbfSGeert Uytterhoeven 				dev->regions[dev->region_idx].id, start_sector,
2059aea8cbfSGeert Uytterhoeven 				sectors, 0, dev->bounce_lpar, &dev->tag);
2069aea8cbfSGeert Uytterhoeven 	if (res) {
2079aea8cbfSGeert Uytterhoeven 		dev_err(&dev->sbd.core, "%s:%u: write failed %d\n", __func__,
2089aea8cbfSGeert Uytterhoeven 			__LINE__, res);
2099aea8cbfSGeert Uytterhoeven 		return DID_ERROR << 16;
2109aea8cbfSGeert Uytterhoeven 	}
2119aea8cbfSGeert Uytterhoeven 
2129aea8cbfSGeert Uytterhoeven 	return 0;
2139aea8cbfSGeert Uytterhoeven }
2149aea8cbfSGeert Uytterhoeven 
215f281233dSJeff Garzik static int ps3rom_queuecommand_lck(struct scsi_cmnd *cmd,
2169aea8cbfSGeert Uytterhoeven 			       void (*done)(struct scsi_cmnd *))
2179aea8cbfSGeert Uytterhoeven {
2189aea8cbfSGeert Uytterhoeven 	struct ps3rom_private *priv = shost_priv(cmd->device->host);
2199aea8cbfSGeert Uytterhoeven 	struct ps3_storage_device *dev = priv->dev;
2209aea8cbfSGeert Uytterhoeven 	unsigned char opcode;
2219aea8cbfSGeert Uytterhoeven 	int res;
2229aea8cbfSGeert Uytterhoeven 
2239aea8cbfSGeert Uytterhoeven #ifdef DEBUG
2249aea8cbfSGeert Uytterhoeven 	scsi_print_command(cmd);
2259aea8cbfSGeert Uytterhoeven #endif
2269aea8cbfSGeert Uytterhoeven 
2279aea8cbfSGeert Uytterhoeven 	priv->curr_cmd = cmd;
2289aea8cbfSGeert Uytterhoeven 	cmd->scsi_done = done;
2299aea8cbfSGeert Uytterhoeven 
2309aea8cbfSGeert Uytterhoeven 	opcode = cmd->cmnd[0];
2319aea8cbfSGeert Uytterhoeven 	/*
2329aea8cbfSGeert Uytterhoeven 	 * While we can submit READ/WRITE SCSI commands as ATAPI commands,
2339aea8cbfSGeert Uytterhoeven 	 * it's recommended for various reasons (performance, error handling,
2349aea8cbfSGeert Uytterhoeven 	 * ...) to use lv1_storage_{read,write}() instead
2359aea8cbfSGeert Uytterhoeven 	 */
2369aea8cbfSGeert Uytterhoeven 	switch (opcode) {
2379aea8cbfSGeert Uytterhoeven 	case READ_10:
2389aea8cbfSGeert Uytterhoeven 		res = ps3rom_read_request(dev, cmd, srb10_lba(cmd),
2399aea8cbfSGeert Uytterhoeven 					  srb10_len(cmd));
2409aea8cbfSGeert Uytterhoeven 		break;
2419aea8cbfSGeert Uytterhoeven 
2429aea8cbfSGeert Uytterhoeven 	case WRITE_10:
2439aea8cbfSGeert Uytterhoeven 		res = ps3rom_write_request(dev, cmd, srb10_lba(cmd),
2449aea8cbfSGeert Uytterhoeven 					   srb10_len(cmd));
2459aea8cbfSGeert Uytterhoeven 		break;
2469aea8cbfSGeert Uytterhoeven 
2479aea8cbfSGeert Uytterhoeven 	default:
2489aea8cbfSGeert Uytterhoeven 		res = ps3rom_atapi_request(dev, cmd);
2499aea8cbfSGeert Uytterhoeven 		break;
2509aea8cbfSGeert Uytterhoeven 	}
2519aea8cbfSGeert Uytterhoeven 
2529aea8cbfSGeert Uytterhoeven 	if (res) {
2539aea8cbfSGeert Uytterhoeven 		memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
2549aea8cbfSGeert Uytterhoeven 		cmd->result = res;
2559aea8cbfSGeert Uytterhoeven 		cmd->sense_buffer[0] = 0x70;
2569aea8cbfSGeert Uytterhoeven 		cmd->sense_buffer[2] = ILLEGAL_REQUEST;
2579aea8cbfSGeert Uytterhoeven 		priv->curr_cmd = NULL;
2589aea8cbfSGeert Uytterhoeven 		cmd->scsi_done(cmd);
2599aea8cbfSGeert Uytterhoeven 	}
2609aea8cbfSGeert Uytterhoeven 
2619aea8cbfSGeert Uytterhoeven 	return 0;
2629aea8cbfSGeert Uytterhoeven }
2639aea8cbfSGeert Uytterhoeven 
264f281233dSJeff Garzik static DEF_SCSI_QCMD(ps3rom_queuecommand)
265f281233dSJeff Garzik 
2669aea8cbfSGeert Uytterhoeven static int decode_lv1_status(u64 status, unsigned char *sense_key,
2679aea8cbfSGeert Uytterhoeven 			     unsigned char *asc, unsigned char *ascq)
2689aea8cbfSGeert Uytterhoeven {
2699aea8cbfSGeert Uytterhoeven 	if (((status >> 24) & 0xff) != SAM_STAT_CHECK_CONDITION)
2709aea8cbfSGeert Uytterhoeven 		return -1;
2719aea8cbfSGeert Uytterhoeven 
2729aea8cbfSGeert Uytterhoeven 	*sense_key = (status >> 16) & 0xff;
2739aea8cbfSGeert Uytterhoeven 	*asc       = (status >>  8) & 0xff;
2749aea8cbfSGeert Uytterhoeven 	*ascq      =  status        & 0xff;
2759aea8cbfSGeert Uytterhoeven 	return 0;
2769aea8cbfSGeert Uytterhoeven }
2779aea8cbfSGeert Uytterhoeven 
2789aea8cbfSGeert Uytterhoeven static irqreturn_t ps3rom_interrupt(int irq, void *data)
2799aea8cbfSGeert Uytterhoeven {
2809aea8cbfSGeert Uytterhoeven 	struct ps3_storage_device *dev = data;
2819aea8cbfSGeert Uytterhoeven 	struct Scsi_Host *host;
2829aea8cbfSGeert Uytterhoeven 	struct ps3rom_private *priv;
2839aea8cbfSGeert Uytterhoeven 	struct scsi_cmnd *cmd;
2849aea8cbfSGeert Uytterhoeven 	int res;
2859aea8cbfSGeert Uytterhoeven 	u64 tag, status;
2869aea8cbfSGeert Uytterhoeven 	unsigned char sense_key, asc, ascq;
2879aea8cbfSGeert Uytterhoeven 
2889aea8cbfSGeert Uytterhoeven 	res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
2899aea8cbfSGeert Uytterhoeven 	/*
2909aea8cbfSGeert Uytterhoeven 	 * status = -1 may mean that ATAPI transport completed OK, but
2919aea8cbfSGeert Uytterhoeven 	 * ATAPI command itself resulted CHECK CONDITION
2929aea8cbfSGeert Uytterhoeven 	 * so, upper layer should issue REQUEST_SENSE to check the sense data
2939aea8cbfSGeert Uytterhoeven 	 */
2949aea8cbfSGeert Uytterhoeven 
2959aea8cbfSGeert Uytterhoeven 	if (tag != dev->tag)
2969aea8cbfSGeert Uytterhoeven 		dev_err(&dev->sbd.core,
2977ad489e3SStephen Rothwell 			"%s:%u: tag mismatch, got %llx, expected %llx\n",
2989aea8cbfSGeert Uytterhoeven 			__func__, __LINE__, tag, dev->tag);
2999aea8cbfSGeert Uytterhoeven 
3009aea8cbfSGeert Uytterhoeven 	if (res) {
3017ad489e3SStephen Rothwell 		dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%llx\n",
3029aea8cbfSGeert Uytterhoeven 			__func__, __LINE__, res, status);
3039aea8cbfSGeert Uytterhoeven 		return IRQ_HANDLED;
3049aea8cbfSGeert Uytterhoeven 	}
3059aea8cbfSGeert Uytterhoeven 
306c4b512bcSGeert Uytterhoeven 	host = ps3_system_bus_get_drvdata(&dev->sbd);
3079aea8cbfSGeert Uytterhoeven 	priv = shost_priv(host);
3089aea8cbfSGeert Uytterhoeven 	cmd = priv->curr_cmd;
3099aea8cbfSGeert Uytterhoeven 
3109aea8cbfSGeert Uytterhoeven 	if (!status) {
3119aea8cbfSGeert Uytterhoeven 		/* OK, completed */
3129aea8cbfSGeert Uytterhoeven 		if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
313944cf8b4SFUJITA Tomonori 			int len;
314944cf8b4SFUJITA Tomonori 
315944cf8b4SFUJITA Tomonori 			len = scsi_sg_copy_from_buffer(cmd,
316944cf8b4SFUJITA Tomonori 						       dev->bounce_buf,
317944cf8b4SFUJITA Tomonori 						       dev->bounce_size);
318944cf8b4SFUJITA Tomonori 
319944cf8b4SFUJITA Tomonori 			scsi_set_resid(cmd, scsi_bufflen(cmd) - len);
3209aea8cbfSGeert Uytterhoeven 		}
3219aea8cbfSGeert Uytterhoeven 		cmd->result = DID_OK << 16;
3229aea8cbfSGeert Uytterhoeven 		goto done;
3239aea8cbfSGeert Uytterhoeven 	}
3249aea8cbfSGeert Uytterhoeven 
3259aea8cbfSGeert Uytterhoeven 	if (cmd->cmnd[0] == REQUEST_SENSE) {
3269aea8cbfSGeert Uytterhoeven 		/* SCSI spec says request sense should never get error */
3279aea8cbfSGeert Uytterhoeven 		dev_err(&dev->sbd.core, "%s:%u: end error without autosense\n",
3289aea8cbfSGeert Uytterhoeven 			__func__, __LINE__);
3299aea8cbfSGeert Uytterhoeven 		cmd->result = DID_ERROR << 16 | SAM_STAT_CHECK_CONDITION;
3309aea8cbfSGeert Uytterhoeven 		goto done;
3319aea8cbfSGeert Uytterhoeven 	}
3329aea8cbfSGeert Uytterhoeven 
3339aea8cbfSGeert Uytterhoeven 	if (decode_lv1_status(status, &sense_key, &asc, &ascq)) {
3349aea8cbfSGeert Uytterhoeven 		cmd->result = DID_ERROR << 16;
3359aea8cbfSGeert Uytterhoeven 		goto done;
3369aea8cbfSGeert Uytterhoeven 	}
3379aea8cbfSGeert Uytterhoeven 
33853df8ba8SFUJITA Tomonori 	scsi_build_sense_buffer(0, cmd->sense_buffer, sense_key, asc, ascq);
3399aea8cbfSGeert Uytterhoeven 	cmd->result = SAM_STAT_CHECK_CONDITION;
3409aea8cbfSGeert Uytterhoeven 
3419aea8cbfSGeert Uytterhoeven done:
3429aea8cbfSGeert Uytterhoeven 	priv->curr_cmd = NULL;
3439aea8cbfSGeert Uytterhoeven 	cmd->scsi_done(cmd);
3449aea8cbfSGeert Uytterhoeven 	return IRQ_HANDLED;
3459aea8cbfSGeert Uytterhoeven }
3469aea8cbfSGeert Uytterhoeven 
3479aea8cbfSGeert Uytterhoeven static struct scsi_host_template ps3rom_host_template = {
3489aea8cbfSGeert Uytterhoeven 	.name =			DEVICE_NAME,
3499aea8cbfSGeert Uytterhoeven 	.slave_configure =	ps3rom_slave_configure,
3509aea8cbfSGeert Uytterhoeven 	.queuecommand =		ps3rom_queuecommand,
3519aea8cbfSGeert Uytterhoeven 	.can_queue =		1,
3529aea8cbfSGeert Uytterhoeven 	.this_id =		7,
3539aea8cbfSGeert Uytterhoeven 	.sg_tablesize =		SG_ALL,
3549aea8cbfSGeert Uytterhoeven 	.cmd_per_lun =		1,
3559aea8cbfSGeert Uytterhoeven 	.emulated =             1,		/* only sg driver uses this */
3569aea8cbfSGeert Uytterhoeven 	.max_sectors =		PS3ROM_MAX_SECTORS,
357944cf8b4SFUJITA Tomonori 	.use_clustering =	ENABLE_CLUSTERING,
3589aea8cbfSGeert Uytterhoeven 	.module =		THIS_MODULE,
3599aea8cbfSGeert Uytterhoeven };
3609aea8cbfSGeert Uytterhoeven 
3619aea8cbfSGeert Uytterhoeven 
3626f039790SGreg Kroah-Hartman static int ps3rom_probe(struct ps3_system_bus_device *_dev)
3639aea8cbfSGeert Uytterhoeven {
3649aea8cbfSGeert Uytterhoeven 	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
3659aea8cbfSGeert Uytterhoeven 	int error;
3669aea8cbfSGeert Uytterhoeven 	struct Scsi_Host *host;
3679aea8cbfSGeert Uytterhoeven 	struct ps3rom_private *priv;
3689aea8cbfSGeert Uytterhoeven 
3699aea8cbfSGeert Uytterhoeven 	if (dev->blk_size != CD_FRAMESIZE) {
3709aea8cbfSGeert Uytterhoeven 		dev_err(&dev->sbd.core,
3717ad489e3SStephen Rothwell 			"%s:%u: cannot handle block size %llu\n", __func__,
3729aea8cbfSGeert Uytterhoeven 			__LINE__, dev->blk_size);
3739aea8cbfSGeert Uytterhoeven 		return -EINVAL;
3749aea8cbfSGeert Uytterhoeven 	}
3759aea8cbfSGeert Uytterhoeven 
3769aea8cbfSGeert Uytterhoeven 	dev->bounce_size = BOUNCE_SIZE;
3779aea8cbfSGeert Uytterhoeven 	dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA);
3789aea8cbfSGeert Uytterhoeven 	if (!dev->bounce_buf)
3799aea8cbfSGeert Uytterhoeven 		return -ENOMEM;
3809aea8cbfSGeert Uytterhoeven 
3819aea8cbfSGeert Uytterhoeven 	error = ps3stor_setup(dev, ps3rom_interrupt);
3829aea8cbfSGeert Uytterhoeven 	if (error)
3839aea8cbfSGeert Uytterhoeven 		goto fail_free_bounce;
3849aea8cbfSGeert Uytterhoeven 
3859aea8cbfSGeert Uytterhoeven 	host = scsi_host_alloc(&ps3rom_host_template,
3869aea8cbfSGeert Uytterhoeven 			       sizeof(struct ps3rom_private));
3879aea8cbfSGeert Uytterhoeven 	if (!host) {
3889aea8cbfSGeert Uytterhoeven 		dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed\n",
3899aea8cbfSGeert Uytterhoeven 			__func__, __LINE__);
3909aea8cbfSGeert Uytterhoeven 		goto fail_teardown;
3919aea8cbfSGeert Uytterhoeven 	}
3929aea8cbfSGeert Uytterhoeven 
3939aea8cbfSGeert Uytterhoeven 	priv = shost_priv(host);
394c4b512bcSGeert Uytterhoeven 	ps3_system_bus_set_drvdata(&dev->sbd, host);
3959aea8cbfSGeert Uytterhoeven 	priv->dev = dev;
3969aea8cbfSGeert Uytterhoeven 
3979aea8cbfSGeert Uytterhoeven 	/* One device/LUN per SCSI bus */
3989aea8cbfSGeert Uytterhoeven 	host->max_id = 1;
3999aea8cbfSGeert Uytterhoeven 	host->max_lun = 1;
4009aea8cbfSGeert Uytterhoeven 
4019aea8cbfSGeert Uytterhoeven 	error = scsi_add_host(host, &dev->sbd.core);
4029aea8cbfSGeert Uytterhoeven 	if (error) {
4039aea8cbfSGeert Uytterhoeven 		dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed %d\n",
4049aea8cbfSGeert Uytterhoeven 			__func__, __LINE__, error);
4059aea8cbfSGeert Uytterhoeven 		error = -ENODEV;
4069aea8cbfSGeert Uytterhoeven 		goto fail_host_put;
4079aea8cbfSGeert Uytterhoeven 	}
4089aea8cbfSGeert Uytterhoeven 
4099aea8cbfSGeert Uytterhoeven 	scsi_scan_host(host);
4109aea8cbfSGeert Uytterhoeven 	return 0;
4119aea8cbfSGeert Uytterhoeven 
4129aea8cbfSGeert Uytterhoeven fail_host_put:
4139aea8cbfSGeert Uytterhoeven 	scsi_host_put(host);
414c4b512bcSGeert Uytterhoeven 	ps3_system_bus_set_drvdata(&dev->sbd, NULL);
4159aea8cbfSGeert Uytterhoeven fail_teardown:
4169aea8cbfSGeert Uytterhoeven 	ps3stor_teardown(dev);
4179aea8cbfSGeert Uytterhoeven fail_free_bounce:
4189aea8cbfSGeert Uytterhoeven 	kfree(dev->bounce_buf);
4199aea8cbfSGeert Uytterhoeven 	return error;
4209aea8cbfSGeert Uytterhoeven }
4219aea8cbfSGeert Uytterhoeven 
4229aea8cbfSGeert Uytterhoeven static int ps3rom_remove(struct ps3_system_bus_device *_dev)
4239aea8cbfSGeert Uytterhoeven {
4249aea8cbfSGeert Uytterhoeven 	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
425c4b512bcSGeert Uytterhoeven 	struct Scsi_Host *host = ps3_system_bus_get_drvdata(&dev->sbd);
4269aea8cbfSGeert Uytterhoeven 
4279aea8cbfSGeert Uytterhoeven 	scsi_remove_host(host);
4289aea8cbfSGeert Uytterhoeven 	ps3stor_teardown(dev);
4299aea8cbfSGeert Uytterhoeven 	scsi_host_put(host);
430c4b512bcSGeert Uytterhoeven 	ps3_system_bus_set_drvdata(&dev->sbd, NULL);
4319aea8cbfSGeert Uytterhoeven 	kfree(dev->bounce_buf);
4329aea8cbfSGeert Uytterhoeven 	return 0;
4339aea8cbfSGeert Uytterhoeven }
4349aea8cbfSGeert Uytterhoeven 
4359aea8cbfSGeert Uytterhoeven static struct ps3_system_bus_driver ps3rom = {
4369aea8cbfSGeert Uytterhoeven 	.match_id	= PS3_MATCH_ID_STOR_ROM,
4379aea8cbfSGeert Uytterhoeven 	.core.name	= DEVICE_NAME,
4389aea8cbfSGeert Uytterhoeven 	.core.owner	= THIS_MODULE,
4399aea8cbfSGeert Uytterhoeven 	.probe		= ps3rom_probe,
4409aea8cbfSGeert Uytterhoeven 	.remove		= ps3rom_remove
4419aea8cbfSGeert Uytterhoeven };
4429aea8cbfSGeert Uytterhoeven 
4439aea8cbfSGeert Uytterhoeven 
4449aea8cbfSGeert Uytterhoeven static int __init ps3rom_init(void)
4459aea8cbfSGeert Uytterhoeven {
4469aea8cbfSGeert Uytterhoeven 	return ps3_system_bus_driver_register(&ps3rom);
4479aea8cbfSGeert Uytterhoeven }
4489aea8cbfSGeert Uytterhoeven 
4499aea8cbfSGeert Uytterhoeven static void __exit ps3rom_exit(void)
4509aea8cbfSGeert Uytterhoeven {
4519aea8cbfSGeert Uytterhoeven 	ps3_system_bus_driver_unregister(&ps3rom);
4529aea8cbfSGeert Uytterhoeven }
4539aea8cbfSGeert Uytterhoeven 
4549aea8cbfSGeert Uytterhoeven module_init(ps3rom_init);
4559aea8cbfSGeert Uytterhoeven module_exit(ps3rom_exit);
4569aea8cbfSGeert Uytterhoeven 
4579aea8cbfSGeert Uytterhoeven MODULE_LICENSE("GPL");
4589aea8cbfSGeert Uytterhoeven MODULE_DESCRIPTION("PS3 BD/DVD/CD-ROM Storage Driver");
4599aea8cbfSGeert Uytterhoeven MODULE_AUTHOR("Sony Corporation");
4609aea8cbfSGeert Uytterhoeven MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_ROM);
461