From 4526a898c68f965c578d5ed5128523848f15b4ac Mon Sep 17 00:00:00 2001 From: scw Date: Fri, 20 Oct 2006 07:11:50 +0000 Subject: [PATCH] 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@ --- sys/dev/scsipi/scsipi_base.c | 52 +++++++++++++++++++++++++++++++----- sys/dev/scsipi/scsipiconf.h | 4 +-- sys/dev/scsipi/sd.c | 15 ++++++----- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/sys/dev/scsipi/scsipi_base.c b/sys/dev/scsipi/scsipi_base.c index 970c6f011219..a7c4f23c9047 100644 --- a/sys/dev/scsipi/scsipi_base.c +++ b/sys/dev/scsipi/scsipi_base.c @@ -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 -__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); } diff --git a/sys/dev/scsipi/scsipiconf.h b/sys/dev/scsipi/scsipiconf.h index c026c21591dc..80ea6b1ef8af 100644 --- a/sys/dev/scsipi/scsipiconf.h +++ b/sys/dev/scsipi/scsipiconf.h @@ -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 *, diff --git a/sys/dev/scsipi/sd.c b/sys/dev/scsipi/sd.c index d5336181288b..5b41db63a994 100644 --- a/sys/dev/scsipi/sd.c +++ b/sys/dev/scsipi/sd.c @@ -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 -__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; } } }