xref: /openbmc/linux/drivers/ps3/ps3stor_lib.c (revision d0edaa28)
1935912c5SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
280071802SGeert Uytterhoeven /*
380071802SGeert Uytterhoeven  * PS3 Storage Library
480071802SGeert Uytterhoeven  *
580071802SGeert Uytterhoeven  * Copyright (C) 2007 Sony Computer Entertainment Inc.
680071802SGeert Uytterhoeven  * Copyright 2007 Sony Corp.
780071802SGeert Uytterhoeven  */
880071802SGeert Uytterhoeven 
980071802SGeert Uytterhoeven #include <linux/dma-mapping.h>
107dfe293cSPaul Gortmaker #include <linux/module.h>
1180071802SGeert Uytterhoeven 
1280071802SGeert Uytterhoeven #include <asm/lv1call.h>
1380071802SGeert Uytterhoeven #include <asm/ps3stor.h>
1480071802SGeert Uytterhoeven 
15bc00351eSGeoff Levand /*
16bc00351eSGeoff Levand  * A workaround for flash memory I/O errors when the internal hard disk
17bc00351eSGeoff Levand  * has not been formatted for OtherOS use.  Delay disk close until flash
18bc00351eSGeoff Levand  * memory is closed.
19bc00351eSGeoff Levand  */
20bc00351eSGeoff Levand 
21bc00351eSGeoff Levand static struct ps3_flash_workaround {
22bc00351eSGeoff Levand 	int flash_open;
23bc00351eSGeoff Levand 	int disk_open;
24bc00351eSGeoff Levand 	struct ps3_system_bus_device *disk_sbd;
25bc00351eSGeoff Levand } ps3_flash_workaround;
26bc00351eSGeoff Levand 
ps3stor_open_hv_device(struct ps3_system_bus_device * sbd)27bc00351eSGeoff Levand static int ps3stor_open_hv_device(struct ps3_system_bus_device *sbd)
28bc00351eSGeoff Levand {
29bc00351eSGeoff Levand 	int error = ps3_open_hv_device(sbd);
30bc00351eSGeoff Levand 
31bc00351eSGeoff Levand 	if (error)
32bc00351eSGeoff Levand 		return error;
33bc00351eSGeoff Levand 
34bc00351eSGeoff Levand 	if (sbd->match_id == PS3_MATCH_ID_STOR_FLASH)
35bc00351eSGeoff Levand 		ps3_flash_workaround.flash_open = 1;
36bc00351eSGeoff Levand 
37bc00351eSGeoff Levand 	if (sbd->match_id == PS3_MATCH_ID_STOR_DISK)
38bc00351eSGeoff Levand 		ps3_flash_workaround.disk_open = 1;
39bc00351eSGeoff Levand 
40bc00351eSGeoff Levand 	return 0;
41bc00351eSGeoff Levand }
42bc00351eSGeoff Levand 
ps3stor_close_hv_device(struct ps3_system_bus_device * sbd)43bc00351eSGeoff Levand static int ps3stor_close_hv_device(struct ps3_system_bus_device *sbd)
44bc00351eSGeoff Levand {
45bc00351eSGeoff Levand 	int error;
46bc00351eSGeoff Levand 
47bc00351eSGeoff Levand 	if (sbd->match_id == PS3_MATCH_ID_STOR_DISK
48bc00351eSGeoff Levand 		&& ps3_flash_workaround.disk_open
49bc00351eSGeoff Levand 		&& ps3_flash_workaround.flash_open) {
50bc00351eSGeoff Levand 		ps3_flash_workaround.disk_sbd = sbd;
51bc00351eSGeoff Levand 		return 0;
52bc00351eSGeoff Levand 	}
53bc00351eSGeoff Levand 
54bc00351eSGeoff Levand 	error = ps3_close_hv_device(sbd);
55bc00351eSGeoff Levand 
56bc00351eSGeoff Levand 	if (error)
57bc00351eSGeoff Levand 		return error;
58bc00351eSGeoff Levand 
59bc00351eSGeoff Levand 	if (sbd->match_id == PS3_MATCH_ID_STOR_DISK)
60bc00351eSGeoff Levand 		ps3_flash_workaround.disk_open = 0;
61bc00351eSGeoff Levand 
62bc00351eSGeoff Levand 	if (sbd->match_id == PS3_MATCH_ID_STOR_FLASH) {
63bc00351eSGeoff Levand 		ps3_flash_workaround.flash_open = 0;
64bc00351eSGeoff Levand 
65bc00351eSGeoff Levand 		if (ps3_flash_workaround.disk_sbd) {
66bc00351eSGeoff Levand 			ps3_close_hv_device(ps3_flash_workaround.disk_sbd);
67bc00351eSGeoff Levand 			ps3_flash_workaround.disk_open = 0;
68bc00351eSGeoff Levand 			ps3_flash_workaround.disk_sbd = NULL;
69bc00351eSGeoff Levand 		}
70bc00351eSGeoff Levand 	}
71bc00351eSGeoff Levand 
72bc00351eSGeoff Levand 	return 0;
73bc00351eSGeoff Levand }
7480071802SGeert Uytterhoeven 
ps3stor_probe_access(struct ps3_storage_device * dev)7580071802SGeert Uytterhoeven static int ps3stor_probe_access(struct ps3_storage_device *dev)
7680071802SGeert Uytterhoeven {
7780071802SGeert Uytterhoeven 	int res, error;
7880071802SGeert Uytterhoeven 	unsigned int i;
7980071802SGeert Uytterhoeven 	unsigned long n;
8080071802SGeert Uytterhoeven 
8180071802SGeert Uytterhoeven 	if (dev->sbd.match_id == PS3_MATCH_ID_STOR_ROM) {
8280071802SGeert Uytterhoeven 		/* special case: CD-ROM is assumed always accessible */
8380071802SGeert Uytterhoeven 		dev->accessible_regions = 1;
8480071802SGeert Uytterhoeven 		return 0;
8580071802SGeert Uytterhoeven 	}
8680071802SGeert Uytterhoeven 
8780071802SGeert Uytterhoeven 	error = -EPERM;
8880071802SGeert Uytterhoeven 	for (i = 0; i < dev->num_regions; i++) {
8980071802SGeert Uytterhoeven 		dev_dbg(&dev->sbd.core,
9080071802SGeert Uytterhoeven 			"%s:%u: checking accessibility of region %u\n",
9180071802SGeert Uytterhoeven 			__func__, __LINE__, i);
9280071802SGeert Uytterhoeven 
9380071802SGeert Uytterhoeven 		dev->region_idx = i;
9480071802SGeert Uytterhoeven 		res = ps3stor_read_write_sectors(dev, dev->bounce_lpar, 0, 1,
9580071802SGeert Uytterhoeven 						 0);
9680071802SGeert Uytterhoeven 		if (res) {
9780071802SGeert Uytterhoeven 			dev_dbg(&dev->sbd.core, "%s:%u: read failed, "
9880071802SGeert Uytterhoeven 				"region %u is not accessible\n", __func__,
9980071802SGeert Uytterhoeven 				__LINE__, i);
10080071802SGeert Uytterhoeven 			continue;
10180071802SGeert Uytterhoeven 		}
10280071802SGeert Uytterhoeven 
10380071802SGeert Uytterhoeven 		dev_dbg(&dev->sbd.core, "%s:%u: region %u is accessible\n",
10480071802SGeert Uytterhoeven 			__func__, __LINE__, i);
10580071802SGeert Uytterhoeven 		set_bit(i, &dev->accessible_regions);
10680071802SGeert Uytterhoeven 
10780071802SGeert Uytterhoeven 		/* We can access at least one region */
10880071802SGeert Uytterhoeven 		error = 0;
10980071802SGeert Uytterhoeven 	}
11080071802SGeert Uytterhoeven 	if (error)
11180071802SGeert Uytterhoeven 		return error;
11280071802SGeert Uytterhoeven 
11380071802SGeert Uytterhoeven 	n = hweight_long(dev->accessible_regions);
11480071802SGeert Uytterhoeven 	if (n > 1)
11580071802SGeert Uytterhoeven 		dev_info(&dev->sbd.core,
11680071802SGeert Uytterhoeven 			 "%s:%u: %lu accessible regions found. Only the first "
117898eb71cSJoe Perches 			 "one will be used\n",
11880071802SGeert Uytterhoeven 			 __func__, __LINE__, n);
11980071802SGeert Uytterhoeven 	dev->region_idx = __ffs(dev->accessible_regions);
12080071802SGeert Uytterhoeven 	dev_info(&dev->sbd.core,
121a9dad6e5SStephen Rothwell 		 "First accessible region has index %u start %llu size %llu\n",
12280071802SGeert Uytterhoeven 		 dev->region_idx, dev->regions[dev->region_idx].start,
12380071802SGeert Uytterhoeven 		 dev->regions[dev->region_idx].size);
12480071802SGeert Uytterhoeven 
12580071802SGeert Uytterhoeven 	return 0;
12680071802SGeert Uytterhoeven }
12780071802SGeert Uytterhoeven 
12880071802SGeert Uytterhoeven 
12980071802SGeert Uytterhoeven /**
13080071802SGeert Uytterhoeven  *	ps3stor_setup - Setup a storage device before use
13180071802SGeert Uytterhoeven  *	@dev: Pointer to a struct ps3_storage_device
13280071802SGeert Uytterhoeven  *	@handler: Pointer to an interrupt handler
13380071802SGeert Uytterhoeven  *
13480071802SGeert Uytterhoeven  *	Returns 0 for success, or an error code
13580071802SGeert Uytterhoeven  */
ps3stor_setup(struct ps3_storage_device * dev,irq_handler_t handler)13680071802SGeert Uytterhoeven int ps3stor_setup(struct ps3_storage_device *dev, irq_handler_t handler)
13780071802SGeert Uytterhoeven {
13880071802SGeert Uytterhoeven 	int error, res, alignment;
13980071802SGeert Uytterhoeven 	enum ps3_dma_page_size page_size;
14080071802SGeert Uytterhoeven 
141bc00351eSGeoff Levand 	error = ps3stor_open_hv_device(&dev->sbd);
14280071802SGeert Uytterhoeven 	if (error) {
14380071802SGeert Uytterhoeven 		dev_err(&dev->sbd.core,
14480071802SGeert Uytterhoeven 			"%s:%u: ps3_open_hv_device failed %d\n", __func__,
14580071802SGeert Uytterhoeven 			__LINE__, error);
14680071802SGeert Uytterhoeven 		goto fail;
14780071802SGeert Uytterhoeven 	}
14880071802SGeert Uytterhoeven 
14980071802SGeert Uytterhoeven 	error = ps3_sb_event_receive_port_setup(&dev->sbd, PS3_BINDING_CPU_ANY,
15080071802SGeert Uytterhoeven 						&dev->irq);
15180071802SGeert Uytterhoeven 	if (error) {
15280071802SGeert Uytterhoeven 		dev_err(&dev->sbd.core,
15380071802SGeert Uytterhoeven 			"%s:%u: ps3_sb_event_receive_port_setup failed %d\n",
15480071802SGeert Uytterhoeven 		       __func__, __LINE__, error);
15580071802SGeert Uytterhoeven 		goto fail_close_device;
15680071802SGeert Uytterhoeven 	}
15780071802SGeert Uytterhoeven 
1586ea741a1SYong Zhang 	error = request_irq(dev->irq, handler, 0,
15980071802SGeert Uytterhoeven 			    dev->sbd.core.driver->name, dev);
16080071802SGeert Uytterhoeven 	if (error) {
16180071802SGeert Uytterhoeven 		dev_err(&dev->sbd.core, "%s:%u: request_irq failed %d\n",
16280071802SGeert Uytterhoeven 			__func__, __LINE__, error);
16380071802SGeert Uytterhoeven 		goto fail_sb_event_receive_port_destroy;
16480071802SGeert Uytterhoeven 	}
16580071802SGeert Uytterhoeven 
16680071802SGeert Uytterhoeven 	alignment = min(__ffs(dev->bounce_size),
16780071802SGeert Uytterhoeven 			__ffs((unsigned long)dev->bounce_buf));
16880071802SGeert Uytterhoeven 	if (alignment < 12) {
16980071802SGeert Uytterhoeven 		dev_err(&dev->sbd.core,
17080071802SGeert Uytterhoeven 			"%s:%u: bounce buffer not aligned (%lx at 0x%p)\n",
17180071802SGeert Uytterhoeven 			__func__, __LINE__, dev->bounce_size, dev->bounce_buf);
17280071802SGeert Uytterhoeven 		error = -EINVAL;
17380071802SGeert Uytterhoeven 		goto fail_free_irq;
17480071802SGeert Uytterhoeven 	} else if (alignment < 16)
17580071802SGeert Uytterhoeven 		page_size = PS3_DMA_4K;
17680071802SGeert Uytterhoeven 	else
17780071802SGeert Uytterhoeven 		page_size = PS3_DMA_64K;
17880071802SGeert Uytterhoeven 	dev->sbd.d_region = &dev->dma_region;
17980071802SGeert Uytterhoeven 	ps3_dma_region_init(&dev->sbd, &dev->dma_region, page_size,
18080071802SGeert Uytterhoeven 			    PS3_DMA_OTHER, dev->bounce_buf, dev->bounce_size);
18180071802SGeert Uytterhoeven 	res = ps3_dma_region_create(&dev->dma_region);
18280071802SGeert Uytterhoeven 	if (res) {
18380071802SGeert Uytterhoeven 		dev_err(&dev->sbd.core, "%s:%u: cannot create DMA region\n",
18480071802SGeert Uytterhoeven 			__func__, __LINE__);
18580071802SGeert Uytterhoeven 		error = -ENOMEM;
18680071802SGeert Uytterhoeven 		goto fail_free_irq;
18780071802SGeert Uytterhoeven 	}
18880071802SGeert Uytterhoeven 
18980071802SGeert Uytterhoeven 	dev->bounce_lpar = ps3_mm_phys_to_lpar(__pa(dev->bounce_buf));
19080071802SGeert Uytterhoeven 	dev->bounce_dma = dma_map_single(&dev->sbd.core, dev->bounce_buf,
19180071802SGeert Uytterhoeven 					 dev->bounce_size, DMA_BIDIRECTIONAL);
192*d0edaa28SVincent Stehlé 	if (dma_mapping_error(&dev->sbd.core, dev->bounce_dma)) {
19380071802SGeert Uytterhoeven 		dev_err(&dev->sbd.core, "%s:%u: map DMA region failed\n",
19480071802SGeert Uytterhoeven 			__func__, __LINE__);
19580071802SGeert Uytterhoeven 		error = -ENODEV;
19680071802SGeert Uytterhoeven 		goto fail_free_dma;
19780071802SGeert Uytterhoeven 	}
19880071802SGeert Uytterhoeven 
19980071802SGeert Uytterhoeven 	error = ps3stor_probe_access(dev);
20080071802SGeert Uytterhoeven 	if (error) {
20180071802SGeert Uytterhoeven 		dev_err(&dev->sbd.core, "%s:%u: No accessible regions found\n",
20280071802SGeert Uytterhoeven 			__func__, __LINE__);
20380071802SGeert Uytterhoeven 		goto fail_unmap_dma;
20480071802SGeert Uytterhoeven 	}
20580071802SGeert Uytterhoeven 	return 0;
20680071802SGeert Uytterhoeven 
20780071802SGeert Uytterhoeven fail_unmap_dma:
20880071802SGeert Uytterhoeven 	dma_unmap_single(&dev->sbd.core, dev->bounce_dma, dev->bounce_size,
20980071802SGeert Uytterhoeven 			 DMA_BIDIRECTIONAL);
21080071802SGeert Uytterhoeven fail_free_dma:
21180071802SGeert Uytterhoeven 	ps3_dma_region_free(&dev->dma_region);
21280071802SGeert Uytterhoeven fail_free_irq:
21380071802SGeert Uytterhoeven 	free_irq(dev->irq, dev);
21480071802SGeert Uytterhoeven fail_sb_event_receive_port_destroy:
21580071802SGeert Uytterhoeven 	ps3_sb_event_receive_port_destroy(&dev->sbd, dev->irq);
21680071802SGeert Uytterhoeven fail_close_device:
217bc00351eSGeoff Levand 	ps3stor_close_hv_device(&dev->sbd);
21880071802SGeert Uytterhoeven fail:
21980071802SGeert Uytterhoeven 	return error;
22080071802SGeert Uytterhoeven }
22180071802SGeert Uytterhoeven EXPORT_SYMBOL_GPL(ps3stor_setup);
22280071802SGeert Uytterhoeven 
22380071802SGeert Uytterhoeven 
22480071802SGeert Uytterhoeven /**
22580071802SGeert Uytterhoeven  *	ps3stor_teardown - Tear down a storage device after use
22680071802SGeert Uytterhoeven  *	@dev: Pointer to a struct ps3_storage_device
22780071802SGeert Uytterhoeven  */
ps3stor_teardown(struct ps3_storage_device * dev)22880071802SGeert Uytterhoeven void ps3stor_teardown(struct ps3_storage_device *dev)
22980071802SGeert Uytterhoeven {
23080071802SGeert Uytterhoeven 	int error;
23180071802SGeert Uytterhoeven 
23280071802SGeert Uytterhoeven 	dma_unmap_single(&dev->sbd.core, dev->bounce_dma, dev->bounce_size,
23380071802SGeert Uytterhoeven 			 DMA_BIDIRECTIONAL);
23480071802SGeert Uytterhoeven 	ps3_dma_region_free(&dev->dma_region);
23580071802SGeert Uytterhoeven 
23680071802SGeert Uytterhoeven 	free_irq(dev->irq, dev);
23780071802SGeert Uytterhoeven 
23880071802SGeert Uytterhoeven 	error = ps3_sb_event_receive_port_destroy(&dev->sbd, dev->irq);
23980071802SGeert Uytterhoeven 	if (error)
24080071802SGeert Uytterhoeven 		dev_err(&dev->sbd.core,
24180071802SGeert Uytterhoeven 			"%s:%u: destroy event receive port failed %d\n",
24280071802SGeert Uytterhoeven 			__func__, __LINE__, error);
24380071802SGeert Uytterhoeven 
244bc00351eSGeoff Levand 	error = ps3stor_close_hv_device(&dev->sbd);
24580071802SGeert Uytterhoeven 	if (error)
24680071802SGeert Uytterhoeven 		dev_err(&dev->sbd.core,
24780071802SGeert Uytterhoeven 			"%s:%u: ps3_close_hv_device failed %d\n", __func__,
24880071802SGeert Uytterhoeven 			__LINE__, error);
24980071802SGeert Uytterhoeven }
25080071802SGeert Uytterhoeven EXPORT_SYMBOL_GPL(ps3stor_teardown);
25180071802SGeert Uytterhoeven 
25280071802SGeert Uytterhoeven 
25380071802SGeert Uytterhoeven /**
25480071802SGeert Uytterhoeven  *	ps3stor_read_write_sectors - read/write from/to a storage device
25580071802SGeert Uytterhoeven  *	@dev: Pointer to a struct ps3_storage_device
25680071802SGeert Uytterhoeven  *	@lpar: HV logical partition address
25780071802SGeert Uytterhoeven  *	@start_sector: First sector to read/write
25880071802SGeert Uytterhoeven  *	@sectors: Number of sectors to read/write
25980071802SGeert Uytterhoeven  *	@write: Flag indicating write (non-zero) or read (zero)
26080071802SGeert Uytterhoeven  *
26180071802SGeert Uytterhoeven  *	Returns 0 for success, -1 in case of failure to submit the command, or
26280071802SGeert Uytterhoeven  *	an LV1 status value in case of other errors
26380071802SGeert Uytterhoeven  */
ps3stor_read_write_sectors(struct ps3_storage_device * dev,u64 lpar,u64 start_sector,u64 sectors,int write)26480071802SGeert Uytterhoeven u64 ps3stor_read_write_sectors(struct ps3_storage_device *dev, u64 lpar,
26580071802SGeert Uytterhoeven 			       u64 start_sector, u64 sectors, int write)
26680071802SGeert Uytterhoeven {
26780071802SGeert Uytterhoeven 	unsigned int region_id = dev->regions[dev->region_idx].id;
26880071802SGeert Uytterhoeven 	const char *op = write ? "write" : "read";
26980071802SGeert Uytterhoeven 	int res;
27080071802SGeert Uytterhoeven 
271a9dad6e5SStephen Rothwell 	dev_dbg(&dev->sbd.core, "%s:%u: %s %llu sectors starting at %llu\n",
27280071802SGeert Uytterhoeven 		__func__, __LINE__, op, sectors, start_sector);
27380071802SGeert Uytterhoeven 
27480071802SGeert Uytterhoeven 	init_completion(&dev->done);
27580071802SGeert Uytterhoeven 	res = write ? lv1_storage_write(dev->sbd.dev_id, region_id,
27680071802SGeert Uytterhoeven 					start_sector, sectors, 0, lpar,
27780071802SGeert Uytterhoeven 					&dev->tag)
27880071802SGeert Uytterhoeven 		    : lv1_storage_read(dev->sbd.dev_id, region_id,
27980071802SGeert Uytterhoeven 				       start_sector, sectors, 0, lpar,
28080071802SGeert Uytterhoeven 				       &dev->tag);
28180071802SGeert Uytterhoeven 	if (res) {
28280071802SGeert Uytterhoeven 		dev_dbg(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__,
28380071802SGeert Uytterhoeven 			__LINE__, op, res);
28480071802SGeert Uytterhoeven 		return -1;
28580071802SGeert Uytterhoeven 	}
28680071802SGeert Uytterhoeven 
28780071802SGeert Uytterhoeven 	wait_for_completion(&dev->done);
28880071802SGeert Uytterhoeven 	if (dev->lv1_status) {
289a9dad6e5SStephen Rothwell 		dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__,
29080071802SGeert Uytterhoeven 			__LINE__, op, dev->lv1_status);
29180071802SGeert Uytterhoeven 		return dev->lv1_status;
29280071802SGeert Uytterhoeven 	}
29380071802SGeert Uytterhoeven 
29480071802SGeert Uytterhoeven 	dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__, __LINE__,
29580071802SGeert Uytterhoeven 		op);
29680071802SGeert Uytterhoeven 
29780071802SGeert Uytterhoeven 	return 0;
29880071802SGeert Uytterhoeven }
29980071802SGeert Uytterhoeven EXPORT_SYMBOL_GPL(ps3stor_read_write_sectors);
30080071802SGeert Uytterhoeven 
30180071802SGeert Uytterhoeven 
30280071802SGeert Uytterhoeven /**
30380071802SGeert Uytterhoeven  *	ps3stor_send_command - send a device command to a storage device
30480071802SGeert Uytterhoeven  *	@dev: Pointer to a struct ps3_storage_device
30580071802SGeert Uytterhoeven  *	@cmd: Command number
30680071802SGeert Uytterhoeven  *	@arg1: First command argument
30780071802SGeert Uytterhoeven  *	@arg2: Second command argument
30880071802SGeert Uytterhoeven  *	@arg3: Third command argument
30980071802SGeert Uytterhoeven  *	@arg4: Fourth command argument
31080071802SGeert Uytterhoeven  *
31180071802SGeert Uytterhoeven  *	Returns 0 for success, -1 in case of failure to submit the command, or
31280071802SGeert Uytterhoeven  *	an LV1 status value in case of other errors
31380071802SGeert Uytterhoeven  */
ps3stor_send_command(struct ps3_storage_device * dev,u64 cmd,u64 arg1,u64 arg2,u64 arg3,u64 arg4)31480071802SGeert Uytterhoeven u64 ps3stor_send_command(struct ps3_storage_device *dev, u64 cmd, u64 arg1,
31580071802SGeert Uytterhoeven 			 u64 arg2, u64 arg3, u64 arg4)
31680071802SGeert Uytterhoeven {
31780071802SGeert Uytterhoeven 	int res;
31880071802SGeert Uytterhoeven 
319a9dad6e5SStephen Rothwell 	dev_dbg(&dev->sbd.core, "%s:%u: send device command 0x%llx\n", __func__,
32080071802SGeert Uytterhoeven 		__LINE__, cmd);
32180071802SGeert Uytterhoeven 
32280071802SGeert Uytterhoeven 	init_completion(&dev->done);
32380071802SGeert Uytterhoeven 
32480071802SGeert Uytterhoeven 	res = lv1_storage_send_device_command(dev->sbd.dev_id, cmd, arg1,
32580071802SGeert Uytterhoeven 					      arg2, arg3, arg4, &dev->tag);
32680071802SGeert Uytterhoeven 	if (res) {
32780071802SGeert Uytterhoeven 		dev_err(&dev->sbd.core,
328a9dad6e5SStephen Rothwell 			"%s:%u: send_device_command 0x%llx failed %d\n",
32980071802SGeert Uytterhoeven 			__func__, __LINE__, cmd, res);
33080071802SGeert Uytterhoeven 		return -1;
33180071802SGeert Uytterhoeven 	}
33280071802SGeert Uytterhoeven 
33380071802SGeert Uytterhoeven 	wait_for_completion(&dev->done);
33480071802SGeert Uytterhoeven 	if (dev->lv1_status) {
335a9dad6e5SStephen Rothwell 		dev_dbg(&dev->sbd.core, "%s:%u: command 0x%llx failed 0x%llx\n",
33680071802SGeert Uytterhoeven 			__func__, __LINE__, cmd, dev->lv1_status);
33780071802SGeert Uytterhoeven 		return dev->lv1_status;
33880071802SGeert Uytterhoeven 	}
33980071802SGeert Uytterhoeven 
340a9dad6e5SStephen Rothwell 	dev_dbg(&dev->sbd.core, "%s:%u: command 0x%llx completed\n", __func__,
34180071802SGeert Uytterhoeven 		__LINE__, cmd);
34280071802SGeert Uytterhoeven 
34380071802SGeert Uytterhoeven 	return 0;
34480071802SGeert Uytterhoeven }
34580071802SGeert Uytterhoeven EXPORT_SYMBOL_GPL(ps3stor_send_command);
34680071802SGeert Uytterhoeven 
34780071802SGeert Uytterhoeven 
34880071802SGeert Uytterhoeven MODULE_LICENSE("GPL");
34980071802SGeert Uytterhoeven MODULE_DESCRIPTION("PS3 Storage Bus Library");
35080071802SGeert Uytterhoeven MODULE_AUTHOR("Sony Corporation");
351