Validate the sector size returned by READ CAPACITY. If it looks bogus

print a warning and fallback to a suitable default.

Fixes a problem on hp700 reported by skrll@
This commit is contained in:
scw 2006-10-20 07:11:50 +00:00
parent e8ac1cad77
commit 4526a898c6
3 changed files with 55 additions and 16 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: scsipi_base.c,v 1.139 2006/10/12 01:31:57 christos Exp $ */
/* $NetBSD: scsipi_base.c,v 1.140 2006/10/20 07:11:50 scw Exp $ */
/*-
* Copyright (c) 1998, 1999, 2000, 2002, 2003, 2004 The NetBSD Foundation, Inc.
@ -38,7 +38,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: scsipi_base.c,v 1.139 2006/10/12 01:31:57 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: scsipi_base.c,v 1.140 2006/10/20 07:11:50 scw Exp $");
#include "opt_scsi.h"
@ -1020,13 +1020,46 @@ scsipi_interpret_sense(struct scsipi_xfer *xs)
}
}
/*
* scsipi_validate_secsize:
*
* Validate the sector size reported by READ_CAPACITY_1[06].
* Use the supplied default if the reported size looks wrong.
*/
static int
scsipi_validate_secsize(struct scsipi_periph *periph, const char *opcode,
int raw_len, int def_len)
{
switch (raw_len) {
case 256:
case 512:
case 1024:
case 2048:
case 4096:
break;
default:
scsipi_printaddr(periph);
printf("%s returned %s sector size: 0x%x. Defaulting to %d "
"bytes.\n", opcode, (raw_len ^ (1 << (ffs(raw_len) - 1))) ?
"preposterous" : "unsupported", raw_len, def_len);
/*FALLTHROUGH*/
case 0:
raw_len = def_len;
break;
}
return (raw_len);
}
/*
* scsipi_size:
*
* Find out from the device what its capacity is.
*/
u_int64_t
scsipi_size(struct scsipi_periph *periph, int *secsize, int flags)
scsipi_size(struct scsipi_periph *periph, int *secsize, int defsize, int flags)
{
union {
struct scsipi_read_capacity_10 cmd;
@ -1050,8 +1083,11 @@ scsipi_size(struct scsipi_periph *periph, int *secsize, int flags)
return (0);
if (_4btol(data.data.addr) != 0xffffffff) {
if (secsize)
*secsize = _4btol(data.data.length);
if (secsize) {
*secsize = scsipi_validate_secsize(periph,
"READ_CAPACITY_10", _4btol(data.data.length),
defsize);
}
return (_4btol(data.data.addr) + 1);
}
@ -1071,8 +1107,10 @@ scsipi_size(struct scsipi_periph *periph, int *secsize, int flags)
flags | XS_CTL_DATA_IN | XS_CTL_DATA_ONSTACK | XS_CTL_SILENT) != 0)
return (0);
if (secsize)
*secsize = _4btol(data.data16.length);
if (secsize) {
*secsize = scsipi_validate_secsize(periph, "READ_CAPACITY_16",
_4btol(data.data16.length), defsize);
}
return (_8btol(data.data16.addr) + 1);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: scsipiconf.h,v 1.104 2006/10/09 21:29:14 scw Exp $ */
/* $NetBSD: scsipiconf.h,v 1.105 2006/10/20 07:11:50 scw Exp $ */
/*-
* Copyright (c) 1998, 1999, 2000, 2004 The NetBSD Foundation, Inc.
@ -638,7 +638,7 @@ const void *scsipi_inqmatch(struct scsipi_inquiry_pattern *, const void *,
const char *scsipi_dtype(int);
void scsipi_strvis(u_char *, int, const u_char *, int);
int scsipi_execute_xs(struct scsipi_xfer *);
u_int64_t scsipi_size(struct scsipi_periph *, int *, int);
u_int64_t scsipi_size(struct scsipi_periph *, int *, int, int);
int scsipi_test_unit_ready(struct scsipi_periph *, int);
int scsipi_prevent(struct scsipi_periph *, int, int);
int scsipi_inquire(struct scsipi_periph *,

View File

@ -1,4 +1,4 @@
/* $NetBSD: sd.c,v 1.252 2006/10/12 01:31:57 christos Exp $ */
/* $NetBSD: sd.c,v 1.253 2006/10/20 07:11:50 scw Exp $ */
/*-
* Copyright (c) 1998, 2003, 2004 The NetBSD Foundation, Inc.
@ -54,7 +54,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.252 2006/10/12 01:31:57 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.253 2006/10/20 07:11:50 scw Exp $");
#include "opt_scsi.h"
#include "rnd.h"
@ -1661,7 +1661,7 @@ sd_get_simplifiedparms(struct sd_softc *sd, struct disk_parms *dp, int flags)
* XXX probably differs for removable media
*/
dp->blksize = 512;
if ((sectors = scsipi_size(sd->sc_periph, &blksize, flags)) == 0)
if ((sectors = scsipi_size(sd->sc_periph, &blksize, 512, flags)) == 0)
return (SDGP_RESULT_OFFLINE); /* XXX? */
error = scsipi_mode_sense(sd->sc_periph, SMS_DBD, 6,
@ -1673,7 +1673,7 @@ sd_get_simplifiedparms(struct sd_softc *sd, struct disk_parms *dp, int flags)
dp->blksize = _2btol(scsipi_sense.lbs);
if (dp->blksize == 0)
dp->blksize = blksize ? blksize : 512;
dp->blksize = blksize;
/*
* Create a pseudo-geometry.
@ -1707,7 +1707,8 @@ sd_get_capacity(struct sd_softc *sd, struct disk_parms *dp, int flags)
u_int8_t *p;
#endif
dp->disksize = sectors = scsipi_size(sd->sc_periph, &blksize, flags);
dp->disksize = sectors = scsipi_size(sd->sc_periph, &blksize, 512,
flags);
if (sectors == 0) {
struct scsipi_read_format_capacities cmd;
struct {
@ -1762,7 +1763,7 @@ printf("rfc result:"); for (i = sizeof(struct scsipi_capacity_list_header) + dat
memset(&scsipi_sense, 0, sizeof(scsipi_sense));
error = sd_mode_sense(sd, 0, &scsipi_sense,
sizeof(scsipi_sense.blk_desc), 0, flags | XS_CTL_SILENT, &big);
dp->blksize = blksize ? blksize : 512;
dp->blksize = blksize;
if (!error) {
if (big) {
bdesc = (void *)(&scsipi_sense.header.big + 1);
@ -1781,7 +1782,7 @@ printf("page 0 ok\n");
if (bsize >= 8) {
dp->blksize = _3btol(bdesc->blklen);
if (dp->blksize == 0)
dp->blksize = blksize ? blksize : 512;
dp->blksize = blksize;
}
}
}