The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/powerpc/ps3/ps3cdrom.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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: releng/10.1/sys/powerpc/ps3/ps3cdrom.c 255943 2013-09-29 20:10:22Z 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 
   77 struct ps3cdrom_softc;
   78 
   79 struct 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 
   87 TAILQ_HEAD(ps3cdrom_xferq, ps3cdrom_xfer);
   88 
   89 struct 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 
  111 enum 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 
  118 enum lv1_ata_in_out {
  119         DIR_WRITE               = 0x00,
  120         DIR_READ                = 0x01
  121 };
  122 
  123 struct 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 
  134 static void ps3cdrom_action(struct cam_sim *sim, union ccb *ccb);
  135 static void ps3cdrom_poll(struct cam_sim *sim);
  136 static void ps3cdrom_async(void *callback_arg, u_int32_t code,
  137     struct cam_path* path, void *arg);
  138 
  139 static void ps3cdrom_intr(void *arg);
  140 
  141 static void ps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs,
  142     int error);
  143 
  144 static int ps3cdrom_decode_lv1_status(uint64_t status,
  145         u_int8_t *sense_key, u_int8_t *asc, u_int8_t *ascq);
  146 
  147 static int
  148 ps3cdrom_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 
  159 static int
  160 ps3cdrom_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 
  278 fail_unregister_xpt_bus:
  279 
  280         xpt_bus_deregister(cam_sim_path(sc->sc_sim));
  281 
  282 fail_free_sim:
  283 
  284         cam_sim_free(sc->sc_sim, TRUE);
  285 
  286 fail_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 
  293 fail_destroy_dmatag:
  294 
  295         bus_dma_tag_destroy(sc->sc_dmatag);
  296 
  297 fail_teardown_intr:
  298 
  299         bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
  300 
  301 fail_release_intr:
  302 
  303         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
  304 
  305 fail_destroy_lock:
  306 
  307         PS3CDROM_LOCK_DESTROY(sc);
  308 
  309         return (err);
  310 }
  311 
  312 static int
  313 ps3cdrom_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 
  336 static void
  337 ps3cdrom_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_ccb(sc->sc_dmatag, xp->x_dmamap,
  373                     ccb, ps3cdrom_transfer, xp, 0);
  374                 if (err && err != EINPROGRESS) {
  375                         device_printf(dev, "Could not load DMA map (%d)\n",
  376                             err);
  377 
  378                         xp->x_ccb = NULL;
  379                         TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
  380                         ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
  381                         break;
  382                 }
  383                 return;
  384         case XPT_SET_TRAN_SETTINGS:
  385                 ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
  386                 break;
  387         case XPT_GET_TRAN_SETTINGS:
  388         {
  389                 struct ccb_trans_settings *cts = &ccb->cts;
  390 
  391                 cts->protocol = PROTO_SCSI;
  392                 cts->protocol_version = SCSI_REV_2;
  393                 cts->transport = XPORT_SPI;
  394                 cts->transport_version = 2;
  395                 cts->proto_specific.valid = 0;
  396                 cts->xport_specific.valid = 0;
  397                 ccb->ccb_h.status = CAM_REQ_CMP;
  398                 break;
  399         }
  400         case XPT_RESET_BUS:
  401         case XPT_RESET_DEV:
  402                 ccb->ccb_h.status = CAM_REQ_CMP;
  403                 break;
  404         case XPT_CALC_GEOMETRY:
  405                 cam_calc_geometry(&ccb->ccg, 1);
  406                 break;
  407         case XPT_PATH_INQ:
  408         {
  409                 struct ccb_pathinq *cpi = &ccb->cpi;
  410 
  411                 cpi->version_num = 1;
  412                 cpi->hba_inquiry = 0;
  413                 cpi->target_sprt = 0;
  414                 cpi->hba_inquiry = PI_SDTR_ABLE;
  415                 cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN | PIM_NO_6_BYTE;
  416                 cpi->hba_eng_cnt = 0;
  417                 bzero(cpi->vuhba_flags, sizeof(cpi->vuhba_flags));
  418                 cpi->max_target = 0;
  419                 cpi->max_lun = 0;
  420                 cpi->initiator_id = 7;
  421                 cpi->bus_id = cam_sim_bus(sim);
  422                 cpi->unit_number = cam_sim_unit(sim);
  423                 cpi->base_transfer_speed = 150000;
  424                 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
  425                 strncpy(cpi->hba_vid, "Sony", HBA_IDLEN);
  426                 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
  427                 cpi->transport = XPORT_SPI;
  428                 cpi->transport_version = 2;
  429                 cpi->protocol = PROTO_SCSI;
  430                 cpi->protocol_version = SCSI_REV_2;
  431                 cpi->maxio = PAGE_SIZE;
  432                 cpi->ccb_h.status = CAM_REQ_CMP;
  433                 break;
  434         }
  435         default:
  436                 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
  437                     ("unsupported function code 0x%02x\n",
  438                     ccb->ccb_h.func_code));
  439                 ccb->ccb_h.status = CAM_REQ_INVALID;
  440                 break;
  441         }
  442 
  443         xpt_done(ccb);
  444 }
  445 
  446 static void
  447 ps3cdrom_poll(struct cam_sim *sim)
  448 {
  449         ps3cdrom_intr(cam_sim_softc(sim));
  450 }
  451 
  452 static void
  453 ps3cdrom_async(void *callback_arg, u_int32_t code,
  454         struct cam_path* path, void *arg)
  455 {
  456         switch (code) {
  457         case AC_LOST_DEVICE:
  458                 xpt_print_path(path);
  459                 break;
  460         default:
  461                 break;
  462         }
  463 }
  464 
  465 static void
  466 ps3cdrom_intr(void *arg)
  467 {
  468         struct ps3cdrom_softc *sc = (struct ps3cdrom_softc *) arg;
  469         device_t dev = sc->sc_dev;
  470         uint64_t devid = ps3bus_get_device(dev);
  471         struct ps3cdrom_xfer *xp;
  472         union ccb *ccb;
  473         u_int8_t *cdb, sense_key, asc, ascq;
  474         uint64_t tag, status;
  475 
  476         if (lv1_storage_get_async_status(devid, &tag, &status) != 0)
  477                 return;
  478 
  479         PS3CDROM_LOCK(sc);
  480 
  481         /* Find transfer with the returned tag */
  482 
  483         TAILQ_FOREACH(xp, &sc->sc_active_xferq, x_queue) {
  484                 if (xp->x_tag == tag)
  485                         break;
  486         }
  487 
  488         if (xp) {
  489                 ccb = xp->x_ccb;
  490                 cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ?
  491                             ccb->csio.cdb_io.cdb_ptr :
  492                             ccb->csio.cdb_io.cdb_bytes;
  493 
  494                 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
  495                    ("ATAPI command 0x%02x tag 0x%016lx completed (0x%016lx)\n",
  496                     cdb[0], tag, status));
  497 
  498                 if (!status) {
  499                         ccb->csio.scsi_status = SCSI_STATUS_OK;
  500                         ccb->csio.resid = 0;
  501                         ccb->ccb_h.status = CAM_REQ_CMP;
  502                 } else {
  503                         ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
  504                         ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
  505 
  506                         if (!ps3cdrom_decode_lv1_status(status, &sense_key,
  507                             &asc, &ascq)) {
  508 
  509                                 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
  510                                    ("sense key 0x%02x asc 0x%02x ascq 0x%02x\n",
  511                                     sense_key, asc, ascq));
  512 
  513                                 scsi_set_sense_data(&ccb->csio.sense_data,
  514                                     /*sense_format*/ SSD_TYPE_NONE,
  515                                     /*current_error*/ 1,
  516                                     sense_key,
  517                                     asc,
  518                                     ascq,
  519                                     SSD_ELEM_NONE);
  520                                 ccb->csio.sense_len = SSD_FULL_SIZE;
  521                                 ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR |
  522                                     CAM_AUTOSNS_VALID;
  523                         }
  524 
  525                         if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
  526                                 ccb->csio.resid = ccb->csio.dxfer_len;
  527                 }
  528 
  529                 if (ccb->ccb_h.flags & CAM_DIR_IN)
  530                         bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
  531                             BUS_DMASYNC_POSTREAD);
  532 
  533                 bus_dmamap_unload(sc->sc_dmatag, xp->x_dmamap);
  534 
  535                 xp->x_ccb = NULL;
  536                 TAILQ_REMOVE(&sc->sc_active_xferq, xp, x_queue);
  537                 TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
  538 
  539                 xpt_done(ccb);
  540         } else {
  541                 device_printf(dev,
  542                     "Could not find transfer with tag 0x%016lx\n",  tag);
  543         }
  544 
  545         PS3CDROM_UNLOCK(sc);
  546 }
  547 
  548 static void
  549 ps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
  550 {
  551         struct ps3cdrom_xfer *xp = (struct ps3cdrom_xfer *) arg;
  552         struct ps3cdrom_softc *sc = xp->x_sc;
  553         device_t dev = sc->sc_dev;
  554         uint64_t devid = ps3bus_get_device(dev);
  555         union ccb *ccb = xp->x_ccb;
  556         u_int8_t *cdb;
  557         uint64_t start_sector, block_count;
  558         int err;
  559 
  560         KASSERT(nsegs == 1 || nsegs == 0,
  561             ("ps3cdrom_transfer: invalid number of DMA segments %d", nsegs));
  562         KASSERT(error == 0, ("ps3cdrom_transfer: DMA error %d", error));
  563 
  564         PS3CDROM_ASSERT_LOCKED(sc);
  565 
  566         if (error) {
  567                 device_printf(dev, "Could not load DMA map (%d)\n",  error);
  568 
  569                 xp->x_ccb = NULL;
  570                 TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
  571                 ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
  572                 xpt_done(ccb);
  573                 return;
  574         }
  575 
  576         cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ?
  577                     ccb->csio.cdb_io.cdb_ptr :
  578                     ccb->csio.cdb_io.cdb_bytes;
  579 
  580         CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
  581            ("ATAPI command 0x%02x cdb_len %d dxfer_len %d\n ", cdb[0],
  582             ccb->csio.cdb_len, ccb->csio.dxfer_len));
  583 
  584         switch (cdb[0]) {
  585         case READ_10:
  586                 KASSERT(nsegs == 1, ("ps3cdrom_transfer: no data to read"));
  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                 KASSERT(nsegs == 1, ("ps3cdrom_transfer: no data to write"));
  599                 start_sector = (cdb[2] << 24) | (cdb[3] << 16) |
  600                     (cdb[4] << 8) | cdb[5];
  601                 block_count = (cdb[7] << 8) | cdb[8];
  602 
  603                 bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
  604                     BUS_DMASYNC_PREWRITE);
  605                 err = lv1_storage_write(devid, 0 /* region id */,
  606                     start_sector, block_count, 0 /* flags */,
  607                     segs[0].ds_addr, &xp->x_tag);
  608                 break;
  609         default:
  610                 {
  611                 struct lv1_atapi_cmd atapi_cmd;
  612 
  613                 bzero(&atapi_cmd, sizeof(atapi_cmd));
  614                 atapi_cmd.pktlen = 12;
  615                 bcopy(cdb, atapi_cmd.pkt, ccb->csio.cdb_len);
  616 
  617                 if (ccb->ccb_h.flags & CAM_DIR_IN) {
  618                         atapi_cmd.in_out = DIR_READ;
  619                         atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ?
  620                             DMA_PROTO : PIO_DATA_IN_PROTO;
  621                 } else if (ccb->ccb_h.flags & CAM_DIR_OUT) {
  622                         atapi_cmd.in_out = DIR_WRITE;
  623                         atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ?
  624                             DMA_PROTO : PIO_DATA_OUT_PROTO;
  625                 } else {
  626                         atapi_cmd.proto = NON_DATA_PROTO;
  627                 }
  628 
  629                 atapi_cmd.nblocks = atapi_cmd.arglen =
  630                     (nsegs == 0) ? 0 : segs[0].ds_len;
  631                 atapi_cmd.blksize = 1;
  632                 atapi_cmd.buf = (nsegs == 0) ? 0 : segs[0].ds_addr;
  633 
  634                 if (ccb->ccb_h.flags & CAM_DIR_OUT)
  635                         bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
  636                             BUS_DMASYNC_PREWRITE);
  637 
  638                 err = lv1_storage_send_device_command(devid,
  639                     LV1_STORAGE_SEND_ATAPI_COMMAND, vtophys(&atapi_cmd),
  640                     sizeof(atapi_cmd), atapi_cmd.buf, atapi_cmd.arglen,
  641                     &xp->x_tag);
  642         
  643                 break;
  644                 }
  645         }
  646 
  647         if (err) {
  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(&ccb->csio.sense_data, sizeof(ccb->csio.sense_data));
  657                 /* Invalid field in parameter list */
  658                 scsi_set_sense_data(&ccb->csio.sense_data,
  659                                     /*sense_format*/ SSD_TYPE_NONE,
  660                                     /*current_error*/ 1,
  661                                     /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
  662                                     /*asc*/ 0x26,
  663                                     /*ascq*/ 0x00,
  664                                     SSD_ELEM_NONE);
  665 
  666                 ccb->csio.sense_len = SSD_FULL_SIZE;
  667                 ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
  668                 ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
  669                 xpt_done(ccb);
  670         } else {
  671                 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
  672                    ("ATAPI command 0x%02x tag 0x%016lx submitted\n ", cdb[0],
  673                    xp->x_tag));
  674 
  675                 TAILQ_INSERT_TAIL(&sc->sc_active_xferq, xp, x_queue);
  676                 ccb->ccb_h.status |= CAM_SIM_QUEUED;
  677         }
  678 }
  679 
  680 static int
  681 ps3cdrom_decode_lv1_status(uint64_t status, u_int8_t *sense_key, u_int8_t *asc,
  682     u_int8_t *ascq)
  683 {
  684         if (((status >> 24) & 0xff) != SCSI_STATUS_CHECK_COND)
  685                 return -1;
  686 
  687         *sense_key = (status >> 16) & 0xff;
  688         *asc = (status >> 8) & 0xff;
  689         *ascq = status & 0xff;
  690 
  691         return (0);
  692 }
  693 
  694 static device_method_t ps3cdrom_methods[] = {
  695         DEVMETHOD(device_probe,         ps3cdrom_probe),
  696         DEVMETHOD(device_attach,        ps3cdrom_attach),
  697         DEVMETHOD(device_detach,        ps3cdrom_detach),
  698         {0, 0},
  699 };
  700 
  701 static driver_t ps3cdrom_driver = {
  702         "ps3cdrom",
  703         ps3cdrom_methods,
  704         sizeof(struct ps3cdrom_softc),
  705 };
  706 
  707 static devclass_t ps3cdrom_devclass;
  708 
  709 DRIVER_MODULE(ps3cdrom, ps3bus, ps3cdrom_driver, ps3cdrom_devclass, 0, 0);
  710 MODULE_DEPEND(ps3cdrom, cam, 1, 1, 1);

Cache object: d477d3bc826047d8d246c6e9b2156f8a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.