Set bp->b_resid properly after data transfer is complete.

Fixes unexpected "Bad address" errors on file read ops since January 2006.

The problem is reported and tracked by Yasushi Oshima.
This commit is contained in:
tsutsui 2010-08-31 12:12:48 +00:00
parent 5de383f454
commit 1f68cc819a
1 changed files with 24 additions and 15 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: gdrom.c,v 1.26 2008/08/01 20:19:49 marcus Exp $ */
/* $NetBSD: gdrom.c,v 1.27 2010/08/31 12:12:48 tsutsui Exp $ */
/*-
* Copyright (c) 2001 Marcus Comstedt
@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: gdrom.c,v 1.26 2008/08/01 20:19:49 marcus Exp $");
__KERNEL_RCSID(0, "$NetBSD: gdrom.c,v 1.27 2010/08/31 12:12:48 tsutsui Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -118,10 +118,12 @@ struct gd_toc {
#define GDROM_COND GDROM(0x9c)
int gdrom_getstat(void);
int gdrom_do_command(struct gdrom_softc *, void *, void *, unsigned int);
int gdrom_command_sense(struct gdrom_softc *, void *, void *, unsigned int);
int gdrom_do_command(struct gdrom_softc *, void *, void *, unsigned int,
int *);
int gdrom_command_sense(struct gdrom_softc *, void *, void *, unsigned int,
int *);
int gdrom_read_toc(struct gdrom_softc *, struct gd_toc *);
int gdrom_read_sectors(struct gdrom_softc *, void *, int, int);
int gdrom_read_sectors(struct gdrom_softc *, void *, int, int, int *);
int gdrom_mount_disk(struct gdrom_softc *);
int gdrom_intr(void *);
@ -202,7 +204,7 @@ gdrom_intr(void *arg)
int gdrom_do_command(struct gdrom_softc *sc, void *req, void *buf,
unsigned int nbyt)
unsigned int nbyt, int *resid)
{
int i, s;
short *ptr = req;
@ -239,12 +241,15 @@ int gdrom_do_command(struct gdrom_softc *sc, void *req, void *buf,
splx(s);
if (resid != NULL)
*resid = sc->cmd_result_size;
return sc->cmd_cond;
}
int gdrom_command_sense(struct gdrom_softc *sc, void *req, void *buf,
unsigned int nbyt)
unsigned int nbyt, int *resid)
{
/* 76543210 76543210
0 0x13 -
@ -257,7 +262,7 @@ int gdrom_command_sense(struct gdrom_softc *sc, void *req, void *buf,
unsigned char cmd[12];
int sense_key, sense_specific;
int cond = gdrom_do_command(sc, req, buf, nbyt);
int cond = gdrom_do_command(sc, req, buf, nbyt, resid);
if (cond < 0) {
#ifdef GDROMDEBUG
@ -278,7 +283,7 @@ int gdrom_command_sense(struct gdrom_softc *sc, void *req, void *buf,
cmd[0] = 0x13;
cmd[4] = sizeof(sense_data);
gdrom_do_command(sc, cmd, sense_data, sizeof(sense_data));
gdrom_do_command(sc, cmd, sense_data, sizeof(sense_data), NULL);
sense_key = sense_data[1] & 0xf;
sense_specific = sense_data[4];
@ -314,10 +319,11 @@ int gdrom_read_toc(struct gdrom_softc *sc, struct gd_toc *toc)
cmd[3] = sizeof(struct gd_toc) >> 8;
cmd[4] = sizeof(struct gd_toc) & 0xff;
return gdrom_command_sense(sc, cmd, toc, sizeof(struct gd_toc));
return gdrom_command_sense(sc, cmd, toc, sizeof(struct gd_toc), NULL);
}
int gdrom_read_sectors(struct gdrom_softc *sc, void *buf, int sector, int cnt)
int gdrom_read_sectors(struct gdrom_softc *sc, void *buf, int sector, int cnt,
int *resid)
{
/* 76543210 76543210
0 0x30 datafmt
@ -339,7 +345,7 @@ int gdrom_read_sectors(struct gdrom_softc *sc, void *buf, int sector, int cnt)
cmd[9] = cnt>>8;
cmd[10] = cnt;
return gdrom_command_sense(sc, cmd, buf, cnt << 11);
return gdrom_command_sense(sc, cmd, buf, cnt << 11, resid);
}
int gdrom_mount_disk(struct gdrom_softc *sc)
@ -358,7 +364,7 @@ int gdrom_mount_disk(struct gdrom_softc *sc)
cmd[0] = 0x70;
cmd[1] = 0x1f;
return gdrom_command_sense(sc, cmd, NULL, 0);
return gdrom_command_sense(sc, cmd, NULL, 0, NULL);
}
int
@ -468,7 +474,7 @@ void
gdromstrategy(struct buf *bp)
{
struct gdrom_softc *sc;
int s, unit, error;
int s, unit, error, resid;
#ifdef GDROMDEBUG
printf("GDROM: strategy\n");
#endif
@ -493,11 +499,14 @@ gdromstrategy(struct buf *bp)
splx(s);
if ((error = gdrom_read_sectors(sc, bp->b_data, bp->b_rawblkno,
bp->b_bcount >> 11)))
bp->b_bcount >> 11, &resid)))
bp->b_error = error;
sc->is_busy = 0;
wakeup(&sc->is_busy);
bp->b_resid = resid;
biodone(bp);
return;
done:
bp->b_resid = bp->b_bcount;