int ch_getelemstatus(struct ch_softc *sc, int first, int count, caddr_t data, size_t datalen, int voltag) { struct scsi_read_element_status *cmd; struct scsi_xfer *xs; int error; /* * Build SCSI command. */ xs = scsi_xs_get(sc->sc_link, SCSI_DATA_IN); if (xs == NULL) return (ENOMEM); xs->cmdlen = sizeof(*cmd); xs->data = data; xs->datalen = datalen; xs->retries = CHRETRIES; xs->timeout = 100000; cmd = (struct scsi_read_element_status *)xs->cmd; cmd->opcode = READ_ELEMENT_STATUS; _lto2b(first, cmd->sea); _lto2b(count, cmd->count); _lto3b(datalen, cmd->len); if (voltag) cmd->byte2 |= READ_ELEMENT_STATUS_VOLTAG; error = scsi_xs_sync(xs); scsi_xs_put(xs); return (error); }
static int ch_getelemstatus(struct ch_softc *sc, int first, int count, void *data, size_t datalen, int scsiflags, int flags) { struct scsi_read_element_status cmd; /* * Build SCSI command. */ memset(&cmd, 0, sizeof(cmd)); cmd.opcode = READ_ELEMENT_STATUS; cmd.byte2 = ELEMENT_TYPE_ALL; if (flags & CESR_VOLTAGS) cmd.byte2 |= READ_ELEMENT_STATUS_VOLTAG; _lto2b(first, cmd.sea); _lto2b(count, cmd.count); _lto3b(datalen, cmd.len); /* * Send command to changer. */ return (scsipi_command(sc->sc_periph, (void *)&cmd, sizeof(cmd), (void *)data, datalen, CHRETRIES, CHTIMEOUT, NULL, scsiflags | XS_CTL_DATA_IN)); }
/* * read the requested number of bytes/lines from the scanner */ static int mustek_read(struct ss_softc *ss, struct buf *bp) { struct mustek_read_cmd cmd; struct scsipi_xfer *xs; struct scsipi_periph *periph = ss->sc_periph; u_long lines_to_read; int error; SC_DEBUG(periph, SCSIPI_DB1, ("mustek_read: start\n")); memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MUSTEK_READ; /* instead of the bytes, the mustek wants the number of lines */ lines_to_read = bp->b_bcount / ((ss->sio.scan_pixels_per_line * ss->sio.scan_bits_per_pixel) / 8); SC_DEBUG(periph, SCSIPI_DB1, ("mustek_read: read %ld lines\n", lines_to_read)); _lto3b(lines_to_read, cmd.length); /* * go ask the adapter to do all this for us */ xs = scsipi_make_xs(periph, (struct scsipi_generic *) &cmd, sizeof(cmd), (u_char *) bp->b_data, bp->b_bcount, MUSTEK_RETRIES, 10000, bp, XS_CTL_NOSLEEP | XS_CTL_ASYNC | XS_CTL_DATA_IN); if (xs == NULL) { /* * out of memory. Keep this buffer in the queue, and * retry later. */ callout_reset(&ss->sc_callout, hz / 2, ssrestart, periph); return(0); } #ifdef DIAGNOSTIC if (BUFQ_GET(ss->buf_queue) != bp) panic("ssstart(): dequeued wrong buf"); #else BUFQ_GET(ss->buf_queue); #endif error = scsipi_execute_xs(xs); /* with a scsipi_xfer preallocated, scsipi_command can't fail */ KASSERT(error == 0); ss->sio.scan_lines -= lines_to_read; #if 0 if (ss->sio.scan_lines < 0) ss->sio.scan_lines = 0; #endif ss->sio.scan_window_size -= bp->b_bcount; #if 0 if (ss->sio.scan_window_size < 0) ss->sio.scan_window_size = 0; #endif return (0); }
void sd_cmd_rw6(struct scsi_xfer *xs, int read, u_int64_t secno, u_int nsecs) { struct scsi_rw *cmd = (struct scsi_rw *)xs->cmd; cmd->opcode = read ? READ_COMMAND : WRITE_COMMAND; _lto3b(secno, cmd->addr); cmd->length = nsecs; xs->cmdlen = sizeof(*cmd); }
static int scanjet_read(struct ss_softc *ss, struct buf *bp) { struct scsi_rw_scanner cmd; struct scsipi_xfer *xs; struct scsipi_periph *periph = ss->sc_periph; int error; /* * Fill out the scsi command */ memset(&cmd, 0, sizeof(cmd)); cmd.opcode = READ; /* * Handle "fixed-block-mode" tape drives by using the * block count instead of the length. */ _lto3b(bp->b_bcount, cmd.len); /* * go ask the adapter to do all this for us */ xs = scsipi_make_xs(periph, (struct scsipi_generic *) &cmd, sizeof(cmd), (u_char *) bp->b_data, bp->b_bcount, SCANJET_RETRIES, 100000, bp, XS_CTL_NOSLEEP | XS_CTL_ASYNC | XS_CTL_DATA_IN); if (xs == NULL) { /* * out of memory. Keep this buffer in the queue, and * retry later. */ callout_reset(&ss->sc_callout, hz / 2, ssrestart, periph); return(0); } #ifdef DIAGNOSTIC if (BUFQ_GET(ss->buf_queue) != bp) panic("ssstart(): dequeued wrong buf"); #else BUFQ_GET(ss->buf_queue); #endif error = scsipi_execute_xs(xs); /* with a scsipi_xfer preallocated, scsipi_command can't fail */ KASSERT(error == 0); ss->sio.scan_window_size -= bp->b_bcount; #if 0 if (ss->sio.scan_window_size < 0) ss->sio.scan_window_size = 0; #endif return (0); }
/* * Send a filled out parameter structure to the drive to * set it into the desire modes etc. */ static int st_scsibus_mode_select(struct st_softc *st, int flags) { u_int scsi_select_len; struct scsi_select { struct scsi_mode_parameter_header_6 header; struct scsi_general_block_descriptor blk_desc; u_char sense_data[MAX_PAGE_0_SIZE]; } scsi_select; struct scsipi_periph *periph = st->sc_periph; scsi_select_len = 12 + st->page_0_size; /* * This quirk deals with drives that have only one valid mode * and think this gives them license to reject all mode selects, * even if the selected mode is the one that is supported. */ if (st->quirks & ST_Q_UNIMODAL) { SC_DEBUG(periph, SCSIPI_DB3, ("not setting density 0x%x blksize 0x%x\n", st->density, st->blksize)); return (0); } /* * Set up for a mode select */ memset(&scsi_select, 0, scsi_select_len); scsi_select.header.blk_desc_len = sizeof(struct scsi_general_block_descriptor); scsi_select.header.dev_spec &= ~SMH_DSP_BUFF_MODE; scsi_select.blk_desc.density = st->density; if (st->flags & ST_DONTBUFFER) scsi_select.header.dev_spec |= SMH_DSP_BUFF_MODE_OFF; else scsi_select.header.dev_spec |= SMH_DSP_BUFF_MODE_ON; if (st->flags & ST_FIXEDBLOCKS) _lto3b(st->blksize, scsi_select.blk_desc.blklen); if (st->page_0_size) memcpy(scsi_select.sense_data, st->sense_data, st->page_0_size); /* * do the command */ return scsipi_mode_select(periph, 0, &scsi_select.header, scsi_select_len, flags | XS_CTL_DATA_ONSTACK, ST_RETRIES, ST_CTL_TIME); }
/*--------------------------------------------------------------------------- * *--------------------------------------------------------------------------*/ 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); }
/* * Do a synchronous read. Used to read responses to control messages. */ static int scanjet_ctl_read(struct ss_softc *ss, char *tbuf, u_int size) { struct scsi_rw_scanner cmd; int flags; flags = 0; if ((ss->flags & SSF_AUTOCONF) != 0) flags |= XS_CTL_DISCOVERY; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = READ; _lto3b(size, cmd.len); return (scsipi_command(ss->sc_periph, (void *)&cmd, sizeof(cmd), (void *)tbuf, size, 0, 100000, NULL, flags | XS_CTL_DATA_IN | XS_CTL_DATA_ONSTACK)); }
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 wdc_atapi_tape_done(struct channel_softc *chp, struct wdc_xfer *xfer, int timeout, struct atapi_return_args *ret) { struct scsi_xfer *sc_xfer = xfer->cmd; if (sc_xfer->error != XS_NOERROR) { xfer->next = wdc_atapi_done; return; } _lto3b(xfer->transfer_len, ((struct scsi_rw_tape *) sc_xfer->cmd)->len); xfer->c_bcount = sc_xfer->datalen; xfer->c_done = NULL; xfer->c_skip = 0; xfer->next = wdc_atapi_real_start; return; }
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); } }
/* * 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; } } }
/* * 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; }
void wdc_atapi_send_cmd(struct scsi_xfer *sc_xfer) { struct atapiscsi_softc *as = sc_xfer->sc_link->adapter_softc; struct channel_softc *chp = as->chp; struct ata_drive_datas *drvp = &chp->ch_drive[as->drive]; struct wdc_xfer *xfer; int s; int idx; WDCDEBUG_PRINT(("wdc_atapi_send_cmd %s:%d:%d start\n", chp->wdc->sc_dev.dv_xname, chp->channel, as->drive), DEBUG_XFERS); if (sc_xfer->sc_link->target != 0) { sc_xfer->error = XS_DRIVER_STUFFUP; scsi_done(sc_xfer); return; } xfer = sc_xfer->io; wdc_scrub_xfer(xfer); if (sc_xfer->flags & SCSI_POLL) xfer->c_flags |= C_POLL; xfer->drive = as->drive; xfer->c_flags |= C_ATAPI; xfer->cmd = sc_xfer; xfer->databuf = sc_xfer->data; xfer->c_bcount = sc_xfer->datalen; xfer->c_start = wdc_atapi_start; xfer->c_intr = wdc_atapi_intr; timeout_set(&xfer->atapi_poll_to, wdc_atapi_timer_handler, chp); WDCDEBUG_PRINT(("wdc_atapi_send_cmd %s:%d:%d ", chp->wdc->sc_dev.dv_xname, chp->channel, as->drive), DEBUG_XFERS | DEBUG_ERRORS); for (idx = 0; idx < sc_xfer->cmdlen; idx++) { WDCDEBUG_PRINT((" %02x", ((unsigned char *)sc_xfer->cmd)[idx]), DEBUG_XFERS | DEBUG_ERRORS); } WDCDEBUG_PRINT(("\n"), DEBUG_XFERS | DEBUG_ERRORS); s = splbio(); if (drvp->atapi_cap & ACAP_DSC) { WDCDEBUG_PRINT(("about to send cmd 0x%x ", sc_xfer->cmd->opcode), DEBUG_DSC); switch (sc_xfer->cmd->opcode) { case READ: case WRITE: xfer->c_flags |= C_MEDIA_ACCESS; /* If we are not in buffer availability mode, we limit the first request to 0 bytes, which gets us into buffer availability mode without holding the bus. */ if (!(drvp->drive_flags & DRIVE_DSCBA)) { xfer->c_bcount = 0; xfer->transfer_len = _3btol(((struct scsi_rw_tape *) sc_xfer->cmd)->len); _lto3b(0, ((struct scsi_rw_tape *) sc_xfer->cmd)->len); xfer->c_done = wdc_atapi_tape_done; WDCDEBUG_PRINT( ("R/W in completion mode, do 0 blocks\n"), DEBUG_DSC); } else WDCDEBUG_PRINT(("R/W %d blocks %d bytes\n", _3btol(((struct scsi_rw_tape *) sc_xfer->cmd)->len), sc_xfer->datalen), DEBUG_DSC); /* DSC will change to buffer availability mode. We reflect this in wdc_atapi_intr. */ break; case ERASE: /* Media access commands */ case LOAD: case REWIND: case SPACE: case WRITE_FILEMARKS: #if 0 case LOCATE: case READ_POSITION: #endif xfer->c_flags |= C_MEDIA_ACCESS; break; default: WDCDEBUG_PRINT(("no media access\n"), DEBUG_DSC); } } wdc_exec_xfer(chp, xfer); splx(s); }