void sd_cmd_rw12(struct scsi_xfer *xs, int read, u_int64_t secno, u_int nsecs) { struct scsi_rw_12 *cmd = (struct scsi_rw_12 *)xs->cmd; cmd->opcode = read ? READ_12 : WRITE_12; _lto4b(secno, cmd->addr); _lto4b(nsecs, cmd->length); xs->cmdlen = sizeof(*cmd); }
/*--------------------------------------------------------------------------- * *--------------------------------------------------------------------------*/ scsi_command_t * SCSI_rw_command (int rw, uint blkno, uint bcount) { scsi_command_t *c = (scsi_command_t *) ≻ memset(c,0,sizeof(scsi_command_t)); /* if (((blkno & 0x1fffff) == blkno) && ((nblks & 0xff) == nblks)) { */ /* transfer can be described in small RW SCSI command, so do it */ /* struct scsi_rw *cmd_small = (struct scsi_rw *) &(c->command); cmd_small->opcode = (rw == B_READ) ? READ_COMMAND : WRITE_COMMAND; _lto3b (blkno, cmd_small->addr); cmd_small->length = nblks & 0xff; c->length = sizeof (struct scsi_rw); } else */ { struct scsi_rw_10 *cmd_big = (struct scsi_rw_10 *) &(c->command); cmd_big->opcode = (rw == B_READ) ? READ_10 : WRITE_10; _lto4b (blkno, cmd_big->addr); _lto2b (bcount, cmd_big->length); c->length = sizeof (struct scsi_rw_10); } c->datalen = bcount*SECT_SIZE; return ((scsi_command_t *) c); }
int scsi_read(struct scsi_private *priv, daddr32_t blk, size_t size, void *buf, size_t *rsize) { union { struct scsi_rw rw; struct scsi_rw_big rw_big; struct scsi_rw_12 rw_12; } cmd; int nsecs; size_t cmdlen; int i, rc; nsecs = (size + DEV_BSIZE - 1) >> _DEV_BSHIFT; for (i = SCSI_RETRIES; i != 0; i--) { memset(&cmd, 0, sizeof cmd); /* XXX SDEV_ONLYBIG quirk */ if ((blk & 0x1fffff) == blk && (nsecs & 0xff) == nsecs) { cmd.rw.opcode = READ_COMMAND; _lto3b(blk, cmd.rw.addr); cmd.rw.length = nsecs; cmdlen = sizeof cmd.rw; } else if ((nsecs & 0xffff) == nsecs) { cmd.rw_big.opcode = READ_BIG; _lto4b(blk, cmd.rw_big.addr); _lto2b(nsecs, cmd.rw_big.length); cmdlen = sizeof cmd.rw_big; } else { cmd.rw_12.opcode = READ_12; _lto4b(blk, cmd.rw_12.addr); _lto4b(nsecs, cmd.rw_12.length); cmdlen = sizeof cmd.rw_12; } rc = (*priv->scsicmd)(priv->scsicookie, &cmd, sizeof cmd, buf, size, rsize); if (rc == 0) break; } return rc; }
void sd_cmd_rw16(struct scsi_xfer *xs, int read, daddr64_t blkno, u_int nblks) { struct scsi_rw_16 *cmd = (struct scsi_rw_16 *)xs->cmd; cmd->opcode = read ? READ_16 : WRITE_16; _lto8b(blkno, cmd->addr); _lto4b(nblks, cmd->length); xs->cmdlen = sizeof(*cmd); }
void vdsk_scsi_capacity(struct scsi_xfer *xs) { struct vdsk_softc *sc = xs->sc_link->adapter_softc; struct scsi_read_cap_data rcd; uint64_t capacity; bzero(&rcd, sizeof(rcd)); capacity = sc->sc_vdisk_size - 1; if (capacity > 0xffffffff) capacity = 0xffffffff; _lto4b(capacity, rcd.addr); _lto4b(sc->sc_vdisk_block_size, rcd.length); bcopy(&rcd, xs->data, MIN(sizeof(rcd), xs->datalen)); vdsk_scsi_done(xs, XS_NOERROR); }
void sd_cmd_rw10(struct scsi_xfer *xs, int read, daddr64_t blkno, u_int nblks) { struct scsi_rw_big *cmd = (struct scsi_rw_big *)xs->cmd; cmd->opcode = read ? READ_BIG : WRITE_BIG; _lto4b(blkno, cmd->addr); _lto2b(nblks, cmd->length); xs->cmdlen = sizeof(*cmd); }
/* * sd_read_capacity: * * Find out from the device what its capacity is. */ static uint64_t sd_read_capacity(struct sd_softc *sd, int *blksize) { union { struct scsipi_read_capacity_10 cmd; struct scsipi_read_capacity_16 cmd16; } cmd; union { struct scsipi_read_capacity_10_data data; struct scsipi_read_capacity_16_data data16; } data; uint64_t rv; memset(&cmd, 0, sizeof(cmd)); cmd.cmd.opcode = READ_CAPACITY_10; /* * If the command works, interpret the result as a 4 byte * number of blocks */ rv = 0; memset(&data, 0, sizeof(data.data)); if (scsi_command(sd, (void *)&cmd.cmd, sizeof(cmd.cmd), (void *)&data, sizeof(data.data)) != 0) goto out; if (_4btol(data.data.addr) != 0xffffffff) { *blksize = _4btol(data.data.length); rv = _4btol(data.data.addr) + 1; goto out; } /* * Device is larger than can be reflected by READ CAPACITY (10). * Try READ CAPACITY (16). */ memset(&cmd, 0, sizeof(cmd)); cmd.cmd16.opcode = READ_CAPACITY_16; cmd.cmd16.byte2 = SRC16_SERVICE_ACTION; _lto4b(sizeof(data.data16), cmd.cmd16.len); memset(&data, 0, sizeof(data.data16)); if (scsi_command(sd, (void *)&cmd.cmd16, sizeof(cmd.cmd16), (void *)&data, sizeof(data.data16)) != 0) goto out; *blksize = _4btol(data.data16.length); rv = _8btol(data.data16.addr) + 1; out: return rv; }
/*--------------------------------------------------------------------------- * *--------------------------------------------------------------------------*/ scsi_command_t * SCSI_read_defect_data (uint datalen) { scsi_command_t *c = (scsi_command_t *) ≻ #ifdef USE_READ_DEFECT_DATA_10 struct scsi_read_defect_data_10 *cmd = (struct scsi_read_defect_data_10 *) &(c->command); memset(c,0,sizeof(scsi_command_t)); #ifdef DIXTRAC_FREEBSD_CAM // CAM restricts I/O to 64K of I/O, rounded up to include the full set of pages // so limit max I/O size to 60 Kbytes datalen = min(datalen, (60*1024)); #else datalen = min(datalen, 0xFFFF); #endif //DIXTRAC_FREEBSD_CAM c->length = 10; cmd->opcode = READ_DEFECT_DATA_10; cmd->format = SRDDH10_PLIST | SRDDH10_GLIST | SRDDH10_PHYSICAL_SECTOR_FORMAT; _lto2b(datalen,cmd->alloc_length); /* alloclen */ #else struct scsi_read_defect_data_12 *cmd = (struct scsi_read_defect_data_12 *) &(c->command); memset(c,0,sizeof(scsi_command_t)); #ifdef DIXTRAC_FREEBSD_CAM // CAM restricts I/O to 64K of I/O, rounded up to include the full set of pages // so limit max I/O size to 60 Kbytes datalen = min(datalen, (60*1024)); #else datalen = min(datalen, 0x1FFFF); #endif //DIXTRAC_FREEBSD_CAM c->length = 12; cmd->opcode = READ_DEFECT_DATA_12; cmd->format = SRDDH12_PLIST | SRDDH12_GLIST | SRDDH12_PHYSICAL_SECTOR_FORMAT; _lto4b(datalen, cmd->alloc_length); /* alloclen */ #endif c->datalen = datalen; cmd->byte2 = 0; /* LUN + reserved */ cmd->reserved[0] = 0; cmd->reserved[1] = 0; cmd->reserved[1] = 0; cmd->reserved[3] = 0; cmd->control = 0; /* unknown control bits */ return ((scsi_command_t *) c); }
/* * Get scsi driver to send a "start playing" command */ int cd_play(struct cd_softc *cd, int blkno, int nblks) { struct scsi_play scsi_cmd; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.opcode = PLAY; _lto4b(blkno, scsi_cmd.blk_addr); _lto2b(nblks, scsi_cmd.xfer_len); return (scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd), 0, 0, SCSI_RETRIES, 200000, NULL, 0)); }
void vdsk_scsi_capacity16(struct scsi_xfer *xs) { struct vdsk_softc *sc = xs->sc_link->adapter_softc; struct scsi_read_cap_data_16 rcd; bzero(&rcd, sizeof(rcd)); _lto8b(sc->sc_vdisk_size - 1, rcd.addr); _lto4b(sc->sc_vdisk_block_size, rcd.length); bcopy(&rcd, xs->data, MIN(sizeof(rcd), xs->datalen)); vdsk_scsi_done(xs, XS_NOERROR); }
/*--------------------------------------------------------------------------- * *--------------------------------------------------------------------------*/ scsi_command_t * SCSI_read_capacity(uint lbn,u_int8_t pmi) { scsi_command_t *c = (scsi_command_t *) ≻ struct scsi_read_capacity *cmd = (struct scsi_read_capacity *) &(c->command); memset(c,0,sizeof(scsi_command_t)); c->length = sizeof (struct scsi_read_capacity); c->datalen = READCAP_LENGTH; cmd->opcode = READ_CAPACITY; cmd->byte2 = 0x0; /* LUN=0 */ _lto4b (lbn,cmd->addr); /* __lto3b(0,cmd->unused); */ cmd->unused[2]=pmi; return ((scsi_command_t *) c); }
/*--------------------------------------------------------------------------- * *--------------------------------------------------------------------------*/ int create_lba_to_phys_page(char *p,int addr) { memset(p,0,TRANS_ADDR_PAGE_LEN+4); p[0]=TRANS_ADDR_PAGE; p[1]=0; p[2]=0; p[3]=TRANS_ADDR_PAGE_LEN; p[4] = 0x0; /* supplied format */ p[5] = 0x05; /* translate format */ _lto4b(addr,(u_int8_t *) &p[6]); return(TRANS_ADDR_PAGE_LEN+4); }
/*--------------------------------------------------------------------------- * *--------------------------------------------------------------------------*/ int create_phys_to_lba_page(char *p,int cyl,int head,int sector) { memset(p,0,TRANS_ADDR_PAGE_LEN+4); p[0]=TRANS_ADDR_PAGE; p[1]=0; p[2]=0; p[3]=TRANS_ADDR_PAGE_LEN; p[4] = 0x05; /* supplied format */ p[5] = 0x0; /* translate format */ _lto3b(cyl,(u_int8_t *) &p[6]); p[9] = (u_int8_t) head; _lto4b(sector,(u_int8_t *) &p[10]); return(TRANS_ADDR_PAGE_LEN+4); }
int sd_read_cap_16(struct sd_softc *sc, int flags) { struct scsi_read_capacity_16 cdb; struct scsi_read_cap_data_16 *rdcap; struct scsi_xfer *xs; int rv = ENOMEM; CLR(flags, SCSI_IGNORE_ILLEGAL_REQUEST); rdcap = dma_alloc(sizeof(*rdcap), (ISSET(flags, SCSI_NOSLEEP) ? PR_NOWAIT : PR_WAITOK) | PR_ZERO); if (rdcap == NULL) return (ENOMEM); xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT); if (xs == NULL) goto done; bzero(&cdb, sizeof(cdb)); cdb.opcode = READ_CAPACITY_16; cdb.byte2 = SRC16_SERVICE_ACTION; _lto4b(sizeof(*rdcap), cdb.length); memcpy(xs->cmd, &cdb, sizeof(cdb)); xs->cmdlen = sizeof(cdb); xs->data = (void *)rdcap; xs->datalen = sizeof(*rdcap); xs->timeout = 20000; rv = scsi_xs_sync(xs); scsi_xs_put(xs); if (rv == 0) { sc->params.disksize = _8btol(rdcap->addr) + 1; sc->params.secsize = _4btol(rdcap->length); if (ISSET(_2btol(rdcap->lowest_aligned), READ_CAP_16_TPE)) SET(sc->flags, SDF_THIN); else CLR(sc->flags, SDF_THIN); } done: dma_free(rdcap, sizeof(*rdcap)); return (rv); }
/*--------------------------------------------------------------------------- * *--------------------------------------------------------------------------*/ scsi_command_t * SCSI_seek_command (uint lbn) { scsi_command_t *c = (scsi_command_t *) ≻ struct scsi_seek_extended *cmd = (struct scsi_seek_extended *) &(c->command); memset (c, 0,sizeof(scsi_command_t)); c->length = 10; c->datalen = 0; cmd->opcode = SEEK_EXTENDED; /* lbn */ _lto4b(lbn,cmd->lbn); return ((scsi_command_t *) c); }
static int ld_twa_scsicmd(struct ld_twa_softc *sc, struct twa_request *tr, struct buf *bp) { if (tr->tr_flags == TWA_CMD_DATA_IN) { tr->tr_command->command.cmd_pkt_9k.cdb[0] = WRITE_16; } else { tr->tr_command->command.cmd_pkt_9k.cdb[0] = READ_16; } tr->tr_command->command.cmd_pkt_9k.cdb[1] = (sc->sc_hwunit << 5); /* lun for CDB */ _lto8b(htole64(bp->b_rawblkno), &tr->tr_command->command.cmd_pkt_9k.cdb[2]); _lto4b(htole32((bp->b_bcount / TWA_SECTOR_SIZE)), &tr->tr_command->command.cmd_pkt_9k.cdb[10]); tr->tr_command->command.cmd_pkt_9k.cdb[14] = 0; tr->tr_command->command.cmd_pkt_9k.cdb[15] = 0; return (0); }
struct scsi_generic * build_scsi_rw_command (int rw, uint blkno, uint bcount, int *cmdlen) { uint nblks = howmany (bcount, SECT_SIZE); if (((blkno & 0x1fffff) == blkno) && ((nblks & 0xff) == nblks)) { /* transfer can be described in small RW SCSI command, so do it */ struct scsi_rw *cmd_small = (struct scsi_rw *) malloc (sizeof(struct scsi_rw)); bzero (cmd_small, sizeof(struct scsi_rw)); cmd_small->opcode = (rw == B_READ) ? READ_COMMAND : WRITE_COMMAND; _lto3b (blkno, cmd_small->addr); cmd_small->length = nblks & 0xff; *cmdlen = sizeof (struct scsi_rw); return ((struct scsi_generic *) cmd_small); } else { struct scsi_rw_big *cmd_big = (struct scsi_rw_big *) malloc (sizeof(struct scsi_rw_big)); bzero (cmd_big, sizeof(struct scsi_rw_big)); cmd_big->opcode = (rw == B_READ) ? READ_BIG : WRITE_BIG; _lto4b (blkno, cmd_big->addr); _lto2b (nblks, cmd_big->length); *cmdlen = sizeof (struct scsi_rw_big); return ((struct scsi_generic *) cmd_big); } }
SANE_Status sane_start (SANE_Handle handle) { char *mode_str; Ibm_Scanner *s = handle; SANE_Status status; struct ibm_window_data wbuf; struct measurements_units_page mup; DBG (11, ">> sane_start\n"); /* First make sure we have a current parameter set. Some of the parameters will be overwritten below, but that's OK. */ status = sane_get_parameters (s, 0); if (status != SANE_STATUS_GOOD) return status; status = sanei_scsi_open (s->hw->sane.name, &s->fd, 0, 0); if (status != SANE_STATUS_GOOD) { DBG (1, "open of %s failed: %s\n", s->hw->sane.name, sane_strstatus (status)); return (status); } mode_str = s->val[OPT_MODE].s; s->xres = s->val[OPT_X_RESOLUTION].w; s->yres = s->val[OPT_Y_RESOLUTION].w; s->ulx = s->val[OPT_TL_X].w; s->uly = s->val[OPT_TL_Y].w; s->width = s->val[OPT_BR_X].w - s->val[OPT_TL_X].w; s->length = s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w; s->brightness = s->val[OPT_BRIGHTNESS].w; s->contrast = s->val[OPT_CONTRAST].w; s->bpp = s->params.depth; if (strcmp (mode_str, SANE_VALUE_SCAN_MODE_LINEART) == 0) { s->image_composition = IBM_BINARY_MONOCHROME; } else if (strcmp (mode_str, SANE_VALUE_SCAN_MODE_HALFTONE) == 0) { s->image_composition = IBM_DITHERED_MONOCHROME; } else if (strcmp (mode_str, SANE_VALUE_SCAN_MODE_GRAY) == 0) { s->image_composition = IBM_GRAYSCALE; } memset (&wbuf, 0, sizeof (wbuf)); /* next line commented out by mf */ /* _lto2b(sizeof(wbuf) - 8, wbuf.len); */ /* next line by mf */ _lto2b(IBM_WINDOW_DATA_SIZE, wbuf.len); /* size=320 */ _lto2b(s->xres, wbuf.x_res); _lto2b(s->yres, wbuf.y_res); _lto4b(s->ulx, wbuf.x_org); _lto4b(s->uly, wbuf.y_org); _lto4b(s->width, wbuf.width); _lto4b(s->length, wbuf.length); wbuf.image_comp = s->image_composition; /* if you throw the MRIF bit the brighness control reverses too */ /* so I reverse the reversal in software for symmetry's sake */ if (wbuf.image_comp == IBM_GRAYSCALE || wbuf.image_comp == IBM_DITHERED_MONOCHROME) { if (wbuf.image_comp == IBM_GRAYSCALE) wbuf.mrif_filtering_gamma_id = (SANE_Byte) 0x80; /* it was 0x90 */ if (wbuf.image_comp == IBM_DITHERED_MONOCHROME) wbuf.mrif_filtering_gamma_id = (SANE_Byte) 0x10; wbuf.brightness = 256 - (SANE_Byte) s->brightness; /* if (is50) wbuf.contrast = (SANE_Byte) s->contrast; else */ wbuf.contrast = 256 - (SANE_Byte) s->contrast; } else /* wbuf.image_comp == IBM_BINARY_MONOCHROME */ { wbuf.mrif_filtering_gamma_id = (SANE_Byte) 0x00; wbuf.brightness = (SANE_Byte) s->brightness; wbuf.contrast = (SANE_Byte) s->contrast; } wbuf.threshold = 0; wbuf.bits_per_pixel = s->bpp; wbuf.halftone_code = 2; /* diithering */ wbuf.halftone_id = 0x0A; /* 8x8 Bayer pattenr */ wbuf.pad_type = 3; wbuf.bit_ordering[0] = 0; wbuf.bit_ordering[1] = 7; /* modified by mf (it was 3) */ DBG (5, "xres=%d\n", _2btol(wbuf.x_res)); DBG (5, "yres=%d\n", _2btol(wbuf.y_res)); DBG (5, "ulx=%d\n", _4btol(wbuf.x_org)); DBG (5, "uly=%d\n", _4btol(wbuf.y_org)); DBG (5, "width=%d\n", _4btol(wbuf.width)); DBG (5, "length=%d\n", _4btol(wbuf.length)); DBG (5, "image_comp=%d\n", wbuf.image_comp); DBG (11, "sane_start: sending SET WINDOW\n"); status = set_window (s->fd, &wbuf); if (status != SANE_STATUS_GOOD) { DBG (1, "SET WINDOW failed: %s\n", sane_strstatus (status)); return (status); } DBG (11, "sane_start: sending GET WINDOW\n"); memset (&wbuf, 0, sizeof (wbuf)); status = get_window (s->fd, &wbuf); if (status != SANE_STATUS_GOOD) { DBG (1, "GET WINDOW failed: %s\n", sane_strstatus (status)); return (status); } DBG (5, "xres=%d\n", _2btol(wbuf.x_res)); DBG (5, "yres=%d\n", _2btol(wbuf.y_res)); DBG (5, "ulx=%d\n", _4btol(wbuf.x_org)); DBG (5, "uly=%d\n", _4btol(wbuf.y_org)); DBG (5, "width=%d\n", _4btol(wbuf.width)); DBG (5, "length=%d\n", _4btol(wbuf.length)); DBG (5, "image_comp=%d\n", wbuf.image_comp); DBG (11, "sane_start: sending MODE SELECT\n"); memset (&mup, 0, sizeof (mup)); mup.page_code = MEASUREMENTS_PAGE; mup.parameter_length = 0x06; mup.bmu = INCHES; mup.mud[0] = (DEFAULT_MUD >> 8) & 0xff; mup.mud[1] = (DEFAULT_MUD & 0xff); /* next lines by mf */ mup.adf_page_code = 0x26; mup.adf_parameter_length = 6; if (s->adf_state == ADF_ARMED) mup.adf_control = 1; else mup.adf_control = 0; /* end lines by mf */ status = mode_select (s->fd, (struct mode_pages *) &mup); if (status != SANE_STATUS_GOOD) { DBG (1, "attach: MODE_SELECT failed\n"); return (SANE_STATUS_INVAL); } status = trigger_scan (s->fd); if (status != SANE_STATUS_GOOD) { DBG (1, "start of scan failed: %s\n", sane_strstatus (status)); /* next line introduced not to freeze xscanimage */ do_cancel(s); return status; } /* Wait for scanner to become ready to transmit data */ status = ibm_wait_ready (s); if (status != SANE_STATUS_GOOD) { DBG (1, "GET DATA STATUS failed: %s\n", sane_strstatus (status)); return (status); } s->bytes_to_read = s->params.bytes_per_line * s->params.lines; DBG (1, "%d pixels per line, %d bytes, %d lines high, total %lu bytes, " "dpi=%d\n", s->params.pixels_per_line, s->params.bytes_per_line, s->params.lines, (u_long) s->bytes_to_read, s->val[OPT_Y_RESOLUTION].w); s->scanning = SANE_TRUE; DBG (11, "<< sane_start\n"); return (SANE_STATUS_GOOD); }
/* * Read some data. */ int sdstrategy(void *f, int rw, daddr_t dblk, size_t size, void *p, size_t *rsize) { struct sd_softc *sd; struct disklabel *lp; struct partition *pp; struct scsipi_generic *cmdp; struct scsipi_rw_16 cmd16; struct scsipi_rw_10 cmd_big; struct scsi_rw_6 cmd_small; daddr_t blkno; int cmdlen, nsect, i; uint8_t *buf; if (size == 0) return 0; if (rw != F_READ) return EOPNOTSUPP; buf = p; sd = f; lp = &sd->sc_label; pp = &lp->d_partitions[sd->sc_part]; if (!(sd->sc_flags & FLAGS_MEDIA_LOADED)) return EIO; nsect = howmany(size, lp->d_secsize); blkno = dblk + pp->p_offset; for (i = 0; i < nsect; i++, blkno++) { int error; /* * Fill out the scsi command. Use the smallest CDB possible * (6-byte, 10-byte, or 16-byte). */ if ((blkno & 0x1fffff) == blkno) { /* 6-byte CDB */ memset(&cmd_small, 0, sizeof(cmd_small)); cmd_small.opcode = SCSI_READ_6_COMMAND; _lto3b(blkno, cmd_small.addr); cmd_small.length = 1; cmdlen = sizeof(cmd_small); cmdp = (struct scsipi_generic *)&cmd_small; } else if ((blkno & 0xffffffff) == blkno) { /* 10-byte CDB */ memset(&cmd_big, 0, sizeof(cmd_big)); cmd_small.opcode = READ_10; _lto4b(blkno, cmd_big.addr); _lto2b(1, cmd_big.length); cmdlen = sizeof(cmd_big); cmdp = (struct scsipi_generic *)&cmd_big; } else { /* 16-byte CDB */ memset(&cmd16, 0, sizeof(cmd16)); cmd_small.opcode = READ_16; _lto8b(blkno, cmd16.addr); _lto4b(1, cmd16.length); cmdlen = sizeof(cmd16); cmdp = (struct scsipi_generic *)&cmd16; } error = scsi_command(sd, cmdp, cmdlen, buf, lp->d_secsize); if (error) return error; buf += lp->d_secsize; } *rsize = size; return 0; }
/* * cdstart looks to see if there is a buf waiting for the device * and that the device is not already busy. If both are true, * It deques the buf and creates a scsi command to perform the * transfer in the buf. The transfer request will call scsi_done * on completion, which will in turn call this routine again * so that the next queued transfer is performed. * The bufs are queued by the strategy routine (cdstrategy) * * This routine is also called after other non-queued requests * have been made of the scsi driver, to ensure that the queue * continues to be drained. * * must be called at the correct (highish) spl level * cdstart() is called at splbio from cdstrategy, cdrestart and scsi_done */ void cdstart(void *v) { struct cd_softc *cd = v; struct scsi_link *sc_link = cd->sc_link; struct buf *bp = 0; struct buf *dp; struct scsi_rw_big cmd_big; struct scsi_rw cmd_small; struct scsi_generic *cmdp; int blkno, nblks, cmdlen, error; struct partition *p; splassert(IPL_BIO); SC_DEBUG(sc_link, SDEV_DB2, ("cdstart\n")); /* * Check if the device has room for another command */ while (sc_link->openings > 0) { /* * there is excess capacity, but a special waits * It'll need the adapter as soon as we clear out of the * way and let it run (user level wait). */ if (sc_link->flags & SDEV_WAITING) { sc_link->flags &= ~SDEV_WAITING; wakeup((caddr_t)sc_link); return; } /* * See if there is a buf with work for us to do.. */ dp = &cd->buf_queue; if ((bp = dp->b_actf) == NULL) /* yes, an assign */ return; dp->b_actf = bp->b_actf; /* * If the device has become invalid, abort all the * reads and writes until all files have been closed and * re-opened */ if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) { bp->b_error = EIO; bp->b_flags |= B_ERROR; bp->b_resid = bp->b_bcount; biodone(bp); continue; } /* * We have a buf, now we should make a command * * First, translate the block to absolute and put it in terms * of the logical blocksize of the device. */ blkno = bp->b_blkno / (cd->sc_dk.dk_label->d_secsize / DEV_BSIZE); p = &cd->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]; blkno += DL_GETPOFFSET(p); nblks = howmany(bp->b_bcount, cd->sc_dk.dk_label->d_secsize); /* * Fill out the scsi command. If the transfer will * fit in a "small" cdb, use it. */ if (!(sc_link->flags & SDEV_ATAPI) && !(sc_link->quirks & SDEV_ONLYBIG) && ((blkno & 0x1fffff) == blkno) && ((nblks & 0xff) == nblks)) { /* * We can fit in a small cdb. */ bzero(&cmd_small, sizeof(cmd_small)); cmd_small.opcode = (bp->b_flags & B_READ) ? READ_COMMAND : WRITE_COMMAND; _lto3b(blkno, cmd_small.addr); cmd_small.length = nblks & 0xff; cmdlen = sizeof(cmd_small); cmdp = (struct scsi_generic *)&cmd_small; } else { /* * Need a large cdb. */ bzero(&cmd_big, sizeof(cmd_big)); cmd_big.opcode = (bp->b_flags & B_READ) ? READ_BIG : WRITE_BIG; _lto4b(blkno, cmd_big.addr); _lto2b(nblks, cmd_big.length); cmdlen = sizeof(cmd_big); cmdp = (struct scsi_generic *)&cmd_big; } /* Instrumentation. */ disk_busy(&cd->sc_dk); /* * Call the routine that chats with the adapter. * Note: we cannot sleep as we may be an interrupt */ error = scsi_scsi_cmd(sc_link, cmdp, cmdlen, (u_char *) bp->b_data, bp->b_bcount, SCSI_RETRIES, 30000, bp, SCSI_NOSLEEP | ((bp->b_flags & B_READ) ? SCSI_DATA_IN : SCSI_DATA_OUT)); switch (error) { case 0: timeout_del(&cd->sc_timeout); break; case EAGAIN: /* * The device can't start another i/o. Try again later. */ dp->b_actf = bp; disk_unbusy(&cd->sc_dk, 0, 0); timeout_add(&cd->sc_timeout, 1); return; default: disk_unbusy(&cd->sc_dk, 0, 0); printf("%s: not queued, error %d\n", cd->sc_dev.dv_xname, error); break; } } }
/* * This is pretty much a CD target for now */ static void scsitest_request(struct scsipi_channel *chan, scsipi_adapter_req_t req, void *arg) { struct scsipi_xfer *xs = arg; struct scsipi_generic *cmd = xs->cmd; #ifdef USE_TOSI_ISO int error; #endif if (req != ADAPTER_REQ_RUN_XFER) return; //show_scsipi_xs(xs); switch (cmd->opcode) { case SCSI_TEST_UNIT_READY: if (isofd == -1) sense_notready(xs); break; case INQUIRY: { struct scsipi_inquiry_data *inqbuf = (void *)xs->data; memset(inqbuf, 0, sizeof(*inqbuf)); inqbuf->device = T_CDROM; inqbuf->dev_qual2 = SID_REMOVABLE; strcpy(inqbuf->vendor, "RUMPHOBO"); strcpy(inqbuf->product, "It's a LIE"); strcpy(inqbuf->revision, "0.00"); break; } case READ_CD_CAPACITY: { struct scsipi_read_cd_cap_data *ret = (void *)xs->data; _lto4b(CDBLOCKSIZE, ret->length); _lto4b(mycdsize, ret->addr); break; } case READ_DISCINFO: { struct scsipi_read_discinfo_data *ret = (void *)xs->data; memset(ret, 0, sizeof(*ret)); break; } case READ_TRACKINFO: { struct scsipi_read_trackinfo_data *ret = (void *)xs->data; _lto4b(mycdsize, ret->track_size); break; } case READ_TOC: { struct scsipi_toc_header *ret = (void *)xs->data; memset(ret, 0, sizeof(*ret)); break; } case START_STOP: { struct scsipi_start_stop *param = (void *)cmd; if (param->how & SSS_LOEJ) { #ifdef USE_TOSI_ISO rumpuser_close(isofd, &error); #endif isofd = -1; } break; } case SCSI_SYNCHRONIZE_CACHE_10: { if (isofd == -1) { if ((xs->xs_control & XS_CTL_SILENT) == 0) atomic_inc_uint(&rump_scsitest_err [RUMP_SCSITEST_NOISYSYNC]); sense_notready(xs); } break; } case GET_CONFIGURATION: { memset(xs->data, 0, sizeof(struct scsipi_get_conf_data)); break; } case SCSI_READ_6_COMMAND: { #ifdef USE_TOSI_ISO struct scsi_rw_6 *param = (void *)cmd; printf("reading %d bytes from %d\n", param->length * CDBLOCKSIZE, _3btol(param->addr) * CDBLOCKSIZE); rumpuser_pread(isofd, xs->data, param->length * CDBLOCKSIZE, _3btol(param->addr) * CDBLOCKSIZE, &error); #endif break; } case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL: /* hardcoded for now */ break; default: printf("unhandled opcode 0x%x\n", cmd->opcode); break; } scsipi_done(xs); }
int dvd_auth(struct cd_softc *cd, union dvd_authinfo *a) { struct scsi_generic cmd; u_int8_t buf[20]; int error; bzero(cmd.bytes, sizeof(cmd.bytes)); bzero(buf, sizeof(buf)); switch (a->type) { case DVD_LU_SEND_AGID: cmd.opcode = GPCMD_REPORT_KEY; cmd.bytes[8] = 8; cmd.bytes[9] = 0 | (0 << 6); error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 8, SCSI_RETRIES, 30000, NULL, SCSI_DATA_IN); if (error) return (error); a->lsa.agid = buf[7] >> 6; return (0); case DVD_LU_SEND_CHALLENGE: cmd.opcode = GPCMD_REPORT_KEY; cmd.bytes[8] = 16; cmd.bytes[9] = 1 | (a->lsc.agid << 6); error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 16, SCSI_RETRIES, 30000, NULL, SCSI_DATA_IN); if (error) return (error); dvd_copy_challenge(a->lsc.chal, &buf[4]); return (0); case DVD_LU_SEND_KEY1: cmd.opcode = GPCMD_REPORT_KEY; cmd.bytes[8] = 12; cmd.bytes[9] = 2 | (a->lsk.agid << 6); error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 12, SCSI_RETRIES, 30000, NULL, SCSI_DATA_IN); if (error) return (error); dvd_copy_key(a->lsk.key, &buf[4]); return (0); case DVD_LU_SEND_TITLE_KEY: cmd.opcode = GPCMD_REPORT_KEY; _lto4b(a->lstk.lba, &cmd.bytes[1]); cmd.bytes[8] = 12; cmd.bytes[9] = 4 | (a->lstk.agid << 6); error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 12, SCSI_RETRIES, 30000, NULL, SCSI_DATA_IN); if (error) return (error); a->lstk.cpm = (buf[4] >> 7) & 1; a->lstk.cp_sec = (buf[4] >> 6) & 1; a->lstk.cgms = (buf[4] >> 4) & 3; dvd_copy_key(a->lstk.title_key, &buf[5]); return (0); case DVD_LU_SEND_ASF: cmd.opcode = GPCMD_REPORT_KEY; cmd.bytes[8] = 8; cmd.bytes[9] = 5 | (a->lsasf.agid << 6); error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 8, SCSI_RETRIES, 30000, NULL, SCSI_DATA_IN); if (error) return (error); a->lsasf.asf = buf[7] & 1; return (0); case DVD_HOST_SEND_CHALLENGE: cmd.opcode = GPCMD_SEND_KEY; cmd.bytes[8] = 16; cmd.bytes[9] = 1 | (a->hsc.agid << 6); buf[1] = 14; dvd_copy_challenge(&buf[4], a->hsc.chal); error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 16, SCSI_RETRIES, 30000, NULL, SCSI_DATA_OUT); if (error) return (error); a->type = DVD_LU_SEND_KEY1; return (0); case DVD_HOST_SEND_KEY2: cmd.opcode = GPCMD_SEND_KEY; cmd.bytes[8] = 12; cmd.bytes[9] = 3 | (a->hsk.agid << 6); buf[1] = 10; dvd_copy_key(&buf[4], a->hsk.key); error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 12, SCSI_RETRIES, 30000, NULL, SCSI_DATA_OUT); if (error) { a->type = DVD_AUTH_FAILURE; return (error); } a->type = DVD_AUTH_ESTABLISHED; return (0); case DVD_INVALIDATE_AGID: cmd.opcode = GPCMD_REPORT_KEY; cmd.bytes[9] = 0x3f | (a->lsa.agid << 6); error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 16, SCSI_RETRIES, 30000, NULL, 0); if (error) return (error); return (0); case DVD_LU_SEND_RPC_STATE: cmd.opcode = GPCMD_REPORT_KEY; cmd.bytes[8] = 8; cmd.bytes[9] = 8 | (0 << 6); error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 8, SCSI_RETRIES, 30000, NULL, SCSI_DATA_IN); if (error) return (error); a->lrpcs.type = (buf[4] >> 6) & 3; a->lrpcs.vra = (buf[4] >> 3) & 7; a->lrpcs.ucca = (buf[4]) & 7; a->lrpcs.region_mask = buf[5]; a->lrpcs.rpc_scheme = buf[6]; return (0); case DVD_HOST_SEND_RPC_STATE: cmd.opcode = GPCMD_SEND_KEY; cmd.bytes[8] = 8; cmd.bytes[9] = 6 | (0 << 6); buf[1] = 6; buf[4] = a->hrpcs.pdrc; error = scsi_scsi_cmd(cd->sc_link, &cmd, sizeof(cmd), buf, 8, SCSI_RETRIES, 30000, NULL, SCSI_DATA_OUT); if (error) return (error); return (0); default: return (ENOTTY); } }