File Index
Files and directories
Sign in
FILE

ps3rom.c

File preview with syntax highlighting.

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