1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru)
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/sysctl.h>
32#include <sys/disk.h>
33#include <sys/bio.h>
34#include <sys/bus.h>
35#include <sys/conf.h>
36#include <sys/kernel.h>
37#include <sys/kthread.h>
38#include <sys/lock.h>
39#include <sys/malloc.h>
40#include <sys/module.h>
41#include <sys/mutex.h>
42
43#include <vm/vm.h>
44#include <vm/pmap.h>
45
46#include <machine/pio.h>
47#include <machine/bus.h>
48#include <machine/platform.h>
49#include <machine/resource.h>
50#include <sys/bus.h>
51#include <sys/rman.h>
52
53#include <geom/geom_disk.h>
54
55#include "ps3bus.h"
56#include "ps3-hvcall.h"
57
58#define PS3DISK_LOCK_INIT(_sc)		\
59	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), "ps3disk", MTX_DEF)
60#define PS3DISK_LOCK_DESTROY(_sc)	mtx_destroy(&_sc->sc_mtx);
61#define PS3DISK_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
62#define	PS3DISK_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
63#define PS3DISK_ASSERT_LOCKED(_sc)	mtx_assert(&_sc->sc_mtx, MA_OWNED);
64#define PS3DISK_ASSERT_UNLOCKED(_sc)	mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
65
66#define LV1_STORAGE_ATA_HDDOUT 		0x23
67
68static SYSCTL_NODE(_hw, OID_AUTO, ps3disk, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
69    "PS3 Disk driver parameters");
70
71#ifdef PS3DISK_DEBUG
72static int ps3disk_debug = 0;
73SYSCTL_INT(_hw_ps3disk, OID_AUTO, debug, CTLFLAG_RW, &ps3disk_debug,
74	0, "control debugging printfs");
75TUNABLE_INT("hw.ps3disk.debug", &ps3disk_debug);
76enum {
77	PS3DISK_DEBUG_INTR	= 0x00000001,
78	PS3DISK_DEBUG_TASK	= 0x00000002,
79	PS3DISK_DEBUG_READ	= 0x00000004,
80	PS3DISK_DEBUG_WRITE	= 0x00000008,
81	PS3DISK_DEBUG_FLUSH	= 0x00000010,
82	PS3DISK_DEBUG_ANY	= 0xffffffff
83};
84#define	DPRINTF(sc, m, fmt, ...)				\
85do {								\
86	if (sc->sc_debug & (m))					\
87		printf(fmt, __VA_ARGS__);			\
88} while (0)
89#else
90#define	DPRINTF(sc, m, fmt, ...)
91#endif
92
93struct ps3disk_region {
94	uint64_t r_id;
95	uint64_t r_start;
96	uint64_t r_size;
97	uint64_t r_flags;
98};
99
100struct ps3disk_softc {
101	device_t sc_dev;
102
103	struct mtx sc_mtx;
104
105	uint64_t sc_blksize;
106	uint64_t sc_nblocks;
107
108	uint64_t sc_nregs;
109	struct ps3disk_region *sc_reg;
110
111	int sc_irqid;
112	struct resource	*sc_irq;
113	void *sc_irqctx;
114
115	struct disk **sc_disk;
116
117	struct bio_queue_head sc_bioq;
118	struct bio_queue_head sc_deferredq;
119	struct proc *sc_task;
120
121	bus_dma_tag_t sc_dmatag;
122
123	int sc_running;
124	int sc_debug;
125};
126
127static int ps3disk_open(struct disk *dp);
128static int ps3disk_close(struct disk *dp);
129static void ps3disk_strategy(struct bio *bp);
130
131static void ps3disk_task(void *arg);
132static void ps3disk_intr(void *arg);
133static int ps3disk_get_disk_geometry(struct ps3disk_softc *sc);
134static int ps3disk_enum_regions(struct ps3disk_softc *sc);
135static void ps3disk_transfer(void *arg, bus_dma_segment_t *segs, int nsegs,
136    int error);
137
138static void ps3disk_sysctlattach(struct ps3disk_softc *sc);
139
140static MALLOC_DEFINE(M_PS3DISK, "ps3disk", "PS3 Disk");
141
142static int
143ps3disk_probe(device_t dev)
144{
145	if (ps3bus_get_bustype(dev) != PS3_BUSTYPE_STORAGE ||
146	    ps3bus_get_devtype(dev) != PS3_DEVTYPE_DISK)
147		return (ENXIO);
148
149	device_set_desc(dev, "Playstation 3 Disk");
150
151	return (BUS_PROBE_SPECIFIC);
152}
153
154static int
155ps3disk_attach(device_t dev)
156{
157	struct ps3disk_softc *sc;
158	struct disk *d;
159	intmax_t mb;
160	uint64_t junk;
161	char unit;
162	int i, err;
163
164	sc = device_get_softc(dev);
165	sc->sc_dev = dev;
166
167	PS3DISK_LOCK_INIT(sc);
168
169	err = ps3disk_get_disk_geometry(sc);
170	if (err) {
171		device_printf(dev, "Could not get disk geometry\n");
172		err = ENXIO;
173		goto fail_destroy_lock;
174	}
175
176	device_printf(dev, "block size %lu total blocks %lu\n",
177	    sc->sc_blksize, sc->sc_nblocks);
178
179	err = ps3disk_enum_regions(sc);
180	if (err) {
181		device_printf(dev, "Could not enumerate disk regions\n");
182		err = ENXIO;
183		goto fail_destroy_lock;
184	}
185
186	device_printf(dev, "Found %lu regions\n", sc->sc_nregs);
187
188	if (!sc->sc_nregs) {
189		err = ENXIO;
190		goto fail_destroy_lock;
191	}
192
193	/* Setup interrupt handler */
194	sc->sc_irqid = 0;
195	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid,
196	    RF_ACTIVE);
197	if (!sc->sc_irq) {
198		device_printf(dev, "Could not allocate IRQ\n");
199		err = ENXIO;
200		goto fail_free_regions;
201	}
202
203	err = bus_setup_intr(dev, sc->sc_irq,
204	    INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY,
205	    NULL, ps3disk_intr, sc, &sc->sc_irqctx);
206	if (err) {
207		device_printf(dev, "Could not setup IRQ\n");
208		err = ENXIO;
209		goto fail_release_intr;
210	}
211
212	/* Setup DMA */
213	err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0,
214	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
215	    BUS_SPACE_UNRESTRICTED, 1, PAGE_SIZE, 0,
216	    busdma_lock_mutex, &sc->sc_mtx, &sc->sc_dmatag);
217	if (err) {
218		device_printf(dev, "Could not create DMA tag\n");
219		err = ENXIO;
220		goto fail_teardown_intr;
221	}
222
223	/* Setup disks */
224
225	sc->sc_disk = malloc(sc->sc_nregs * sizeof(struct disk *),
226	    M_PS3DISK, M_ZERO | M_WAITOK);
227	if (!sc->sc_disk) {
228		device_printf(dev, "Could not allocate disk(s)\n");
229		err = ENOMEM;
230		goto fail_teardown_intr;
231	}
232
233	for (i = 0; i < sc->sc_nregs; i++) {
234		struct ps3disk_region *rp = &sc->sc_reg[i];
235
236		d = sc->sc_disk[i] = disk_alloc();
237		d->d_open = ps3disk_open;
238		d->d_close = ps3disk_close;
239		d->d_strategy = ps3disk_strategy;
240		d->d_name = "ps3disk";
241		d->d_drv1 = sc;
242		d->d_maxsize = PAGE_SIZE;
243		d->d_sectorsize = sc->sc_blksize;
244		d->d_unit = i;
245		d->d_mediasize = sc->sc_reg[i].r_size * sc->sc_blksize;
246		d->d_flags |= DISKFLAG_CANFLUSHCACHE;
247
248		mb = d->d_mediasize >> 20;
249		unit = 'M';
250		if (mb >= 10240) {
251			unit = 'G';
252			mb /= 1024;
253		}
254
255		/* Test to see if we can read this region */
256		err = lv1_storage_read(ps3bus_get_device(dev), d->d_unit,
257		    0, 0, rp->r_flags, 0, &junk);
258		device_printf(dev, "region %d %ju%cB%s\n", i, mb, unit,
259		    (err == LV1_DENIED_BY_POLICY) ?  " (hypervisor protected)"
260		    : "");
261
262		if (err != LV1_DENIED_BY_POLICY)
263			disk_create(d, DISK_VERSION);
264	}
265	err = 0;
266
267	bioq_init(&sc->sc_bioq);
268	bioq_init(&sc->sc_deferredq);
269	kproc_create(&ps3disk_task, sc, &sc->sc_task, 0, 0, "ps3disk");
270
271	ps3disk_sysctlattach(sc);
272	sc->sc_running = 1;
273	return (0);
274
275fail_teardown_intr:
276	bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
277fail_release_intr:
278	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
279fail_free_regions:
280	free(sc->sc_reg, M_PS3DISK);
281fail_destroy_lock:
282	PS3DISK_LOCK_DESTROY(sc);
283	return (err);
284}
285
286static int
287ps3disk_detach(device_t dev)
288{
289	struct ps3disk_softc *sc = device_get_softc(dev);
290	int i;
291
292	for (i = 0; i < sc->sc_nregs; i++)
293		disk_destroy(sc->sc_disk[i]);
294
295	bus_dma_tag_destroy(sc->sc_dmatag);
296
297	bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
298	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
299
300	free(sc->sc_disk, M_PS3DISK);
301	free(sc->sc_reg, M_PS3DISK);
302
303	PS3DISK_LOCK_DESTROY(sc);
304
305	return (0);
306}
307
308static int
309ps3disk_open(struct disk *dp)
310{
311	return (0);
312}
313
314static int
315ps3disk_close(struct disk *dp)
316{
317	return (0);
318}
319
320/* Process deferred blocks */
321static void
322ps3disk_task(void *arg)
323{
324	struct ps3disk_softc *sc = (struct ps3disk_softc *) arg;
325	struct bio *bp;
326
327	while (1) {
328		kproc_suspend_check(sc->sc_task);
329		tsleep(&sc->sc_deferredq, PRIBIO, "ps3disk", 10);
330
331		PS3DISK_LOCK(sc);
332		bp = bioq_takefirst(&sc->sc_deferredq);
333		PS3DISK_UNLOCK(sc);
334
335		if (bp == NULL)
336			continue;
337
338		if (bp->bio_driver1 != NULL) {
339			bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t)
340			    bp->bio_driver1);
341			bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t)
342			    bp->bio_driver1);
343		}
344
345		ps3disk_strategy(bp);
346	}
347
348	kproc_exit(0);
349}
350
351static void
352ps3disk_strategy(struct bio *bp)
353{
354	struct ps3disk_softc *sc = (struct ps3disk_softc *)bp->bio_disk->d_drv1;
355	int err;
356
357	if (sc == NULL) {
358		bp->bio_flags |= BIO_ERROR;
359		bp->bio_error = EINVAL;
360		biodone(bp);
361		return;
362	}
363
364	PS3DISK_LOCK(sc);
365	bp->bio_resid = bp->bio_bcount;
366	bioq_insert_tail(&sc->sc_bioq, bp);
367
368	DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: bio_cmd 0x%02x\n",
369	    __func__, bp->bio_cmd);
370
371	err = 0;
372	if (bp->bio_cmd == BIO_FLUSH) {
373		bp->bio_driver1 = 0;
374		err = lv1_storage_send_device_command(
375		    ps3bus_get_device(sc->sc_dev), LV1_STORAGE_ATA_HDDOUT,
376		    0, 0, 0, 0, (uint64_t *)&bp->bio_driver2);
377		if (err == LV1_BUSY)
378			err = EAGAIN;
379	} else if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) {
380		if (bp->bio_bcount % sc->sc_blksize != 0) {
381			err = EINVAL;
382		} else {
383			bus_dmamap_create(sc->sc_dmatag, BUS_DMA_COHERENT,
384			    (bus_dmamap_t *)(&bp->bio_driver1));
385			err = bus_dmamap_load(sc->sc_dmatag,
386			    (bus_dmamap_t)(bp->bio_driver1), bp->bio_data,
387			    bp->bio_bcount, ps3disk_transfer, bp, 0);
388			if (err == EINPROGRESS)
389				err = 0;
390		}
391	} else {
392		err = EINVAL;
393	}
394
395	if (err == EAGAIN) {
396		bioq_remove(&sc->sc_bioq, bp);
397		bioq_insert_tail(&sc->sc_deferredq, bp);
398	} else if (err != 0) {
399		bp->bio_error = err;
400		bp->bio_flags |= BIO_ERROR;
401		bioq_remove(&sc->sc_bioq, bp);
402		disk_err(bp, "hard error", -1, 1);
403		biodone(bp);
404	}
405
406	PS3DISK_UNLOCK(sc);
407}
408
409static void
410ps3disk_intr(void *arg)
411{
412	struct ps3disk_softc *sc = (struct ps3disk_softc *) arg;
413	device_t dev = sc->sc_dev;
414	uint64_t devid = ps3bus_get_device(dev);
415	struct bio *bp;
416	uint64_t tag, status;
417
418	if (lv1_storage_get_async_status(devid, &tag, &status) != 0)
419		return;
420
421	PS3DISK_LOCK(sc);
422
423	DPRINTF(sc, PS3DISK_DEBUG_INTR, "%s: tag 0x%016lx "
424	    "status 0x%016lx\n", __func__, tag, status);
425
426	/* Locate the matching request */
427	TAILQ_FOREACH(bp, &sc->sc_bioq.queue, bio_queue) {
428		if ((uint64_t)bp->bio_driver2 != tag)
429			continue;
430
431		if (status != 0) {
432			device_printf(sc->sc_dev, "%s error (%#lx)\n",
433			    (bp->bio_cmd == BIO_READ) ? "Read" : "Write",
434			    status);
435			bp->bio_error = EIO;
436			bp->bio_flags |= BIO_ERROR;
437		} else {
438			bp->bio_error = 0;
439			bp->bio_resid = 0;
440			bp->bio_flags |= BIO_DONE;
441		}
442
443		if (bp->bio_driver1 != NULL) {
444			if (bp->bio_cmd == BIO_READ)
445				bus_dmamap_sync(sc->sc_dmatag, (bus_dmamap_t)
446				    bp->bio_driver1, BUS_DMASYNC_POSTREAD);
447			bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t)
448			    bp->bio_driver1);
449			bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t)
450			    bp->bio_driver1);
451		}
452
453		bioq_remove(&sc->sc_bioq, bp);
454		biodone(bp);
455		break;
456	}
457
458	if (bioq_first(&sc->sc_deferredq) != NULL)
459		wakeup(&sc->sc_deferredq);
460
461	PS3DISK_UNLOCK(sc);
462}
463
464static int
465ps3disk_get_disk_geometry(struct ps3disk_softc *sc)
466{
467	device_t dev = sc->sc_dev;
468	uint64_t bus_index = ps3bus_get_busidx(dev);
469	uint64_t dev_index = ps3bus_get_devidx(dev);
470	uint64_t junk;
471	int err;
472
473	err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
474	    (lv1_repository_string("bus") >> 32) | bus_index,
475	    lv1_repository_string("dev") | dev_index,
476	    lv1_repository_string("blk_size"), 0, &sc->sc_blksize, &junk);
477	if (err) {
478		device_printf(dev, "Could not get block size (0x%08x)\n", err);
479		return (ENXIO);
480	}
481
482	err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
483	    (lv1_repository_string("bus") >> 32) | bus_index,
484	    lv1_repository_string("dev") | dev_index,
485	    lv1_repository_string("n_blocks"), 0, &sc->sc_nblocks, &junk);
486	if (err) {
487		device_printf(dev, "Could not get total number of blocks "
488		    "(0x%08x)\n", err);
489		err = ENXIO;
490	}
491
492	return (err);
493}
494
495static int
496ps3disk_enum_regions(struct ps3disk_softc *sc)
497{
498	device_t dev = sc->sc_dev;
499	uint64_t bus_index = ps3bus_get_busidx(dev);
500	uint64_t dev_index = ps3bus_get_devidx(dev);
501	uint64_t junk;
502	int i, err;
503
504	/* Read number of regions */
505
506	err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
507	    (lv1_repository_string("bus") >> 32) | bus_index,
508	    lv1_repository_string("dev") | dev_index,
509	    lv1_repository_string("n_regs"), 0, &sc->sc_nregs, &junk);
510	if (err) {
511		device_printf(dev, "Could not get number of regions (0x%08x)\n",
512		    err);
513		err = ENXIO;
514		goto fail;
515	}
516
517	if (!sc->sc_nregs)
518		return 0;
519
520	sc->sc_reg = malloc(sc->sc_nregs * sizeof(struct ps3disk_region),
521	    M_PS3DISK, M_ZERO | M_WAITOK);
522	if (!sc->sc_reg) {
523		err = ENOMEM;
524		goto fail;
525	}
526
527	/* Setup regions */
528
529	for (i = 0; i < sc->sc_nregs; i++) {
530		err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
531		    (lv1_repository_string("bus") >> 32) | bus_index,
532		    lv1_repository_string("dev") | dev_index,
533		    lv1_repository_string("region") | i,
534		    lv1_repository_string("id"), &sc->sc_reg[i].r_id, &junk);
535		if (err) {
536			device_printf(dev, "Could not get region id (0x%08x)\n",
537			    err);
538			err = ENXIO;
539			goto fail;
540		}
541
542		err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
543		    (lv1_repository_string("bus") >> 32) | bus_index,
544		    lv1_repository_string("dev") | dev_index,
545		    lv1_repository_string("region") | i,
546		    lv1_repository_string("start"), &sc->sc_reg[i].r_start,
547		    &junk);
548		if (err) {
549			device_printf(dev, "Could not get region start "
550			    "(0x%08x)\n", err);
551			err = ENXIO;
552			goto fail;
553		}
554
555		err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
556		    (lv1_repository_string("bus") >> 32) | bus_index,
557		    lv1_repository_string("dev") | dev_index,
558		    lv1_repository_string("region") | i,
559		    lv1_repository_string("size"), &sc->sc_reg[i].r_size,
560		    &junk);
561		if (err) {
562			device_printf(dev, "Could not get region size "
563			    "(0x%08x)\n", err);
564			err = ENXIO;
565			goto fail;
566		}
567
568		if (i == 0)
569			sc->sc_reg[i].r_flags = 0x2;
570		else
571			sc->sc_reg[i].r_flags = 0;
572	}
573
574	return (0);
575
576fail:
577
578	sc->sc_nregs = 0;
579	if (sc->sc_reg)
580		free(sc->sc_reg, M_PS3DISK);
581
582	return (err);
583}
584
585static void
586ps3disk_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
587{
588	struct bio *bp = (struct bio *)(arg);
589	struct ps3disk_softc *sc = (struct ps3disk_softc *)bp->bio_disk->d_drv1;
590	struct ps3disk_region *rp = &sc->sc_reg[bp->bio_disk->d_unit];
591	uint64_t devid = ps3bus_get_device(sc->sc_dev);
592	uint64_t block;
593	int i, err;
594
595	/* Locks already held by busdma */
596	PS3DISK_ASSERT_LOCKED(sc);
597
598	if (error) {
599		bp->bio_error = error;
600		bp->bio_flags |= BIO_ERROR;
601		bioq_remove(&sc->sc_bioq, bp);
602		biodone(bp);
603		return;
604	}
605
606	block = bp->bio_pblkno;
607	for (i = 0; i < nsegs; i++) {
608		KASSERT((segs[i].ds_len % sc->sc_blksize) == 0,
609		    ("DMA fragments not blocksize multiples"));
610
611		if (bp->bio_cmd == BIO_READ) {
612			err = lv1_storage_read(devid, rp->r_id,
613			    block, segs[i].ds_len/sc->sc_blksize,
614			    rp->r_flags, segs[i].ds_addr,
615			    (uint64_t *)&bp->bio_driver2);
616		} else {
617			bus_dmamap_sync(sc->sc_dmatag,
618			    (bus_dmamap_t)bp->bio_driver1,
619			    BUS_DMASYNC_PREWRITE);
620			err = lv1_storage_write(devid, rp->r_id,
621			    block, segs[i].ds_len/sc->sc_blksize,
622			    rp->r_flags, segs[i].ds_addr,
623			    (uint64_t *)&bp->bio_driver2);
624		}
625
626		if (err) {
627			if (err == LV1_BUSY) {
628				bioq_remove(&sc->sc_bioq, bp);
629				bioq_insert_tail(&sc->sc_deferredq, bp);
630			} else {
631				bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t)
632				    bp->bio_driver1);
633				bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t)
634				    bp->bio_driver1);
635				device_printf(sc->sc_dev, "Could not read "
636				    "sectors (0x%08x)\n", err);
637				bp->bio_error = EINVAL;
638				bp->bio_flags |= BIO_ERROR;
639				bioq_remove(&sc->sc_bioq, bp);
640				biodone(bp);
641			}
642
643			break;
644		}
645
646		DPRINTF(sc, PS3DISK_DEBUG_READ, "%s: tag 0x%016lx\n",
647		    __func__, sc->sc_bounce_tag);
648	}
649}
650
651#ifdef PS3DISK_DEBUG
652static int
653ps3disk_sysctl_debug(SYSCTL_HANDLER_ARGS)
654{
655	struct ps3disk_softc *sc = arg1;
656	int debug, error;
657
658	debug = sc->sc_debug;
659
660	error = sysctl_handle_int(oidp, &debug, 0, req);
661	if (error || !req->newptr)
662		return error;
663
664	sc->sc_debug = debug;
665
666	return 0;
667}
668#endif
669
670static void
671ps3disk_sysctlattach(struct ps3disk_softc *sc)
672{
673#ifdef PS3DISK_DEBUG
674	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
675	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
676
677	sc->sc_debug = ps3disk_debug;
678
679	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
680	    "debug", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0,
681	    ps3disk_sysctl_debug, "I", "control debugging printfs");
682#endif
683}
684
685static device_method_t ps3disk_methods[] = {
686	DEVMETHOD(device_probe,		ps3disk_probe),
687	DEVMETHOD(device_attach,	ps3disk_attach),
688	DEVMETHOD(device_detach,	ps3disk_detach),
689	{0, 0},
690};
691
692static driver_t ps3disk_driver = {
693	"ps3disk",
694	ps3disk_methods,
695	sizeof(struct ps3disk_softc),
696};
697
698DRIVER_MODULE(ps3disk, ps3bus, ps3disk_driver, 0, 0);
699