1224857Snwhitehorn/*- 2224857Snwhitehorn * Copyright (C) 2010 Nathan Whitehorn 3224857Snwhitehorn * Copyright (C) 2011 glevand <geoffrey.levand@mail.ru> 4224857Snwhitehorn * All rights reserved. 5224857Snwhitehorn * 6224857Snwhitehorn * Redistribution and use in source and binary forms, with or without 7224857Snwhitehorn * modification, are permitted provided that the following conditions 8224857Snwhitehorn * are met: 9224857Snwhitehorn * 1. Redistributions of source code must retain the above copyright 10224857Snwhitehorn * notice, this list of conditions and the following disclaimer, 11224857Snwhitehorn * without modification, immediately at the beginning of the file. 12224857Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 13224857Snwhitehorn * notice, this list of conditions and the following disclaimer in the 14224857Snwhitehorn * documentation and/or other materials provided with the distribution. 15224857Snwhitehorn * 16224857Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17224857Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18224857Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19224857Snwhitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20224857Snwhitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21224857Snwhitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22224857Snwhitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23224857Snwhitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24224857Snwhitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25224857Snwhitehorn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26224857Snwhitehorn */ 27224857Snwhitehorn 28224857Snwhitehorn#include <sys/cdefs.h> 29224857Snwhitehorn__FBSDID("$FreeBSD: releng/11.0/sys/powerpc/ps3/ps3cdrom.c 295880 2016-02-22 09:02:20Z skra $"); 30224857Snwhitehorn 31224857Snwhitehorn#include <sys/param.h> 32224857Snwhitehorn#include <sys/module.h> 33224857Snwhitehorn#include <sys/systm.h> 34224857Snwhitehorn#include <sys/kernel.h> 35224857Snwhitehorn#include <sys/ata.h> 36224857Snwhitehorn#include <sys/bus.h> 37224857Snwhitehorn#include <sys/conf.h> 38224857Snwhitehorn#include <sys/kthread.h> 39224857Snwhitehorn#include <sys/lock.h> 40224857Snwhitehorn#include <sys/malloc.h> 41224857Snwhitehorn#include <sys/mutex.h> 42224857Snwhitehorn 43224857Snwhitehorn#include <vm/vm.h> 44224857Snwhitehorn#include <vm/pmap.h> 45224857Snwhitehorn 46224857Snwhitehorn#include <machine/pio.h> 47224857Snwhitehorn#include <machine/bus.h> 48224857Snwhitehorn#include <machine/platform.h> 49224857Snwhitehorn#include <machine/resource.h> 50224857Snwhitehorn#include <sys/bus.h> 51224857Snwhitehorn#include <sys/rman.h> 52224857Snwhitehorn 53224857Snwhitehorn#include <cam/cam.h> 54224857Snwhitehorn#include <cam/cam_ccb.h> 55224857Snwhitehorn#include <cam/cam_sim.h> 56224857Snwhitehorn#include <cam/cam_xpt_sim.h> 57224857Snwhitehorn#include <cam/cam_debug.h> 58224857Snwhitehorn#include <cam/scsi/scsi_all.h> 59224857Snwhitehorn 60224857Snwhitehorn#include "ps3bus.h" 61224857Snwhitehorn#include "ps3-hvcall.h" 62224857Snwhitehorn 63224857Snwhitehorn#define PS3CDROM_LOCK_INIT(_sc) \ 64224857Snwhitehorn mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), "ps3cdrom", \ 65224857Snwhitehorn MTX_DEF) 66224857Snwhitehorn#define PS3CDROM_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 67224857Snwhitehorn#define PS3CDROM_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 68224857Snwhitehorn#define PS3CDROM_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 69224857Snwhitehorn#define PS3CDROM_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); 70224857Snwhitehorn#define PS3CDROM_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); 71224857Snwhitehorn 72224857Snwhitehorn#define PS3CDROM_MAX_XFERS 3 73224857Snwhitehorn 74224857Snwhitehorn#define LV1_STORAGE_SEND_ATAPI_COMMAND 0x01 75224857Snwhitehorn 76224857Snwhitehornstruct ps3cdrom_softc; 77224857Snwhitehorn 78224857Snwhitehornstruct ps3cdrom_xfer { 79224857Snwhitehorn TAILQ_ENTRY(ps3cdrom_xfer) x_queue; 80224857Snwhitehorn struct ps3cdrom_softc *x_sc; 81224857Snwhitehorn union ccb *x_ccb; 82224857Snwhitehorn bus_dmamap_t x_dmamap; 83224857Snwhitehorn uint64_t x_tag; 84224857Snwhitehorn}; 85224857Snwhitehorn 86224857SnwhitehornTAILQ_HEAD(ps3cdrom_xferq, ps3cdrom_xfer); 87224857Snwhitehorn 88224857Snwhitehornstruct ps3cdrom_softc { 89224857Snwhitehorn device_t sc_dev; 90224857Snwhitehorn 91224857Snwhitehorn struct mtx sc_mtx; 92224857Snwhitehorn 93224857Snwhitehorn uint64_t sc_blksize; 94224857Snwhitehorn uint64_t sc_nblocks; 95224857Snwhitehorn 96224857Snwhitehorn int sc_irqid; 97224857Snwhitehorn struct resource *sc_irq; 98224857Snwhitehorn void *sc_irqctx; 99224857Snwhitehorn 100224857Snwhitehorn bus_dma_tag_t sc_dmatag; 101224857Snwhitehorn 102224857Snwhitehorn struct cam_sim *sc_sim; 103224857Snwhitehorn struct cam_path *sc_path; 104224857Snwhitehorn 105224857Snwhitehorn struct ps3cdrom_xfer sc_xfer[PS3CDROM_MAX_XFERS]; 106224857Snwhitehorn struct ps3cdrom_xferq sc_active_xferq; 107224857Snwhitehorn struct ps3cdrom_xferq sc_free_xferq; 108224857Snwhitehorn}; 109224857Snwhitehorn 110224857Snwhitehornenum lv1_ata_proto { 111224857Snwhitehorn NON_DATA_PROTO = 0x00, 112224857Snwhitehorn PIO_DATA_IN_PROTO = 0x01, 113224857Snwhitehorn PIO_DATA_OUT_PROTO = 0x02, 114224857Snwhitehorn DMA_PROTO = 0x03 115224857Snwhitehorn}; 116224857Snwhitehorn 117224857Snwhitehornenum lv1_ata_in_out { 118224857Snwhitehorn DIR_WRITE = 0x00, 119224857Snwhitehorn DIR_READ = 0x01 120224857Snwhitehorn}; 121224857Snwhitehorn 122224857Snwhitehornstruct lv1_atapi_cmd { 123224857Snwhitehorn uint8_t pkt[32]; 124224857Snwhitehorn uint32_t pktlen; 125224857Snwhitehorn uint32_t nblocks; 126224857Snwhitehorn uint32_t blksize; 127224857Snwhitehorn uint32_t proto; /* enum lv1_ata_proto */ 128224857Snwhitehorn uint32_t in_out; /* enum lv1_ata_in_out */ 129224857Snwhitehorn uint64_t buf; 130224857Snwhitehorn uint32_t arglen; 131224857Snwhitehorn}; 132224857Snwhitehorn 133224857Snwhitehornstatic void ps3cdrom_action(struct cam_sim *sim, union ccb *ccb); 134224857Snwhitehornstatic void ps3cdrom_poll(struct cam_sim *sim); 135224857Snwhitehornstatic void ps3cdrom_async(void *callback_arg, u_int32_t code, 136224857Snwhitehorn struct cam_path* path, void *arg); 137224857Snwhitehorn 138224857Snwhitehornstatic void ps3cdrom_intr(void *arg); 139224857Snwhitehorn 140224857Snwhitehornstatic void ps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, 141224857Snwhitehorn int error); 142224857Snwhitehorn 143224857Snwhitehornstatic int ps3cdrom_decode_lv1_status(uint64_t status, 144224857Snwhitehorn u_int8_t *sense_key, u_int8_t *asc, u_int8_t *ascq); 145224857Snwhitehorn 146224857Snwhitehornstatic int 147224857Snwhitehornps3cdrom_probe(device_t dev) 148224857Snwhitehorn{ 149224857Snwhitehorn if (ps3bus_get_bustype(dev) != PS3_BUSTYPE_STORAGE || 150224857Snwhitehorn ps3bus_get_devtype(dev) != PS3_DEVTYPE_CDROM) 151224857Snwhitehorn return (ENXIO); 152224857Snwhitehorn 153224857Snwhitehorn device_set_desc(dev, "Playstation 3 CDROM"); 154224857Snwhitehorn 155224857Snwhitehorn return (BUS_PROBE_SPECIFIC); 156224857Snwhitehorn} 157224857Snwhitehorn 158224857Snwhitehornstatic int 159224857Snwhitehornps3cdrom_attach(device_t dev) 160224857Snwhitehorn{ 161224857Snwhitehorn struct ps3cdrom_softc *sc = device_get_softc(dev); 162224857Snwhitehorn struct cam_devq *devq; 163224857Snwhitehorn struct ps3cdrom_xfer *xp; 164224857Snwhitehorn struct ccb_setasync csa; 165224857Snwhitehorn int i, err; 166224857Snwhitehorn 167224857Snwhitehorn sc->sc_dev = dev; 168224857Snwhitehorn 169224857Snwhitehorn PS3CDROM_LOCK_INIT(sc); 170224857Snwhitehorn 171224857Snwhitehorn /* Setup interrupt handler */ 172224857Snwhitehorn 173224857Snwhitehorn sc->sc_irqid = 0; 174224857Snwhitehorn sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid, 175224857Snwhitehorn RF_ACTIVE); 176224857Snwhitehorn if (!sc->sc_irq) { 177224857Snwhitehorn device_printf(dev, "Could not allocate IRQ\n"); 178224857Snwhitehorn err = ENXIO; 179224857Snwhitehorn goto fail_destroy_lock; 180224857Snwhitehorn } 181224857Snwhitehorn 182224857Snwhitehorn err = bus_setup_intr(dev, sc->sc_irq, 183224857Snwhitehorn INTR_TYPE_CAM | INTR_MPSAFE | INTR_ENTROPY, 184224857Snwhitehorn NULL, ps3cdrom_intr, sc, &sc->sc_irqctx); 185224857Snwhitehorn if (err) { 186224857Snwhitehorn device_printf(dev, "Could not setup IRQ\n"); 187224857Snwhitehorn err = ENXIO; 188224857Snwhitehorn goto fail_release_intr; 189224857Snwhitehorn } 190224857Snwhitehorn 191224857Snwhitehorn /* Setup DMA */ 192224857Snwhitehorn 193224857Snwhitehorn err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0, 194224857Snwhitehorn BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 195224857Snwhitehorn BUS_SPACE_UNRESTRICTED, 1, PAGE_SIZE, 0, 196224857Snwhitehorn busdma_lock_mutex, &sc->sc_mtx, &sc->sc_dmatag); 197224857Snwhitehorn if (err) { 198224857Snwhitehorn device_printf(dev, "Could not create DMA tag\n"); 199224857Snwhitehorn err = ENXIO; 200224857Snwhitehorn goto fail_teardown_intr; 201224857Snwhitehorn } 202224857Snwhitehorn 203224857Snwhitehorn /* Setup transfer queues */ 204224857Snwhitehorn 205224857Snwhitehorn TAILQ_INIT(&sc->sc_active_xferq); 206224857Snwhitehorn TAILQ_INIT(&sc->sc_free_xferq); 207224857Snwhitehorn 208224857Snwhitehorn for (i = 0; i < PS3CDROM_MAX_XFERS; i++) { 209224857Snwhitehorn xp = &sc->sc_xfer[i]; 210224857Snwhitehorn xp->x_sc = sc; 211224857Snwhitehorn 212224857Snwhitehorn err = bus_dmamap_create(sc->sc_dmatag, BUS_DMA_COHERENT, 213224857Snwhitehorn &xp->x_dmamap); 214224857Snwhitehorn if (err) { 215224857Snwhitehorn device_printf(dev, "Could not create DMA map (%d)\n", 216224857Snwhitehorn err); 217224857Snwhitehorn goto fail_destroy_dmamap; 218224857Snwhitehorn } 219224857Snwhitehorn 220224857Snwhitehorn TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue); 221224857Snwhitehorn } 222224857Snwhitehorn 223224857Snwhitehorn /* Setup CAM */ 224224857Snwhitehorn 225224857Snwhitehorn devq = cam_simq_alloc(PS3CDROM_MAX_XFERS - 1); 226224857Snwhitehorn if (!devq) { 227224857Snwhitehorn device_printf(dev, "Could not allocate SIM queue\n"); 228224857Snwhitehorn err = ENOMEM; 229224857Snwhitehorn goto fail_destroy_dmatag; 230224857Snwhitehorn } 231224857Snwhitehorn 232224857Snwhitehorn sc->sc_sim = cam_sim_alloc(ps3cdrom_action, ps3cdrom_poll, "ps3cdrom", 233224857Snwhitehorn sc, device_get_unit(dev), &sc->sc_mtx, PS3CDROM_MAX_XFERS - 1, 0, 234224857Snwhitehorn devq); 235224857Snwhitehorn if (!sc->sc_sim) { 236224857Snwhitehorn device_printf(dev, "Could not allocate SIM\n"); 237224857Snwhitehorn cam_simq_free(devq); 238224857Snwhitehorn err = ENOMEM; 239224857Snwhitehorn goto fail_destroy_dmatag; 240224857Snwhitehorn } 241224857Snwhitehorn 242224857Snwhitehorn /* Setup XPT */ 243224857Snwhitehorn 244224857Snwhitehorn PS3CDROM_LOCK(sc); 245224857Snwhitehorn 246224857Snwhitehorn err = xpt_bus_register(sc->sc_sim, dev, 0); 247224857Snwhitehorn if (err != CAM_SUCCESS) { 248224857Snwhitehorn device_printf(dev, "Could not register XPT bus\n"); 249224857Snwhitehorn err = ENXIO; 250224857Snwhitehorn PS3CDROM_UNLOCK(sc); 251224857Snwhitehorn goto fail_free_sim; 252224857Snwhitehorn } 253224857Snwhitehorn 254224857Snwhitehorn err = xpt_create_path(&sc->sc_path, NULL, cam_sim_path(sc->sc_sim), 255224857Snwhitehorn CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 256224857Snwhitehorn if (err != CAM_REQ_CMP) { 257224857Snwhitehorn device_printf(dev, "Could not create XPT path\n"); 258224857Snwhitehorn err = ENOMEM; 259224857Snwhitehorn PS3CDROM_UNLOCK(sc); 260224857Snwhitehorn goto fail_unregister_xpt_bus; 261224857Snwhitehorn } 262224857Snwhitehorn 263224857Snwhitehorn xpt_setup_ccb(&csa.ccb_h, sc->sc_path, 5); 264224857Snwhitehorn csa.ccb_h.func_code = XPT_SASYNC_CB; 265224857Snwhitehorn csa.event_enable = AC_LOST_DEVICE; 266224857Snwhitehorn csa.callback = ps3cdrom_async; 267224857Snwhitehorn csa.callback_arg = sc->sc_sim; 268224857Snwhitehorn xpt_action((union ccb *) &csa); 269224857Snwhitehorn 270224857Snwhitehorn CAM_DEBUG(sc->sc_path, CAM_DEBUG_TRACE, 271224857Snwhitehorn ("registered SIM for ps3cdrom%d\n", device_get_unit(dev))); 272224857Snwhitehorn 273224857Snwhitehorn PS3CDROM_UNLOCK(sc); 274224857Snwhitehorn 275224857Snwhitehorn return (BUS_PROBE_SPECIFIC); 276224857Snwhitehorn 277224857Snwhitehornfail_unregister_xpt_bus: 278224857Snwhitehorn 279224857Snwhitehorn xpt_bus_deregister(cam_sim_path(sc->sc_sim)); 280224857Snwhitehorn 281224857Snwhitehornfail_free_sim: 282224857Snwhitehorn 283224857Snwhitehorn cam_sim_free(sc->sc_sim, TRUE); 284224857Snwhitehorn 285224857Snwhitehornfail_destroy_dmamap: 286224857Snwhitehorn 287224857Snwhitehorn while ((xp = TAILQ_FIRST(&sc->sc_free_xferq))) { 288224857Snwhitehorn TAILQ_REMOVE(&sc->sc_free_xferq, xp, x_queue); 289224857Snwhitehorn bus_dmamap_destroy(sc->sc_dmatag, xp->x_dmamap); 290224857Snwhitehorn } 291224857Snwhitehorn 292224857Snwhitehornfail_destroy_dmatag: 293224857Snwhitehorn 294224857Snwhitehorn bus_dma_tag_destroy(sc->sc_dmatag); 295224857Snwhitehorn 296224857Snwhitehornfail_teardown_intr: 297224857Snwhitehorn 298224857Snwhitehorn bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx); 299224857Snwhitehorn 300224857Snwhitehornfail_release_intr: 301224857Snwhitehorn 302224857Snwhitehorn bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq); 303224857Snwhitehorn 304224857Snwhitehornfail_destroy_lock: 305224857Snwhitehorn 306224857Snwhitehorn PS3CDROM_LOCK_DESTROY(sc); 307224857Snwhitehorn 308224857Snwhitehorn return (err); 309224857Snwhitehorn} 310224857Snwhitehorn 311224857Snwhitehornstatic int 312224857Snwhitehornps3cdrom_detach(device_t dev) 313224857Snwhitehorn{ 314224857Snwhitehorn struct ps3cdrom_softc *sc = device_get_softc(dev); 315224857Snwhitehorn int i; 316224857Snwhitehorn 317224857Snwhitehorn xpt_async(AC_LOST_DEVICE, sc->sc_path, NULL); 318224857Snwhitehorn xpt_free_path(sc->sc_path); 319224857Snwhitehorn xpt_bus_deregister(cam_sim_path(sc->sc_sim)); 320224857Snwhitehorn cam_sim_free(sc->sc_sim, TRUE); 321224857Snwhitehorn 322224857Snwhitehorn for (i = 0; i < PS3CDROM_MAX_XFERS; i++) 323224857Snwhitehorn bus_dmamap_destroy(sc->sc_dmatag, sc->sc_xfer[i].x_dmamap); 324224857Snwhitehorn 325224857Snwhitehorn bus_dma_tag_destroy(sc->sc_dmatag); 326224857Snwhitehorn 327224857Snwhitehorn bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx); 328224857Snwhitehorn bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq); 329224857Snwhitehorn 330224857Snwhitehorn PS3CDROM_LOCK_DESTROY(sc); 331224857Snwhitehorn 332224857Snwhitehorn return (0); 333224857Snwhitehorn} 334224857Snwhitehorn 335224857Snwhitehornstatic void 336224857Snwhitehornps3cdrom_action(struct cam_sim *sim, union ccb *ccb) 337224857Snwhitehorn{ 338224857Snwhitehorn struct ps3cdrom_softc *sc = (struct ps3cdrom_softc *)cam_sim_softc(sim); 339224857Snwhitehorn device_t dev = sc->sc_dev; 340224857Snwhitehorn struct ps3cdrom_xfer *xp; 341224857Snwhitehorn int err; 342224857Snwhitehorn 343224857Snwhitehorn PS3CDROM_ASSERT_LOCKED(sc); 344224857Snwhitehorn 345224857Snwhitehorn CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, 346224857Snwhitehorn ("function code 0x%02x\n", ccb->ccb_h.func_code)); 347224857Snwhitehorn 348224857Snwhitehorn switch (ccb->ccb_h.func_code) { 349224857Snwhitehorn case XPT_SCSI_IO: 350224857Snwhitehorn if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) 351224857Snwhitehorn break; 352224857Snwhitehorn 353224857Snwhitehorn if(ccb->ccb_h.target_id > 0) { 354224857Snwhitehorn ccb->ccb_h.status = CAM_TID_INVALID; 355224857Snwhitehorn break; 356224857Snwhitehorn } 357224857Snwhitehorn 358224857Snwhitehorn if(ccb->ccb_h.target_lun > 0) { 359224857Snwhitehorn ccb->ccb_h.status = CAM_LUN_INVALID; 360224857Snwhitehorn break; 361224857Snwhitehorn } 362224857Snwhitehorn 363224857Snwhitehorn xp = TAILQ_FIRST(&sc->sc_free_xferq); 364224857Snwhitehorn 365224857Snwhitehorn KASSERT(xp != NULL, ("no free transfers")); 366224857Snwhitehorn 367224857Snwhitehorn xp->x_ccb = ccb; 368224857Snwhitehorn 369224857Snwhitehorn TAILQ_REMOVE(&sc->sc_free_xferq, xp, x_queue); 370224857Snwhitehorn 371246713Skib err = bus_dmamap_load_ccb(sc->sc_dmatag, xp->x_dmamap, 372246713Skib ccb, ps3cdrom_transfer, xp, 0); 373224857Snwhitehorn if (err && err != EINPROGRESS) { 374224857Snwhitehorn device_printf(dev, "Could not load DMA map (%d)\n", 375224857Snwhitehorn err); 376224857Snwhitehorn 377224857Snwhitehorn xp->x_ccb = NULL; 378224857Snwhitehorn TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue); 379224857Snwhitehorn ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 380224857Snwhitehorn break; 381224857Snwhitehorn } 382224857Snwhitehorn return; 383224857Snwhitehorn case XPT_SET_TRAN_SETTINGS: 384224857Snwhitehorn ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 385224857Snwhitehorn break; 386224857Snwhitehorn case XPT_GET_TRAN_SETTINGS: 387224857Snwhitehorn { 388224857Snwhitehorn struct ccb_trans_settings *cts = &ccb->cts; 389224857Snwhitehorn 390224857Snwhitehorn cts->protocol = PROTO_SCSI; 391224857Snwhitehorn cts->protocol_version = SCSI_REV_2; 392224857Snwhitehorn cts->transport = XPORT_SPI; 393224857Snwhitehorn cts->transport_version = 2; 394224857Snwhitehorn cts->proto_specific.valid = 0; 395224857Snwhitehorn cts->xport_specific.valid = 0; 396224857Snwhitehorn ccb->ccb_h.status = CAM_REQ_CMP; 397224857Snwhitehorn break; 398224857Snwhitehorn } 399224857Snwhitehorn case XPT_RESET_BUS: 400224857Snwhitehorn case XPT_RESET_DEV: 401224857Snwhitehorn ccb->ccb_h.status = CAM_REQ_CMP; 402224857Snwhitehorn break; 403224857Snwhitehorn case XPT_CALC_GEOMETRY: 404224857Snwhitehorn cam_calc_geometry(&ccb->ccg, 1); 405224857Snwhitehorn break; 406224857Snwhitehorn case XPT_PATH_INQ: 407224857Snwhitehorn { 408224857Snwhitehorn struct ccb_pathinq *cpi = &ccb->cpi; 409224857Snwhitehorn 410224857Snwhitehorn cpi->version_num = 1; 411224857Snwhitehorn cpi->hba_inquiry = 0; 412224857Snwhitehorn cpi->target_sprt = 0; 413224857Snwhitehorn cpi->hba_inquiry = PI_SDTR_ABLE; 414224857Snwhitehorn cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN | PIM_NO_6_BYTE; 415224857Snwhitehorn cpi->hba_eng_cnt = 0; 416224857Snwhitehorn bzero(cpi->vuhba_flags, sizeof(cpi->vuhba_flags)); 417224857Snwhitehorn cpi->max_target = 0; 418224857Snwhitehorn cpi->max_lun = 0; 419224857Snwhitehorn cpi->initiator_id = 7; 420224857Snwhitehorn cpi->bus_id = cam_sim_bus(sim); 421224857Snwhitehorn cpi->unit_number = cam_sim_unit(sim); 422224857Snwhitehorn cpi->base_transfer_speed = 150000; 423224857Snwhitehorn strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 424224857Snwhitehorn strncpy(cpi->hba_vid, "Sony", HBA_IDLEN); 425224857Snwhitehorn strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 426224857Snwhitehorn cpi->transport = XPORT_SPI; 427224857Snwhitehorn cpi->transport_version = 2; 428224857Snwhitehorn cpi->protocol = PROTO_SCSI; 429224857Snwhitehorn cpi->protocol_version = SCSI_REV_2; 430224857Snwhitehorn cpi->maxio = PAGE_SIZE; 431224857Snwhitehorn cpi->ccb_h.status = CAM_REQ_CMP; 432224857Snwhitehorn break; 433224857Snwhitehorn } 434224857Snwhitehorn default: 435224857Snwhitehorn CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, 436224857Snwhitehorn ("unsupported function code 0x%02x\n", 437224857Snwhitehorn ccb->ccb_h.func_code)); 438224857Snwhitehorn ccb->ccb_h.status = CAM_REQ_INVALID; 439224857Snwhitehorn break; 440224857Snwhitehorn } 441224857Snwhitehorn 442224857Snwhitehorn xpt_done(ccb); 443224857Snwhitehorn} 444224857Snwhitehorn 445224857Snwhitehornstatic void 446224857Snwhitehornps3cdrom_poll(struct cam_sim *sim) 447224857Snwhitehorn{ 448224857Snwhitehorn ps3cdrom_intr(cam_sim_softc(sim)); 449224857Snwhitehorn} 450224857Snwhitehorn 451224857Snwhitehornstatic void 452224857Snwhitehornps3cdrom_async(void *callback_arg, u_int32_t code, 453224857Snwhitehorn struct cam_path* path, void *arg) 454224857Snwhitehorn{ 455224857Snwhitehorn switch (code) { 456224857Snwhitehorn case AC_LOST_DEVICE: 457224857Snwhitehorn xpt_print_path(path); 458224857Snwhitehorn break; 459224857Snwhitehorn default: 460224857Snwhitehorn break; 461224857Snwhitehorn } 462224857Snwhitehorn} 463224857Snwhitehorn 464224857Snwhitehornstatic void 465224857Snwhitehornps3cdrom_intr(void *arg) 466224857Snwhitehorn{ 467224857Snwhitehorn struct ps3cdrom_softc *sc = (struct ps3cdrom_softc *) arg; 468224857Snwhitehorn device_t dev = sc->sc_dev; 469224857Snwhitehorn uint64_t devid = ps3bus_get_device(dev); 470224857Snwhitehorn struct ps3cdrom_xfer *xp; 471224857Snwhitehorn union ccb *ccb; 472224857Snwhitehorn u_int8_t *cdb, sense_key, asc, ascq; 473224857Snwhitehorn uint64_t tag, status; 474224857Snwhitehorn 475224857Snwhitehorn if (lv1_storage_get_async_status(devid, &tag, &status) != 0) 476224857Snwhitehorn return; 477224857Snwhitehorn 478224857Snwhitehorn PS3CDROM_LOCK(sc); 479224857Snwhitehorn 480224857Snwhitehorn /* Find transfer with the returned tag */ 481224857Snwhitehorn 482224857Snwhitehorn TAILQ_FOREACH(xp, &sc->sc_active_xferq, x_queue) { 483224857Snwhitehorn if (xp->x_tag == tag) 484224857Snwhitehorn break; 485224857Snwhitehorn } 486224857Snwhitehorn 487224857Snwhitehorn if (xp) { 488224857Snwhitehorn ccb = xp->x_ccb; 489224857Snwhitehorn cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ? 490224857Snwhitehorn ccb->csio.cdb_io.cdb_ptr : 491224857Snwhitehorn ccb->csio.cdb_io.cdb_bytes; 492224857Snwhitehorn 493224857Snwhitehorn CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, 494224857Snwhitehorn ("ATAPI command 0x%02x tag 0x%016lx completed (0x%016lx)\n", 495224857Snwhitehorn cdb[0], tag, status)); 496224857Snwhitehorn 497224857Snwhitehorn if (!status) { 498224857Snwhitehorn ccb->csio.scsi_status = SCSI_STATUS_OK; 499224857Snwhitehorn ccb->csio.resid = 0; 500224857Snwhitehorn ccb->ccb_h.status = CAM_REQ_CMP; 501224857Snwhitehorn } else { 502224857Snwhitehorn ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; 503224857Snwhitehorn ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 504224857Snwhitehorn 505224857Snwhitehorn if (!ps3cdrom_decode_lv1_status(status, &sense_key, 506224857Snwhitehorn &asc, &ascq)) { 507224857Snwhitehorn 508224857Snwhitehorn CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, 509224857Snwhitehorn ("sense key 0x%02x asc 0x%02x ascq 0x%02x\n", 510224857Snwhitehorn sense_key, asc, ascq)); 511224857Snwhitehorn 512225950Sken scsi_set_sense_data(&ccb->csio.sense_data, 513225950Sken /*sense_format*/ SSD_TYPE_NONE, 514225950Sken /*current_error*/ 1, 515225950Sken sense_key, 516225950Sken asc, 517225950Sken ascq, 518225950Sken SSD_ELEM_NONE); 519225950Sken ccb->csio.sense_len = SSD_FULL_SIZE; 520224857Snwhitehorn ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | 521224857Snwhitehorn CAM_AUTOSNS_VALID; 522224857Snwhitehorn } 523224857Snwhitehorn 524224857Snwhitehorn if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) 525224857Snwhitehorn ccb->csio.resid = ccb->csio.dxfer_len; 526224857Snwhitehorn } 527224857Snwhitehorn 528224857Snwhitehorn if (ccb->ccb_h.flags & CAM_DIR_IN) 529224857Snwhitehorn bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap, 530224857Snwhitehorn BUS_DMASYNC_POSTREAD); 531224857Snwhitehorn 532224857Snwhitehorn bus_dmamap_unload(sc->sc_dmatag, xp->x_dmamap); 533224857Snwhitehorn 534224857Snwhitehorn xp->x_ccb = NULL; 535224857Snwhitehorn TAILQ_REMOVE(&sc->sc_active_xferq, xp, x_queue); 536224857Snwhitehorn TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue); 537224857Snwhitehorn 538224857Snwhitehorn xpt_done(ccb); 539224857Snwhitehorn } else { 540224857Snwhitehorn device_printf(dev, 541224857Snwhitehorn "Could not find transfer with tag 0x%016lx\n", tag); 542224857Snwhitehorn } 543224857Snwhitehorn 544224857Snwhitehorn PS3CDROM_UNLOCK(sc); 545224857Snwhitehorn} 546224857Snwhitehorn 547224857Snwhitehornstatic void 548224857Snwhitehornps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 549224857Snwhitehorn{ 550224857Snwhitehorn struct ps3cdrom_xfer *xp = (struct ps3cdrom_xfer *) arg; 551224857Snwhitehorn struct ps3cdrom_softc *sc = xp->x_sc; 552224857Snwhitehorn device_t dev = sc->sc_dev; 553224857Snwhitehorn uint64_t devid = ps3bus_get_device(dev); 554224857Snwhitehorn union ccb *ccb = xp->x_ccb; 555224857Snwhitehorn u_int8_t *cdb; 556224857Snwhitehorn uint64_t start_sector, block_count; 557224857Snwhitehorn int err; 558224857Snwhitehorn 559255943Snwhitehorn KASSERT(nsegs == 1 || nsegs == 0, 560255943Snwhitehorn ("ps3cdrom_transfer: invalid number of DMA segments %d", nsegs)); 561255943Snwhitehorn KASSERT(error == 0, ("ps3cdrom_transfer: DMA error %d", error)); 562224857Snwhitehorn 563224857Snwhitehorn PS3CDROM_ASSERT_LOCKED(sc); 564224857Snwhitehorn 565224857Snwhitehorn if (error) { 566224857Snwhitehorn device_printf(dev, "Could not load DMA map (%d)\n", error); 567224857Snwhitehorn 568224857Snwhitehorn xp->x_ccb = NULL; 569224857Snwhitehorn TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue); 570224857Snwhitehorn ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 571224857Snwhitehorn xpt_done(ccb); 572224857Snwhitehorn return; 573224857Snwhitehorn } 574224857Snwhitehorn 575224857Snwhitehorn cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ? 576224857Snwhitehorn ccb->csio.cdb_io.cdb_ptr : 577224857Snwhitehorn ccb->csio.cdb_io.cdb_bytes; 578224857Snwhitehorn 579224857Snwhitehorn CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, 580224857Snwhitehorn ("ATAPI command 0x%02x cdb_len %d dxfer_len %d\n ", cdb[0], 581224857Snwhitehorn ccb->csio.cdb_len, ccb->csio.dxfer_len)); 582224857Snwhitehorn 583224857Snwhitehorn switch (cdb[0]) { 584224857Snwhitehorn case READ_10: 585255943Snwhitehorn KASSERT(nsegs == 1, ("ps3cdrom_transfer: no data to read")); 586224857Snwhitehorn start_sector = (cdb[2] << 24) | (cdb[3] << 16) | 587224857Snwhitehorn (cdb[4] << 8) | cdb[5]; 588224857Snwhitehorn block_count = (cdb[7] << 8) | cdb[8]; 589224857Snwhitehorn 590224857Snwhitehorn err = lv1_storage_read(devid, 0 /* region id */, 591224857Snwhitehorn start_sector, block_count, 0 /* flags */, segs[0].ds_addr, 592224857Snwhitehorn &xp->x_tag); 593224857Snwhitehorn bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap, 594224857Snwhitehorn BUS_DMASYNC_POSTREAD); 595224857Snwhitehorn break; 596224857Snwhitehorn case WRITE_10: 597255943Snwhitehorn KASSERT(nsegs == 1, ("ps3cdrom_transfer: no data to write")); 598224857Snwhitehorn start_sector = (cdb[2] << 24) | (cdb[3] << 16) | 599224857Snwhitehorn (cdb[4] << 8) | cdb[5]; 600224857Snwhitehorn block_count = (cdb[7] << 8) | cdb[8]; 601224857Snwhitehorn 602224857Snwhitehorn bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap, 603224857Snwhitehorn BUS_DMASYNC_PREWRITE); 604224857Snwhitehorn err = lv1_storage_write(devid, 0 /* region id */, 605224857Snwhitehorn start_sector, block_count, 0 /* flags */, 606224857Snwhitehorn segs[0].ds_addr, &xp->x_tag); 607224857Snwhitehorn break; 608224857Snwhitehorn default: 609224857Snwhitehorn { 610224857Snwhitehorn struct lv1_atapi_cmd atapi_cmd; 611224857Snwhitehorn 612224857Snwhitehorn bzero(&atapi_cmd, sizeof(atapi_cmd)); 613224857Snwhitehorn atapi_cmd.pktlen = 12; 614224857Snwhitehorn bcopy(cdb, atapi_cmd.pkt, ccb->csio.cdb_len); 615224857Snwhitehorn 616224857Snwhitehorn if (ccb->ccb_h.flags & CAM_DIR_IN) { 617224857Snwhitehorn atapi_cmd.in_out = DIR_READ; 618224857Snwhitehorn atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ? 619224857Snwhitehorn DMA_PROTO : PIO_DATA_IN_PROTO; 620224857Snwhitehorn } else if (ccb->ccb_h.flags & CAM_DIR_OUT) { 621224857Snwhitehorn atapi_cmd.in_out = DIR_WRITE; 622224857Snwhitehorn atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ? 623224857Snwhitehorn DMA_PROTO : PIO_DATA_OUT_PROTO; 624224857Snwhitehorn } else { 625224857Snwhitehorn atapi_cmd.proto = NON_DATA_PROTO; 626224857Snwhitehorn } 627224857Snwhitehorn 628255943Snwhitehorn atapi_cmd.nblocks = atapi_cmd.arglen = 629255943Snwhitehorn (nsegs == 0) ? 0 : segs[0].ds_len; 630224857Snwhitehorn atapi_cmd.blksize = 1; 631255943Snwhitehorn atapi_cmd.buf = (nsegs == 0) ? 0 : segs[0].ds_addr; 632224857Snwhitehorn 633224857Snwhitehorn if (ccb->ccb_h.flags & CAM_DIR_OUT) 634224857Snwhitehorn bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap, 635224857Snwhitehorn BUS_DMASYNC_PREWRITE); 636224857Snwhitehorn 637224857Snwhitehorn err = lv1_storage_send_device_command(devid, 638224857Snwhitehorn LV1_STORAGE_SEND_ATAPI_COMMAND, vtophys(&atapi_cmd), 639224857Snwhitehorn sizeof(atapi_cmd), atapi_cmd.buf, atapi_cmd.arglen, 640224857Snwhitehorn &xp->x_tag); 641224857Snwhitehorn 642224857Snwhitehorn break; 643224857Snwhitehorn } 644224857Snwhitehorn } 645224857Snwhitehorn 646224857Snwhitehorn if (err) { 647224857Snwhitehorn device_printf(dev, "ATAPI command 0x%02x failed (%d)\n", 648224857Snwhitehorn cdb[0], err); 649224857Snwhitehorn 650224857Snwhitehorn bus_dmamap_unload(sc->sc_dmatag, xp->x_dmamap); 651224857Snwhitehorn 652224857Snwhitehorn xp->x_ccb = NULL; 653224857Snwhitehorn TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue); 654224857Snwhitehorn 655225950Sken bzero(&ccb->csio.sense_data, sizeof(ccb->csio.sense_data)); 656225950Sken /* Invalid field in parameter list */ 657225950Sken scsi_set_sense_data(&ccb->csio.sense_data, 658225950Sken /*sense_format*/ SSD_TYPE_NONE, 659225950Sken /*current_error*/ 1, 660225950Sken /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 661225950Sken /*asc*/ 0x26, 662225950Sken /*ascq*/ 0x00, 663225950Sken SSD_ELEM_NONE); 664225950Sken 665225950Sken ccb->csio.sense_len = SSD_FULL_SIZE; 666225950Sken ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; 667224857Snwhitehorn ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; 668224857Snwhitehorn xpt_done(ccb); 669224857Snwhitehorn } else { 670224857Snwhitehorn CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, 671224857Snwhitehorn ("ATAPI command 0x%02x tag 0x%016lx submitted\n ", cdb[0], 672224857Snwhitehorn xp->x_tag)); 673224857Snwhitehorn 674224857Snwhitehorn TAILQ_INSERT_TAIL(&sc->sc_active_xferq, xp, x_queue); 675224857Snwhitehorn ccb->ccb_h.status |= CAM_SIM_QUEUED; 676224857Snwhitehorn } 677224857Snwhitehorn} 678224857Snwhitehorn 679224857Snwhitehornstatic int 680224857Snwhitehornps3cdrom_decode_lv1_status(uint64_t status, u_int8_t *sense_key, u_int8_t *asc, 681224857Snwhitehorn u_int8_t *ascq) 682224857Snwhitehorn{ 683224857Snwhitehorn if (((status >> 24) & 0xff) != SCSI_STATUS_CHECK_COND) 684224857Snwhitehorn return -1; 685224857Snwhitehorn 686224857Snwhitehorn *sense_key = (status >> 16) & 0xff; 687224857Snwhitehorn *asc = (status >> 8) & 0xff; 688224857Snwhitehorn *ascq = status & 0xff; 689224857Snwhitehorn 690224857Snwhitehorn return (0); 691224857Snwhitehorn} 692224857Snwhitehorn 693224857Snwhitehornstatic device_method_t ps3cdrom_methods[] = { 694224857Snwhitehorn DEVMETHOD(device_probe, ps3cdrom_probe), 695224857Snwhitehorn DEVMETHOD(device_attach, ps3cdrom_attach), 696224857Snwhitehorn DEVMETHOD(device_detach, ps3cdrom_detach), 697224857Snwhitehorn {0, 0}, 698224857Snwhitehorn}; 699224857Snwhitehorn 700224857Snwhitehornstatic driver_t ps3cdrom_driver = { 701224857Snwhitehorn "ps3cdrom", 702224857Snwhitehorn ps3cdrom_methods, 703224857Snwhitehorn sizeof(struct ps3cdrom_softc), 704224857Snwhitehorn}; 705224857Snwhitehorn 706224857Snwhitehornstatic devclass_t ps3cdrom_devclass; 707224857Snwhitehorn 708224857SnwhitehornDRIVER_MODULE(ps3cdrom, ps3bus, ps3cdrom_driver, ps3cdrom_devclass, 0, 0); 709224857SnwhitehornMODULE_DEPEND(ps3cdrom, cam, 1, 1, 1); 710