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:
parent
93f4534edf
commit
80620a83a7
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,24 +790,29 @@ 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) {
|
||||
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,12 +869,35 @@ 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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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,24 +813,29 @@ 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) {
|
||||
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,12 +902,36 @@ 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
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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,15 +1177,13 @@ 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) {
|
||||
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;
|
||||
|
@ -1187,7 +1191,14 @@ ststart(struct scsipi_periph *periph)
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue