version 1.114, 1999/09/30 22:57:55 |
version 1.114.2.7, 2001/02/11 19:16:19 |
|
|
#include <sys/mtio.h> |
#include <sys/mtio.h> |
#include <sys/device.h> |
#include <sys/device.h> |
#include <sys/conf.h> |
#include <sys/conf.h> |
|
#include <sys/kernel.h> |
#if NRND > 0 |
#if NRND > 0 |
#include <sys/rnd.h> |
#include <sys/rnd.h> |
#endif |
#endif |
|
|
#define ST_CTL_TIME (30 * 1000) /* 30 seconds */ |
#define ST_CTL_TIME (30 * 1000) /* 30 seconds */ |
#define ST_SPC_TIME (4 * 60 * 60 * 1000) /* 4 hours */ |
#define ST_SPC_TIME (4 * 60 * 60 * 1000) /* 4 hours */ |
|
|
|
#ifndef ST_MOUNT_DELAY |
|
#define ST_MOUNT_DELAY 0 |
|
#endif |
|
|
/* |
/* |
* Define various devices that we know mis-behave in some way, |
* Define various devices that we know mis-behave in some way, |
* and note how they are bad, so we can correct for them |
* and note how they are bad, so we can correct for them |
Line 118 struct quirkdata { |
|
Line 123 struct quirkdata { |
|
#define ST_Q_IGNORE_LOADS 0x0004 |
#define ST_Q_IGNORE_LOADS 0x0004 |
#define ST_Q_BLKSIZE 0x0008 /* variable-block media_blksize > 0 */ |
#define ST_Q_BLKSIZE 0x0008 /* variable-block media_blksize > 0 */ |
#define ST_Q_UNIMODAL 0x0010 /* unimode drive rejects mode select */ |
#define ST_Q_UNIMODAL 0x0010 /* unimode drive rejects mode select */ |
|
#define ST_Q_NOPREVENT 0x0020 /* does not support PREVENT */ |
|
#define ST_Q_ERASE_NOIMM 0x0040 /* drive rejects ERASE/w Immed bit */ |
u_int page_0_size; |
u_int page_0_size; |
#define MAX_PAGE_0_SIZE 64 |
#define MAX_PAGE_0_SIZE 64 |
struct modes modes[4]; |
struct modes modes[4]; |
Line 128 struct st_quirk_inquiry_pattern { |
|
Line 135 struct st_quirk_inquiry_pattern { |
|
struct quirkdata quirkdata; |
struct quirkdata quirkdata; |
}; |
}; |
|
|
struct st_quirk_inquiry_pattern st_quirk_patterns[] = { |
const struct st_quirk_inquiry_pattern st_quirk_patterns[] = { |
{{T_SEQUENTIAL, T_REMOV, |
{{T_SEQUENTIAL, T_REMOV, |
" ", " ", " "}, {0, 0, { |
" ", " ", " "}, {0, 0, { |
{ST_Q_FORCE_BLKSIZE, 512, 0}, /* minor 0-3 */ |
{ST_Q_FORCE_BLKSIZE, 512, 0}, /* minor 0-3 */ |
Line 193 struct st_quirk_inquiry_pattern st_quirk |
|
Line 200 struct st_quirk_inquiry_pattern st_quirk |
|
{0, 0, QIC_120} /* minor 12-15 */ |
{0, 0, QIC_120} /* minor 12-15 */ |
}}}, |
}}}, |
{{T_SEQUENTIAL, T_REMOV, |
{{T_SEQUENTIAL, T_REMOV, |
"ARCHIVE ", "VIPER 150 21247", ""}, {0, 12, { |
"ARCHIVE ", "VIPER 150 21247", ""}, {ST_Q_ERASE_NOIMM, 12, { |
{ST_Q_SENSE_HELP, 0, 0}, /* minor 0-3 */ |
{ST_Q_SENSE_HELP, 0, 0}, /* minor 0-3 */ |
{0, 0, QIC_150}, /* minor 4-7 */ |
{0, 0, QIC_150}, /* minor 4-7 */ |
{0, 0, QIC_120}, /* minor 8-11 */ |
{0, 0, QIC_120}, /* minor 8-11 */ |
{0, 0, QIC_24} /* minor 12-15 */ |
{0, 0, QIC_24} /* minor 12-15 */ |
}}}, |
}}}, |
{{T_SEQUENTIAL, T_REMOV, |
{{T_SEQUENTIAL, T_REMOV, |
"ARCHIVE ", "VIPER 150 21531", ""}, {0, 12, { |
"ARCHIVE ", "VIPER 150 21531", ""}, {ST_Q_ERASE_NOIMM, 12, { |
{ST_Q_SENSE_HELP, 0, 0}, /* minor 0-3 */ |
{ST_Q_SENSE_HELP, 0, 0}, /* minor 0-3 */ |
{0, 0, QIC_150}, /* minor 4-7 */ |
{0, 0, QIC_150}, /* minor 4-7 */ |
{0, 0, QIC_120}, /* minor 8-11 */ |
{0, 0, QIC_120}, /* minor 8-11 */ |
Line 242 struct st_quirk_inquiry_pattern st_quirk |
|
Line 249 struct st_quirk_inquiry_pattern st_quirk |
|
{0, 0, 0} /* minor 12-15 */ |
{0, 0, 0} /* minor 12-15 */ |
}}}, |
}}}, |
{{T_SEQUENTIAL, T_REMOV, |
{{T_SEQUENTIAL, T_REMOV, |
"STK", "9490", ""}, |
"STK", "9490", ""}, |
{ST_Q_FORCE_BLKSIZE, 0, { |
{ST_Q_FORCE_BLKSIZE, 0, { |
{0, 0, 0}, /* minor 0-3 */ |
{0, 0, 0}, /* minor 0-3 */ |
{0, 0, 0}, /* minor 4-7 */ |
{0, 0, 0}, /* minor 4-7 */ |
Line 280 struct st_quirk_inquiry_pattern st_quirk |
|
Line 287 struct st_quirk_inquiry_pattern st_quirk |
|
{0, 0, 0} /* minor 12-15 */ |
{0, 0, 0} /* minor 12-15 */ |
}}}, |
}}}, |
#endif |
#endif |
|
{{T_SEQUENTIAL, T_REMOV, |
|
"TEAC ", "MT-2ST/N50 ", ""}, {ST_Q_IGNORE_LOADS, 0, { |
|
{0, 0, 0}, /* minor 0-3 */ |
|
{0, 0, 0}, /* minor 4-7 */ |
|
{0, 0, 0}, /* minor 8-11 */ |
|
{0, 0, 0} /* minor 12-15 */ |
|
}}}, |
|
{{T_SEQUENTIAL, T_REMOV, |
|
"OnStream", "ADR50 Drive", ""}, {ST_Q_UNIMODAL, 0, { |
|
{ST_Q_FORCE_BLKSIZE, 512, 0}, /* minor 0-3 */ |
|
{ST_Q_FORCE_BLKSIZE, 512, 0}, /* minor 4-7 */ |
|
{ST_Q_FORCE_BLKSIZE, 512, 0}, /* minor 8-11 */ |
|
{ST_Q_FORCE_BLKSIZE, 512, 0}, /* minor 12-15 */ |
|
}}}, |
|
{{T_SEQUENTIAL, T_REMOV, |
|
"NCR H621", "0-STD-03-46F880 ", ""}, {ST_Q_NOPREVENT, 0, { |
|
{0, 0, 0}, /* minor 0-3 */ |
|
{0, 0, 0}, /* minor 4-7 */ |
|
{0, 0, 0}, /* minor 8-11 */ |
|
{0, 0, 0} /* minor 12-15 */ |
|
}}}, |
}; |
}; |
|
|
#define NOEJECT 0 |
#define NOEJECT 0 |
Line 296 struct st_softc { |
|
Line 324 struct st_softc { |
|
u_int last_dsty; /* last density opened */ |
u_int last_dsty; /* last density opened */ |
short mt_resid; /* last (short) resid */ |
short mt_resid; /* last (short) resid */ |
short mt_erreg; /* last error (sense key) seen */ |
short mt_erreg; /* last error (sense key) seen */ |
|
#define mt_key mt_erreg |
|
u_int8_t asc; /* last asc code seen */ |
|
u_int8_t ascq; /* last asc code seen */ |
/*--------------------device/scsi parameters---------------------------------*/ |
/*--------------------device/scsi parameters---------------------------------*/ |
struct scsipi_link *sc_link; /* our link to the adpter etc. */ |
struct scsipi_periph *sc_periph;/* our link to the adpter etc. */ |
/*--------------------parameters reported by the device ---------------------*/ |
/*--------------------parameters reported by the device ---------------------*/ |
int blkmin; /* min blk size */ |
int blkmin; /* min blk size */ |
int blkmax; /* max blk size */ |
int blkmax; /* max blk size */ |
Line 320 struct st_softc { |
|
Line 351 struct st_softc { |
|
* additional sense data needed |
* additional sense data needed |
* for mode sense/select. |
* for mode sense/select. |
*/ |
*/ |
struct buf buf_queue; /* the queue of pending IO */ |
struct buf_queue buf_queue; /* the queue of pending IO */ |
/* operations */ |
/* operations */ |
#if NRND > 0 |
#if NRND > 0 |
rndsource_element_t rnd_source; |
rndsource_element_t rnd_source; |
Line 336 void st_loadquirks __P((struct st_softc |
|
Line 367 void st_loadquirks __P((struct st_softc |
|
int st_mount_tape __P((dev_t, int)); |
int st_mount_tape __P((dev_t, int)); |
void st_unmount __P((struct st_softc *, boolean)); |
void st_unmount __P((struct st_softc *, boolean)); |
int st_decide_mode __P((struct st_softc *, boolean)); |
int st_decide_mode __P((struct st_softc *, boolean)); |
void ststart __P((void *)); |
void ststart __P((struct scsipi_periph *)); |
void stdone __P((struct scsipi_xfer *)); |
void stdone __P((struct scsipi_xfer *)); |
int st_read __P((struct st_softc *, char *, int, int)); |
int st_read __P((struct st_softc *, char *, int, int)); |
int st_read_block_limits __P((struct st_softc *, int)); |
int st_read_block_limits __P((struct st_softc *, int)); |
Line 360 struct cfattach st_ca = { |
|
Line 391 struct cfattach st_ca = { |
|
|
|
extern struct cfdriver st_cd; |
extern struct cfdriver st_cd; |
|
|
struct scsipi_device st_switch = { |
const struct scsipi_periphsw st_switch = { |
st_interpret_sense, |
st_interpret_sense, |
ststart, |
ststart, |
NULL, |
NULL, |
Line 430 stattach(parent, self, aux) |
|
Line 461 stattach(parent, self, aux) |
|
{ |
{ |
struct st_softc *st = (void *)self; |
struct st_softc *st = (void *)self; |
struct scsipibus_attach_args *sa = aux; |
struct scsipibus_attach_args *sa = aux; |
struct scsipi_link *sc_link = sa->sa_sc_link; |
struct scsipi_periph *periph = sa->sa_periph; |
|
|
SC_DEBUG(sc_link, SDEV_DB2, ("stattach: ")); |
SC_DEBUG(periph, SCSIPI_DB2, ("stattach: ")); |
|
|
/* |
/* |
* Store information needed to contact our base driver |
* Store information needed to contact our base driver |
*/ |
*/ |
st->sc_link = sc_link; |
st->sc_periph = periph; |
sc_link->device = &st_switch; |
periph->periph_dev = &st->sc_dev; |
sc_link->device_softc = st; |
periph->periph_switch = &st_switch; |
sc_link->openings = 1; |
|
|
|
/* |
/* |
* Set initial flags |
* Set initial flags |
Line 454 stattach(parent, self, aux) |
|
Line 484 stattach(parent, self, aux) |
|
*/ |
*/ |
st_identify_drive(st, &sa->sa_inqbuf); |
st_identify_drive(st, &sa->sa_inqbuf); |
/* |
/* |
* Use the subdriver to request information regarding |
* Use the subdriver to request information regarding the drive. |
* the drive. We cannot use interrupts yet, so the |
|
* request must specify this. |
|
*/ |
*/ |
printf("\n"); |
printf("\n"); |
printf("%s: %s", st->sc_dev.dv_xname, st->quirkdata ? "rogue, " : ""); |
printf("%s: %s", st->sc_dev.dv_xname, st->quirkdata ? "rogue, " : ""); |
if (scsipi_test_unit_ready(sc_link, |
if (scsipi_test_unit_ready(periph, |
XS_CTL_DISCOVERY | XS_CTL_SILENT | XS_CTL_IGNORE_MEDIA_CHANGE) || |
XS_CTL_DISCOVERY | XS_CTL_SILENT | XS_CTL_IGNORE_MEDIA_CHANGE) || |
st_mode_sense(st, |
st_mode_sense(st, |
XS_CTL_DISCOVERY | XS_CTL_SILENT | XS_CTL_IGNORE_MEDIA_CHANGE)) |
XS_CTL_DISCOVERY | XS_CTL_SILENT | XS_CTL_IGNORE_MEDIA_CHANGE)) |
printf("drive empty\n"); |
printf("drive empty\n"); |
else { |
else { |
printf("density code 0x%x, ", st->media_density); |
printf("density code %d, ", st->media_density); |
if (st->media_blksize > 0) |
if (st->media_blksize > 0) |
printf("%d-byte", st->media_blksize); |
printf("%d-byte", st->media_blksize); |
else |
else |
Line 478 stattach(parent, self, aux) |
|
Line 506 stattach(parent, self, aux) |
|
/* |
/* |
* Set up the buf queue for this device |
* Set up the buf queue for this device |
*/ |
*/ |
st->buf_queue.b_active = 0; |
BUFQ_INIT(&st->buf_queue); |
st->buf_queue.b_actf = 0; |
|
st->buf_queue.b_actb = &st->buf_queue.b_actf; |
|
|
|
#if NRND > 0 |
#if NRND > 0 |
rnd_attach_source(&st->rnd_source, st->sc_dev.dv_xname, |
rnd_attach_source(&st->rnd_source, st->sc_dev.dv_xname, |
Line 541 st_loadquirks(st) |
|
Line 567 st_loadquirks(st) |
|
mode2->density = mode->density; |
mode2->density = mode->density; |
st->modeflags[i] |= DENSITY_SET_BY_QUIRK; |
st->modeflags[i] |= DENSITY_SET_BY_QUIRK; |
} |
} |
|
mode2->quirks |= mode->quirks; |
mode++; |
mode++; |
mode2++; |
mode2++; |
} |
} |
Line 556 stopen(dev, flags, mode, p) |
|
Line 583 stopen(dev, flags, mode, p) |
|
int mode; |
int mode; |
struct proc *p; |
struct proc *p; |
{ |
{ |
int unit; |
|
u_int stmode, dsty; |
u_int stmode, dsty; |
int error; |
int error, sflags, unit, tries, ntries; |
struct st_softc *st; |
struct st_softc *st; |
struct scsipi_link *sc_link; |
struct scsipi_periph *periph; |
|
struct scsipi_adapter *adapt; |
|
|
unit = STUNIT(dev); |
unit = STUNIT(dev); |
if (unit >= st_cd.cd_ndevs) |
if (unit >= st_cd.cd_ndevs) |
Line 571 stopen(dev, flags, mode, p) |
|
Line 598 stopen(dev, flags, mode, p) |
|
|
|
stmode = STMODE(dev); |
stmode = STMODE(dev); |
dsty = STDSTY(dev); |
dsty = STDSTY(dev); |
sc_link = st->sc_link; |
|
|
|
SC_DEBUG(sc_link, SDEV_DB1, ("open: dev=0x%x (unit %d (of %d))\n", dev, |
periph = st->sc_periph; |
|
adapt = periph->periph_channel->chan_adapter; |
|
|
|
SC_DEBUG(periph, SCSIPI_DB1, ("open: dev=0x%x (unit %d (of %d))\n", dev, |
unit, st_cd.cd_ndevs)); |
unit, st_cd.cd_ndevs)); |
|
|
|
|
/* |
/* |
* Only allow one at a time |
* Only allow one at a time |
*/ |
*/ |
if (sc_link->flags & SDEV_OPEN) { |
if (periph->periph_flags & PERIPH_OPEN) { |
printf("%s: already open\n", st->sc_dev.dv_xname); |
printf("%s: already open\n", st->sc_dev.dv_xname); |
return (EBUSY); |
return (EBUSY); |
} |
} |
|
|
if ((error = scsipi_adapter_addref(sc_link)) != 0) |
if ((error = scsipi_adapter_addref(adapt)) != 0) |
return (error); |
return (error); |
|
|
/* |
/* |
Line 593 stopen(dev, flags, mode, p) |
|
Line 622 stopen(dev, flags, mode, p) |
|
*/ |
*/ |
st->mt_resid = 0; |
st->mt_resid = 0; |
st->mt_erreg = 0; |
st->mt_erreg = 0; |
|
st->asc = 0; |
|
st->ascq = 0; |
|
|
/* |
/* |
* Catch any unit attention errors. |
* Catch any unit attention errors. Be silent about this |
|
* unless we're already mounted. We ignore media change |
|
* if we're in control mode or not mounted yet. |
*/ |
*/ |
error = scsipi_test_unit_ready(sc_link, XS_CTL_IGNORE_MEDIA_CHANGE | |
if ((st->flags & ST_MOUNTED) == 0 || stmode == CTRL_MODE) { |
(stmode == CTRL_MODE ? XS_CTL_SILENT : 0)); |
#ifdef SCSIDEBUG |
if (error && stmode != CTRL_MODE) { |
sflags = XS_CTL_IGNORE_MEDIA_CHANGE; |
goto bad; |
#else |
|
sflags = XS_CTL_SILENT|XS_CTL_IGNORE_MEDIA_CHANGE; |
|
#endif |
|
} else |
|
sflags = 0; |
|
|
|
/* |
|
* If we're already mounted or we aren't configured for |
|
* a mount delay, only try a test unit ready once. Otherwise, |
|
* try up to ST_MOUNT_DELAY times with a rest interval of |
|
* one second between each try. |
|
*/ |
|
|
|
if ((st->flags & ST_MOUNTED) || ST_MOUNT_DELAY == 0) { |
|
ntries = 1; |
|
} else { |
|
ntries = ST_MOUNT_DELAY; |
} |
} |
sc_link->flags |= SDEV_OPEN; /* unit attn are now errors */ |
|
|
for (error = tries = 0; tries < ntries; tries++) { |
|
int slpintr, oflags; |
|
|
|
/* |
|
* If we had no error, or we're opening the control mode |
|
* device, we jump out right away. |
|
*/ |
|
|
|
error = scsipi_test_unit_ready(periph, sflags); |
|
if (error == 0 || stmode == CTRL_MODE) { |
|
break; |
|
} |
|
|
|
/* |
|
* We had an error. |
|
* |
|
* If we're already mounted or we aren't configured for |
|
* a mount delay, or the error isn't a NOT READY error, |
|
* skip to the error exit now. |
|
*/ |
|
if ((st->flags & ST_MOUNTED) || ST_MOUNT_DELAY == 0 || |
|
(st->mt_key != SKEY_NOT_READY)) { |
|
goto bad; |
|
} |
|
|
|
/* |
|
* clear any latched errors. |
|
*/ |
|
st->mt_resid = 0; |
|
st->mt_erreg = 0; |
|
st->asc = 0; |
|
st->ascq = 0; |
|
|
|
/* |
|
* Fake that we have the device open so |
|
* we block other apps from getting in. |
|
*/ |
|
|
|
oflags = periph->periph_flags; |
|
periph->periph_flags |= PERIPH_OPEN; |
|
|
|
slpintr = tsleep(&lbolt, PUSER|PCATCH, "stload", 0); |
|
|
|
periph->periph_flags = oflags; /* restore flags */ |
|
if (slpintr) { |
|
goto bad; |
|
} |
|
} |
|
|
|
|
/* |
/* |
* If the mode is 3 (e.g. minor = 3,7,11,15) then the device has |
* If the mode is 3 (e.g. minor = 3,7,11,15) then the device has |
Line 612 stopen(dev, flags, mode, p) |
|
Line 710 stopen(dev, flags, mode, p) |
|
* as to whether or not we got a NOT READY for the above |
* as to whether or not we got a NOT READY for the above |
* unit attention). If a tape is there, go do a mount sequence. |
* unit attention). If a tape is there, go do a mount sequence. |
*/ |
*/ |
if (stmode == CTRL_MODE && st->mt_erreg == SKEY_NOT_READY) { |
if (stmode == CTRL_MODE && st->mt_key == SKEY_NOT_READY) { |
|
periph->periph_flags |= PERIPH_OPEN; |
return (0); |
return (0); |
} |
} |
|
|
/* |
/* |
|
* If we get this far and had an error set, that means we failed |
|
* to pass the 'test unit ready' test for the non-controlmode device, |
|
* so we bounce the open. |
|
*/ |
|
|
|
if (error) |
|
return (error); |
|
|
|
/* |
|
* Else, we're now committed to saying we're open. |
|
*/ |
|
|
|
periph->periph_flags |= PERIPH_OPEN; /* unit attn are now errors */ |
|
|
|
/* |
* If it's a different mode, or if the media has been |
* If it's a different mode, or if the media has been |
* invalidated, unmount the tape from the previous |
* invalidated, unmount the tape from the previous |
* session but continue with open processing |
* session but continue with open processing |
*/ |
*/ |
if (st->last_dsty != dsty || !(sc_link->flags & SDEV_MEDIA_LOADED)) |
if (st->last_dsty != dsty || |
|
(periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) |
st_unmount(st, NOEJECT); |
st_unmount(st, NOEJECT); |
|
|
/* |
/* |
Line 629 stopen(dev, flags, mode, p) |
|
Line 744 stopen(dev, flags, mode, p) |
|
* mount session. |
* mount session. |
*/ |
*/ |
if (!(st->flags & ST_MOUNTED)) { |
if (!(st->flags & ST_MOUNTED)) { |
st_mount_tape(dev, flags); |
if ((error = st_mount_tape(dev, flags)) != 0) |
|
goto bad; |
st->last_dsty = dsty; |
st->last_dsty = dsty; |
} |
} |
|
|
SC_DEBUG(sc_link, SDEV_DB2, ("open complete\n")); |
SC_DEBUG(periph, SCSIPI_DB2, ("open complete\n")); |
return (0); |
return (0); |
|
|
bad: |
bad: |
st_unmount(st, NOEJECT); |
st_unmount(st, NOEJECT); |
scsipi_adapter_delref(sc_link); |
scsipi_adapter_delref(adapt); |
sc_link->flags &= ~SDEV_OPEN; |
periph->periph_flags &= ~PERIPH_OPEN; |
return (error); |
return (error); |
} |
} |
|
|
Line 656 stclose(dev, flags, mode, p) |
|
Line 772 stclose(dev, flags, mode, p) |
|
{ |
{ |
int stxx, error = 0; |
int stxx, error = 0; |
struct st_softc *st = st_cd.cd_devs[STUNIT(dev)]; |
struct st_softc *st = st_cd.cd_devs[STUNIT(dev)]; |
|
struct scsipi_periph *periph = st->sc_periph; |
|
struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter; |
|
|
SC_DEBUG(st->sc_link, SDEV_DB1, ("closing\n")); |
SC_DEBUG(st->sc_periph, SCSIPI_DB1, ("closing\n")); |
|
|
/* |
/* |
* Make sure that a tape opened in write-only mode will have |
* Make sure that a tape opened in write-only mode will have |
Line 697 stclose(dev, flags, mode, p) |
|
Line 815 stclose(dev, flags, mode, p) |
|
* |
* |
* file - FMK - file - FMK ... file - FMK FMK (EOM) |
* file - FMK - file - FMK ... file - FMK FMK (EOM) |
*/ |
*/ |
if (!(st->sc_link->flags & SDEV_MEDIA_LOADED)) { |
if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) { |
st_unmount(st, NOEJECT); |
st_unmount(st, NOEJECT); |
} else if (error == 0) { |
} else if (error == 0) { |
/* |
/* |
Line 709 stclose(dev, flags, mode, p) |
|
Line 827 stclose(dev, flags, mode, p) |
|
* operation a write? |
* operation a write? |
* |
* |
* Are there supposed to be 2FM at EOD? |
* Are there supposed to be 2FM at EOD? |
* |
* |
* If both statements are true, then we backspace |
* If both statements are true, then we backspace |
* one filemark. |
* one filemark. |
*/ |
*/ |
Line 725 stclose(dev, flags, mode, p) |
|
Line 843 stclose(dev, flags, mode, p) |
|
break; |
break; |
} |
} |
|
|
scsipi_wait_drain(st->sc_link); |
scsipi_wait_drain(periph); |
|
|
scsipi_adapter_delref(st->sc_link); |
scsipi_adapter_delref(adapt); |
st->sc_link->flags &= ~SDEV_OPEN; |
periph->periph_flags &= ~PERIPH_OPEN; |
|
|
return (error); |
return (error); |
} |
} |
Line 746 st_mount_tape(dev, flags) |
|
Line 864 st_mount_tape(dev, flags) |
|
int unit; |
int unit; |
u_int dsty; |
u_int dsty; |
struct st_softc *st; |
struct st_softc *st; |
struct scsipi_link *sc_link; |
struct scsipi_periph *periph; |
int error = 0; |
int error = 0; |
|
|
unit = STUNIT(dev); |
unit = STUNIT(dev); |
dsty = STDSTY(dev); |
dsty = STDSTY(dev); |
st = st_cd.cd_devs[unit]; |
st = st_cd.cd_devs[unit]; |
sc_link = st->sc_link; |
periph = st->sc_periph; |
|
|
if (st->flags & ST_MOUNTED) |
if (st->flags & ST_MOUNTED) |
return (0); |
return (0); |
|
|
SC_DEBUG(sc_link, SDEV_DB1, ("mounting\n ")); |
SC_DEBUG(periph, SCSIPI_DB1, ("mounting\n ")); |
st->flags |= ST_NEW_MOUNT; |
st->flags |= ST_NEW_MOUNT; |
st->quirks = st->drive_quirks | st->modes[dsty].quirks; |
st->quirks = st->drive_quirks | st->modes[dsty].quirks; |
/* |
/* |
* If the media is new, then make sure we give it a chance to |
* If the media is new, then make sure we give it a chance to |
* to do a 'load' instruction. (We assume it is new.) |
* to do a 'load' instruction. (We assume it is new.) |
*/ |
*/ |
if ((error = st_load(st, LD_LOAD, 0)) != 0) |
if ((error = st_load(st, LD_LOAD, XS_CTL_SILENT)) != 0) |
return (error); |
return (error); |
/* |
/* |
* Throw another dummy instruction to catch |
* Throw another dummy instruction to catch |
Line 772 st_mount_tape(dev, flags) |
|
Line 890 st_mount_tape(dev, flags) |
|
* these after doing a Load instruction (with |
* these after doing a Load instruction (with |
* the MEDIUM MAY HAVE CHANGED asc/ascq). |
* the MEDIUM MAY HAVE CHANGED asc/ascq). |
*/ |
*/ |
scsipi_test_unit_ready(sc_link, XS_CTL_SILENT); /* XXX */ |
scsipi_test_unit_ready(periph, XS_CTL_SILENT); /* XXX */ |
|
|
/* |
/* |
* Some devices can't tell you much until they have been |
* Some devices can't tell you much until they have been |
Line 823 st_mount_tape(dev, flags) |
|
Line 941 st_mount_tape(dev, flags) |
|
printf("%s: cannot set selected mode\n", st->sc_dev.dv_xname); |
printf("%s: cannot set selected mode\n", st->sc_dev.dv_xname); |
return (error); |
return (error); |
} |
} |
scsipi_prevent(sc_link, PR_PREVENT, |
if (!(st->quirks & ST_Q_NOPREVENT)) { |
XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_NOT_READY); |
scsipi_prevent(periph, PR_PREVENT, |
|
XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_NOT_READY); |
|
} |
st->flags &= ~ST_NEW_MOUNT; |
st->flags &= ~ST_NEW_MOUNT; |
st->flags |= ST_MOUNTED; |
st->flags |= ST_MOUNTED; |
sc_link->flags |= SDEV_MEDIA_LOADED; /* move earlier? */ |
periph->periph_flags |= PERIPH_MEDIA_LOADED; /* move earlier? */ |
|
|
return (0); |
return (0); |
} |
} |
Line 843 st_unmount(st, eject) |
|
Line 963 st_unmount(st, eject) |
|
struct st_softc *st; |
struct st_softc *st; |
boolean eject; |
boolean eject; |
{ |
{ |
struct scsipi_link *sc_link = st->sc_link; |
struct scsipi_periph *periph = st->sc_periph; |
int nmarks; |
int nmarks; |
|
|
if (!(st->flags & ST_MOUNTED)) |
if ((st->flags & ST_MOUNTED) == 0) |
return; |
return; |
SC_DEBUG(sc_link, SDEV_DB1, ("unmounting\n")); |
SC_DEBUG(periph, SCSIPI_DB1, ("unmounting\n")); |
st_check_eod(st, FALSE, &nmarks, XS_CTL_IGNORE_NOT_READY); |
st_check_eod(st, FALSE, &nmarks, XS_CTL_IGNORE_NOT_READY); |
st_rewind(st, 0, XS_CTL_IGNORE_NOT_READY); |
st_rewind(st, 0, XS_CTL_IGNORE_NOT_READY); |
scsipi_prevent(sc_link, PR_ALLOW, |
|
|
/* |
|
* Section 9.3.3 of the SCSI specs states that a device shall return |
|
* the density value specified in the last succesfull MODE SELECT |
|
* after an unload operation, in case it is not able to |
|
* automatically determine the density of the new medium. |
|
* |
|
* So we instruct the device to use the default density, which will |
|
* prevent the use of stale density values (in particular, |
|
* in st_touch_tape(). |
|
*/ |
|
st->density = 0; |
|
if (st_mode_select(st, 0) != 0) { |
|
printf("%s: WARNING: cannot revert to default density\n", |
|
st->sc_dev.dv_xname); |
|
} |
|
|
|
scsipi_prevent(periph, PR_ALLOW, |
XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_NOT_READY); |
XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_NOT_READY); |
if (eject) |
if (eject) |
st_load(st, LD_UNLOAD, XS_CTL_IGNORE_NOT_READY); |
st_load(st, LD_UNLOAD, XS_CTL_IGNORE_NOT_READY); |
st->flags &= ~(ST_MOUNTED | ST_NEW_MOUNT); |
st->flags &= ~(ST_MOUNTED | ST_NEW_MOUNT); |
sc_link->flags &= ~SDEV_MEDIA_LOADED; |
periph->periph_flags &= ~PERIPH_MEDIA_LOADED; |
} |
} |
|
|
/* |
/* |
Line 869 st_decide_mode(st, first_read) |
|
Line 1006 st_decide_mode(st, first_read) |
|
struct st_softc *st; |
struct st_softc *st; |
boolean first_read; |
boolean first_read; |
{ |
{ |
#ifdef SCSIDEBUG |
|
struct scsipi_link *sc_link = st->sc_link; |
|
#endif |
|
|
|
SC_DEBUG(sc_link, SDEV_DB2, ("starting block mode decision\n")); |
SC_DEBUG(st->sc_periph, SCSIPI_DB2, ("starting block mode decision\n")); |
|
|
/* |
/* |
* If the drive can only handle fixed-length blocks and only at |
* If the drive can only handle fixed-length blocks and only at |
Line 882 st_decide_mode(st, first_read) |
|
Line 1016 st_decide_mode(st, first_read) |
|
if (st->blkmin && (st->blkmin == st->blkmax)) { |
if (st->blkmin && (st->blkmin == st->blkmax)) { |
st->flags |= ST_FIXEDBLOCKS; |
st->flags |= ST_FIXEDBLOCKS; |
st->blksize = st->blkmin; |
st->blksize = st->blkmin; |
SC_DEBUG(sc_link, SDEV_DB3, |
SC_DEBUG(st->sc_periph, SCSIPI_DB3, |
("blkmin == blkmax of %d\n", st->blkmin)); |
("blkmin == blkmax of %d\n", st->blkmin)); |
goto done; |
goto done; |
} |
} |
Line 897 st_decide_mode(st, first_read) |
|
Line 1031 st_decide_mode(st, first_read) |
|
case DDS: |
case DDS: |
st->flags &= ~ST_FIXEDBLOCKS; |
st->flags &= ~ST_FIXEDBLOCKS; |
st->blksize = 0; |
st->blksize = 0; |
SC_DEBUG(sc_link, SDEV_DB3, ("density specified variable\n")); |
SC_DEBUG(st->sc_periph, SCSIPI_DB3, |
|
("density specified variable\n")); |
goto done; |
goto done; |
case QIC_11: |
case QIC_11: |
case QIC_24: |
case QIC_24: |
Line 905 st_decide_mode(st, first_read) |
|
Line 1040 st_decide_mode(st, first_read) |
|
case QIC_150: |
case QIC_150: |
case QIC_525: |
case QIC_525: |
case QIC_1320: |
case QIC_1320: |
|
case QIC_3095: |
|
case QIC_3220: |
st->flags |= ST_FIXEDBLOCKS; |
st->flags |= ST_FIXEDBLOCKS; |
if (st->media_blksize > 0) |
if (st->media_blksize > 0) |
st->blksize = st->media_blksize; |
st->blksize = st->media_blksize; |
else |
else |
st->blksize = DEF_FIXED_BSIZE; |
st->blksize = DEF_FIXED_BSIZE; |
SC_DEBUG(sc_link, SDEV_DB3, ("density specified fixed\n")); |
SC_DEBUG(st->sc_periph, SCSIPI_DB3, |
|
("density specified fixed\n")); |
goto done; |
goto done; |
} |
} |
/* |
/* |
Line 927 st_decide_mode(st, first_read) |
|
Line 1065 st_decide_mode(st, first_read) |
|
else |
else |
st->flags &= ~ST_FIXEDBLOCKS; |
st->flags &= ~ST_FIXEDBLOCKS; |
st->blksize = st->media_blksize; |
st->blksize = st->media_blksize; |
SC_DEBUG(sc_link, SDEV_DB3, |
SC_DEBUG(st->sc_periph, SCSIPI_DB3, |
("Used media_blksize of %d\n", st->media_blksize)); |
("Used media_blksize of %d\n", st->media_blksize)); |
goto done; |
goto done; |
} |
} |
Line 937 st_decide_mode(st, first_read) |
|
Line 1075 st_decide_mode(st, first_read) |
|
*/ |
*/ |
st->flags &= ~ST_FIXEDBLOCKS; |
st->flags &= ~ST_FIXEDBLOCKS; |
st->blksize = 0; |
st->blksize = 0; |
SC_DEBUG(sc_link, SDEV_DB3, |
SC_DEBUG(st->sc_periph, SCSIPI_DB3, |
("Give up and default to variable mode\n")); |
("Give up and default to variable mode\n")); |
|
|
done: |
done: |
|
|
case QIC_150: |
case QIC_150: |
case QIC_525: |
case QIC_525: |
case QIC_1320: |
case QIC_1320: |
|
case QIC_3095: |
|
case QIC_3220: |
st->flags &= ~ST_2FM_AT_EOD; |
st->flags &= ~ST_2FM_AT_EOD; |
break; |
break; |
default: |
default: |
|
|
struct buf *bp; |
struct buf *bp; |
{ |
{ |
struct st_softc *st = st_cd.cd_devs[STUNIT(bp->b_dev)]; |
struct st_softc *st = st_cd.cd_devs[STUNIT(bp->b_dev)]; |
struct buf *dp; |
|
int s; |
int s; |
|
|
SC_DEBUG(st->sc_link, SDEV_DB1, |
SC_DEBUG(st->sc_periph, SCSIPI_DB1, |
("ststrategy %ld bytes @ blk %d\n", bp->b_bcount, bp->b_blkno)); |
("ststrategy %ld bytes @ blk %d\n", bp->b_bcount, bp->b_blkno)); |
/* |
/* |
* If it's a null transfer, return immediatly |
* If it's a null transfer, return immediatly |
|
|
* at the end (a bit silly because we only have on user.. |
* at the end (a bit silly because we only have on user.. |
* (but it could fork())) |
* (but it could fork())) |
*/ |
*/ |
dp = &st->buf_queue; |
BUFQ_INSERT_TAIL(&st->buf_queue, bp); |
bp->b_actf = NULL; |
|
bp->b_actb = dp->b_actb; |
|
*dp->b_actb = bp; |
|
dp->b_actb = &bp->b_actf; |
|
|
|
/* |
/* |
* Tell the device to get going on the transfer if it's |
* Tell the device to get going on the transfer if it's |
* not doing anything, otherwise just wait for completion |
* not doing anything, otherwise just wait for completion |
* (All a bit silly if we're only allowing 1 open but..) |
* (All a bit silly if we're only allowing 1 open but..) |
*/ |
*/ |
ststart(st); |
ststart(st->sc_periph); |
|
|
splx(s); |
splx(s); |
return; |
return; |
|
|
* ststart() is called at splbio |
* ststart() is called at splbio |
*/ |
*/ |
void |
void |
ststart(v) |
ststart(periph) |
void *v; |
struct scsipi_periph *periph; |
{ |
{ |
struct st_softc *st = v; |
struct st_softc *st = (void *)periph->periph_dev; |
struct scsipi_link *sc_link = st->sc_link; |
struct buf *bp; |
register struct buf *bp, *dp; |
|
struct scsi_rw_tape cmd; |
struct scsi_rw_tape cmd; |
int flags, error; |
int flags, error; |
|
|
SC_DEBUG(sc_link, SDEV_DB2, ("ststart ")); |
SC_DEBUG(periph, SCSIPI_DB2, ("ststart ")); |
/* |
/* |
* See if there is a buf to do and we are not already |
* See if there is a buf to do and we are not already |
* doing one |
* doing one |
*/ |
*/ |
while (sc_link->active < sc_link->openings) { |
while (periph->periph_active < periph->periph_openings) { |
/* if a special awaits, let it proceed first */ |
/* if a special awaits, let it proceed first */ |
if (sc_link->flags & SDEV_WAITING) { |
if (periph->periph_flags & PERIPH_WAITING) { |
sc_link->flags &= ~SDEV_WAITING; |
periph->periph_flags &= ~PERIPH_WAITING; |
wakeup((caddr_t)sc_link); |
wakeup((caddr_t)periph); |
return; |
return; |
} |
} |
|
|
dp = &st->buf_queue; |
if ((bp = BUFQ_FIRST(&st->buf_queue)) == NULL) |
if ((bp = dp->b_actf) == NULL) |
|
return; |
return; |
if ((dp = bp->b_actf) != NULL) |
BUFQ_REMOVE(&st->buf_queue, bp); |
dp->b_actb = bp->b_actb; |
|
else |
|
st->buf_queue.b_actb = bp->b_actb; |
|
*bp->b_actb = dp; |
|
|
|
/* |
/* |
* if the device has been unmounted bye the user |
* If the device has been unmounted by the user |
* then throw away all requests until done |
* then throw away all requests until done. |
*/ |
*/ |
if (!(st->flags & ST_MOUNTED) || |
if ((st->flags & ST_MOUNTED) == 0 || |
!(sc_link->flags & SDEV_MEDIA_LOADED)) { |
(periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) { |
/* make sure that one implies the other.. */ |
/* make sure that one implies the other.. */ |
sc_link->flags &= ~SDEV_MEDIA_LOADED; |
periph->periph_flags &= ~PERIPH_MEDIA_LOADED; |
bp->b_flags |= B_ERROR; |
bp->b_flags |= B_ERROR; |
bp->b_error = EIO; |
bp->b_error = EIO; |
bp->b_resid = bp->b_bcount; |
bp->b_resid = bp->b_bcount; |
|
|
} |
} |
/* |
/* |
* If we are at EOM but have not reported it |
* If we are at EOM but have not reported it |
* yet then we should report it now. |
* yet then we should report it now. |
*/ |
*/ |
if (st->flags & (ST_EOM_PENDING|ST_EIO_PENDING)) { |
if (st->flags & (ST_EOM_PENDING|ST_EIO_PENDING)) { |
bp->b_resid = bp->b_bcount; |
bp->b_resid = bp->b_bcount; |
|
|
} |
} |
|
|
/* |
/* |
* Fill out the scsi command |
* Fill out the scsi command |
*/ |
*/ |
bzero(&cmd, sizeof(cmd)); |
bzero(&cmd, sizeof(cmd)); |
|
flags = XS_CTL_NOSLEEP | XS_CTL_ASYNC; |
if ((bp->b_flags & B_READ) == B_WRITE) { |
if ((bp->b_flags & B_READ) == B_WRITE) { |
cmd.opcode = WRITE; |
cmd.opcode = WRITE; |
st->flags &= ~ST_FM_WRITTEN; |
st->flags &= ~ST_FM_WRITTEN; |
flags = XS_CTL_DATA_OUT; |
flags |= XS_CTL_DATA_OUT; |
} else { |
} else { |
cmd.opcode = READ; |
cmd.opcode = READ; |
flags = XS_CTL_DATA_IN; |
flags |= XS_CTL_DATA_IN; |
} |
} |
|
|
/* |
/* |
|
|
|
|
/* |
/* |
* go ask the adapter to do all this for us |
* go ask the adapter to do all this for us |
* XXX Really need NOSLEEP? |
|
*/ |
*/ |
error = scsipi_command(sc_link, |
error = scsipi_command(periph, |
(struct scsipi_generic *)&cmd, sizeof(cmd), |
(struct scsipi_generic *)&cmd, sizeof(cmd), |
(u_char *)bp->b_data, bp->b_bcount, |
(u_char *)bp->b_data, bp->b_bcount, |
0, ST_IO_TIME, bp, flags | XS_CTL_NOSLEEP | XS_CTL_ASYNC); |
0, ST_IO_TIME, bp, flags); |
if (error) { |
if (error) { |
printf("%s: not queued, error %d\n", |
printf("%s: not queued, error %d\n", |
st->sc_dev.dv_xname, error); |
st->sc_dev.dv_xname, error); |
|
|
stdone(xs) |
stdone(xs) |
struct scsipi_xfer *xs; |
struct scsipi_xfer *xs; |
{ |
{ |
|
struct st_softc *st = (void *)xs->xs_periph->periph_dev; |
|
|
if (xs->bp != NULL) { |
if (xs->bp != NULL) { |
struct st_softc *st = xs->sc_link->device_softc; |
|
if ((xs->bp->b_flags & B_READ) == B_WRITE) { |
if ((xs->bp->b_flags & B_READ) == B_WRITE) { |
st->flags |= ST_WRITTEN; |
st->flags |= ST_WRITTEN; |
} else { |
} else { |
Line 1219 stread(dev, uio, iomode) |
|
Line 1348 stread(dev, uio, iomode) |
|
struct st_softc *st = st_cd.cd_devs[STUNIT(dev)]; |
struct st_softc *st = st_cd.cd_devs[STUNIT(dev)]; |
|
|
return (physio(ststrategy, NULL, dev, B_READ, |
return (physio(ststrategy, NULL, dev, B_READ, |
st->sc_link->adapter->scsipi_minphys, uio)); |
st->sc_periph->periph_channel->chan_adapter->adapt_minphys, uio)); |
} |
} |
|
|
int |
int |
Line 1231 stwrite(dev, uio, iomode) |
|
Line 1360 stwrite(dev, uio, iomode) |
|
struct st_softc *st = st_cd.cd_devs[STUNIT(dev)]; |
struct st_softc *st = st_cd.cd_devs[STUNIT(dev)]; |
|
|
return (physio(ststrategy, NULL, dev, B_WRITE, |
return (physio(ststrategy, NULL, dev, B_WRITE, |
st->sc_link->adapter->scsipi_minphys, uio)); |
st->sc_periph->periph_channel->chan_adapter->adapt_minphys, uio)); |
} |
} |
|
|
/* |
/* |
Line 1273 stioctl(dev, cmd, arg, flag, p) |
|
Line 1402 stioctl(dev, cmd, arg, flag, p) |
|
* (to get the current state of READONLY) |
* (to get the current state of READONLY) |
*/ |
*/ |
error = st_mode_sense(st, XS_CTL_SILENT); |
error = st_mode_sense(st, XS_CTL_SILENT); |
if (error) |
if (error) { |
break; |
/* |
SC_DEBUG(st->sc_link, SDEV_DB1, ("[ioctl: get status]\n")); |
* Ignore the error if in control mode; |
|
* this is mandated by st(4). |
|
*/ |
|
if (STMODE(dev) != CTRL_MODE) |
|
break; |
|
error = 0; |
|
} |
|
SC_DEBUG(st->sc_periph, SCSIPI_DB1, ("[ioctl: get status]\n")); |
bzero(g, sizeof(struct mtget)); |
bzero(g, sizeof(struct mtget)); |
g->mt_type = 0x7; /* Ultrix compat *//*? */ |
g->mt_type = 0x7; /* Ultrix compat *//*? */ |
g->mt_blksiz = st->blksize; |
g->mt_blksiz = st->blksize; |
Line 1299 stioctl(dev, cmd, arg, flag, p) |
|
Line 1435 stioctl(dev, cmd, arg, flag, p) |
|
*/ |
*/ |
st->mt_resid = 0; |
st->mt_resid = 0; |
st->mt_erreg = 0; |
st->mt_erreg = 0; |
|
st->asc = 0; |
|
st->ascq = 0; |
break; |
break; |
} |
} |
case MTIOCTOP: { |
case MTIOCTOP: { |
|
|
SC_DEBUG(st->sc_link, SDEV_DB1, |
SC_DEBUG(st->sc_periph, SCSIPI_DB1, |
("[ioctl: op=0x%x count=0x%x]\n", mt->mt_op, |
("[ioctl: op=0x%x count=0x%x]\n", mt->mt_op, |
mt->mt_count)); |
mt->mt_count)); |
|
|
Line 1428 stioctl(dev, cmd, arg, flag, p) |
|
Line 1566 stioctl(dev, cmd, arg, flag, p) |
|
|
|
|
|
default: |
default: |
error = scsipi_do_ioctl(st->sc_link, dev, cmd, arg, |
error = scsipi_do_ioctl(st->sc_periph, dev, cmd, arg, |
flag, p); |
flag, p); |
break; |
break; |
} |
} |
|
|
/* |
/* |
* Check that the mode being asked for is aggreeable to the |
* Check that the mode being asked for is aggreeable to the |
* drive. If not, put it back the way it was. |
* drive. If not, put it back the way it was. |
|
* |
|
* If in control mode, we can make (persistent) mode changes |
|
* even if no medium is loaded (see st(4)). |
*/ |
*/ |
if ((error = st_mode_select(st, 0)) != 0) {/* put it back as it was */ |
if ((STMODE(dev) != CTRL_MODE || (st->flags & ST_MOUNTED) != 0) && |
|
(error = st_mode_select(st, 0)) != 0) { |
|
/* put it back as it was */ |
printf("%s: cannot set selected mode\n", st->sc_dev.dv_xname); |
printf("%s: cannot set selected mode\n", st->sc_dev.dv_xname); |
st->density = hold_density; |
st->density = hold_density; |
st->blksize = hold_blksize; |
st->blksize = hold_blksize; |
Line 1497 st_read(st, buf, size, flags) |
|
Line 1640 st_read(st, buf, size, flags) |
|
cmd.len); |
cmd.len); |
} else |
} else |
_lto3b(size, cmd.len); |
_lto3b(size, cmd.len); |
return (scsipi_command(st->sc_link, |
return (scsipi_command(st->sc_periph, |
(struct scsipi_generic *)&cmd, sizeof(cmd), |
(struct scsipi_generic *)&cmd, sizeof(cmd), |
(u_char *)buf, size, 0, ST_IO_TIME, NULL, flags | XS_CTL_DATA_IN)); |
(u_char *)buf, size, 0, ST_IO_TIME, NULL, flags | XS_CTL_DATA_IN)); |
} |
} |
Line 1512 st_read_block_limits(st, flags) |
|
Line 1655 st_read_block_limits(st, flags) |
|
{ |
{ |
struct scsi_block_limits cmd; |
struct scsi_block_limits cmd; |
struct scsi_block_limits_data block_limits; |
struct scsi_block_limits_data block_limits; |
struct scsipi_link *sc_link = st->sc_link; |
struct scsipi_periph *periph = st->sc_periph; |
int error; |
int error; |
|
|
/* |
/* |
* First check if we have it all loaded |
|
*/ |
|
if ((sc_link->flags & SDEV_MEDIA_LOADED)) |
|
return (0); |
|
|
|
/* |
|
* do a 'Read Block Limits' |
* do a 'Read Block Limits' |
*/ |
*/ |
bzero(&cmd, sizeof(cmd)); |
bzero(&cmd, sizeof(cmd)); |
Line 1530 st_read_block_limits(st, flags) |
|
Line 1667 st_read_block_limits(st, flags) |
|
/* |
/* |
* do the command, update the global values |
* do the command, update the global values |
*/ |
*/ |
error = scsipi_command(sc_link, (struct scsipi_generic *)&cmd, |
error = scsipi_command(periph, (struct scsipi_generic *)&cmd, |
sizeof(cmd), (u_char *)&block_limits, sizeof(block_limits), |
sizeof(cmd), (u_char *)&block_limits, sizeof(block_limits), |
ST_RETRIES, ST_CTL_TIME, NULL, flags | XS_CTL_DATA_IN); |
ST_RETRIES, ST_CTL_TIME, NULL, |
|
flags | XS_CTL_DATA_IN | XS_CTL_DATA_ONSTACK); |
if (error) |
if (error) |
return (error); |
return (error); |
|
|
st->blkmin = _2btol(block_limits.min_length); |
st->blkmin = _2btol(block_limits.min_length); |
st->blkmax = _3btol(block_limits.max_length); |
st->blkmax = _3btol(block_limits.max_length); |
|
|
SC_DEBUG(sc_link, SDEV_DB3, |
SC_DEBUG(periph, SCSIPI_DB3, |
("(%d <= blksize <= %d)\n", st->blkmin, st->blkmax)); |
("(%d <= blksize <= %d)\n", st->blkmin, st->blkmax)); |
return (0); |
return (0); |
} |
} |
Line 1567 st_mode_sense(st, flags) |
|
Line 1705 st_mode_sense(st, flags) |
|
struct scsi_blk_desc blk_desc; |
struct scsi_blk_desc blk_desc; |
u_char sense_data[MAX_PAGE_0_SIZE]; |
u_char sense_data[MAX_PAGE_0_SIZE]; |
} scsipi_sense; |
} scsipi_sense; |
struct scsipi_link *sc_link = st->sc_link; |
struct scsipi_periph *periph = st->sc_periph; |
|
|
scsipi_sense_len = 12 + st->page_0_size; |
scsipi_sense_len = 12 + st->page_0_size; |
|
|
Line 1584 st_mode_sense(st, flags) |
|
Line 1722 st_mode_sense(st, flags) |
|
* or if we need it as a template for the mode select |
* or if we need it as a template for the mode select |
* store it away. |
* store it away. |
*/ |
*/ |
error = scsipi_command(sc_link, (struct scsipi_generic *)&cmd, |
error = scsipi_command(periph, (struct scsipi_generic *)&cmd, |
sizeof(cmd), (u_char *)&scsipi_sense, scsipi_sense_len, |
sizeof(cmd), (u_char *)&scsipi_sense, scsipi_sense_len, |
ST_RETRIES, ST_CTL_TIME, NULL, flags | XS_CTL_DATA_IN); |
ST_RETRIES, ST_CTL_TIME, NULL, |
|
flags | XS_CTL_DATA_IN | XS_CTL_DATA_ONSTACK); |
if (error) |
if (error) |
return (error); |
return (error); |
|
|
Line 1597 st_mode_sense(st, flags) |
|
Line 1736 st_mode_sense(st, flags) |
|
st->flags |= ST_READONLY; |
st->flags |= ST_READONLY; |
else |
else |
st->flags &= ~ST_READONLY; |
st->flags &= ~ST_READONLY; |
SC_DEBUG(sc_link, SDEV_DB3, |
SC_DEBUG(periph, SCSIPI_DB3, |
("density code 0x%x, %d-byte blocks, write-%s, ", |
("density code %d, %d-byte blocks, write-%s, ", |
st->media_density, st->media_blksize, |
st->media_density, st->media_blksize, |
st->flags & ST_READONLY ? "protected" : "enabled")); |
st->flags & ST_READONLY ? "protected" : "enabled")); |
SC_DEBUG(sc_link, SDEV_DB3, |
SC_DEBUG(periph, SCSIPI_DB3, |
("%sbuffered\n", |
("%sbuffered\n", |
scsipi_sense.header.dev_spec & SMH_DSP_BUFF_MODE ? "" : "un")); |
scsipi_sense.header.dev_spec & SMH_DSP_BUFF_MODE ? "" : "un")); |
if (st->page_0_size) |
if (st->page_0_size) |
bcopy(scsipi_sense.sense_data, st->sense_data, |
bcopy(scsipi_sense.sense_data, st->sense_data, |
st->page_0_size); |
st->page_0_size); |
sc_link->flags |= SDEV_MEDIA_LOADED; |
periph->periph_flags |= PERIPH_MEDIA_LOADED; |
return (0); |
return (0); |
} |
} |
|
|
Line 1627 st_mode_select(st, flags) |
|
Line 1766 st_mode_select(st, flags) |
|
struct scsi_blk_desc blk_desc; |
struct scsi_blk_desc blk_desc; |
u_char sense_data[MAX_PAGE_0_SIZE]; |
u_char sense_data[MAX_PAGE_0_SIZE]; |
} scsi_select; |
} scsi_select; |
struct scsipi_link *sc_link = st->sc_link; |
struct scsipi_periph *periph = st->sc_periph; |
|
|
scsi_select_len = 12 + st->page_0_size; |
scsi_select_len = 12 + st->page_0_size; |
|
|
Line 1637 st_mode_select(st, flags) |
|
Line 1776 st_mode_select(st, flags) |
|
* even if the selected mode is the one that is supported. |
* even if the selected mode is the one that is supported. |
*/ |
*/ |
if (st->quirks & ST_Q_UNIMODAL) { |
if (st->quirks & ST_Q_UNIMODAL) { |
SC_DEBUG(sc_link, SDEV_DB3, |
SC_DEBUG(periph, SCSIPI_DB3, |
("not setting density 0x%x blksize 0x%x\n", |
("not setting density 0x%x blksize 0x%x\n", |
st->density, st->blksize)); |
st->density, st->blksize)); |
return (0); |
return (0); |
Line 1666 st_mode_select(st, flags) |
|
Line 1805 st_mode_select(st, flags) |
|
/* |
/* |
* do the command |
* do the command |
*/ |
*/ |
return (scsipi_command(sc_link, (struct scsipi_generic *)&cmd, |
return (scsipi_command(periph, (struct scsipi_generic *)&cmd, |
sizeof(cmd), (u_char *)&scsi_select, scsi_select_len, |
sizeof(cmd), (u_char *)&scsi_select, scsi_select_len, |
ST_RETRIES, ST_CTL_TIME, NULL, flags | XS_CTL_DATA_OUT)); |
ST_RETRIES, ST_CTL_TIME, NULL, |
|
flags | XS_CTL_DATA_OUT | XS_CTL_DATA_ONSTACK)); |
} |
} |
|
|
int |
int |
Line 1687 st_cmprss(st, onoff) |
|
Line 1827 st_cmprss(st, onoff) |
|
} scsi_pdata; |
} scsi_pdata; |
struct scsi_tape_dev_conf_page *ptr; |
struct scsi_tape_dev_conf_page *ptr; |
struct scsi_tape_dev_compression_page *cptr; |
struct scsi_tape_dev_compression_page *cptr; |
struct scsipi_link *sc_link = st->sc_link; |
struct scsipi_periph *periph = st->sc_periph; |
int error, ison, flags; |
int error, ison, flags; |
|
|
scsi_dlen = sizeof(scsi_pdata); |
scsi_dlen = sizeof(scsi_pdata); |
Line 1709 st_cmprss(st, onoff) |
|
Line 1849 st_cmprss(st, onoff) |
|
*/ |
*/ |
again: |
again: |
bzero(&scsi_pdata, scsi_dlen); |
bzero(&scsi_pdata, scsi_dlen); |
error = scsipi_command(sc_link, |
error = scsipi_command(periph, |
(struct scsipi_generic *)&scmd, sizeof(scmd), |
(struct scsipi_generic *)&scmd, sizeof(scmd), |
(u_char *)&scsi_pdata, scsi_dlen, |
(u_char *)&scsi_pdata, scsi_dlen, |
ST_RETRIES, ST_CTL_TIME, NULL, flags | XS_CTL_DATA_IN); |
ST_RETRIES, ST_CTL_TIME, NULL, |
|
flags | XS_CTL_DATA_IN | XS_CTL_DATA_ONSTACK); |
|
|
if (error) { |
if (error) { |
if (scmd.byte2 != SMS_DBD) { |
if (scmd.byte2 != SMS_DBD) { |
|
|
/* |
/* |
* Do the command |
* Do the command |
*/ |
*/ |
error = scsipi_command(sc_link, |
error = scsipi_command(periph, |
(struct scsipi_generic *)&mcmd, sizeof(mcmd), |
(struct scsipi_generic *)&mcmd, sizeof(mcmd), |
(u_char *)&scsi_pdata, scsi_dlen, |
(u_char *)&scsi_pdata, scsi_dlen, |
ST_RETRIES, ST_CTL_TIME, NULL, flags | XS_CTL_DATA_OUT); |
ST_RETRIES, ST_CTL_TIME, NULL, |
|
flags | XS_CTL_DATA_OUT | XS_CTL_DATA_ONSTACK); |
|
|
if (error && (scmd.page & SMS_PAGE_CODE) == 0xf) { |
if (error && (scmd.page & SMS_PAGE_CODE) == 0xf) { |
/* |
/* |
Line 1828 st_erase(st, full, flags) |
|
Line 1970 st_erase(st, full, flags) |
|
bzero(&cmd, sizeof(cmd)); |
bzero(&cmd, sizeof(cmd)); |
cmd.opcode = ERASE; |
cmd.opcode = ERASE; |
if (full) { |
if (full) { |
cmd.byte2 = SE_IMMED|SE_LONG; |
cmd.byte2 = SE_LONG; |
tmo = ST_SPC_TIME; |
tmo = ST_SPC_TIME; |
} else { |
} else { |
tmo = ST_IO_TIME; |
tmo = ST_IO_TIME; |
cmd.byte2 = SE_IMMED; |
|
} |
} |
|
|
/* |
/* |
* XXX We always do this asynchronously, for now. How long should |
* XXX We always do this asynchronously, for now, unless the device |
* we wait if we want to (eventually) to it synchronously? |
* has the ST_Q_ERASE_NOIMM quirk. How long should we wait if we |
|
* want to (eventually) to it synchronously? |
*/ |
*/ |
return (scsipi_command(st->sc_link, |
if ((st->quirks & ST_Q_ERASE_NOIMM) == 0) |
|
cmd.byte2 |= SE_IMMED; |
|
|
|
return (scsipi_command(st->sc_periph, |
(struct scsipi_generic *)&cmd, sizeof(cmd), |
(struct scsipi_generic *)&cmd, sizeof(cmd), |
0, 0, ST_RETRIES, tmo, NULL, flags)); |
0, 0, ST_RETRIES, tmo, NULL, flags)); |
} |
} |
Line 1927 st_space(st, number, what, flags) |
|
Line 2072 st_space(st, number, what, flags) |
|
cmd.byte2 = what; |
cmd.byte2 = what; |
_lto3b(number, cmd.number); |
_lto3b(number, cmd.number); |
|
|
return (scsipi_command(st->sc_link, |
return (scsipi_command(st->sc_periph, |
(struct scsipi_generic *)&cmd, sizeof(cmd), |
(struct scsipi_generic *)&cmd, sizeof(cmd), |
0, 0, 0, ST_SPC_TIME, NULL, flags)); |
0, 0, 0, ST_SPC_TIME, NULL, flags)); |
} |
} |
Line 1967 st_write_filemarks(st, number, flags) |
|
Line 2112 st_write_filemarks(st, number, flags) |
|
cmd.opcode = WRITE_FILEMARKS; |
cmd.opcode = WRITE_FILEMARKS; |
_lto3b(number, cmd.number); |
_lto3b(number, cmd.number); |
|
|
return (scsipi_command(st->sc_link, |
return (scsipi_command(st->sc_periph, |
(struct scsipi_generic *)&cmd, sizeof(cmd), |
(struct scsipi_generic *)&cmd, sizeof(cmd), |
0, 0, 0, ST_IO_TIME * 4, NULL, flags)); |
0, 0, 0, ST_IO_TIME * 4, NULL, flags)); |
} |
} |
Line 2042 st_load(st, type, flags) |
|
Line 2187 st_load(st, type, flags) |
|
cmd.opcode = LOAD; |
cmd.opcode = LOAD; |
cmd.how = type; |
cmd.how = type; |
|
|
error = scsipi_command(st->sc_link, |
error = scsipi_command(st->sc_periph, |
(struct scsipi_generic *)&cmd, sizeof(cmd), |
(struct scsipi_generic *)&cmd, sizeof(cmd), |
0, 0, ST_RETRIES, ST_SPC_TIME, NULL, flags); |
0, 0, ST_RETRIES, ST_SPC_TIME, NULL, flags); |
if (error) { |
if (error) { |
Line 2077 st_rewind(st, immediate, flags) |
|
Line 2222 st_rewind(st, immediate, flags) |
|
cmd.opcode = REWIND; |
cmd.opcode = REWIND; |
cmd.byte2 = immediate; |
cmd.byte2 = immediate; |
|
|
error = scsipi_command(st->sc_link, |
error = scsipi_command(st->sc_periph, |
(struct scsipi_generic *)&cmd, sizeof(cmd), 0, 0, ST_RETRIES, |
(struct scsipi_generic *)&cmd, sizeof(cmd), 0, 0, ST_RETRIES, |
immediate ? ST_CTL_TIME: ST_SPC_TIME, NULL, flags); |
immediate ? ST_CTL_TIME: ST_SPC_TIME, NULL, flags); |
if (error) { |
if (error) { |
Line 2116 st_rdpos(st, hard, blkptr) |
|
Line 2261 st_rdpos(st, hard, blkptr) |
|
if (hard) |
if (hard) |
cmd.byte1 = 1; |
cmd.byte1 = 1; |
|
|
error = scsipi_command(st->sc_link, |
error = scsipi_command(st->sc_periph, |
(struct scsipi_generic *)&cmd, sizeof(cmd), (u_char *)&posdata, |
(struct scsipi_generic *)&cmd, sizeof(cmd), (u_char *)&posdata, |
sizeof(posdata), ST_RETRIES, ST_CTL_TIME, NULL, |
sizeof(posdata), ST_RETRIES, ST_CTL_TIME, NULL, |
XS_CTL_SILENT | XS_CTL_DATA_IN); |
XS_CTL_SILENT | XS_CTL_DATA_IN | XS_CTL_DATA_ONSTACK); |
|
|
if (error == 0) { |
if (error == 0) { |
#if 0 |
#if 0 |
Line 2165 st_setpos(st, hard, blkptr) |
|
Line 2310 st_setpos(st, hard, blkptr) |
|
if (hard) |
if (hard) |
cmd.byte2 = 1 << 2; |
cmd.byte2 = 1 << 2; |
_lto4b(*blkptr, cmd.blkaddr); |
_lto4b(*blkptr, cmd.blkaddr); |
error = scsipi_command(st->sc_link, |
error = scsipi_command(st->sc_periph, |
(struct scsipi_generic *)&cmd, sizeof(cmd), |
(struct scsipi_generic *)&cmd, sizeof(cmd), |
NULL, 0, ST_RETRIES, ST_SPC_TIME, NULL, 0); |
NULL, 0, ST_RETRIES, ST_SPC_TIME, NULL, 0); |
/* |
/* |
|
|
st_interpret_sense(xs) |
st_interpret_sense(xs) |
struct scsipi_xfer *xs; |
struct scsipi_xfer *xs; |
{ |
{ |
struct scsipi_link *sc_link = xs->sc_link; |
struct scsipi_periph *periph = xs->xs_periph; |
struct scsipi_sense_data *sense = &xs->sense.scsi_sense; |
struct scsipi_sense_data *sense = &xs->sense.scsi_sense; |
struct buf *bp = xs->bp; |
struct buf *bp = xs->bp; |
struct st_softc *st = sc_link->device_softc; |
struct st_softc *st = (void *)periph->periph_dev; |
int retval = SCSIRET_CONTINUE; |
int retval = EJUSTRETURN; |
int doprint = ((xs->xs_control & XS_CTL_SILENT) == 0); |
int doprint = ((xs->xs_control & XS_CTL_SILENT) == 0); |
u_int8_t key; |
u_int8_t key; |
int32_t info; |
int32_t info; |
Line 2209 st_interpret_sense(xs) |
|
Line 2354 st_interpret_sense(xs) |
|
info = xs->datalen; /* bad choice if fixed blocks */ |
info = xs->datalen; /* bad choice if fixed blocks */ |
key = sense->flags & SSD_KEY; |
key = sense->flags & SSD_KEY; |
st->mt_erreg = key; |
st->mt_erreg = key; |
|
st->asc = sense->add_sense_code; |
|
st->ascq = sense->add_sense_code_qual; |
st->mt_resid = (short) info; |
st->mt_resid = (short) info; |
|
|
/* |
/* |
* If the device is not open yet, let generic handle |
* If the device is not open yet, let generic handle |
*/ |
*/ |
if ((sc_link->flags & SDEV_OPEN) == 0) { |
if ((periph->periph_flags & PERIPH_OPEN) == 0) { |
return (retval); |
return (retval); |
} |
} |
|
|
Line 2250 st_interpret_sense(xs) |
|
Line 2397 st_interpret_sense(xs) |
|
* information. |
* information. |
*/ |
*/ |
if ((st->quirks & ST_Q_SENSE_HELP) && |
if ((st->quirks & ST_Q_SENSE_HELP) && |
!(sc_link->flags & SDEV_MEDIA_LOADED)) |
(periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) |
st->blksize -= 512; |
st->blksize -= 512; |
} |
} |
/* |
/* |
Line 2262 st_interpret_sense(xs) |
|
Line 2409 st_interpret_sense(xs) |
|
if (st->flags & ST_AT_FILEMARK) { |
if (st->flags & ST_AT_FILEMARK) { |
if (bp) |
if (bp) |
bp->b_resid = xs->resid; |
bp->b_resid = xs->resid; |
return (SCSIRET_NOERROR); |
return (0); |
} |
} |
} |
} |
} else { /* must be variable mode */ |
} else { /* must be variable mode */ |
Line 2277 st_interpret_sense(xs) |
|
Line 2424 st_interpret_sense(xs) |
|
*/ |
*/ |
if (st->flags & ST_EARLYWARN) { |
if (st->flags & ST_EARLYWARN) { |
st->flags |= ST_EOM_PENDING; |
st->flags |= ST_EOM_PENDING; |
retval = SCSIRET_NOERROR; |
retval = 0; |
} else { |
} else { |
retval = EIO; |
retval = EIO; |
} |
} |
Line 2290 st_interpret_sense(xs) |
|
Line 2437 st_interpret_sense(xs) |
|
doprint = 0; |
doprint = 0; |
} |
} |
} else if (sense->flags & SSD_FILEMARK) { |
} else if (sense->flags & SSD_FILEMARK) { |
retval = SCSIRET_NOERROR; |
retval = 0; |
} else if (sense->flags & SSD_ILI) { |
} else if (sense->flags & SSD_ILI) { |
if (info < 0) { |
if (info < 0) { |
/* |
/* |
Line 2305 st_interpret_sense(xs) |
|
Line 2452 st_interpret_sense(xs) |
|
} |
} |
retval = EIO; |
retval = EIO; |
} else { |
} else { |
retval = SCSIRET_NOERROR; |
retval = 0; |
} |
} |
} |
} |
xs->resid = info; |
xs->resid = info; |
Line 2313 st_interpret_sense(xs) |
|
Line 2460 st_interpret_sense(xs) |
|
bp->b_resid = info; |
bp->b_resid = info; |
} |
} |
|
|
#ifndef SCSIDEBUG |
#ifdef SCSIPI_DEBUG |
if (retval == SCSIRET_NOERROR && key == SKEY_NO_SENSE) { |
if (retval == 0 && key == SKEY_NO_SENSE) |
doprint = 0; |
doprint = 0; |
} |
|
#endif |
#endif |
if (key == SKEY_BLANK_CHECK) { |
if (key == SKEY_BLANK_CHECK) { |
/* |
/* |
Line 2326 st_interpret_sense(xs) |
|
Line 2472 st_interpret_sense(xs) |
|
* MODE SENSE information. |
* MODE SENSE information. |
*/ |
*/ |
if ((st->quirks & ST_Q_SENSE_HELP) && |
if ((st->quirks & ST_Q_SENSE_HELP) && |
!(sc_link->flags & SDEV_MEDIA_LOADED)) { |
(periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) { |
/* still starting */ |
/* still starting */ |
st->blksize -= 512; |
st->blksize -= 512; |
} else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ))) { |
} else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ))) { |
Line 2336 st_interpret_sense(xs) |
|
Line 2482 st_interpret_sense(xs) |
|
bp->b_resid = xs->resid; |
bp->b_resid = xs->resid; |
/* return an EOF */ |
/* return an EOF */ |
} |
} |
retval = SCSIRET_NOERROR; |
retval = 0; |
} |
} |
} |
} |
#ifdef SCSIVERBOSE |
|
|
/* |
|
* If generic sense processing will continue, we should not |
|
* print sense info here. |
|
*/ |
|
if (retval == EJUSTRETURN) |
|
doprint = 0; |
|
|
if (doprint) { |
if (doprint) { |
|
#ifdef SCSIVERBOSE |
scsipi_print_sense(xs, 0); |
scsipi_print_sense(xs, 0); |
} |
|
#else |
#else |
if (doprint) { |
scsipi_printaddr(periph); |
xs->sc_link->sc_print_addr(xs->sc_link); |
|
printf("Sense Key 0x%02x", key); |
printf("Sense Key 0x%02x", key); |
if ((sense->error_code & SSD_ERRCODE_VALID) != 0) { |
if ((sense->error_code & SSD_ERRCODE_VALID) != 0) { |
switch (key) { |
switch (key) { |
case SKEY_NOT_READY: |
case SKEY_NOT_READY: |
case SKEY_ILLEGAL_REQUEST: |
case SKEY_ILLEGAL_REQUEST: |
case SKEY_UNIT_ATTENTION: |
case SKEY_UNIT_ATTENTION: |
Line 2356 st_interpret_sense(xs) |
|
Line 2508 st_interpret_sense(xs) |
|
break; |
break; |
case SKEY_BLANK_CHECK: |
case SKEY_BLANK_CHECK: |
printf(", requested size: %d (decimal)", info); |
printf(", requested size: %d (decimal)", info); |
break; |
break; |
case SKEY_ABORTED_COMMAND: |
case SKEY_ABORTED_COMMAND: |
if (xs->retries) |
if (xs->retries) |
printf(", retrying"); |
printf(", retrying"); |
Line 2366 st_interpret_sense(xs) |
|
Line 2518 st_interpret_sense(xs) |
|
default: |
default: |
printf(", info = %d (decimal)", info); |
printf(", info = %d (decimal)", info); |
} |
} |
} |
} |
if (sense->extra_len != 0) { |
if (sense->extra_len != 0) { |
int n; |
int n; |
printf(", data ="); |
printf(", data ="); |
for (n = 0; n < sense->extra_len; n++) |
for (n = 0; n < sense->extra_len; n++) |
printf(" %02x", sense->cmd_spec_info[n]); |
printf(" %02x", sense->cmd_spec_info[n]); |
} |
} |
printf("\n"); |
printf("\n"); |
} |
|
#endif |
#endif |
|
} |
return (retval); |
return (retval); |
} |
} |
|
|
Line 2409 st_touch_tape(st) |
|
Line 2561 st_touch_tape(st) |
|
|
|
if ((error = st_mode_sense(st, 0)) != 0) |
if ((error = st_mode_sense(st, 0)) != 0) |
goto bad; |
goto bad; |
st->blksize = 1024; |
|
|
/* |
|
* If the block size is already known from the |
|
* sense data, use it. Else start probing at 1024. |
|
*/ |
|
if (st->media_blksize > 0) |
|
st->blksize = st->media_blksize; |
|
else |
|
st->blksize = 1024; |
|
|
do { |
do { |
switch (st->blksize) { |
switch (st->blksize) { |
case 512: |
case 512: |
Line 2421 st_touch_tape(st) |
|
Line 2582 st_touch_tape(st) |
|
readsize = 1; |
readsize = 1; |
st->flags &= ~ST_FIXEDBLOCKS; |
st->flags &= ~ST_FIXEDBLOCKS; |
} |
} |
if ((error = st_mode_select(st, 0)) != 0) |
if ((error = st_mode_select(st, XS_CTL_SILENT)) != 0) { |
goto bad; |
/* |
|
* The device did not agree with the proposed |
|
* block size. If we exhausted our options, |
|
* return failure, else try another. |
|
*/ |
|
if (readsize == 1) |
|
goto bad; |
|
st->blksize -= 512; |
|
continue; |
|
} |
st_read(st, buf, readsize, XS_CTL_SILENT); /* XXX */ |
st_read(st, buf, readsize, XS_CTL_SILENT); /* XXX */ |
if ((error = st_rewind(st, 0, 0)) != 0) { |
if ((error = st_rewind(st, 0, 0)) != 0) { |
bad: free(buf, M_TEMP); |
bad: free(buf, M_TEMP); |