2 * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/sysctl.h>
37 #include <sys/kernel.h>
38 #include <sys/kthread.h>
40 #include <sys/malloc.h>
41 #include <sys/module.h>
42 #include <sys/mutex.h>
47 #include <machine/pio.h>
48 #include <machine/bus.h>
49 #include <machine/platform.h>
50 #include <machine/resource.h>
54 #include <geom/geom_disk.h>
57 #include "ps3-hvcall.h"
59 #define PS3DISK_LOCK_INIT(_sc) \
60 mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), "ps3disk", MTX_DEF)
61 #define PS3DISK_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
62 #define PS3DISK_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
63 #define PS3DISK_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
64 #define PS3DISK_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
65 #define PS3DISK_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
67 #define LV1_STORAGE_ATA_HDDOUT 0x23
69 static SYSCTL_NODE(_hw
, OID_AUTO
, ps3disk
, CTLFLAG_RD
, 0,
70 "PS3 Disk driver parameters");
73 static int ps3disk_debug
= 0;
74 SYSCTL_INT(_hw_ps3disk
, OID_AUTO
, debug
, CTLFLAG_RW
, &ps3disk_debug
,
75 0, "control debugging printfs");
76 TUNABLE_INT("hw.ps3disk.debug", &ps3disk_debug
);
78 PS3DISK_DEBUG_INTR
= 0x00000001,
79 PS3DISK_DEBUG_TASK
= 0x00000002,
80 PS3DISK_DEBUG_READ
= 0x00000004,
81 PS3DISK_DEBUG_WRITE
= 0x00000008,
82 PS3DISK_DEBUG_FLUSH
= 0x00000010,
83 PS3DISK_DEBUG_ANY
= 0xffffffff
85 #define DPRINTF(sc, m, fmt, ...) \
87 if (sc->sc_debug & (m)) \
88 printf(fmt, __VA_ARGS__); \
91 #define DPRINTF(sc, m, fmt, ...)
94 struct ps3disk_region
{
101 struct ps3disk_softc
{
110 struct ps3disk_region
*sc_reg
;
113 struct resource
*sc_irq
;
116 struct disk
**sc_disk
;
118 struct bio_queue_head sc_bioq
;
119 struct bio_queue_head sc_deferredq
;
120 struct proc
*sc_task
;
122 bus_dma_tag_t sc_dmatag
;
128 static int ps3disk_open(struct disk
*dp
);
129 static int ps3disk_close(struct disk
*dp
);
130 static void ps3disk_strategy(struct bio
*bp
);
132 static void ps3disk_task(void *arg
);
133 static void ps3disk_intr(void *arg
);
134 static int ps3disk_get_disk_geometry(struct ps3disk_softc
*sc
);
135 static int ps3disk_enum_regions(struct ps3disk_softc
*sc
);
136 static void ps3disk_transfer(void *arg
, bus_dma_segment_t
*segs
, int nsegs
,
139 static void ps3disk_sysctlattach(struct ps3disk_softc
*sc
);
141 static MALLOC_DEFINE(M_PS3DISK
, "ps3disk", "PS3 Disk");
144 ps3disk_probe(device_t dev
)
146 if (ps3bus_get_bustype(dev
) != PS3_BUSTYPE_STORAGE
||
147 ps3bus_get_devtype(dev
) != PS3_DEVTYPE_DISK
)
150 device_set_desc(dev
, "Playstation 3 Disk");
152 return (BUS_PROBE_SPECIFIC
);
156 ps3disk_attach(device_t dev
)
158 struct ps3disk_softc
*sc
;
165 sc
= device_get_softc(dev
);
168 PS3DISK_LOCK_INIT(sc
);
170 err
= ps3disk_get_disk_geometry(sc
);
172 device_printf(dev
, "Could not get disk geometry\n");
174 goto fail_destroy_lock
;
177 device_printf(dev
, "block size %lu total blocks %lu\n",
178 sc
->sc_blksize
, sc
->sc_nblocks
);
180 err
= ps3disk_enum_regions(sc
);
182 device_printf(dev
, "Could not enumerate disk regions\n");
184 goto fail_destroy_lock
;
187 device_printf(dev
, "Found %lu regions\n", sc
->sc_nregs
);
191 goto fail_destroy_lock
;
194 /* Setup interrupt handler */
196 sc
->sc_irq
= bus_alloc_resource_any(dev
, SYS_RES_IRQ
, &sc
->sc_irqid
,
199 device_printf(dev
, "Could not allocate IRQ\n");
201 goto fail_free_regions
;
204 err
= bus_setup_intr(dev
, sc
->sc_irq
,
205 INTR_TYPE_BIO
| INTR_MPSAFE
| INTR_ENTROPY
,
206 NULL
, ps3disk_intr
, sc
, &sc
->sc_irqctx
);
208 device_printf(dev
, "Could not setup IRQ\n");
210 goto fail_release_intr
;
214 err
= bus_dma_tag_create(bus_get_dma_tag(dev
), 4096, 0,
215 BUS_SPACE_MAXADDR
, BUS_SPACE_MAXADDR
, NULL
, NULL
,
216 BUS_SPACE_UNRESTRICTED
, 1, PAGE_SIZE
, 0,
217 busdma_lock_mutex
, &sc
->sc_mtx
, &sc
->sc_dmatag
);
219 device_printf(dev
, "Could not create DMA tag\n");
221 goto fail_teardown_intr
;
226 sc
->sc_disk
= malloc(sc
->sc_nregs
* sizeof(struct disk
*),
227 M_PS3DISK
, M_ZERO
| M_WAITOK
);
229 device_printf(dev
, "Could not allocate disk(s)\n");
231 goto fail_teardown_intr
;
234 for (i
= 0; i
< sc
->sc_nregs
; i
++) {
235 struct ps3disk_region
*rp
= &sc
->sc_reg
[i
];
237 d
= sc
->sc_disk
[i
] = disk_alloc();
238 d
->d_open
= ps3disk_open
;
239 d
->d_close
= ps3disk_close
;
240 d
->d_strategy
= ps3disk_strategy
;
241 d
->d_name
= "ps3disk";
243 d
->d_maxsize
= PAGE_SIZE
;
244 d
->d_sectorsize
= sc
->sc_blksize
;
246 d
->d_mediasize
= sc
->sc_reg
[i
].r_size
* sc
->sc_blksize
;
247 d
->d_flags
|= DISKFLAG_CANFLUSHCACHE
;
249 mb
= d
->d_mediasize
>> 20;
256 /* Test to see if we can read this region */
257 err
= lv1_storage_read(ps3bus_get_device(dev
), d
->d_unit
,
258 0, 0, rp
->r_flags
, 0, &junk
);
259 device_printf(dev
, "region %d %ju%cB%s\n", i
, mb
, unit
,
260 (err
== LV1_DENIED_BY_POLICY
) ? " (hypervisor protected)"
263 if (err
!= LV1_DENIED_BY_POLICY
)
264 disk_create(d
, DISK_VERSION
);
268 bioq_init(&sc
->sc_bioq
);
269 bioq_init(&sc
->sc_deferredq
);
270 kproc_create(&ps3disk_task
, sc
, &sc
->sc_task
, 0, 0, "ps3disk");
272 ps3disk_sysctlattach(sc
);
277 bus_teardown_intr(dev
, sc
->sc_irq
, sc
->sc_irqctx
);
279 bus_release_resource(dev
, SYS_RES_IRQ
, sc
->sc_irqid
, sc
->sc_irq
);
281 free(sc
->sc_reg
, M_PS3DISK
);
283 PS3DISK_LOCK_DESTROY(sc
);
288 ps3disk_detach(device_t dev
)
290 struct ps3disk_softc
*sc
= device_get_softc(dev
);
293 for (i
= 0; i
< sc
->sc_nregs
; i
++)
294 disk_destroy(sc
->sc_disk
[i
]);
296 bus_dma_tag_destroy(sc
->sc_dmatag
);
298 bus_teardown_intr(dev
, sc
->sc_irq
, sc
->sc_irqctx
);
299 bus_release_resource(dev
, SYS_RES_IRQ
, sc
->sc_irqid
, sc
->sc_irq
);
301 free(sc
->sc_disk
, M_PS3DISK
);
302 free(sc
->sc_reg
, M_PS3DISK
);
304 PS3DISK_LOCK_DESTROY(sc
);
310 ps3disk_open(struct disk
*dp
)
316 ps3disk_close(struct disk
*dp
)
321 /* Process deferred blocks */
323 ps3disk_task(void *arg
)
325 struct ps3disk_softc
*sc
= (struct ps3disk_softc
*) arg
;
330 kproc_suspend_check(sc
->sc_task
);
331 tsleep(&sc
->sc_deferredq
, PRIBIO
, "ps3disk", 10);
334 bp
= bioq_takefirst(&sc
->sc_deferredq
);
340 if (bp
->bio_driver1
!= NULL
) {
341 bus_dmamap_unload(sc
->sc_dmatag
, (bus_dmamap_t
)
343 bus_dmamap_destroy(sc
->sc_dmatag
, (bus_dmamap_t
)
347 ps3disk_strategy(bp
);
354 ps3disk_strategy(struct bio
*bp
)
356 struct ps3disk_softc
*sc
= (struct ps3disk_softc
*)bp
->bio_disk
->d_drv1
;
360 bp
->bio_flags
|= BIO_ERROR
;
361 bp
->bio_error
= EINVAL
;
367 bp
->bio_resid
= bp
->bio_bcount
;
368 bioq_insert_tail(&sc
->sc_bioq
, bp
);
370 DPRINTF(sc
, PS3DISK_DEBUG_TASK
, "%s: bio_cmd 0x%02x\n",
371 __func__
, bp
->bio_cmd
);
374 if (bp
->bio_cmd
== BIO_FLUSH
) {
376 err
= lv1_storage_send_device_command(
377 ps3bus_get_device(sc
->sc_dev
), LV1_STORAGE_ATA_HDDOUT
,
378 0, 0, 0, 0, (uint64_t *)&bp
->bio_driver2
);
381 } else if (bp
->bio_cmd
== BIO_READ
|| bp
->bio_cmd
== BIO_WRITE
) {
382 if (bp
->bio_bcount
% sc
->sc_blksize
!= 0) {
385 bus_dmamap_create(sc
->sc_dmatag
, BUS_DMA_COHERENT
,
386 (bus_dmamap_t
*)(&bp
->bio_driver1
));
387 err
= bus_dmamap_load(sc
->sc_dmatag
,
388 (bus_dmamap_t
)(bp
->bio_driver1
), bp
->bio_data
,
389 bp
->bio_bcount
, ps3disk_transfer
, bp
, 0);
390 if (err
== EINPROGRESS
)
398 bioq_remove(&sc
->sc_bioq
, bp
);
399 bioq_insert_tail(&sc
->sc_deferredq
, bp
);
400 } else if (err
!= 0) {
402 bp
->bio_flags
|= BIO_ERROR
;
403 bioq_remove(&sc
->sc_bioq
, bp
);
404 disk_err(bp
, "hard error", -1, 1);
412 ps3disk_intr(void *arg
)
414 struct ps3disk_softc
*sc
= (struct ps3disk_softc
*) arg
;
415 device_t dev
= sc
->sc_dev
;
416 uint64_t devid
= ps3bus_get_device(dev
);
418 uint64_t tag
, status
;
420 if (lv1_storage_get_async_status(devid
, &tag
, &status
) != 0)
425 DPRINTF(sc
, PS3DISK_DEBUG_INTR
, "%s: tag 0x%016lx "
426 "status 0x%016lx\n", __func__
, tag
, status
);
428 /* Locate the matching request */
429 TAILQ_FOREACH(bp
, &sc
->sc_bioq
.queue
, bio_queue
) {
430 if ((uint64_t)bp
->bio_driver2
!= tag
)
434 device_printf(sc
->sc_dev
, "%s error (%#lx)\n",
435 (bp
->bio_cmd
== BIO_READ
) ? "Read" : "Write",
438 bp
->bio_flags
|= BIO_ERROR
;
442 bp
->bio_flags
|= BIO_DONE
;
445 if (bp
->bio_driver1
!= NULL
) {
446 if (bp
->bio_cmd
== BIO_READ
)
447 bus_dmamap_sync(sc
->sc_dmatag
, (bus_dmamap_t
)
448 bp
->bio_driver1
, BUS_DMASYNC_POSTREAD
);
449 bus_dmamap_unload(sc
->sc_dmatag
, (bus_dmamap_t
)
451 bus_dmamap_destroy(sc
->sc_dmatag
, (bus_dmamap_t
)
455 bioq_remove(&sc
->sc_bioq
, bp
);
460 if (bioq_first(&sc
->sc_deferredq
) != NULL
)
461 wakeup(&sc
->sc_deferredq
);
467 ps3disk_get_disk_geometry(struct ps3disk_softc
*sc
)
469 device_t dev
= sc
->sc_dev
;
470 uint64_t bus_index
= ps3bus_get_busidx(dev
);
471 uint64_t dev_index
= ps3bus_get_devidx(dev
);
475 err
= lv1_get_repository_node_value(PS3_LPAR_ID_PME
,
476 (lv1_repository_string("bus") >> 32) | bus_index
,
477 lv1_repository_string("dev") | dev_index
,
478 lv1_repository_string("blk_size"), 0, &sc
->sc_blksize
, &junk
);
480 device_printf(dev
, "Could not get block size (0x%08x)\n", err
);
484 err
= lv1_get_repository_node_value(PS3_LPAR_ID_PME
,
485 (lv1_repository_string("bus") >> 32) | bus_index
,
486 lv1_repository_string("dev") | dev_index
,
487 lv1_repository_string("n_blocks"), 0, &sc
->sc_nblocks
, &junk
);
489 device_printf(dev
, "Could not get total number of blocks "
498 ps3disk_enum_regions(struct ps3disk_softc
*sc
)
500 device_t dev
= sc
->sc_dev
;
501 uint64_t bus_index
= ps3bus_get_busidx(dev
);
502 uint64_t dev_index
= ps3bus_get_devidx(dev
);
506 /* Read number of regions */
508 err
= lv1_get_repository_node_value(PS3_LPAR_ID_PME
,
509 (lv1_repository_string("bus") >> 32) | bus_index
,
510 lv1_repository_string("dev") | dev_index
,
511 lv1_repository_string("n_regs"), 0, &sc
->sc_nregs
, &junk
);
513 device_printf(dev
, "Could not get number of regions (0x%08x)\n",
522 sc
->sc_reg
= malloc(sc
->sc_nregs
* sizeof(struct ps3disk_region
),
523 M_PS3DISK
, M_ZERO
| M_WAITOK
);
531 for (i
= 0; i
< sc
->sc_nregs
; i
++) {
532 err
= lv1_get_repository_node_value(PS3_LPAR_ID_PME
,
533 (lv1_repository_string("bus") >> 32) | bus_index
,
534 lv1_repository_string("dev") | dev_index
,
535 lv1_repository_string("region") | i
,
536 lv1_repository_string("id"), &sc
->sc_reg
[i
].r_id
, &junk
);
538 device_printf(dev
, "Could not get region id (0x%08x)\n",
544 err
= lv1_get_repository_node_value(PS3_LPAR_ID_PME
,
545 (lv1_repository_string("bus") >> 32) | bus_index
,
546 lv1_repository_string("dev") | dev_index
,
547 lv1_repository_string("region") | i
,
548 lv1_repository_string("start"), &sc
->sc_reg
[i
].r_start
,
551 device_printf(dev
, "Could not get region start "
557 err
= lv1_get_repository_node_value(PS3_LPAR_ID_PME
,
558 (lv1_repository_string("bus") >> 32) | bus_index
,
559 lv1_repository_string("dev") | dev_index
,
560 lv1_repository_string("region") | i
,
561 lv1_repository_string("size"), &sc
->sc_reg
[i
].r_size
,
564 device_printf(dev
, "Could not get region size "
571 sc
->sc_reg
[i
].r_flags
= 0x2;
573 sc
->sc_reg
[i
].r_flags
= 0;
582 free(sc
->sc_reg
, M_PS3DISK
);
588 ps3disk_transfer(void *arg
, bus_dma_segment_t
*segs
, int nsegs
, int error
)
590 struct bio
*bp
= (struct bio
*)(arg
);
591 struct ps3disk_softc
*sc
= (struct ps3disk_softc
*)bp
->bio_disk
->d_drv1
;
592 struct ps3disk_region
*rp
= &sc
->sc_reg
[bp
->bio_disk
->d_unit
];
593 uint64_t devid
= ps3bus_get_device(sc
->sc_dev
);
597 /* Locks already held by busdma */
598 PS3DISK_ASSERT_LOCKED(sc
);
601 bp
->bio_error
= error
;
602 bp
->bio_flags
|= BIO_ERROR
;
603 bioq_remove(&sc
->sc_bioq
, bp
);
608 block
= bp
->bio_pblkno
;
609 for (i
= 0; i
< nsegs
; i
++) {
610 KASSERT((segs
[i
].ds_len
% sc
->sc_blksize
) == 0,
611 ("DMA fragments not blocksize multiples"));
613 if (bp
->bio_cmd
== BIO_READ
) {
614 err
= lv1_storage_read(devid
, rp
->r_id
,
615 block
, segs
[i
].ds_len
/sc
->sc_blksize
,
616 rp
->r_flags
, segs
[i
].ds_addr
,
617 (uint64_t *)&bp
->bio_driver2
);
619 bus_dmamap_sync(sc
->sc_dmatag
,
620 (bus_dmamap_t
)bp
->bio_driver1
,
621 BUS_DMASYNC_PREWRITE
);
622 err
= lv1_storage_write(devid
, rp
->r_id
,
623 block
, segs
[i
].ds_len
/sc
->sc_blksize
,
624 rp
->r_flags
, segs
[i
].ds_addr
,
625 (uint64_t *)&bp
->bio_driver2
);
629 if (err
== LV1_BUSY
) {
630 bioq_remove(&sc
->sc_bioq
, bp
);
631 bioq_insert_tail(&sc
->sc_deferredq
, bp
);
633 bus_dmamap_unload(sc
->sc_dmatag
, (bus_dmamap_t
)
635 bus_dmamap_destroy(sc
->sc_dmatag
, (bus_dmamap_t
)
637 device_printf(sc
->sc_dev
, "Could not read "
638 "sectors (0x%08x)\n", err
);
639 bp
->bio_error
= EINVAL
;
640 bp
->bio_flags
|= BIO_ERROR
;
641 bioq_remove(&sc
->sc_bioq
, bp
);
648 DPRINTF(sc
, PS3DISK_DEBUG_READ
, "%s: tag 0x%016lx\n",
649 __func__
, sc
->sc_bounce_tag
);
655 ps3disk_sysctl_debug(SYSCTL_HANDLER_ARGS
)
657 struct ps3disk_softc
*sc
= arg1
;
660 debug
= sc
->sc_debug
;
662 error
= sysctl_handle_int(oidp
, &debug
, 0, req
);
663 if (error
|| !req
->newptr
)
666 sc
->sc_debug
= debug
;
673 ps3disk_sysctlattach(struct ps3disk_softc
*sc
)
676 struct sysctl_ctx_list
*ctx
= device_get_sysctl_ctx(sc
->sc_dev
);
677 struct sysctl_oid
*tree
= device_get_sysctl_tree(sc
->sc_dev
);
679 sc
->sc_debug
= ps3disk_debug
;
681 SYSCTL_ADD_PROC(ctx
, SYSCTL_CHILDREN(tree
), OID_AUTO
,
682 "debug", CTLTYPE_INT
| CTLFLAG_RW
, sc
, 0,
683 ps3disk_sysctl_debug
, "I", "control debugging printfs");
687 static device_method_t ps3disk_methods
[] = {
688 DEVMETHOD(device_probe
, ps3disk_probe
),
689 DEVMETHOD(device_attach
, ps3disk_attach
),
690 DEVMETHOD(device_detach
, ps3disk_detach
),
694 static driver_t ps3disk_driver
= {
697 sizeof(struct ps3disk_softc
),
700 static devclass_t ps3disk_devclass
;
702 DRIVER_MODULE(ps3disk
, ps3bus
, ps3disk_driver
, ps3disk_devclass
, 0, 0);