diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2005-05-25 20:52:42 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2005-05-25 20:52:42 +0000 |
commit | 8864d54939803f5c472b21b73056f2f8de3d31c2 (patch) | |
tree | f48986aba38da3c117de4a5896d88caaf539aad5 /sys | |
parent | 5c433857e84069e8f66922a2975b92e208971563 (diff) |
Introduce safer, more general mode sense capability. Transparently use
both 10 byte and 6 byte MODE SENSE commands and just return error
checked values.
Convert sd_scsi.c to use new mechanism for non-optical drives. USB
umass devices will now display actual mode sense info if it is
available via a 10 byte MODE SENSE. Which may mean 0 heads, etc. is
shown until cosmetics are finalized.
ok marco@ 'that is pretty cool' deraadt@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/scsi/scsi_all.h | 27 | ||||
-rw-r--r-- | sys/scsi/scsi_base.c | 110 | ||||
-rw-r--r-- | sys/scsi/scsi_disk.h | 8 | ||||
-rw-r--r-- | sys/scsi/scsiconf.h | 7 | ||||
-rw-r--r-- | sys/scsi/sd_scsi.c | 148 |
5 files changed, 213 insertions, 87 deletions
diff --git a/sys/scsi/scsi_all.h b/sys/scsi/scsi_all.h index 49b8faf46c7..62edd4be07e 100644 --- a/sys/scsi/scsi_all.h +++ b/sys/scsi/scsi_all.h @@ -1,4 +1,4 @@ -/* $OpenBSD: scsi_all.h,v 1.22 2005/04/06 20:50:31 marco Exp $ */ +/* $OpenBSD: scsi_all.h,v 1.23 2005/05/25 20:52:41 krw Exp $ */ /* $NetBSD: scsi_all.h,v 1.10 1996/09/12 01:57:17 thorpej Exp $ */ /* @@ -294,6 +294,19 @@ struct scsi_blk_desc { u_int8_t blklen[3]; }; +struct scsi_mode_direct_blk_desc { + u_int8_t nblocks[4]; + u_int8_t density; + u_int8_t blklen[3]; +}; + +struct scsi_mode_blk_desc_big { + u_int8_t nblocks[8]; + u_int8_t density; + u_int8_t reserved[3]; + u_int8_t blklen[4]; +}; + struct scsi_mode_header { u_int8_t data_length; /* Sense data length */ u_int8_t medium_type; @@ -305,10 +318,20 @@ struct scsi_mode_header_big { u_int8_t data_length[2]; /* Sense data length */ u_int8_t medium_type; u_int8_t dev_spec; - u_int8_t unused[2]; + u_int8_t reserved; +#define LONGLBA 0x01 + u_int8_t reserved2; u_int8_t blk_desc_len[2]; }; +struct scsi_mode_sense_buf { + union { + struct scsi_mode_header hdr; + struct scsi_mode_header_big hdr_big; + } headers; + u_char pad[248]; /* To total length of 256 bytes. */ +}; + /* * SPI status information unit. See section 14.3.5 of SPI-3. */ diff --git a/sys/scsi/scsi_base.c b/sys/scsi/scsi_base.c index 9aebd2227af..2153cddbac3 100644 --- a/sys/scsi/scsi_base.c +++ b/sys/scsi/scsi_base.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scsi_base.c,v 1.69 2005/05/22 01:12:47 krw Exp $ */ +/* $OpenBSD: scsi_base.c,v 1.70 2005/05/25 20:52:41 krw Exp $ */ /* $NetBSD: scsi_base.c,v 1.43 1997/04/02 02:29:36 mycroft Exp $ */ /* @@ -422,6 +422,114 @@ scsi_mode_sense_big(sc_link, byte2, page, data, len, flags, timeout) return (error); } +void * +scsi_mode_sense_page(hdr, page_len) + struct scsi_mode_header *hdr; + const int page_len; +{ + int total_length, header_length; + + total_length = hdr->data_length + sizeof(hdr->data_length); + header_length = sizeof(*hdr) + hdr->blk_desc_len; + + if ((total_length - header_length) < page_len) + return (NULL); + + return ((u_char *)hdr + header_length); +} + +void * +scsi_mode_sense_big_page(hdr, page_len) + struct scsi_mode_header_big *hdr; + const int page_len; +{ + int total_length, header_length; + + total_length = _2btol(hdr->data_length) + sizeof(hdr->data_length); + header_length = sizeof(*hdr) + _2btol(hdr->blk_desc_len); + + if ((total_length - header_length) < page_len) + return (NULL); + + return ((u_char *)hdr + header_length); +} + +int +scsi_do_mode_sense(sc_link, page, buf, page_data, density, block_count, + block_size, page_len, flags) + struct scsi_link *sc_link; + struct scsi_mode_sense_buf *buf; + int page, page_len, *density, *block_count, *block_size; + void **page_data; +{ + struct scsi_mode_blk_desc_big *desc_big; + struct scsi_mode_direct_blk_desc *desc; + struct scsi_mode_header_big *hdr_big; + struct scsi_mode_header *hdr; + u_char *cbuf = (u_char *)buf; + int error, blk_desc_len; + + *page_data = NULL; + + if (density) + *density = 0; + if (block_count) + /* XXX We don't do block_count at this time. */ + *block_count = 0; + if (block_size) + *block_size = 0; + + /* Try 10 byte mode sense request. Don't bother with SMS_DBD. */ + error = scsi_mode_sense_big(sc_link, 0, page, &buf->headers.hdr_big, + sizeof(*buf), flags, 20000); + hdr_big = &buf->headers.hdr_big; + if (error == 0 && _2btol(hdr_big->data_length) > 0) { + cbuf += sizeof(struct scsi_mode_header_big); + *page_data = scsi_mode_sense_big_page(hdr_big, page_len); + blk_desc_len = _2btol(hdr_big->blk_desc_len); + if ((hdr_big->reserved & LONGLBA) == 0) + goto eight_byte; + /* 16 byte block descriptors. */ + if (blk_desc_len < sizeof(struct scsi_mode_blk_desc_big)) + return (0); + desc_big = (struct scsi_mode_blk_desc_big *)cbuf; + if (density) + *density = desc_big->density; + if (block_size) + *block_size = _4btol(desc_big->blklen); + return (0); + } + + if (sc_link->flags & SDEV_ONLYBIG) + return (EIO); + + /* Try 6 byte mode sense request. Don't bother with SMS_DBD. */ + error = scsi_mode_sense(sc_link, 0, page, &buf->headers.hdr, + sizeof(*buf), flags, 20000); + if (error != 0) + return (error); + + hdr = &buf->headers.hdr; + if (hdr->data_length == 0) + return (EIO); + + cbuf += sizeof(struct scsi_mode_header); + *page_data = scsi_mode_sense_page(hdr, page_len); + blk_desc_len = hdr->blk_desc_len; + +eight_byte: + if (blk_desc_len < sizeof(struct scsi_mode_direct_blk_desc)) + return (0); + + desc = (struct scsi_mode_direct_blk_desc *)cbuf; + if (density) + *density = desc->density; + if (block_size) + *block_size = _3btol(desc->blklen); + + return (0); +} + int scsi_mode_select(sc_link, byte2, data, len, flags, timeout) struct scsi_link *sc_link; diff --git a/sys/scsi/scsi_disk.h b/sys/scsi/scsi_disk.h index cb93bcd8c30..71c32cfdc8a 100644 --- a/sys/scsi/scsi_disk.h +++ b/sys/scsi/scsi_disk.h @@ -1,4 +1,4 @@ -/* $OpenBSD: scsi_disk.h,v 1.14 2003/06/24 22:42:07 mickey Exp $ */ +/* $OpenBSD: scsi_disk.h,v 1.15 2005/05/25 20:52:41 krw Exp $ */ /* $NetBSD: scsi_disk.h,v 1.10 1996/07/05 16:19:05 christos Exp $ */ /* @@ -236,12 +236,6 @@ struct scsi_reassign_blocks_data { } defect_descriptor[1]; }; -struct scsi_disk_blk_desc { - u_int8_t nblocks[4]; - u_int8_t density; - u_int8_t blklen[3]; -}; - union scsi_disk_pages { #define DISK_PGCODE 0x3F /* only 6 bits valid */ struct page_disk_format { diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h index 52c09756127..87d1e270ff4 100644 --- a/sys/scsi/scsiconf.h +++ b/sys/scsi/scsiconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: scsiconf.h,v 1.52 2005/05/14 00:20:43 krw Exp $ */ +/* $OpenBSD: scsiconf.h,v 1.53 2005/05/25 20:52:41 krw Exp $ */ /* $NetBSD: scsiconf.h,v 1.35 1997/04/02 02:29:38 mycroft Exp $ */ /* @@ -335,6 +335,11 @@ int scsi_mode_sense(struct scsi_link *, int, int, struct scsi_mode_header *, size_t, int, int); int scsi_mode_sense_big(struct scsi_link *, int, int, struct scsi_mode_header_big *, size_t, int, int); +void * scsi_mode_sense_page(struct scsi_mode_header *, int); +void * scsi_mode_sense_big_page(struct scsi_mode_header_big *, int); +int scsi_do_mode_sense(struct scsi_link *, int, + struct scsi_mode_sense_buf *, void **, int *, int *, int *, int, + int); int scsi_mode_select(struct scsi_link *, int, struct scsi_mode_header *, size_t, int, int); int scsi_mode_select_big(struct scsi_link *, int, diff --git a/sys/scsi/sd_scsi.c b/sys/scsi/sd_scsi.c index 74b46567254..47785001fc4 100644 --- a/sys/scsi/sd_scsi.c +++ b/sys/scsi/sd_scsi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sd_scsi.c,v 1.11 2005/05/24 20:48:43 krw Exp $ */ +/* $OpenBSD: sd_scsi.c,v 1.12 2005/05/25 20:52:41 krw Exp $ */ /* $NetBSD: sd_scsi.c,v 1.8 1998/10/08 20:21:13 thorpej Exp $ */ /*- @@ -138,9 +138,10 @@ sd_scsibus_get_parms(sd, dp, flags) int flags; { struct sd_scsibus_mode_sense_data scsi_sense; - union scsi_disk_pages *sense_pages; - u_int16_t rpm; - int page, error; + struct scsi_mode_sense_buf buf; + union scsi_disk_pages *sense_pages = NULL; + u_int16_t rpm = 0; + int page, error, blksize; dp->rot_rate = 3600; @@ -151,103 +152,98 @@ sd_scsibus_get_parms(sd, dp, flags) if (sd->type == T_OPTICAL) return (sd_scsibus_get_optparms(sd, dp, flags)); - error = scsi_mode_sense(sd->sc_link, 0, page = 4, - (struct scsi_mode_header *)&scsi_sense, sizeof(scsi_sense), - flags | SCSI_SILENT, 6000); + error = scsi_do_mode_sense(sd->sc_link, page = 4, &buf, + (void **)&sense_pages, NULL, NULL, &blksize, + sizeof(sense_pages->rigid_geometry), flags | SCSI_SILENT); if (error == 0) { - sense_pages = (union scsi_disk_pages *) - ((char *)&scsi_sense.blk_desc + - (size_t)scsi_sense.header.blk_desc_len); - SC_DEBUG(sd->sc_link, SDEV_DB3, - ("%d cyls, %d heads, %d precomp, %d red_write," - " %d land_zone\n", - _3btol(sense_pages->rigid_geometry.ncyl), - sense_pages->rigid_geometry.nheads, - _2btol(sense_pages->rigid_geometry.st_cyl_wp), - _2btol(sense_pages->rigid_geometry.st_cyl_rwc), - _2btol(sense_pages->rigid_geometry.land_zone))); - - /* - * KLUDGE!! (for zone recorded disks) - * give a number of sectors so that sec * trks * cyls - * is <= disk_size - * can lead to wasted space! THINK ABOUT THIS ! - */ - dp->heads = sense_pages->rigid_geometry.nheads; - dp->cyls = _3btol(sense_pages->rigid_geometry.ncyl); - rpm = _2btol(scsi_sense.pages.rigid_geometry.rpm); - if (rpm) - dp->rot_rate = rpm; - if (scsi_sense.header.blk_desc_len >= 8) - dp->blksize = _3btol(scsi_sense.blk_desc.blklen); - else - dp->blksize = 0; + if (sense_pages) { + SC_DEBUG(sd->sc_link, SDEV_DB3, + ("%d cyls, %d heads, %d precomp, %d red_write," + " %d land_zone\n", + _3btol(sense_pages->rigid_geometry.ncyl), + sense_pages->rigid_geometry.nheads, + _2btol(sense_pages->rigid_geometry.st_cyl_wp), + _2btol(sense_pages->rigid_geometry.st_cyl_rwc), + _2btol(sense_pages->rigid_geometry.land_zone))); + /* + * KLUDGE!! (for zone recorded disks) + * give a number of sectors so that sec * trks * cyls + * is <= disk_size + * can lead to wasted space! THINK ABOUT THIS ! + */ + dp->heads = sense_pages->rigid_geometry.nheads; + dp->cyls = _3btol(sense_pages->rigid_geometry.ncyl); + rpm = _2btol(sense_pages->rigid_geometry.rpm); + } + dp->disksize = scsi_size(sd->sc_link, flags); - if (dp->heads == 0 || dp->cyls == 0) + if (dp->disksize == 0 || dp->heads == 0 || dp->cyls == 0) goto fake_it; - if (dp->blksize == 0) - dp->blksize = 512; - - dp->disksize = scsi_size(sd->sc_link, flags); - if (dp->disksize == 0) - return (SDGP_RESULT_OFFLINE); - /* XXX dubious on SCSI */ dp->sectors = dp->disksize / (dp->heads * dp->cyls); + if (rpm) + dp->rot_rate = rpm; + + dp->blksize = (blksize == 0) ? 512 : blksize; + return (SDGP_RESULT_OK); } - error = scsi_mode_sense(sd->sc_link, 0, page = 5, - (struct scsi_mode_header *)&scsi_sense, sizeof(scsi_sense), - flags | SCSI_SILENT, 6000); + error = scsi_do_mode_sense(sd->sc_link, page = 5, &buf, + (void **)&sense_pages, NULL, NULL, &blksize, + sizeof(sense_pages->flex_geometry), flags | SCSI_SILENT); if (error == 0) { - sense_pages = (union scsi_disk_pages *) - ((char *)&scsi_sense.blk_desc + - (size_t)scsi_sense.header.blk_desc_len); - dp->heads = sense_pages->flex_geometry.nheads; - dp->cyls = _2btol(sense_pages->flex_geometry.ncyl); - rpm = _2btol(scsi_sense.pages.flex_geometry.rpm); - if (rpm) - dp->rot_rate = rpm; - if (scsi_sense.header.blk_desc_len >= 8) - dp->blksize = _3btol(scsi_sense.blk_desc.blklen); - else + if (sense_pages) { + dp->heads = sense_pages->flex_geometry.nheads; + dp->cyls = _2btol(sense_pages->flex_geometry.ncyl); + dp->sectors = sense_pages->flex_geometry.ph_sec_tr; dp->blksize = _2btol(sense_pages->flex_geometry.bytes_s); - dp->sectors = sense_pages->flex_geometry.ph_sec_tr; - dp->disksize = dp->heads * dp->cyls * dp->sectors; - if (dp->disksize == 0) + rpm = _2btol(scsi_sense.pages.flex_geometry.rpm); + } + if (dp->cyls == 0 || dp->heads == 0 || dp->cyls == 0) goto fake_it; - if (dp->blksize == 0) + + dp->disksize = dp->heads * dp->cyls * dp->sectors; + + if (rpm) + dp->rot_rate = rpm; + + if (blksize) + dp->blksize = blksize; + else if (dp->blksize == 0) dp->blksize = 512; + return (SDGP_RESULT_OK); } - /* T_RDIRECT define page 6. */ - error = scsi_mode_sense(sd->sc_link, 0, page = 6, - (struct scsi_mode_header *)&scsi_sense, sizeof(scsi_sense), - flags | SCSI_SILENT, 6000); + /* T_RDIRECT defines page 6. */ + if (sd->type != T_RDIRECT) + goto fake_it; + + error = scsi_do_mode_sense(sd->sc_link, page = 6, &buf, + (void **)&sense_pages, NULL, NULL, &blksize, + sizeof(sense_pages->reduced_geometry), flags | SCSI_SILENT); if (error == 0) { - sense_pages = (union scsi_disk_pages *) - ((char *)&scsi_sense.blk_desc + - (size_t)scsi_sense.header.blk_desc_len); dp->heads = 64; dp->sectors = 32; - dp->disksize = - _4btol(sense_pages->reduced_geometry.sectors+1); - dp->cyls = dp->disksize / (64 * 32); - if (scsi_sense.header.blk_desc_len >= 8) - dp->blksize = _3btol(scsi_sense.blk_desc.blklen); - else + if (sense_pages) { + dp->disksize = + _4btol(sense_pages->reduced_geometry.sectors+1); dp->blksize = _2btol(sense_pages->reduced_geometry.bytes_s); - - if (dp->disksize == 0 || - sense_pages->reduced_geometry.sectors[0] != 0) + dp->sectors = sense_pages->reduced_geometry.sectors[0]; + } + if (dp->disksize == 0 || dp->sectors == 0) goto fake_it; + dp->cyls = dp->disksize / (dp->heads * dp->sectors); + + if (blksize) + dp->blksize = blksize; + if (dp->blksize == 0) dp->blksize = 512; |