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)); }
static int ch_position(struct ch_softc *sc, struct changer_position_request *cp) { struct scsi_position_to_element cmd; u_int16_t dst; /* * Check arguments. */ if (cp->cp_type > CHET_DT) return (EINVAL); if (cp->cp_unit > (sc->sc_counts[cp->cp_type] - 1)) return (ENODEV); /* * Calculate the destination element. */ dst = sc->sc_firsts[cp->cp_type] + cp->cp_unit; /* * Build the SCSI command. */ memset(&cmd, 0, sizeof(cmd)); cmd.opcode = POSITION_TO_ELEMENT; _lto2b(sc->sc_picker, cmd.tea); _lto2b(dst, cmd.dst); if (cp->cp_flags & CP_INVERT) cmd.flags |= POSITION_TO_ELEMENT_INVERT; /* * Send command to changer. */ return (scsipi_command(sc->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0, CHRETRIES, CHTIMEOUT, NULL, 0)); }
static int ch_exchange(struct ch_softc *sc, struct changer_exchange_request *ce) { struct scsi_exchange_medium cmd; u_int16_t src, dst1, dst2; /* * Check arguments. */ if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) || (ce->ce_sdsttype > CHET_DT)) return (EINVAL); if ((ce->ce_srcunit > (sc->sc_counts[ce->ce_srctype] - 1)) || (ce->ce_fdstunit > (sc->sc_counts[ce->ce_fdsttype] - 1)) || (ce->ce_sdstunit > (sc->sc_counts[ce->ce_sdsttype] - 1))) return (ENODEV); /* * Check the request against the changer's capabilities. */ if (((sc->sc_exchangemask[ce->ce_srctype] & (1 << ce->ce_fdsttype)) == 0) || ((sc->sc_exchangemask[ce->ce_fdsttype] & (1 << ce->ce_sdsttype)) == 0)) return (ENODEV); /* * Calculate the source and destination elements. */ src = sc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit; dst1 = sc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit; dst2 = sc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit; /* * Build the SCSI command. */ memset(&cmd, 0, sizeof(cmd)); cmd.opcode = EXCHANGE_MEDIUM; _lto2b(sc->sc_picker, cmd.tea); _lto2b(src, cmd.src); _lto2b(dst1, cmd.fdst); _lto2b(dst2, cmd.sdst); if (ce->ce_flags & CE_INVERT1) cmd.flags |= EXCHANGE_MEDIUM_INV1; if (ce->ce_flags & CE_INVERT2) cmd.flags |= EXCHANGE_MEDIUM_INV2; /* * Send command to changer. */ return (scsipi_command(sc->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0, CHRETRIES, CHTIMEOUT, NULL, 0)); }
int ch_move(struct ch_softc *sc, struct changer_move *cm) { struct scsi_move_medium *cmd; struct scsi_xfer *xs; int error; u_int16_t fromelem, toelem; /* * Check arguments. */ if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT)) return (EINVAL); if ((cm->cm_fromunit > (sc->sc_counts[cm->cm_fromtype] - 1)) || (cm->cm_tounit > (sc->sc_counts[cm->cm_totype] - 1))) return (ENODEV); /* * Check the request against the changer's capabilities. */ if ((sc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0) return (EINVAL); /* * Calculate the source and destination elements. */ fromelem = sc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit; toelem = sc->sc_firsts[cm->cm_totype] + cm->cm_tounit; /* * Build the SCSI command. */ xs = scsi_xs_get(sc->sc_link, 0); if (xs == NULL) return (ENOMEM); xs->cmdlen = sizeof(*cmd); xs->retries = CHRETRIES; xs->timeout = 100000; cmd = (struct scsi_move_medium *)xs->cmd; cmd->opcode = MOVE_MEDIUM; _lto2b(sc->sc_picker, cmd->tea); _lto2b(fromelem, cmd->src); _lto2b(toelem, cmd->dst); if (cm->cm_flags & CM_INVERT) cmd->flags |= MOVE_MEDIUM_INVERT; error = scsi_xs_sync(xs); scsi_xs_put(xs); return (error); }
/*--------------------------------------------------------------------------- * *--------------------------------------------------------------------------*/ 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); }
static int ch_voltag_convert_out(const struct changer_voltag *cv, struct changer_volume_tag *sv) { int i; memset(sv, ' ', sizeof(struct changer_volume_tag)); for (i = 0; i < sizeof(sv->volid); i++) { if (cv->cv_tag[i] == '\0') break; /* * Limit the character set to what is suggested in * the SCSI-2 spec. */ if ((cv->cv_tag[i] < '0' || cv->cv_tag[i] > '9') && (cv->cv_tag[i] < 'A' || cv->cv_tag[i] > 'Z') && (cv->cv_tag[i] != '_')) return (EINVAL); sv->volid[i] = cv->cv_tag[i]; } _lto2b(cv->cv_serial, sv->volseq); return (0); }
int emc_inquiry(struct emc_softc *sc, char *model, char *serial) { u_int8_t *buffer; struct scsi_inquiry *cdb; struct scsi_xfer *xs; size_t length; int error; u_int8_t slen, mlen; length = MIN(sc->sc_path.p_link->inqdata.additional_length + 5, 255); if (length < 160) { printf("%s: FC (Legacy)\n"); return (0); } buffer = dma_alloc(length, PR_WAITOK); xs = scsi_xs_get(sc->sc_path.p_link, scsi_autoconf); if (xs == NULL) { error = EBUSY; goto done; } cdb = (struct scsi_inquiry *)xs->cmd; cdb->opcode = INQUIRY; _lto2b(length, cdb->length); xs->cmdlen = sizeof(*cdb); xs->flags |= SCSI_DATA_IN; xs->data = buffer; xs->datalen = length; error = scsi_xs_sync(xs); scsi_xs_put(xs); if (error != 0) goto done; slen = buffer[160]; if (slen == 0 || slen + 161 > length) { error = EIO; goto done; } mlen = buffer[99]; if (mlen == 0 || slen + mlen + 161 > length) { error = EIO; goto done; } scsi_strvis(serial, buffer + 161, slen); scsi_strvis(model, buffer + 161 + slen, mlen); error = 0; done: dma_free(buffer, length); return (error); }
static int ch_move(struct ch_softc *sc, struct changer_move_request *cm) { struct scsi_move_medium cmd; u_int16_t fromelem, toelem; /* * Check arguments. */ if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT)) return (EINVAL); if ((cm->cm_fromunit > (sc->sc_counts[cm->cm_fromtype] - 1)) || (cm->cm_tounit > (sc->sc_counts[cm->cm_totype] - 1))) return (ENODEV); /* * Check the request against the changer's capabilities. */ if ((sc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0) return (ENODEV); /* * Calculate the source and destination elements. */ fromelem = sc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit; toelem = sc->sc_firsts[cm->cm_totype] + cm->cm_tounit; /* * Build the SCSI command. */ memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MOVE_MEDIUM; _lto2b(sc->sc_picker, cmd.tea); _lto2b(fromelem, cmd.src); _lto2b(toelem, cmd.dst); if (cm->cm_flags & CM_INVERT) cmd.flags |= MOVE_MEDIUM_INVERT; /* * Send command to changer. */ return (scsipi_command(sc->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0, CHRETRIES, CHTIMEOUT, NULL, 0)); }
int ch_position(struct ch_softc *sc, struct changer_position *cp) { struct scsi_position_to_element *cmd; struct scsi_xfer *xs; int error; u_int16_t dst; /* * Check arguments. */ if (cp->cp_type > CHET_DT) return (EINVAL); if (cp->cp_unit > (sc->sc_counts[cp->cp_type] - 1)) return (ENODEV); /* * Calculate the destination element. */ dst = sc->sc_firsts[cp->cp_type] + cp->cp_unit; /* * Build the SCSI command. */ xs = scsi_xs_get(sc->sc_link, 0); if (xs == NULL) return (ENOMEM); xs->cmdlen = sizeof(*cmd); xs->retries = CHRETRIES; xs->timeout = 100000; cmd = (struct scsi_position_to_element *)xs->cmd; cmd->opcode = POSITION_TO_ELEMENT; _lto2b(sc->sc_picker, cmd->tea); _lto2b(dst, cmd->dst); if (cp->cp_flags & CP_INVERT) cmd->flags |= POSITION_TO_ELEMENT_INVERT; error = scsi_xs_sync(xs); scsi_xs_put(xs); return (error); }
void sd_cmd_rw10(struct scsi_xfer *xs, int read, u_int64_t secno, u_int nsecs) { struct scsi_rw_big *cmd = (struct scsi_rw_big *)xs->cmd; cmd->opcode = read ? READ_BIG : WRITE_BIG; _lto4b(secno, cmd->addr); _lto2b(nsecs, cmd->length); xs->cmdlen = sizeof(*cmd); }
/*--------------------------------------------------------------------------- * *--------------------------------------------------------------------------*/ 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)); }
int safte_match(struct device *parent, void *match, void *aux) { struct scsi_attach_args *sa = aux; struct scsi_inquiry_data *inq = sa->sa_inqbuf; struct scsi_inquiry_data inqbuf; struct scsi_inquiry cmd; struct safte_inq *si = (struct safte_inq *)&inqbuf.extra; int length, flags; if (inq == NULL) return (0); /* match on dell enclosures */ if ((inq->device & SID_TYPE) == T_PROCESSOR && SCSISPC(inq->version) == 3) return (2); if ((inq->device & SID_TYPE) != T_PROCESSOR || SCSISPC(inq->version) != 2 || (inq->response_format & SID_ANSII) != 2) return (0); length = inq->additional_length + SAFTE_EXTRA_OFFSET; if (length < SAFTE_INQ_LEN) return (0); if (length > sizeof(inqbuf)) length = sizeof(inqbuf); memset(&cmd, 0, sizeof(cmd)); cmd.opcode = INQUIRY; _lto2b(length, cmd.length); memset(&inqbuf, 0, sizeof(inqbuf)); memset(&inqbuf.extra, ' ', sizeof(inqbuf.extra)); flags = SCSI_DATA_IN; if (cold) flags |= SCSI_AUTOCONF; if (scsi_scsi_cmd(sa->sa_sc_link, (struct scsi_generic *)&cmd, sizeof(cmd), (u_char *)&inqbuf, length, 2, 10000, NULL, flags) != 0) return (0); if (memcmp(si->ident, SAFTE_IDENT, sizeof(si->ident)) == 0) return (2); return (0); }
int emc_inquiry(struct emc_softc *sc, char *model, char *serial) { u_int8_t buffer[255]; struct scsi_inquiry *cdb; struct scsi_xfer *xs; size_t length; int error; u_int8_t slen, mlen; length = MIN(sc->sc_path.p_link->inqdata.additional_length + 5, sizeof(buffer)); if (length < 160) { printf("%s: FC (Legacy)\n"); return (0); } xs = scsi_xs_get(sc->sc_path.p_link, scsi_autoconf); if (xs == NULL) return (EBUSY); cdb = (struct scsi_inquiry *)xs->cmd; cdb->opcode = INQUIRY; _lto2b(length, cdb->length); xs->cmdlen = sizeof(*cdb); xs->flags |= SCSI_DATA_IN; xs->data = buffer; xs->datalen = length; error = scsi_xs_sync(xs); scsi_xs_put(xs); if (error != 0) return (error); slen = buffer[160]; if (slen == 0 || slen + 161 > length) return (EIO); mlen = buffer[99]; if (mlen == 0 || slen + mlen + 161 > length) return (EIO); scsi_strvis(serial, buffer + 161, slen); scsi_strvis(model, buffer + 161 + slen, mlen); return (0); }
/* * Read subchannel */ int cd_read_subchannel(struct cd_softc *cd, int mode, int format, int track, struct cd_sub_channel_info *data, int len) { struct scsi_read_subchannel scsi_cmd; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.opcode = READ_SUBCHANNEL; if (mode == CD_MSF_FORMAT) scsi_cmd.byte2 |= CD_MSF; scsi_cmd.byte3 = SRS_SUBQ; scsi_cmd.subchan_format = format; scsi_cmd.track = track; _lto2b(len, scsi_cmd.data_len); return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd, sizeof(struct scsi_read_subchannel), (u_char *)data, len, SCSI_RETRIES, 5000, NULL, SCSI_DATA_IN|SCSI_SILENT); }
/*--------------------------------------------------------------------------- * *--------------------------------------------------------------------------*/ scsi_command_t * SCSI_recv_diag_command (uint datalength) { scsi_command_t *c = (scsi_command_t *) ≻ struct scsi_generic *cmd = (struct scsi_generic *) &(c->command); memset(c,0,sizeof(scsi_command_t)); c->length = sizeof(struct scsi_send_diag); c->datalen = datalength; cmd->opcode = RECEIVE_DIAGNOSTIC; cmd->bytes[0] = 0x0; /* allocation length */ _lto2b(datalength,&cmd->bytes[2]); 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; }
/* * Read table of contents */ int cd_read_toc(struct cd_softc *cd, int mode, int start, void *data, int len, int control) { struct scsi_read_toc scsi_cmd; bzero(&scsi_cmd, sizeof(scsi_cmd)); bzero(data, len); scsi_cmd.opcode = READ_TOC; if (mode == CD_MSF_FORMAT) scsi_cmd.byte2 |= CD_MSF; scsi_cmd.from_track = start; _lto2b(len, scsi_cmd.data_len); scsi_cmd.control = control; return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd, sizeof(struct scsi_read_toc), (u_char *)data, len, SCSI_RETRIES, 5000, NULL, SCSI_DATA_IN | SCSI_IGNORE_ILLEGAL_REQUEST); }
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); } }
/*--------------------------------------------------------------------------- * *--------------------------------------------------------------------------*/ scsi_command_t * SCSI_send_diag_command (uint datalength) { scsi_command_t *c = (scsi_command_t *) ≻ struct scsi_send_diag *cmd = (struct scsi_send_diag *) &(c->command); memset(c,0,sizeof(scsi_command_t)); c->length = sizeof(struct scsi_send_diag); c->datalen = datalength; cmd->opcode = SEND_DIAGNOSTIC; cmd->byte2 = SSD_PF; /* page format conforms to SCSI-2 */ if (scsi_version >= 2) { cmd->byte2 = SSD_PF; /* page format conforms to SCSI-2 */ } else { cmd->byte2 = 0; /* page format conforms to SCSI v.1 */ } _lto2b(datalength,cmd->paramlen); /* printf("Send Diag command: "); */ /* print_hexpage((char *) cmd,6); */ return ((scsi_command_t *) c); }
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); }
/* * 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; } } }
/* * Get the scsi driver to send a full inquiry to the * device and use the * results to fill out the disk parameter structure. */ static int sd_get_capacity(struct sd_softc *sd) { struct disk_parms *dp = &sd->sc_params; uint64_t blocks; int error, blksize; dp->disksize = blocks = sd_read_capacity(sd, &blksize); if (blocks == 0) { struct scsipi_read_format_capacities cmd; struct { struct scsipi_capacity_list_header header; struct scsipi_capacity_descriptor desc; } __packed data; memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); cmd.opcode = READ_FORMAT_CAPACITIES; _lto2b(sizeof(data), cmd.length); error = scsi_command(sd, (void *)&cmd, sizeof(cmd), (void *)&data, sizeof(data)); if (error == EFTYPE) /* Medium Format Corrupted, handle as not formatted */ return SDGP_RESULT_UNFORMATTED; if (error || data.header.length == 0) return SDGP_RESULT_OFFLINE; switch (data.desc.byte5 & SCSIPI_CAP_DESC_CODE_MASK) { case SCSIPI_CAP_DESC_CODE_RESERVED: case SCSIPI_CAP_DESC_CODE_FORMATTED: break; case SCSIPI_CAP_DESC_CODE_UNFORMATTED: return SDGP_RESULT_UNFORMATTED; case SCSIPI_CAP_DESC_CODE_NONE: return SDGP_RESULT_OFFLINE; } dp->disksize = blocks = _4btol(data.desc.nblks); if (blocks == 0) return SDGP_RESULT_OFFLINE; /* XXX? */ blksize = _3btol(data.desc.blklen); } else if (!sd_validate_blksize(blksize)) { struct sd_mode_sense_data scsipi_sense; int bsize; memset(&scsipi_sense, 0, sizeof(scsipi_sense)); error = scsi_mode_sense(sd, 0, 0, &scsipi_sense.header, sizeof(struct scsi_mode_parameter_header_6) + sizeof(scsipi_sense.blk_desc)); if (!error) { bsize = scsipi_sense.header.blk_desc_len; if (bsize >= 8) blksize = _3btol(scsipi_sense.blk_desc.blklen); } } if (!sd_validate_blksize(blksize)) blksize = SD_DEFAULT_BLKSIZE; dp->blksize = blksize; dp->disksize512 = (blocks * dp->blksize) / DEV_BSIZE; return 0; }
/* * trigger the scanner to start a scan operation * this includes sending the mode- and window-data, starting the scanner * and getting the image size info */ static int mustek_trigger_scanner(struct ss_softc *ss) { struct mustek_mode_select_cmd mode_cmd; struct mustek_mode_select_data mode_data; struct mustek_set_window_cmd window_cmd; struct mustek_set_window_data window_data; struct mustek_start_scan_cmd start_scan_cmd; struct scsipi_periph *periph = ss->sc_periph; int pixel_tlx, pixel_tly, pixel_brx, pixel_bry, paperlength; int error; mustek_compute_sizes(ss); SC_DEBUG(periph, SCSIPI_DB1, ("mustek_trigger_scanner\n")); /* set the window params and send the scsi command */ memset(&window_cmd, 0, sizeof(window_cmd)); window_cmd.opcode = MUSTEK_SET_WINDOW; window_cmd.length = sizeof(window_data); memset(&window_data, 0, sizeof(window_data)); window_data.frame.header = MUSTEK_LINEART_BACKGROUND | MUSTEK_UNIT_SPEC; #ifdef MUSTEK_INCH_SPEC /* the positional values are all 1 byte because 256 / 8 = 32" */ pixel_tlx = ss->sio.scan_x_origin / 150; pixel_tly = ss->sio.scan_y_origin / 150; pixel_brx = pixel_tlx + ss->sio.scan_width / 150; pixel_bry = pixel_tly + ss->sio.scan_height / 150; #else pixel_tlx = (ss->sio.scan_x_origin * ss->sio.scan_x_resolution) / 1200; pixel_tly = (ss->sio.scan_y_origin * ss->sio.scan_y_resolution) / 1200; pixel_brx = pixel_tlx + (ss->sio.scan_width * ss->sio.scan_x_resolution) / 1200; pixel_bry = pixel_tly + (ss->sio.scan_height * ss->sio.scan_y_resolution) / 1200; #endif _lto2l(pixel_tlx, window_data.frame.tl_x); _lto2l(pixel_tly, window_data.frame.tl_y); _lto2l(pixel_brx, window_data.frame.br_x); _lto2l(pixel_bry, window_data.frame.br_y); #if MUSTEK_WINDOWS >= 1 window_data.window1 = window_data.frame; window_data.window1.header = MUSTEK_WINDOW_MASK | MUSTEK_UNIT_SPEC; #endif /* send the set window command to the scanner */ SC_DEBUG(periph, SCSIPI_DB1, ("mustek_set_parms: set_window\n")); error = scsipi_command(periph, (void *)&window_cmd, sizeof(window_cmd), (void *)&window_data, sizeof(window_data), MUSTEK_RETRIES, 5000, NULL, XS_CTL_DATA_OUT); if (error) return error; /* * do what it takes to actualize the mode */ memset(&mode_cmd, 0, sizeof(mode_cmd)); mode_cmd.opcode = MUSTEK_MODE_SELECT; _lto2b(sizeof(mode_data), mode_cmd.length); memset(&mode_data, 0, sizeof(mode_data)); mode_data.mode = MUSTEK_MODE_MASK | MUSTEK_HT_PATTERN_BUILTIN | MUSTEK_UNIT_SPEC; if (ss->sio.scan_x_resolution <= 300) mode_data.resolution = ss->sio.scan_x_resolution / 3; else /* * the resolution values is computed by modulo 100, but not * for 600dpi, where the value is 100 (a bit tricky, but ...) */ mode_data.resolution = ((ss->sio.scan_x_resolution - 1) % 100) + 1; mode_data.brightness = (ss->sio.scan_brightness - 64) / 3; mode_data.contrast = (ss->sio.scan_contrast - 16) / 7; mode_data.grain = 0; mode_data.velocity = ss->sio.scan_quality / 20 - 1; #ifdef MUSTEK_INCH_SPEC paperlength = 14 * 8; /* 14" */ #else paperlength = 14 * ss->sio.scan_y_resolution; /* 14" */ #endif _lto2l(paperlength, mode_data.paperlength); SC_DEBUG(periph, SCSIPI_DB1, ("mustek_trigger_scanner: mode_select\n")); /* send the command to the scanner */ error = scsipi_command(periph, (void *)&mode_cmd, sizeof(mode_cmd), (void *)&mode_data, sizeof(mode_data), MUSTEK_RETRIES, 5000, NULL, XS_CTL_DATA_OUT); if (error) return error; /* * now construct and send the start command */ memset(&start_scan_cmd, 0, sizeof(start_scan_cmd)); start_scan_cmd.opcode = MUSTEK_START_STOP; start_scan_cmd.mode = MUSTEK_SCAN_START; if (ss->sio.scan_x_resolution <= 300) start_scan_cmd.mode |= MUSTEK_RES_STEP_1; else start_scan_cmd.mode |= MUSTEK_RES_STEP_10; switch (ss->sio.scan_image_mode) { case SIM_BINARY_MONOCHROME: case SIM_DITHERED_MONOCHROME: start_scan_cmd.mode |= MUSTEK_BIT_MODE | MUSTEK_GRAY_FILTER; break; case SIM_GRAYSCALE: start_scan_cmd.mode |= MUSTEK_GRAY_MODE | MUSTEK_GRAY_FILTER; break; case SIM_RED: start_scan_cmd.mode |= MUSTEK_GRAY_MODE | MUSTEK_RED_FILTER; break; case SIM_GREEN: start_scan_cmd.mode |= MUSTEK_GRAY_MODE | MUSTEK_GREEN_FILTER; break; case SIM_BLUE: start_scan_cmd.mode |= MUSTEK_GRAY_MODE | MUSTEK_BLUE_FILTER; break; } /* send the command to the scanner */ SC_DEBUG(periph, SCSIPI_DB1, ("mustek_trigger_scanner: start_scan\n")); error = scsipi_command(periph, (void *)&start_scan_cmd, sizeof(start_scan_cmd), NULL, 0, MUSTEK_RETRIES, 5000, NULL, 0); if (error) return error; /* * now check if scanner ready this time with update of size info * we wait here so that if the user issues a read directly afterwards, * the scanner will respond directly (otherwise we had to sleep with * a buffer locked in memory) */ SC_DEBUG(periph, SCSIPI_DB1, ("mustek_trigger_scanner: get_status\n")); error = mustek_get_status(ss, 60, 1); if (error) return error; return 0; }
/* * 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; }
static int ch_setvoltag(struct ch_softc *sc, struct changer_set_voltag_request *csvr) { struct scsi_send_volume_tag cmd; struct changer_volume_tag voltag; void *data = NULL; size_t datalen = 0; int error; u_int16_t dst; /* * Check arguments. */ if (csvr->csvr_type > CHET_DT) return (EINVAL); if (csvr->csvr_unit > (sc->sc_counts[csvr->csvr_type] - 1)) return (ENODEV); dst = sc->sc_firsts[csvr->csvr_type] + csvr->csvr_unit; /* * Build the SCSI command. */ memset(&cmd, 0, sizeof(cmd)); cmd.opcode = SEND_VOLUME_TAG; _lto2b(dst, cmd.eaddr); #define ALTERNATE (csvr->csvr_flags & CSVR_ALTERNATE) switch (csvr->csvr_flags & CSVR_MODE_MASK) { case CSVR_MODE_SET: cmd.sac = ALTERNATE ? SAC_ASSERT_ALT : SAC_ASSERT_PRIMARY; break; case CSVR_MODE_REPLACE: cmd.sac = ALTERNATE ? SAC_REPLACE_ALT : SAC_REPLACE_PRIMARY; break; case CSVR_MODE_CLEAR: cmd.sac = ALTERNATE ? SAC_UNDEFINED_ALT : SAC_UNDEFINED_PRIMARY; break; default: return (EINVAL); } #undef ALTERNATE if (cmd.sac < SAC_UNDEFINED_PRIMARY) { error = ch_voltag_convert_out(&csvr->csvr_voltag, &voltag); if (error) return (error); data = &voltag; datalen = sizeof(voltag); _lto2b(datalen, cmd.length); } /* * Send command to changer. */ return (scsipi_command(sc->sc_periph, (void *)&cmd, sizeof(cmd), (void *)data, datalen, CHRETRIES, CHTIMEOUT, NULL, datalen ? XS_CTL_DATA_OUT : 0)); }
int ch_exchange(struct ch_softc *sc, struct changer_exchange *ce) { struct scsi_exchange_medium *cmd; struct scsi_xfer *xs; int error; u_int16_t src, dst1, dst2; /* * Check arguments. */ if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) || (ce->ce_sdsttype > CHET_DT)) return (EINVAL); if ((ce->ce_srcunit > (sc->sc_counts[ce->ce_srctype] - 1)) || (ce->ce_fdstunit > (sc->sc_counts[ce->ce_fdsttype] - 1)) || (ce->ce_sdstunit > (sc->sc_counts[ce->ce_sdsttype] - 1))) return (ENODEV); /* * Check the request against the changer's capabilities. */ if (((sc->sc_exchangemask[ce->ce_srctype] & (1 << ce->ce_fdsttype)) == 0) || ((sc->sc_exchangemask[ce->ce_fdsttype] & (1 << ce->ce_sdsttype)) == 0)) return (EINVAL); /* * Calculate the source and destination elements. */ src = sc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit; dst1 = sc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit; dst2 = sc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit; /* * Build the SCSI command. */ xs = scsi_xs_get(sc->sc_link, 0); if (xs == NULL) return (ENOMEM); xs->cmdlen = sizeof(*cmd); xs->retries = CHRETRIES; xs->timeout = 100000; cmd = (struct scsi_exchange_medium *)xs->cmd; cmd->opcode = EXCHANGE_MEDIUM; _lto2b(sc->sc_picker, cmd->tea); _lto2b(src, cmd->src); _lto2b(dst1, cmd->fdst); _lto2b(dst2, cmd->sdst); if (ce->ce_flags & CE_INVERT1) cmd->flags |= EXCHANGE_MEDIUM_INV1; if (ce->ce_flags & CE_INVERT2) cmd->flags |= EXCHANGE_MEDIUM_INV2; error = scsi_xs_sync(xs); scsi_xs_put(xs); return (error); }