Subject: kern/12501: ATAPI_READ_FORMAT_CAPACITIES vs READ_CAPACITY in sd_atapi.c
To: None <gnats-bugs@gnats.netbsd.org>
From: None <brett.mccoy@pobox.com>
List: netbsd-bugs
Date: 03/29/2001 12:48:58
>Number: 12501
>Category: kern
>Synopsis: use READ_CAPACITY v. ATAPI_READ_FORMAT_CAPACITIES in sd_atapi.c
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Thu Mar 29 09:49:01 PST 2001
>Closed-Date:
>Last-Modified:
>Originator: Brett McCoy
>Release: 2001-03-29
>Organization:
>Environment:
System: NetBSD morte 1.5T NetBSD 1.5T (MORTEfw) #71: Thu Mar 29 11:33:24 EST 2001 bmccoy@morte:/usr/src/sys/arch/i386/compile/MORTEfw i386
Architecture: i386
Machine: i386
>Description:
sd_atapibus_get_parms in sd_atapi.c uses the
ATAPI_READ_FORMAT_CAPACITIES command to get the number of
sectors and block size from a device. This command is not
well supported on all ATAPI drives, especially flash card
readers. The READ_CAPACITY command is much better supported
and is a much simpler command. It's already used in the
scsipi_size function (in scsipi_base.c). The problem is that
that function only returns the number of sectors and not the
block size.
My request is to modify sd_atapibus_get_parms to use the
READ_CAPCITY command to get the sector count and block size
from the device. I've implemented this by creating a
sd_atapi_size function in sd_atapi.c and calling it from
sd_atapibus_get_parms to set dp->disksize and dp->blksize.
I think it would be better to generalize the scsipi_size
function to return block size as well as sector count. But
this works fine and doesn't add too much extra code.
>How-To-Repeat:
>Fix:
Index: sd_atapi.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/scsipi/sd_atapi.c,v
retrieving revision 1.8
diff -u -r1.8 sd_atapi.c
--- sd_atapi.c 2001/03/20 22:39:08 1.8
+++ sd_atapi.c 2001/03/29 17:45:39
@@ -75,6 +75,8 @@
"", "", ""},
};
+static u_long sd_atapi_size __P((struct scsipi_link *,
+ int, u_long *, u_long *));
static int sd_atapibus_get_parms __P((struct sd_softc *,
struct disk_parms *, int));
@@ -122,58 +124,53 @@
sdattach(parent, sd, sc_link, &sd_atapibus_ops);
}
+/*
+ * Find out from the device what its capacity is.
+ * XXX - this should really use atapi_size, but it
+ * doesn't return block size information.
+ */
+u_long
+sd_atapi_size(sc_link, flags, disksize, blksize)
+ struct scsipi_link *sc_link;
+ int flags;
+ u_long *disksize;
+ u_long *blksize;
+{
+ struct scsipi_read_cap_data rdcap;
+ struct scsipi_read_capacity scsipi_cmd;
+
+ /*
+ * make up a scsipi command and ask the scsipi driver to do
+ * it for you.
+ */
+ bzero(&scsipi_cmd, sizeof(scsipi_cmd));
+ scsipi_cmd.opcode = READ_CAPACITY;
+
+ if (scsipi_command(sc_link, (struct scsipi_generic *)&scsipi_cmd,
+ sizeof(scsipi_cmd), (u_char *)&rdcap, sizeof(rdcap),
+ SCSIPIRETRIES, 20000, NULL,
+ flags | XS_CTL_DATA_IN | XS_CTL_DATA_ONSTACK) != 0) {
+ sc_link->sc_print_addr(sc_link);
+ printf("could not get size\n");
+ return (0);
+ }
+
+ *disksize = _4btol(rdcap.addr) + 1;
+ *blksize = _4btol(rdcap.length);
+ return (*disksize);
+}
+
static int
sd_atapibus_get_parms(sd, dp, flags)
struct sd_softc *sd;
struct disk_parms *dp;
int flags;
{
- struct atapi_read_format_capacities scsipi_cmd;
- struct atapi_capacity_descriptor *descp;
struct atapi_sd_mode_data sense_data;
- char capacity_data[ATAPI_CAP_DESC_SIZE(1)];
int error;
-
- bzero(&scsipi_cmd, sizeof scsipi_cmd);
- scsipi_cmd.opcode = ATAPI_READ_FORMAT_CAPACITIES;
- _lto2b(ATAPI_CAP_DESC_SIZE(1), scsipi_cmd.length);
-
- error = scsipi_command(sd->sc_link,
- (struct scsipi_generic *)&scsipi_cmd, sizeof(scsipi_cmd),
- (void *)capacity_data, ATAPI_CAP_DESC_SIZE(1), SDRETRIES, 20000,
- NULL, flags | XS_CTL_DATA_IN | XS_CTL_DATA_ONSTACK);
- SC_DEBUG(sd->sc_link, SDEV_DB2,
- ("sd_atapibus_get_parms: read format capacities error=%d\n",
- error));
- if (error != 0)
- return (SDGP_RESULT_OFFLINE);
-
- descp = (struct atapi_capacity_descriptor *)
- &capacity_data[ATAPI_CAP_DESC_OFFSET_DESC(0)];
-
- switch (descp->byte5 & ATAPI_CAP_DESC_CODE_MASK) {
- case ATAPI_CAP_DESC_CODE_UNFORMATTED:
- return SDGP_RESULT_UNFORMATTED;
-
- case ATAPI_CAP_DESC_CODE_FORMATTED:
- break;
-
- case 0:
- if (sd->sc_link->quirks & ADEV_BYTE5_ZERO)
- break;
-
- default:
-#ifdef DIAGNOSTIC
- printf("%s: strange capacity descriptor byte5 0x%x\n",
- sd->sc_dev.dv_xname, (u_int)descp->byte5);
-#endif
- /* FALLTHROUGH */
- case ATAPI_CAP_DESC_CODE_NONE:
- return SDGP_RESULT_OFFLINE;
- }
- dp->disksize = _4btol(descp->nblks);
- dp->blksize = _3btol(descp->blklen);
+ if (! sd_atapi_size(sd->sc_link, flags, &dp->disksize, &dp->blksize))
+ return (SDGP_RESULT_OFFLINE);
/*
* First, set up standard fictitious geometry, a la sd_scsi.c.
>Release-Note:
>Audit-Trail:
>Unformatted: