Improve handling of memory shortage, to fix problems like:

sd3(mpt0:0:1:0): unable to allocate scsipi_xfer
sd3: not queued, error 12
Havard Eidnes's analysis of this problem is that the scsipi_xfer pool is
competing for resources with other pools, including the the inode and vnode
pools which can grow quite large.

*_scsipi_cmd(): don't biodone the buffer if scsipi_make_xs() fails, let the
   caller deal with the problem
start function of block devices drivers: dequeue the buffer after the
   scsipi_command() call. If scsipi_command() fails with ENOMEM don't dequeue
   the buffer, and schedule a callout to call the start function after
   some delay.
scsipi_init(): prime the scsipi_xfer_pool with one page. This ensure that
   there is always some scsipi_xfer to play with. If scsipi_command() fails
   because of pool_get(), we're sure there will be resources available later,
   when the pending commands have completed.

Reviewed by Jason Thorpe and Havard Eidnes.
Todo: remove the "unable to allocate scsipi_xfer" and "not queued, error %d"
printfs, but I choose to keep them for now, to help make sure the code does
what it should.
This commit is contained in:
bouyer 2004-08-27 20:37:28 +00:00
parent 93f4534edf
commit 80620a83a7
13 changed files with 230 additions and 78 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: atapi_base.c,v 1.20 2004/08/21 17:40:25 thorpej Exp $ */
/* $NetBSD: atapi_base.c,v 1.21 2004/08/27 20:37:28 bouyer Exp $ */
/*-
* Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
@ -38,7 +38,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: atapi_base.c,v 1.20 2004/08/21 17:40:25 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: atapi_base.c,v 1.21 2004/08/27 20:37:28 bouyer Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -218,7 +218,7 @@ atapi_scsipi_cmd(struct scsipi_periph *periph,
int retries, int timeout, struct buf *bp, int flags)
{
struct scsipi_xfer *xs;
int error, s;
int error;
SC_DEBUG(periph, SCSIPI_DB2, ("atapi_cmd\n"));
@ -229,13 +229,7 @@ atapi_scsipi_cmd(struct scsipi_periph *periph,
if ((xs = scsipi_make_xs(periph, scsipi_cmd, cmdlen, data,
datalen, retries, timeout, bp, flags)) == NULL) {
if (bp != NULL) {
s = splbio();
bp->b_flags |= B_ERROR;
bp->b_error = ENOMEM;
biodone(bp);
splx(s);
}
/* let the caller deal with this */
return (ENOMEM);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: cd.c,v 1.202 2004/08/21 17:40:25 thorpej Exp $ */
/* $NetBSD: cd.c,v 1.203 2004/08/27 20:37:28 bouyer Exp $ */
/*-
* Copyright (c) 1998, 2001, 2003 The NetBSD Foundation, Inc.
@ -54,7 +54,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: cd.c,v 1.202 2004/08/21 17:40:25 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: cd.c,v 1.203 2004/08/27 20:37:28 bouyer Exp $");
#include "rnd.h"
@ -109,6 +109,7 @@ struct cd_toc {
static int cdlock(struct cd_softc *);
static void cdunlock(struct cd_softc *);
static void cdstart(struct scsipi_periph *);
static void cdrestart(void *);
static void cdminphys(struct buf *);
static void cdgetdefaultlabel(struct cd_softc *, struct disklabel *);
static void cdgetdisklabel(struct cd_softc *);
@ -229,6 +230,8 @@ cdattach(struct device *parent, struct device *self, void *aux)
bufq_alloc(&cd->buf_queue, BUFQ_DISKSORT|BUFQ_SORT_RAWBLOCK);
callout_init(&cd->sc_callout);
/*
* Store information needed to contact our base driver
*/
@ -291,6 +294,9 @@ cddetach(struct device *self, int flags)
bmaj = bdevsw_lookup_major(&cd_bdevsw);
cmaj = cdevsw_lookup_major(&cd_cdevsw);
/* kill any pending restart */
callout_stop(&cd->sc_callout);
s = splbio();
/* Kill off any queued buffers. */
@ -784,25 +790,30 @@ cdstart(struct scsipi_periph *periph)
return;
}
/*
* See if there is a buf with work for us to do..
*/
if ((bp = BUFQ_GET(&cd->buf_queue)) == NULL)
return;
/*
* If the device has become invalid, abort all the
* reads and writes until all files have been closed and
* re-opened
*/
if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) {
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
bp->b_resid = bp->b_bcount;
biodone(bp);
continue;
if (__predict_false(
(periph->periph_flags & PERIPH_MEDIA_LOADED) == 0)) {
if ((bp = BUFQ_GET(&cd->buf_queue)) != NULL) {
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
bp->b_resid = bp->b_bcount;
biodone(bp);
continue;
} else {
return;
}
}
/*
* See if there is a buf with work for us to do..
*/
if ((bp = BUFQ_PEEK(&cd->buf_queue)) == NULL)
return;
/*
* We have a buf, now we should make a command.
*/
@ -858,14 +869,37 @@ cdstart(struct scsipi_periph *periph)
error = scsipi_command(periph, cmdp, cmdlen,
(u_char *)bp->b_data, bp->b_bcount,
CDRETRIES, 30000, bp, flags);
if (error) {
if (__predict_false(error)) {
disk_unbusy(&cd->sc_dk, 0, 0);
printf("%s: not queued, error %d\n",
cd->sc_dev.dv_xname, error);
}
if (__predict_false(error == ENOMEM)) {
/*
* out of memory. Keep this buffer in the queue, and
* retry later.
*/
callout_reset(&cd->sc_callout, hz / 2, cdrestart,
periph);
return;
}
#ifdef DIAGNOSTIC
if (BUFQ_GET(&cd->buf_queue) != bp)
panic("cdstart(): dequeued wrong buf");
#else
BUFQ_GET(&cd->buf_queue);
#endif
}
}
static void
cdrestart(void *v)
{
int s = splbio();
cdstart((struct scsipi_periph *)v);
splx(s);
}
static void
cddone(struct scsipi_xfer *xs)
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: cdvar.h,v 1.20 2003/09/08 01:56:34 mycroft Exp $ */
/* $NetBSD: cdvar.h,v 1.21 2004/08/27 20:37:28 bouyer Exp $ */
/*
* Copyright (c) 1997 Manuel Bouyer. All rights reserved.
@ -51,6 +51,7 @@ struct cd_softc {
} params;
struct bufq_state buf_queue;
struct callout sc_callout;
#if NRND > 0
rndsource_element_t rnd_source;

View File

@ -1,4 +1,4 @@
/* $NetBSD: scsi_base.c,v 1.79 2004/08/21 21:29:39 thorpej Exp $ */
/* $NetBSD: scsi_base.c,v 1.80 2004/08/27 20:37:28 bouyer Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: scsi_base.c,v 1.79 2004/08/21 21:29:39 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: scsi_base.c,v 1.80 2004/08/27 20:37:28 bouyer Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -84,7 +84,7 @@ scsi_scsipi_cmd(struct scsipi_periph *periph, struct scsipi_generic *scsipi_cmd,
struct buf *bp, int flags)
{
struct scsipi_xfer *xs;
int error, s;
int error;
SC_DEBUG(periph, SCSIPI_DB2, ("scsi_scsipi_cmd\n"));
@ -95,13 +95,7 @@ scsi_scsipi_cmd(struct scsipi_periph *periph, struct scsipi_generic *scsipi_cmd,
if ((xs = scsipi_make_xs(periph, scsipi_cmd, cmdlen, data,
datalen, retries, timeout, bp, flags)) == NULL) {
if (bp != NULL) {
s = splbio();
bp->b_flags |= B_ERROR;
bp->b_error = ENOMEM;
biodone(bp);
splx(s);
}
/* let the caller deal with this */
return (ENOMEM);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: scsipi_base.c,v 1.109 2004/08/23 20:01:10 bouyer Exp $ */
/* $NetBSD: scsipi_base.c,v 1.110 2004/08/27 20:37:28 bouyer Exp $ */
/*-
* Copyright (c) 1998, 1999, 2000, 2002, 2003 The NetBSD Foundation, Inc.
@ -38,7 +38,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: scsipi_base.c,v 1.109 2004/08/23 20:01:10 bouyer Exp $");
__KERNEL_RCSID(0, "$NetBSD: scsipi_base.c,v 1.110 2004/08/27 20:37:28 bouyer Exp $");
#include "opt_scsi.h"
@ -54,6 +54,7 @@ __KERNEL_RCSID(0, "$NetBSD: scsipi_base.c,v 1.109 2004/08/23 20:01:10 bouyer Exp
#include <sys/proc.h>
#include <sys/kthread.h>
#include <sys/hash.h>
#include <machine/vmparam.h>
#include <dev/scsipi/scsipi_all.h>
#include <dev/scsipi/scsipi_disk.h>
@ -102,6 +103,10 @@ scsipi_init(void)
/* Initialize the scsipi_xfer pool. */
pool_init(&scsipi_xfer_pool, sizeof(struct scsipi_xfer), 0,
0, 0, "scxspl", NULL);
if (pool_prime(&scsipi_xfer_pool,
PAGE_SIZE / sizeof(struct scsipi_xfer)) == ENOMEM) {
printf("WARNING: not enouth memory for scsipi_xfer_pool\n");
}
}
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: sd.c,v 1.220 2004/08/21 22:02:31 thorpej Exp $ */
/* $NetBSD: sd.c,v 1.221 2004/08/27 20:37:28 bouyer Exp $ */
/*-
* Copyright (c) 1998, 2003 The NetBSD Foundation, Inc.
@ -54,7 +54,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.220 2004/08/21 22:02:31 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.221 2004/08/27 20:37:28 bouyer Exp $");
#include "opt_scsi.h"
#include "rnd.h"
@ -100,6 +100,7 @@ static void sdminphys(struct buf *);
static void sdgetdefaultlabel(struct sd_softc *, struct disklabel *);
static void sdgetdisklabel(struct sd_softc *);
static void sdstart(struct scsipi_periph *);
static void sdrestart(void *);
static void sddone(struct scsipi_xfer *);
static void sd_shutdown(void *);
static int sd_interpret_sense(struct scsipi_xfer *);
@ -230,6 +231,8 @@ sdattach(struct device *parent, struct device *self, void *aux)
bufq_alloc(&sd->buf_queue,
BUFQ_DISK_DEFAULT_STRAT()|BUFQ_SORT_RAWBLOCK);
callout_init(&sd->sc_callout);
/*
* Store information needed to contact our base driver
*/
@ -347,6 +350,9 @@ sddetach(struct device *self, int flags)
bmaj = bdevsw_lookup_major(&sd_bdevsw);
cmaj = cdevsw_lookup_major(&sd_cdevsw);
/* kill any pending restart */
callout_stop(&sd->sc_callout);
s = splbio();
/* Kill off any queued buffers. */
@ -807,25 +813,30 @@ sdstart(struct scsipi_periph *periph)
return;
}
/*
* See if there is a buf with work for us to do..
*/
if ((bp = BUFQ_GET(&sd->buf_queue)) == NULL)
return;
/*
* If the device has become invalid, abort all the
* reads and writes until all files have been closed and
* re-opened
*/
if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) {
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
bp->b_resid = bp->b_bcount;
biodone(bp);
continue;
if (__predict_false(
(periph->periph_flags & PERIPH_MEDIA_LOADED) == 0)) {
if ((bp = BUFQ_GET(&sd->buf_queue)) != NULL) {
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
bp->b_resid = bp->b_bcount;
biodone(bp);
continue;
} else {
return;
}
}
/*
* See if there is a buf with work for us to do..
*/
if ((bp = BUFQ_PEEK(&sd->buf_queue)) == NULL)
return;
/*
* We have a buf, now we should make a command.
*/
@ -891,14 +902,38 @@ sdstart(struct scsipi_periph *periph)
error = scsipi_command(periph, cmdp, cmdlen,
(u_char *)bp->b_data, bp->b_bcount,
SDRETRIES, SD_IO_TIMEOUT, bp, flags);
if (error) {
if (__predict_false(error)) {
disk_unbusy(&sd->sc_dk, 0, 0);
printf("%s: not queued, error %d\n",
sd->sc_dev.dv_xname, error);
}
if (__predict_false(error == ENOMEM)) {
/*
* out of memory. Keep this buffer in the queue, and
* retry later.
*/
callout_reset(&sd->sc_callout, hz / 2, sdrestart,
periph);
return;
}
#ifdef DIAGNOSTIC
if (BUFQ_GET(&sd->buf_queue) != bp)
panic("sdstart(): dequeued wrong buf");
#else
BUFQ_GET(&sd->buf_queue);
#endif
}
}
static void
sdrestart(void *v)
{
int s = splbio();
sdstart((struct scsipi_periph *)v);
splx(s);
}
static void
sddone(struct scsipi_xfer *xs)
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: sdvar.h,v 1.21 2004/02/24 15:22:01 wiz Exp $ */
/* $NetBSD: sdvar.h,v 1.22 2004/08/27 20:37:29 bouyer Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -96,6 +96,7 @@ struct sd_softc {
} params;
struct bufq_state buf_queue;
struct callout sc_callout;
u_int8_t type;
char name[16]; /* product name, for default disklabel */

View File

@ -1,4 +1,4 @@
/* $NetBSD: ss.c,v 1.52 2004/08/21 22:02:31 thorpej Exp $ */
/* $NetBSD: ss.c,v 1.53 2004/08/27 20:37:29 bouyer Exp $ */
/*
* Copyright (c) 1995 Kenneth Stailey. All rights reserved.
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ss.c,v 1.52 2004/08/21 22:02:31 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: ss.c,v 1.53 2004/08/27 20:37:29 bouyer Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -163,6 +163,8 @@ ssattach(struct device *parent, struct device *self, void *aux)
*/
bufq_alloc(&ss->buf_queue, BUFQ_FCFS);
callout_init(&ss->sc_callout);
/*
* look for non-standard scanners with help of the quirk table
* and install functions for special handling
@ -190,6 +192,9 @@ ssdetach(struct device *self, int flags)
/* locate the major number */
cmaj = cdevsw_lookup_major(&ss_cdevsw);
/* kill any pending restart */
callout_stop(&ss->sc_callout);
s = splbio();
/* Kill off any queued buffers. */
@ -495,7 +500,7 @@ ssstart(struct scsipi_periph *periph)
/*
* See if there is a buf with work for us to do..
*/
if ((bp = BUFQ_GET(&ss->buf_queue)) == NULL)
if ((bp = BUFQ_PEEK(&ss->buf_queue)) == NULL)
return;
if (ss->special && ss->special->read) {
@ -507,6 +512,15 @@ ssstart(struct scsipi_periph *periph)
}
}
void
ssrestart(void *v)
{
int s = splbio();
ssstart((struct scsipi_periph *)v);
splx(s);
}
/*
* Perform special action on behalf of the user;
* knows about the internals of this device

View File

@ -1,4 +1,4 @@
/* $NetBSD: ss_mustek.c,v 1.19 2004/08/21 22:02:31 thorpej Exp $ */
/* $NetBSD: ss_mustek.c,v 1.20 2004/08/27 20:37:29 bouyer Exp $ */
/*
* Copyright (c) 1995 Joachim Koenig-Baltes. All rights reserved.
@ -46,7 +46,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ss_mustek.c,v 1.19 2004/08/21 22:02:31 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: ss_mustek.c,v 1.20 2004/08/27 20:37:29 bouyer Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@ -486,6 +486,15 @@ mustek_read(struct ss_softc *ss, struct buf *bp)
if (error) {
printf("%s: not queued, error %d\n", ss->sc_dev.dv_xname,
error);
if (error == ENOMEM) {
/*
* out of memory. Keep this buffer in the queue, and
* retry later.
*/
callout_reset(&ss->sc_callout, hz / 2, ssrestart,
periph);
return(0);
}
} else {
ss->sio.scan_lines -= lines_to_read;
if (ss->sio.scan_lines < 0)
@ -494,6 +503,12 @@ mustek_read(struct ss_softc *ss, struct buf *bp)
if (ss->sio.scan_window_size < 0)
ss->sio.scan_window_size = 0;
}
#ifdef DIAGNOSTIC
if (BUFQ_GET(&ss->buf_queue) != bp)
panic("ssstart(): dequeued wrong buf");
#else
BUFQ_GET(&ss->buf_queue);
#endif
return (0);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ss_scanjet.c,v 1.30 2004/08/21 22:02:31 thorpej Exp $ */
/* $NetBSD: ss_scanjet.c,v 1.31 2004/08/27 20:37:29 bouyer Exp $ */
/*
* Copyright (c) 1995 Kenneth Stailey. All rights reserved.
@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ss_scanjet.c,v 1.30 2004/08/21 22:02:31 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: ss_scanjet.c,v 1.31 2004/08/27 20:37:29 bouyer Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -48,6 +48,7 @@ __KERNEL_RCSID(0, "$NetBSD: ss_scanjet.c,v 1.30 2004/08/21 22:02:31 thorpej Exp
#include <sys/device.h>
#include <sys/conf.h> /* for cdevsw */
#include <sys/scanio.h>
#include <sys/kernel.h>
#include <dev/scsipi/scsi_all.h>
#include <dev/scsipi/scsipi_all.h>
@ -284,11 +285,26 @@ scanjet_read(struct ss_softc *ss, struct buf *bp)
if (error) {
printf("%s: not queued, error %d\n", ss->sc_dev.dv_xname,
error);
if (error == ENOMEM) {
/*
* out of memory. Keep this buffer in the queue, and
* retry later.
*/
callout_reset(&ss->sc_callout, hz / 2, ssrestart,
periph);
return(0);
}
} else {
ss->sio.scan_window_size -= bp->b_bcount;
if (ss->sio.scan_window_size < 0)
ss->sio.scan_window_size = 0;
}
#ifdef DIAGNOSTIC
if (BUFQ_GET(&ss->buf_queue) != bp)
panic("ssstart(): dequeued wrong buf");
#else
BUFQ_GET(&ss->buf_queue);
#endif
return (0);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ssvar.h,v 1.11 2004/08/21 20:40:36 thorpej Exp $ */
/* $NetBSD: ssvar.h,v 1.12 2004/08/27 20:37:29 bouyer Exp $ */
/*
* Copyright (c) 1995 Kenneth Stailey. All rights reserved.
@ -68,6 +68,7 @@ struct ss_softc {
struct scsipi_periph *sc_periph; /* contains our targ, lun, etc. */
struct scan_io sio;
struct bufq_state buf_queue; /* the queue of pending IO operations */
struct callout sc_callout; /* to restart the buf queue */
u_int quirks; /* scanner is only mildly twisted */
#define SS_Q_GET_BUFFER_SIZE 0x0001 /* poll for available data in ssread() */
/* truncate to byte boundary is assumed by default unless one of these is set */
@ -77,6 +78,8 @@ struct ss_softc {
struct ss_special *special; /* special handlers for spec. devices */
};
void ssrestart(void *);
/*
* define the special attach routines if configured
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: st.c,v 1.164 2004/08/21 22:16:07 thorpej Exp $ */
/* $NetBSD: st.c,v 1.165 2004/08/27 20:37:29 bouyer Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -57,7 +57,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: st.c,v 1.164 2004/08/21 22:16:07 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: st.c,v 1.165 2004/08/27 20:37:29 bouyer Exp $");
#include "opt_scsi.h"
@ -321,6 +321,7 @@ static int st_mount_tape(dev_t, int);
static void st_unmount(struct st_softc *, boolean);
static int st_decide_mode(struct st_softc *, boolean);
static void ststart(struct scsipi_periph *);
static void strestart(void *);
static void stdone(struct scsipi_xfer *);
static int st_read(struct st_softc *, char *, int, int);
static int st_space(struct st_softc *, int, u_int, int);
@ -377,6 +378,8 @@ stattach(struct device *parent, struct st_softc *st, void *aux)
*/
bufq_alloc(&st->buf_queue, BUFQ_FCFS);
callout_init(&st->sc_callout);
/*
* Check if the drive is a known criminal and take
* Any steps needed to bring it into line
@ -438,6 +441,9 @@ stdetach(struct device *self, int flags)
bmaj = bdevsw_lookup_major(&st_bdevsw);
cmaj = cdevsw_lookup_major(&st_cdevsw);
/* kill any pending restart */
callout_stop(&st->sc_callout);
s = splbio();
/* Kill off any queued buffers. */
@ -1171,23 +1177,28 @@ ststart(struct scsipi_periph *periph)
return;
}
if ((bp = BUFQ_GET(&st->buf_queue)) == NULL)
return;
/*
* If the device has been unmounted by the user
* then throw away all requests until done.
*/
if ((st->flags & ST_MOUNTED) == 0 ||
(periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) {
/* make sure that one implies the other.. */
periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
bp->b_flags |= B_ERROR;
bp->b_error = EIO;
bp->b_resid = bp->b_bcount;
biodone(bp);
continue;
if (__predict_false((st->flags & ST_MOUNTED) == 0 ||
(periph->periph_flags & PERIPH_MEDIA_LOADED) == 0)) {
if ((bp = BUFQ_GET(&st->buf_queue)) != NULL) {
/* make sure that one implies the other.. */
periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
bp->b_flags |= B_ERROR;
bp->b_error = EIO;
bp->b_resid = bp->b_bcount;
biodone(bp);
continue;
} else {
return;
}
}
if ((bp = BUFQ_PEEK(&st->buf_queue)) == NULL)
return;
/*
* only FIXEDBLOCK devices have pending I/O or space operations.
*/
@ -1205,12 +1216,14 @@ ststart(struct scsipi_periph *periph)
* Back up over filemark
*/
if (st_space(st, 0, SP_FILEMARKS, 0)) {
BUFQ_GET(&st->buf_queue);
bp->b_flags |= B_ERROR;
bp->b_error = EIO;
biodone(bp);
continue;
}
} else {
BUFQ_GET(&st->buf_queue);
bp->b_resid = bp->b_bcount;
bp->b_error = 0;
bp->b_flags &= ~B_ERROR;
@ -1225,6 +1238,7 @@ ststart(struct scsipi_periph *periph)
* yet then we should report it now.
*/
if (st->flags & (ST_EOM_PENDING|ST_EIO_PENDING)) {
BUFQ_GET(&st->buf_queue);
bp->b_resid = bp->b_bcount;
if (st->flags & ST_EIO_PENDING) {
bp->b_error = EIO;
@ -1271,13 +1285,37 @@ ststart(struct scsipi_periph *periph)
(struct scsipi_generic *)&cmd, sizeof(cmd),
(u_char *)bp->b_data, bp->b_bcount,
0, ST_IO_TIME, bp, flags);
if (error) {
if (__predict_false(error)) {
printf("%s: not queued, error %d\n",
st->sc_dev.dv_xname, error);
}
if (__predict_false(error == ENOMEM)) {
/*
* out of memory. Keep this buffer in the queue, and
* retry later.
*/
callout_reset(&st->sc_callout, hz / 2, strestart,
periph);
return;
}
#ifdef DIAGNOSTIC
if (BUFQ_GET(&st->buf_queue) != bp)
panic("ststart(): dequeued wrong buf");
#else
BUFQ_GET(&st->buf_queue);
#endif
} /* go back and see if we can cram more work in.. */
}
static void
strestart(void *v)
{
int s = splbio();
ststart((struct scsipi_periph *)v);
splx(s);
}
static void
stdone(struct scsipi_xfer *xs)
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: stvar.h,v 1.8 2004/08/21 22:16:07 thorpej Exp $ */
/* $NetBSD: stvar.h,v 1.9 2004/08/27 20:37:29 bouyer Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -148,6 +148,8 @@ struct st_softc {
*/
struct bufq_state buf_queue; /* the queue of pending IO */
/* operations */
struct callout sc_callout; /* restarting the queue after */
/* transient error */
#if NRND > 0
rndsource_element_t rnd_source;
#endif