ps3cdrom.c revision 225736
1/*- 2 * Copyright (C) 2010 Nathan Whitehorn 3 * Copyright (C) 2011 glevand <geoffrey.levand@mail.ru> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer, 11 * without modification, immediately at the beginning of the file. 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#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: stable/9/sys/powerpc/ps3/ps3cdrom.c 224857 2011-08-14 00:20:37Z nwhitehorn $"); 30 31#include <sys/param.h> 32#include <sys/module.h> 33#include <sys/systm.h> 34#include <sys/kernel.h> 35#include <sys/ata.h> 36#include <sys/bus.h> 37#include <sys/conf.h> 38#include <sys/kthread.h> 39#include <sys/lock.h> 40#include <sys/malloc.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/pmap.h> 50#include <machine/resource.h> 51#include <sys/bus.h> 52#include <sys/rman.h> 53 54#include <cam/cam.h> 55#include <cam/cam_ccb.h> 56#include <cam/cam_sim.h> 57#include <cam/cam_xpt_sim.h> 58#include <cam/cam_debug.h> 59#include <cam/scsi/scsi_all.h> 60 61#include "ps3bus.h" 62#include "ps3-hvcall.h" 63 64#define PS3CDROM_LOCK_INIT(_sc) \ 65 mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), "ps3cdrom", \ 66 MTX_DEF) 67#define PS3CDROM_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 68#define PS3CDROM_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 69#define PS3CDROM_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 70#define PS3CDROM_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); 71#define PS3CDROM_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); 72 73#define PS3CDROM_MAX_XFERS 3 74 75#define LV1_STORAGE_SEND_ATAPI_COMMAND 0x01 76 77struct ps3cdrom_softc; 78 79struct ps3cdrom_xfer { 80 TAILQ_ENTRY(ps3cdrom_xfer) x_queue; 81 struct ps3cdrom_softc *x_sc; 82 union ccb *x_ccb; 83 bus_dmamap_t x_dmamap; 84 uint64_t x_tag; 85}; 86 87TAILQ_HEAD(ps3cdrom_xferq, ps3cdrom_xfer); 88 89struct ps3cdrom_softc { 90 device_t sc_dev; 91 92 struct mtx sc_mtx; 93 94 uint64_t sc_blksize; 95 uint64_t sc_nblocks; 96 97 int sc_irqid; 98 struct resource *sc_irq; 99 void *sc_irqctx; 100 101 bus_dma_tag_t sc_dmatag; 102 103 struct cam_sim *sc_sim; 104 struct cam_path *sc_path; 105 106 struct ps3cdrom_xfer sc_xfer[PS3CDROM_MAX_XFERS]; 107 struct ps3cdrom_xferq sc_active_xferq; 108 struct ps3cdrom_xferq sc_free_xferq; 109}; 110 111enum lv1_ata_proto { 112 NON_DATA_PROTO = 0x00, 113 PIO_DATA_IN_PROTO = 0x01, 114 PIO_DATA_OUT_PROTO = 0x02, 115 DMA_PROTO = 0x03 116}; 117 118enum lv1_ata_in_out { 119 DIR_WRITE = 0x00, 120 DIR_READ = 0x01 121}; 122 123struct lv1_atapi_cmd { 124 uint8_t pkt[32]; 125 uint32_t pktlen; 126 uint32_t nblocks; 127 uint32_t blksize; 128 uint32_t proto; /* enum lv1_ata_proto */ 129 uint32_t in_out; /* enum lv1_ata_in_out */ 130 uint64_t buf; 131 uint32_t arglen; 132}; 133 134static void ps3cdrom_action(struct cam_sim *sim, union ccb *ccb); 135static void ps3cdrom_poll(struct cam_sim *sim); 136static void ps3cdrom_async(void *callback_arg, u_int32_t code, 137 struct cam_path* path, void *arg); 138 139static void ps3cdrom_intr(void *arg); 140 141static void ps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, 142 int error); 143 144static int ps3cdrom_decode_lv1_status(uint64_t status, 145 u_int8_t *sense_key, u_int8_t *asc, u_int8_t *ascq); 146 147static int 148ps3cdrom_probe(device_t dev) 149{ 150 if (ps3bus_get_bustype(dev) != PS3_BUSTYPE_STORAGE || 151 ps3bus_get_devtype(dev) != PS3_DEVTYPE_CDROM) 152 return (ENXIO); 153 154 device_set_desc(dev, "Playstation 3 CDROM"); 155 156 return (BUS_PROBE_SPECIFIC); 157} 158 159static int 160ps3cdrom_attach(device_t dev) 161{ 162 struct ps3cdrom_softc *sc = device_get_softc(dev); 163 struct cam_devq *devq; 164 struct ps3cdrom_xfer *xp; 165 struct ccb_setasync csa; 166 int i, err; 167 168 sc->sc_dev = dev; 169 170 PS3CDROM_LOCK_INIT(sc); 171 172 /* Setup interrupt handler */ 173 174 sc->sc_irqid = 0; 175 sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid, 176 RF_ACTIVE); 177 if (!sc->sc_irq) { 178 device_printf(dev, "Could not allocate IRQ\n"); 179 err = ENXIO; 180 goto fail_destroy_lock; 181 } 182 183 err = bus_setup_intr(dev, sc->sc_irq, 184 INTR_TYPE_CAM | INTR_MPSAFE | INTR_ENTROPY, 185 NULL, ps3cdrom_intr, sc, &sc->sc_irqctx); 186 if (err) { 187 device_printf(dev, "Could not setup IRQ\n"); 188 err = ENXIO; 189 goto fail_release_intr; 190 } 191 192 /* Setup DMA */ 193 194 err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0, 195 BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 196 BUS_SPACE_UNRESTRICTED, 1, PAGE_SIZE, 0, 197 busdma_lock_mutex, &sc->sc_mtx, &sc->sc_dmatag); 198 if (err) { 199 device_printf(dev, "Could not create DMA tag\n"); 200 err = ENXIO; 201 goto fail_teardown_intr; 202 } 203 204 /* Setup transfer queues */ 205 206 TAILQ_INIT(&sc->sc_active_xferq); 207 TAILQ_INIT(&sc->sc_free_xferq); 208 209 for (i = 0; i < PS3CDROM_MAX_XFERS; i++) { 210 xp = &sc->sc_xfer[i]; 211 xp->x_sc = sc; 212 213 err = bus_dmamap_create(sc->sc_dmatag, BUS_DMA_COHERENT, 214 &xp->x_dmamap); 215 if (err) { 216 device_printf(dev, "Could not create DMA map (%d)\n", 217 err); 218 goto fail_destroy_dmamap; 219 } 220 221 TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue); 222 } 223 224 /* Setup CAM */ 225 226 devq = cam_simq_alloc(PS3CDROM_MAX_XFERS - 1); 227 if (!devq) { 228 device_printf(dev, "Could not allocate SIM queue\n"); 229 err = ENOMEM; 230 goto fail_destroy_dmatag; 231 } 232 233 sc->sc_sim = cam_sim_alloc(ps3cdrom_action, ps3cdrom_poll, "ps3cdrom", 234 sc, device_get_unit(dev), &sc->sc_mtx, PS3CDROM_MAX_XFERS - 1, 0, 235 devq); 236 if (!sc->sc_sim) { 237 device_printf(dev, "Could not allocate SIM\n"); 238 cam_simq_free(devq); 239 err = ENOMEM; 240 goto fail_destroy_dmatag; 241 } 242 243 /* Setup XPT */ 244 245 PS3CDROM_LOCK(sc); 246 247 err = xpt_bus_register(sc->sc_sim, dev, 0); 248 if (err != CAM_SUCCESS) { 249 device_printf(dev, "Could not register XPT bus\n"); 250 err = ENXIO; 251 PS3CDROM_UNLOCK(sc); 252 goto fail_free_sim; 253 } 254 255 err = xpt_create_path(&sc->sc_path, NULL, cam_sim_path(sc->sc_sim), 256 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 257 if (err != CAM_REQ_CMP) { 258 device_printf(dev, "Could not create XPT path\n"); 259 err = ENOMEM; 260 PS3CDROM_UNLOCK(sc); 261 goto fail_unregister_xpt_bus; 262 } 263 264 xpt_setup_ccb(&csa.ccb_h, sc->sc_path, 5); 265 csa.ccb_h.func_code = XPT_SASYNC_CB; 266 csa.event_enable = AC_LOST_DEVICE; 267 csa.callback = ps3cdrom_async; 268 csa.callback_arg = sc->sc_sim; 269 xpt_action((union ccb *) &csa); 270 271 CAM_DEBUG(sc->sc_path, CAM_DEBUG_TRACE, 272 ("registered SIM for ps3cdrom%d\n", device_get_unit(dev))); 273 274 PS3CDROM_UNLOCK(sc); 275 276 return (BUS_PROBE_SPECIFIC); 277 278fail_unregister_xpt_bus: 279 280 xpt_bus_deregister(cam_sim_path(sc->sc_sim)); 281 282fail_free_sim: 283 284 cam_sim_free(sc->sc_sim, TRUE); 285 286fail_destroy_dmamap: 287 288 while ((xp = TAILQ_FIRST(&sc->sc_free_xferq))) { 289 TAILQ_REMOVE(&sc->sc_free_xferq, xp, x_queue); 290 bus_dmamap_destroy(sc->sc_dmatag, xp->x_dmamap); 291 } 292 293fail_destroy_dmatag: 294 295 bus_dma_tag_destroy(sc->sc_dmatag); 296 297fail_teardown_intr: 298 299 bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx); 300 301fail_release_intr: 302 303 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq); 304 305fail_destroy_lock: 306 307 PS3CDROM_LOCK_DESTROY(sc); 308 309 return (err); 310} 311 312static int 313ps3cdrom_detach(device_t dev) 314{ 315 struct ps3cdrom_softc *sc = device_get_softc(dev); 316 int i; 317 318 xpt_async(AC_LOST_DEVICE, sc->sc_path, NULL); 319 xpt_free_path(sc->sc_path); 320 xpt_bus_deregister(cam_sim_path(sc->sc_sim)); 321 cam_sim_free(sc->sc_sim, TRUE); 322 323 for (i = 0; i < PS3CDROM_MAX_XFERS; i++) 324 bus_dmamap_destroy(sc->sc_dmatag, sc->sc_xfer[i].x_dmamap); 325 326 bus_dma_tag_destroy(sc->sc_dmatag); 327 328 bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx); 329 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq); 330 331 PS3CDROM_LOCK_DESTROY(sc); 332 333 return (0); 334} 335 336static void 337ps3cdrom_action(struct cam_sim *sim, union ccb *ccb) 338{ 339 struct ps3cdrom_softc *sc = (struct ps3cdrom_softc *)cam_sim_softc(sim); 340 device_t dev = sc->sc_dev; 341 struct ps3cdrom_xfer *xp; 342 int err; 343 344 PS3CDROM_ASSERT_LOCKED(sc); 345 346 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, 347 ("function code 0x%02x\n", ccb->ccb_h.func_code)); 348 349 switch (ccb->ccb_h.func_code) { 350 case XPT_SCSI_IO: 351 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) 352 break; 353 354 if(ccb->ccb_h.target_id > 0) { 355 ccb->ccb_h.status = CAM_TID_INVALID; 356 break; 357 } 358 359 if(ccb->ccb_h.target_lun > 0) { 360 ccb->ccb_h.status = CAM_LUN_INVALID; 361 break; 362 } 363 364 xp = TAILQ_FIRST(&sc->sc_free_xferq); 365 366 KASSERT(xp != NULL, ("no free transfers")); 367 368 xp->x_ccb = ccb; 369 370 TAILQ_REMOVE(&sc->sc_free_xferq, xp, x_queue); 371 372 err = bus_dmamap_load(sc->sc_dmatag, xp->x_dmamap, 373 ccb->csio.data_ptr, ccb->csio.dxfer_len, ps3cdrom_transfer, 374 xp, 0); 375 if (err && err != EINPROGRESS) { 376 device_printf(dev, "Could not load DMA map (%d)\n", 377 err); 378 379 xp->x_ccb = NULL; 380 TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue); 381 ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 382 break; 383 } 384 return; 385 case XPT_SET_TRAN_SETTINGS: 386 ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 387 break; 388 case XPT_GET_TRAN_SETTINGS: 389 { 390 struct ccb_trans_settings *cts = &ccb->cts; 391 392 cts->protocol = PROTO_SCSI; 393 cts->protocol_version = SCSI_REV_2; 394 cts->transport = XPORT_SPI; 395 cts->transport_version = 2; 396 cts->proto_specific.valid = 0; 397 cts->xport_specific.valid = 0; 398 ccb->ccb_h.status = CAM_REQ_CMP; 399 break; 400 } 401 case XPT_RESET_BUS: 402 case XPT_RESET_DEV: 403 ccb->ccb_h.status = CAM_REQ_CMP; 404 break; 405 case XPT_CALC_GEOMETRY: 406 cam_calc_geometry(&ccb->ccg, 1); 407 break; 408 case XPT_PATH_INQ: 409 { 410 struct ccb_pathinq *cpi = &ccb->cpi; 411 412 cpi->version_num = 1; 413 cpi->hba_inquiry = 0; 414 cpi->target_sprt = 0; 415 cpi->hba_inquiry = PI_SDTR_ABLE; 416 cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN | PIM_NO_6_BYTE; 417 cpi->hba_eng_cnt = 0; 418 bzero(cpi->vuhba_flags, sizeof(cpi->vuhba_flags)); 419 cpi->max_target = 0; 420 cpi->max_lun = 0; 421 cpi->initiator_id = 7; 422 cpi->bus_id = cam_sim_bus(sim); 423 cpi->unit_number = cam_sim_unit(sim); 424 cpi->base_transfer_speed = 150000; 425 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 426 strncpy(cpi->hba_vid, "Sony", HBA_IDLEN); 427 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 428 cpi->transport = XPORT_SPI; 429 cpi->transport_version = 2; 430 cpi->protocol = PROTO_SCSI; 431 cpi->protocol_version = SCSI_REV_2; 432 cpi->maxio = PAGE_SIZE; 433 cpi->ccb_h.status = CAM_REQ_CMP; 434 break; 435 } 436 default: 437 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, 438 ("unsupported function code 0x%02x\n", 439 ccb->ccb_h.func_code)); 440 ccb->ccb_h.status = CAM_REQ_INVALID; 441 break; 442 } 443 444 xpt_done(ccb); 445} 446 447static void 448ps3cdrom_poll(struct cam_sim *sim) 449{ 450 ps3cdrom_intr(cam_sim_softc(sim)); 451} 452 453static void 454ps3cdrom_async(void *callback_arg, u_int32_t code, 455 struct cam_path* path, void *arg) 456{ 457 switch (code) { 458 case AC_LOST_DEVICE: 459 xpt_print_path(path); 460 break; 461 default: 462 break; 463 } 464} 465 466static void 467ps3cdrom_intr(void *arg) 468{ 469 struct ps3cdrom_softc *sc = (struct ps3cdrom_softc *) arg; 470 device_t dev = sc->sc_dev; 471 uint64_t devid = ps3bus_get_device(dev); 472 struct ps3cdrom_xfer *xp; 473 union ccb *ccb; 474 u_int8_t *cdb, sense_key, asc, ascq; 475 uint64_t tag, status; 476 477 if (lv1_storage_get_async_status(devid, &tag, &status) != 0) 478 return; 479 480 PS3CDROM_LOCK(sc); 481 482 /* Find transfer with the returned tag */ 483 484 TAILQ_FOREACH(xp, &sc->sc_active_xferq, x_queue) { 485 if (xp->x_tag == tag) 486 break; 487 } 488 489 if (xp) { 490 ccb = xp->x_ccb; 491 cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ? 492 ccb->csio.cdb_io.cdb_ptr : 493 ccb->csio.cdb_io.cdb_bytes; 494 495 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, 496 ("ATAPI command 0x%02x tag 0x%016lx completed (0x%016lx)\n", 497 cdb[0], tag, status)); 498 499 if (!status) { 500 ccb->csio.scsi_status = SCSI_STATUS_OK; 501 ccb->csio.resid = 0; 502 ccb->ccb_h.status = CAM_REQ_CMP; 503 } else { 504 ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; 505 ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 506 507 if (!ps3cdrom_decode_lv1_status(status, &sense_key, 508 &asc, &ascq)) { 509 struct scsi_sense_data sense_data; 510 511 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, 512 ("sense key 0x%02x asc 0x%02x ascq 0x%02x\n", 513 sense_key, asc, ascq)); 514 515 bzero(&sense_data, sizeof(sense_data)); 516 sense_data.error_code = SSD_CURRENT_ERROR; 517 sense_data.flags |= sense_key; 518 sense_data.extra_len = 0xa; 519 sense_data.add_sense_code = asc; 520 sense_data.add_sense_code_qual = ascq; 521 ccb->csio.sense_len = sizeof(sense_data); 522 bcopy(&sense_data, &ccb->csio.sense_data, 523 ccb->csio.sense_len); 524 ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | 525 CAM_AUTOSNS_VALID; 526 } 527 528 if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) 529 ccb->csio.resid = ccb->csio.dxfer_len; 530 } 531 532 if (ccb->ccb_h.flags & CAM_DIR_IN) 533 bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap, 534 BUS_DMASYNC_POSTREAD); 535 536 bus_dmamap_unload(sc->sc_dmatag, xp->x_dmamap); 537 538 xp->x_ccb = NULL; 539 TAILQ_REMOVE(&sc->sc_active_xferq, xp, x_queue); 540 TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue); 541 542 xpt_done(ccb); 543 } else { 544 device_printf(dev, 545 "Could not find transfer with tag 0x%016lx\n", tag); 546 } 547 548 PS3CDROM_UNLOCK(sc); 549} 550 551static void 552ps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 553{ 554 struct ps3cdrom_xfer *xp = (struct ps3cdrom_xfer *) arg; 555 struct ps3cdrom_softc *sc = xp->x_sc; 556 device_t dev = sc->sc_dev; 557 uint64_t devid = ps3bus_get_device(dev); 558 union ccb *ccb = xp->x_ccb; 559 u_int8_t *cdb; 560 uint64_t start_sector, block_count; 561 int err; 562 563 KASSERT(nsegs == 1, ("invalid number of DMA segments")); 564 565 PS3CDROM_ASSERT_LOCKED(sc); 566 567 if (error) { 568 device_printf(dev, "Could not load DMA map (%d)\n", error); 569 570 xp->x_ccb = NULL; 571 TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue); 572 ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 573 xpt_done(ccb); 574 return; 575 } 576 577 cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ? 578 ccb->csio.cdb_io.cdb_ptr : 579 ccb->csio.cdb_io.cdb_bytes; 580 581 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, 582 ("ATAPI command 0x%02x cdb_len %d dxfer_len %d\n ", cdb[0], 583 ccb->csio.cdb_len, ccb->csio.dxfer_len)); 584 585 switch (cdb[0]) { 586 case READ_10: 587 start_sector = (cdb[2] << 24) | (cdb[3] << 16) | 588 (cdb[4] << 8) | cdb[5]; 589 block_count = (cdb[7] << 8) | cdb[8]; 590 591 err = lv1_storage_read(devid, 0 /* region id */, 592 start_sector, block_count, 0 /* flags */, segs[0].ds_addr, 593 &xp->x_tag); 594 bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap, 595 BUS_DMASYNC_POSTREAD); 596 break; 597 case WRITE_10: 598 start_sector = (cdb[2] << 24) | (cdb[3] << 16) | 599 (cdb[4] << 8) | cdb[5]; 600 block_count = (cdb[7] << 8) | cdb[8]; 601 602 bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap, 603 BUS_DMASYNC_PREWRITE); 604 err = lv1_storage_write(devid, 0 /* region id */, 605 start_sector, block_count, 0 /* flags */, 606 segs[0].ds_addr, &xp->x_tag); 607 break; 608 default: 609 { 610 struct lv1_atapi_cmd atapi_cmd; 611 612 bzero(&atapi_cmd, sizeof(atapi_cmd)); 613 atapi_cmd.pktlen = 12; 614 bcopy(cdb, atapi_cmd.pkt, ccb->csio.cdb_len); 615 616 if (ccb->ccb_h.flags & CAM_DIR_IN) { 617 atapi_cmd.in_out = DIR_READ; 618 atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ? 619 DMA_PROTO : PIO_DATA_IN_PROTO; 620 } else if (ccb->ccb_h.flags & CAM_DIR_OUT) { 621 atapi_cmd.in_out = DIR_WRITE; 622 atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ? 623 DMA_PROTO : PIO_DATA_OUT_PROTO; 624 } else { 625 atapi_cmd.proto = NON_DATA_PROTO; 626 } 627 628 atapi_cmd.nblocks = atapi_cmd.arglen = segs[0].ds_len; 629 atapi_cmd.blksize = 1; 630 atapi_cmd.buf = segs[0].ds_addr; 631 632 if (ccb->ccb_h.flags & CAM_DIR_OUT) 633 bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap, 634 BUS_DMASYNC_PREWRITE); 635 636 err = lv1_storage_send_device_command(devid, 637 LV1_STORAGE_SEND_ATAPI_COMMAND, vtophys(&atapi_cmd), 638 sizeof(atapi_cmd), atapi_cmd.buf, atapi_cmd.arglen, 639 &xp->x_tag); 640 641 break; 642 } 643 } 644 645 if (err) { 646 struct scsi_sense_data sense_data; 647 648 device_printf(dev, "ATAPI command 0x%02x failed (%d)\n", 649 cdb[0], err); 650 651 bus_dmamap_unload(sc->sc_dmatag, xp->x_dmamap); 652 653 xp->x_ccb = NULL; 654 TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue); 655 656 bzero(&sense_data, sizeof(sense_data)); 657 sense_data.error_code = SSD_CURRENT_ERROR; 658 sense_data.flags |= SSD_KEY_ILLEGAL_REQUEST; 659 ccb->csio.sense_len = sizeof(sense_data); 660 bcopy(&sense_data, &ccb->csio.sense_data, ccb->csio.sense_len); 661 ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; 662 xpt_done(ccb); 663 } else { 664 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, 665 ("ATAPI command 0x%02x tag 0x%016lx submitted\n ", cdb[0], 666 xp->x_tag)); 667 668 TAILQ_INSERT_TAIL(&sc->sc_active_xferq, xp, x_queue); 669 ccb->ccb_h.status |= CAM_SIM_QUEUED; 670 } 671} 672 673static int 674ps3cdrom_decode_lv1_status(uint64_t status, u_int8_t *sense_key, u_int8_t *asc, 675 u_int8_t *ascq) 676{ 677 if (((status >> 24) & 0xff) != SCSI_STATUS_CHECK_COND) 678 return -1; 679 680 *sense_key = (status >> 16) & 0xff; 681 *asc = (status >> 8) & 0xff; 682 *ascq = status & 0xff; 683 684 return (0); 685} 686 687static device_method_t ps3cdrom_methods[] = { 688 DEVMETHOD(device_probe, ps3cdrom_probe), 689 DEVMETHOD(device_attach, ps3cdrom_attach), 690 DEVMETHOD(device_detach, ps3cdrom_detach), 691 {0, 0}, 692}; 693 694static driver_t ps3cdrom_driver = { 695 "ps3cdrom", 696 ps3cdrom_methods, 697 sizeof(struct ps3cdrom_softc), 698}; 699 700static devclass_t ps3cdrom_devclass; 701 702DRIVER_MODULE(ps3cdrom, ps3bus, ps3cdrom_driver, ps3cdrom_devclass, 0, 0); 703MODULE_DEPEND(ps3cdrom, cam, 1, 1, 1); 704