]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/ps3/ps3cdrom.c
MFV r336950: 9290 device removal reduces redundancy of mirrors
[FreeBSD/FreeBSD.git] / sys / powerpc / ps3 / ps3cdrom.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (C) 2010 Nathan Whitehorn
5  * Copyright (C) 2011 glevand <geoffrey.levand@mail.ru>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer,
13  *    without modification, immediately at the beginning of the file.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/module.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/ata.h>
38 #include <sys/bus.h>
39 #include <sys/conf.h>
40 #include <sys/kthread.h>
41 #include <sys/lock.h>
42 #include <sys/malloc.h>
43 #include <sys/mutex.h>
44
45 #include <vm/vm.h>
46 #include <vm/pmap.h>
47
48 #include <machine/pio.h>
49 #include <machine/bus.h>
50 #include <machine/platform.h>
51 #include <machine/resource.h>
52 #include <sys/bus.h>
53 #include <sys/rman.h>
54
55 #include <cam/cam.h>
56 #include <cam/cam_ccb.h>
57 #include <cam/cam_sim.h>
58 #include <cam/cam_xpt_sim.h>
59 #include <cam/cam_debug.h>
60 #include <cam/scsi/scsi_all.h>
61
62 #include "ps3bus.h"
63 #include "ps3-hvcall.h"
64
65 #define PS3CDROM_LOCK_INIT(_sc)         \
66         mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), "ps3cdrom", \
67             MTX_DEF)
68 #define PS3CDROM_LOCK_DESTROY(_sc)      mtx_destroy(&_sc->sc_mtx);
69 #define PS3CDROM_LOCK(_sc)              mtx_lock(&(_sc)->sc_mtx)
70 #define PS3CDROM_UNLOCK(_sc)            mtx_unlock(&(_sc)->sc_mtx)
71 #define PS3CDROM_ASSERT_LOCKED(_sc)     mtx_assert(&_sc->sc_mtx, MA_OWNED);
72 #define PS3CDROM_ASSERT_UNLOCKED(_sc)   mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
73
74 #define PS3CDROM_MAX_XFERS              3
75
76 #define LV1_STORAGE_SEND_ATAPI_COMMAND  0x01
77
78 struct ps3cdrom_softc;
79
80 struct ps3cdrom_xfer {
81         TAILQ_ENTRY(ps3cdrom_xfer) x_queue;
82         struct ps3cdrom_softc *x_sc;
83         union ccb *x_ccb;
84         bus_dmamap_t x_dmamap;
85         uint64_t x_tag;
86 };
87
88 TAILQ_HEAD(ps3cdrom_xferq, ps3cdrom_xfer);
89
90 struct ps3cdrom_softc {
91         device_t sc_dev;
92
93         struct mtx sc_mtx;
94
95         uint64_t sc_blksize;
96         uint64_t sc_nblocks;
97
98         int sc_irqid;
99         struct resource *sc_irq;
100         void *sc_irqctx;
101
102         bus_dma_tag_t sc_dmatag;
103
104         struct cam_sim *sc_sim;
105         struct cam_path *sc_path;
106
107         struct ps3cdrom_xfer sc_xfer[PS3CDROM_MAX_XFERS];
108         struct ps3cdrom_xferq sc_active_xferq;
109         struct ps3cdrom_xferq sc_free_xferq;
110 };
111
112 enum lv1_ata_proto {
113         NON_DATA_PROTO          = 0x00,
114         PIO_DATA_IN_PROTO       = 0x01,
115         PIO_DATA_OUT_PROTO      = 0x02,
116         DMA_PROTO               = 0x03
117 };
118
119 enum lv1_ata_in_out {
120         DIR_WRITE               = 0x00,
121         DIR_READ                = 0x01
122 };
123
124 struct lv1_atapi_cmd {
125         uint8_t pkt[32];
126         uint32_t pktlen;
127         uint32_t nblocks;
128         uint32_t blksize;
129         uint32_t proto;         /* enum lv1_ata_proto */
130         uint32_t in_out;        /* enum lv1_ata_in_out */
131         uint64_t buf;
132         uint32_t arglen;
133 };
134
135 static void ps3cdrom_action(struct cam_sim *sim, union ccb *ccb);
136 static void ps3cdrom_poll(struct cam_sim *sim);
137 static void ps3cdrom_async(void *callback_arg, u_int32_t code,
138     struct cam_path* path, void *arg);
139
140 static void ps3cdrom_intr(void *arg);
141
142 static void ps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs,
143     int error);
144
145 static int ps3cdrom_decode_lv1_status(uint64_t status,
146         u_int8_t *sense_key, u_int8_t *asc, u_int8_t *ascq);
147
148 static int
149 ps3cdrom_probe(device_t dev)
150 {
151         if (ps3bus_get_bustype(dev) != PS3_BUSTYPE_STORAGE ||
152             ps3bus_get_devtype(dev) != PS3_DEVTYPE_CDROM)
153                 return (ENXIO);
154
155         device_set_desc(dev, "Playstation 3 CDROM");
156
157         return (BUS_PROBE_SPECIFIC);
158 }
159
160 static int
161 ps3cdrom_attach(device_t dev)
162 {
163         struct ps3cdrom_softc *sc = device_get_softc(dev);
164         struct cam_devq *devq;
165         struct ps3cdrom_xfer *xp;
166         struct ccb_setasync csa;
167         int i, err;
168
169         sc->sc_dev = dev;
170
171         PS3CDROM_LOCK_INIT(sc);
172
173         /* Setup interrupt handler */
174
175         sc->sc_irqid = 0;
176         sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid,
177             RF_ACTIVE);
178         if (!sc->sc_irq) {
179                 device_printf(dev, "Could not allocate IRQ\n");
180                 err = ENXIO;
181                 goto fail_destroy_lock;
182         }
183
184         err = bus_setup_intr(dev, sc->sc_irq,
185             INTR_TYPE_CAM | INTR_MPSAFE | INTR_ENTROPY,
186             NULL, ps3cdrom_intr, sc, &sc->sc_irqctx);
187         if (err) {
188                 device_printf(dev, "Could not setup IRQ\n");
189                 err = ENXIO;
190                 goto fail_release_intr;
191         }
192
193         /* Setup DMA */
194
195         err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0,
196             BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
197             BUS_SPACE_UNRESTRICTED, 1, PAGE_SIZE, 0,
198             busdma_lock_mutex, &sc->sc_mtx, &sc->sc_dmatag);
199         if (err) {
200                 device_printf(dev, "Could not create DMA tag\n");
201                 err = ENXIO;
202                 goto fail_teardown_intr;
203         }
204
205         /* Setup transfer queues */
206
207         TAILQ_INIT(&sc->sc_active_xferq);
208         TAILQ_INIT(&sc->sc_free_xferq);
209
210         for (i = 0; i < PS3CDROM_MAX_XFERS; i++) {
211                 xp = &sc->sc_xfer[i];
212                 xp->x_sc = sc;
213
214                 err = bus_dmamap_create(sc->sc_dmatag, BUS_DMA_COHERENT,
215                     &xp->x_dmamap);
216                 if (err) {
217                         device_printf(dev, "Could not create DMA map (%d)\n",
218                             err);
219                         goto fail_destroy_dmamap;
220                 }
221
222                 TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
223         }
224
225         /* Setup CAM */
226
227         devq = cam_simq_alloc(PS3CDROM_MAX_XFERS - 1);
228         if (!devq) {
229                 device_printf(dev, "Could not allocate SIM queue\n");
230                 err = ENOMEM;
231                 goto fail_destroy_dmatag;
232         }
233
234         sc->sc_sim = cam_sim_alloc(ps3cdrom_action, ps3cdrom_poll, "ps3cdrom",
235             sc, device_get_unit(dev), &sc->sc_mtx, PS3CDROM_MAX_XFERS - 1, 0,
236             devq);
237         if (!sc->sc_sim) {
238                 device_printf(dev, "Could not allocate SIM\n");
239                 cam_simq_free(devq);
240                 err = ENOMEM;
241                 goto fail_destroy_dmatag;
242         }
243
244         /* Setup XPT */
245
246         PS3CDROM_LOCK(sc);
247
248         err = xpt_bus_register(sc->sc_sim, dev, 0);
249         if (err != CAM_SUCCESS) {
250                 device_printf(dev, "Could not register XPT bus\n");
251                 err = ENXIO;
252                 PS3CDROM_UNLOCK(sc);
253                 goto fail_free_sim;
254         }
255
256         err = xpt_create_path(&sc->sc_path, NULL, cam_sim_path(sc->sc_sim),
257             CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
258         if (err != CAM_REQ_CMP) {
259                 device_printf(dev, "Could not create XPT path\n");
260                 err = ENOMEM;
261                 PS3CDROM_UNLOCK(sc);
262                 goto fail_unregister_xpt_bus;
263         }
264
265         xpt_setup_ccb(&csa.ccb_h, sc->sc_path, 5);
266         csa.ccb_h.func_code = XPT_SASYNC_CB;
267         csa.event_enable = AC_LOST_DEVICE;
268         csa.callback = ps3cdrom_async;
269         csa.callback_arg = sc->sc_sim;
270         xpt_action((union ccb *) &csa);
271
272         CAM_DEBUG(sc->sc_path, CAM_DEBUG_TRACE,
273             ("registered SIM for ps3cdrom%d\n", device_get_unit(dev)));
274
275         PS3CDROM_UNLOCK(sc);
276
277         return (BUS_PROBE_SPECIFIC);
278
279 fail_unregister_xpt_bus:
280
281         xpt_bus_deregister(cam_sim_path(sc->sc_sim));
282
283 fail_free_sim:
284
285         cam_sim_free(sc->sc_sim, TRUE);
286
287 fail_destroy_dmamap:
288
289         while ((xp = TAILQ_FIRST(&sc->sc_free_xferq))) {
290                 TAILQ_REMOVE(&sc->sc_free_xferq, xp, x_queue);
291                 bus_dmamap_destroy(sc->sc_dmatag, xp->x_dmamap);
292         }
293
294 fail_destroy_dmatag:
295
296         bus_dma_tag_destroy(sc->sc_dmatag);
297
298 fail_teardown_intr:
299
300         bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
301
302 fail_release_intr:
303
304         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
305
306 fail_destroy_lock:
307
308         PS3CDROM_LOCK_DESTROY(sc);
309
310         return (err);
311 }
312
313 static int
314 ps3cdrom_detach(device_t dev)
315 {
316         struct ps3cdrom_softc *sc = device_get_softc(dev);
317         int i;
318
319         xpt_async(AC_LOST_DEVICE, sc->sc_path, NULL);
320         xpt_free_path(sc->sc_path);
321         xpt_bus_deregister(cam_sim_path(sc->sc_sim));
322         cam_sim_free(sc->sc_sim, TRUE);
323
324         for (i = 0; i < PS3CDROM_MAX_XFERS; i++)
325                 bus_dmamap_destroy(sc->sc_dmatag, sc->sc_xfer[i].x_dmamap);
326
327         bus_dma_tag_destroy(sc->sc_dmatag);
328
329         bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
330         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
331
332         PS3CDROM_LOCK_DESTROY(sc);
333
334         return (0);
335 }
336
337 static void
338 ps3cdrom_action(struct cam_sim *sim, union ccb *ccb)
339 {
340         struct ps3cdrom_softc *sc = (struct ps3cdrom_softc *)cam_sim_softc(sim);
341         device_t dev = sc->sc_dev;
342         struct ps3cdrom_xfer *xp;
343         int err;
344
345         PS3CDROM_ASSERT_LOCKED(sc);
346
347         CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
348            ("function code 0x%02x\n", ccb->ccb_h.func_code));
349
350         switch (ccb->ccb_h.func_code) {
351         case XPT_SCSI_IO:
352                 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG)
353                         break;
354
355                 if(ccb->ccb_h.target_id > 0) {
356                         ccb->ccb_h.status = CAM_TID_INVALID;
357                         break;
358                 }
359
360                 if(ccb->ccb_h.target_lun > 0) {
361                         ccb->ccb_h.status = CAM_LUN_INVALID;
362                         break;
363                 }
364
365                 xp = TAILQ_FIRST(&sc->sc_free_xferq);
366                 
367                 KASSERT(xp != NULL, ("no free transfers"));
368
369                 xp->x_ccb = ccb;
370
371                 TAILQ_REMOVE(&sc->sc_free_xferq, xp, x_queue);
372
373                 err = bus_dmamap_load_ccb(sc->sc_dmatag, xp->x_dmamap,
374                     ccb, ps3cdrom_transfer, 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                 strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
426                 strlcpy(cpi->hba_vid, "Sony", HBA_IDLEN);
427                 strlcpy(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
447 static void
448 ps3cdrom_poll(struct cam_sim *sim)
449 {
450         ps3cdrom_intr(cam_sim_softc(sim));
451 }
452
453 static void
454 ps3cdrom_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
466 static void
467 ps3cdrom_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
510                                 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
511                                    ("sense key 0x%02x asc 0x%02x ascq 0x%02x\n",
512                                     sense_key, asc, ascq));
513
514                                 scsi_set_sense_data(&ccb->csio.sense_data,
515                                     /*sense_format*/ SSD_TYPE_NONE,
516                                     /*current_error*/ 1,
517                                     sense_key,
518                                     asc,
519                                     ascq,
520                                     SSD_ELEM_NONE);
521                                 ccb->csio.sense_len = SSD_FULL_SIZE;
522                                 ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR |
523                                     CAM_AUTOSNS_VALID;
524                         }
525
526                         if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
527                                 ccb->csio.resid = ccb->csio.dxfer_len;
528                 }
529
530                 if (ccb->ccb_h.flags & CAM_DIR_IN)
531                         bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
532                             BUS_DMASYNC_POSTREAD);
533
534                 bus_dmamap_unload(sc->sc_dmatag, xp->x_dmamap);
535
536                 xp->x_ccb = NULL;
537                 TAILQ_REMOVE(&sc->sc_active_xferq, xp, x_queue);
538                 TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
539
540                 xpt_done(ccb);
541         } else {
542                 device_printf(dev,
543                     "Could not find transfer with tag 0x%016lx\n",  tag);
544         }
545
546         PS3CDROM_UNLOCK(sc);
547 }
548
549 static void
550 ps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
551 {
552         struct ps3cdrom_xfer *xp = (struct ps3cdrom_xfer *) arg;
553         struct ps3cdrom_softc *sc = xp->x_sc;
554         device_t dev = sc->sc_dev;
555         uint64_t devid = ps3bus_get_device(dev);
556         union ccb *ccb = xp->x_ccb;
557         u_int8_t *cdb;
558         uint64_t start_sector, block_count;
559         int err;
560
561         KASSERT(nsegs == 1 || nsegs == 0,
562             ("ps3cdrom_transfer: invalid number of DMA segments %d", nsegs));
563         KASSERT(error == 0, ("ps3cdrom_transfer: DMA error %d", error));
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                 KASSERT(nsegs == 1, ("ps3cdrom_transfer: no data to read"));
588                 start_sector = (cdb[2] << 24) | (cdb[3] << 16) |
589                     (cdb[4] << 8) | cdb[5];
590                 block_count = (cdb[7] << 8) | cdb[8];
591
592                 err = lv1_storage_read(devid, 0 /* region id */,
593                     start_sector, block_count, 0 /* flags */, segs[0].ds_addr,
594                     &xp->x_tag);
595                 bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
596                     BUS_DMASYNC_POSTREAD);
597                 break;
598         case WRITE_10:
599                 KASSERT(nsegs == 1, ("ps3cdrom_transfer: no data to write"));
600                 start_sector = (cdb[2] << 24) | (cdb[3] << 16) |
601                     (cdb[4] << 8) | cdb[5];
602                 block_count = (cdb[7] << 8) | cdb[8];
603
604                 bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
605                     BUS_DMASYNC_PREWRITE);
606                 err = lv1_storage_write(devid, 0 /* region id */,
607                     start_sector, block_count, 0 /* flags */,
608                     segs[0].ds_addr, &xp->x_tag);
609                 break;
610         default:
611                 {
612                 struct lv1_atapi_cmd atapi_cmd;
613
614                 bzero(&atapi_cmd, sizeof(atapi_cmd));
615                 atapi_cmd.pktlen = 12;
616                 bcopy(cdb, atapi_cmd.pkt, ccb->csio.cdb_len);
617
618                 if (ccb->ccb_h.flags & CAM_DIR_IN) {
619                         atapi_cmd.in_out = DIR_READ;
620                         atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ?
621                             DMA_PROTO : PIO_DATA_IN_PROTO;
622                 } else if (ccb->ccb_h.flags & CAM_DIR_OUT) {
623                         atapi_cmd.in_out = DIR_WRITE;
624                         atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ?
625                             DMA_PROTO : PIO_DATA_OUT_PROTO;
626                 } else {
627                         atapi_cmd.proto = NON_DATA_PROTO;
628                 }
629
630                 atapi_cmd.nblocks = atapi_cmd.arglen =
631                     (nsegs == 0) ? 0 : segs[0].ds_len;
632                 atapi_cmd.blksize = 1;
633                 atapi_cmd.buf = (nsegs == 0) ? 0 : segs[0].ds_addr;
634
635                 if (ccb->ccb_h.flags & CAM_DIR_OUT)
636                         bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
637                             BUS_DMASYNC_PREWRITE);
638
639                 err = lv1_storage_send_device_command(devid,
640                     LV1_STORAGE_SEND_ATAPI_COMMAND, vtophys(&atapi_cmd),
641                     sizeof(atapi_cmd), atapi_cmd.buf, atapi_cmd.arglen,
642                     &xp->x_tag);
643         
644                 break;
645                 }
646         }
647
648         if (err) {
649                 device_printf(dev, "ATAPI command 0x%02x failed (%d)\n",
650                     cdb[0], err);
651
652                 bus_dmamap_unload(sc->sc_dmatag, xp->x_dmamap);
653
654                 xp->x_ccb = NULL;
655                 TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
656
657                 bzero(&ccb->csio.sense_data, sizeof(ccb->csio.sense_data));
658                 /* Invalid field in parameter list */
659                 scsi_set_sense_data(&ccb->csio.sense_data,
660                                     /*sense_format*/ SSD_TYPE_NONE,
661                                     /*current_error*/ 1,
662                                     /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
663                                     /*asc*/ 0x26,
664                                     /*ascq*/ 0x00,
665                                     SSD_ELEM_NONE);
666
667                 ccb->csio.sense_len = SSD_FULL_SIZE;
668                 ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
669                 ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
670                 xpt_done(ccb);
671         } else {
672                 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
673                    ("ATAPI command 0x%02x tag 0x%016lx submitted\n ", cdb[0],
674                    xp->x_tag));
675
676                 TAILQ_INSERT_TAIL(&sc->sc_active_xferq, xp, x_queue);
677                 ccb->ccb_h.status |= CAM_SIM_QUEUED;
678         }
679 }
680
681 static int
682 ps3cdrom_decode_lv1_status(uint64_t status, u_int8_t *sense_key, u_int8_t *asc,
683     u_int8_t *ascq)
684 {
685         if (((status >> 24) & 0xff) != SCSI_STATUS_CHECK_COND)
686                 return -1;
687
688         *sense_key = (status >> 16) & 0xff;
689         *asc = (status >> 8) & 0xff;
690         *ascq = status & 0xff;
691
692         return (0);
693 }
694
695 static device_method_t ps3cdrom_methods[] = {
696         DEVMETHOD(device_probe,         ps3cdrom_probe),
697         DEVMETHOD(device_attach,        ps3cdrom_attach),
698         DEVMETHOD(device_detach,        ps3cdrom_detach),
699         {0, 0},
700 };
701
702 static driver_t ps3cdrom_driver = {
703         "ps3cdrom",
704         ps3cdrom_methods,
705         sizeof(struct ps3cdrom_softc),
706 };
707
708 static devclass_t ps3cdrom_devclass;
709
710 DRIVER_MODULE(ps3cdrom, ps3bus, ps3cdrom_driver, ps3cdrom_devclass, 0, 0);
711 MODULE_DEPEND(ps3cdrom, cam, 1, 1, 1);