Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144508729
D13356.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
34 KB
Referenced Files
None
Subscribers
None
D13356.diff
View Options
Index: usr.sbin/Makefile
===================================================================
--- usr.sbin/Makefile
+++ usr.sbin/Makefile
@@ -201,6 +201,7 @@
SUBDIR.${MK_TOOLCHAIN}+= crunch
SUBDIR.${MK_UNBOUND}+= unbound
SUBDIR.${MK_USB}+= uathload
+SUBDIR.${MK_USB}+= ufdformat
SUBDIR.${MK_USB}+= uhsoctl
SUBDIR.${MK_USB}+= usbconfig
SUBDIR.${MK_USB}+= usbdump
Index: usr.sbin/ufdformat/Makefile
===================================================================
--- usr.sbin/ufdformat/Makefile
+++ usr.sbin/ufdformat/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+PROG= ufdformat
+SRCS= ufdformat.c scsi_util.c
+
+WARNS?= 2
+
+LIBADD= cam sbuf
+MAN= ufdformat.1
+
+.include <bsd.prog.mk>
Index: usr.sbin/ufdformat/scsi_util.h
===================================================================
--- usr.sbin/ufdformat/scsi_util.h
+++ usr.sbin/ufdformat/scsi_util.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2004 by Bruce M. Simpson.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SCSI_UTIL_H
+#define _SCSI_UTIL_H
+
+/* XXX: Push to ufdformat.c */
+#define UFI_MODE_SENSE_LEN 10
+#define UFI_MODE_SENSE_TIMEOUT 5
+
+/*
+ * 12-byte FORMAT_UNIT command. Only used by UFI and SFF8077i devices.
+ * XXX: Push to kernel headers?
+ */
+struct scsi_format_unit_12
+{
+ uint8_t opcode;
+ uint8_t byte2; /* Assignments as for 6-byte FORMAT UNIT */
+#define FUFI_ALL_TRACKS 0xFF /* Format the entire unit */
+#define FUFI_SIDE_LOWER 0x0 /* Lower LBA */
+#define FUFI_SIDE_UPPER 0x1 /* Higher LBA */
+#define FUFI_SIDE_ALL FUFI_SIDE_LOWER
+ uint8_t track;
+ uint8_t interleave[2];
+ uint8_t unused00[2];
+ uint8_t param_len[2];
+ uint8_t unused01[3];
+};
+
+struct format_ufi_data {
+ struct format_defect_list_header fdh;
+ struct format_capacity_descriptor fcd;
+};
+
+struct supported_format_descriptors {
+ struct format_capacity_list_header fh;
+ struct format_capacity_descriptor fdcurrmax;
+ struct format_capacity_descriptor fdsupp[4];
+};
+
+void dump_flexible_geometry(struct flexible_disk_page *);
+
+void floppy_geom_scsi_to_fdc(struct fd_type *,
+ const struct flexible_disk_page *,
+ const struct format_capacity_descriptor *);
+
+/* XXX: These two move to kernel headers eventually. */
+void scsi_format_unit_12(struct ccb_scsiio *, u_int32_t,
+ void (*)(struct cam_periph *, union ccb *),
+ u_int8_t, u_int8_t, u_int8_t, u_int16_t, u_int8_t *, u_int32_t,
+ u_int8_t, u_int32_t);
+void scsi_read_format_capacities(struct ccb_scsiio *, u_int32_t,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ u_int8_t tag_action, u_int8_t, u_int8_t *,
+ u_int32_t, u_int8_t, u_int32_t);
+
+void scsi_fillout_format_ufi_data(struct format_ufi_data *,
+ u_int8_t, u_int8_t, struct format_capacity_descriptor *);
+int scsi_get_format_capacities(struct cam_device *, int,
+ int, u_int8_t *, u_int32_t);
+int scsi_get_mode_sense(struct cam_device *, int, int, int, int, int,
+ u_int8_t *, int, int);
+int scsi_get_inquiry(struct cam_device *, int, int,
+ struct scsi_inquiry_data *);
+int scsi_get_flexible_disk_page(struct cam_device *,
+ struct flexible_disk_page *, int, int);
+int scsi_format_track(struct cam_device *, union ccb *,
+ int, int, int head, struct format_capacity_descriptor *);
+void scsi_verify(struct ccb_scsiio *, u_int32_t,
+ void (*)(struct cam_periph *, union ccb *), u_int8_t,
+ u_int8_t, u_int32_t, u_int16_t, u_int8_t, u_int32_t);
+int scsi_verify_track(struct cam_device *, union ccb *,
+ int, int, int head, int);
+
+void sfds_dump_supported_formats(struct supported_format_descriptors *);
+void sfds_dump_desc(char *hdr, int, struct format_capacity_descriptor *);
+
+/* Macros for working with mode pages. */
+#define MODE_PAGE_HEADER_6(mh)\
+ (struct scsi_mode_page_header *)find_mode_page_6(mh)
+
+#define MODE_PAGE_HEADER_10(mh)\
+ (struct scsi_mode_page_header *)find_mode_page_10(mh)
+
+#define MODE_PAGE_DATA(mph)\
+ (u_int8_t *)(mph) + sizeof(struct scsi_mode_page_header)
+
+#endif /* _SCSI_UTIL_H */
Index: usr.sbin/ufdformat/scsi_util.c
===================================================================
--- usr.sbin/ufdformat/scsi_util.c
+++ usr.sbin/ufdformat/scsi_util.c
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2004 by Bruce M. Simpson.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stdint.h>
+#include <sys/ioctl.h>
+#include <sys/fdcio.h> /* XXX */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <sysexits.h>
+
+#include <cam/cam.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_ccb.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_da.h>
+#include <cam/scsi/scsi_pass.h>
+#include <cam/scsi/scsi_message.h>
+#include <camlib.h>
+
+#include "scsi_util.h"
+
+int camverbose = 0;
+
+void
+dump_flexible_geometry(struct flexible_disk_page *flex)
+{
+ u_int16_t tracks;
+ u_int16_t sectorsize;
+
+ tracks = scsi_2btoul(&flex->ncyl_1);
+ sectorsize = scsi_2btoul(&flex->bytes_s_1);
+ fprintf(stderr,
+ "Geometry: %lu cyl %u heads %u secpercyl %lu bytespersec\n",
+ (unsigned long)tracks,
+ flex->nheads,
+ flex->sec_per_track,
+ (unsigned long)sectorsize);
+}
+
+/*
+ * Convert UFI geometry to fdc(4) style geometry, using information
+ * obtained via MODE_SENSE and READ_FORMAT_CAPACITIES.
+ * fcl points to the chosen format_capacity_list entry (normally the
+ * current or maximum value) which is to be used to format the disk.
+ */
+void
+floppy_geom_scsi_to_fdc(struct fd_type *fdt,
+ const struct flexible_disk_page *flexpage,
+ const struct format_capacity_descriptor *fcd)
+{
+
+ bzero(fdt, sizeof(*fdt));
+ fdt->sectrac = flexpage->sec_per_track;
+ /*
+ * Convert sector size to a secsize code for fd_type.
+ * Assume that 'sector' and 'block' mean the same thing here.
+ * Assume that the sector size is always a perfect power of two.
+ */
+ fdt->secsize = ffs(scsi_3btol((u_int8_t *)&fcd->block_length)) - 8;
+ /*fdt->secsize = ffs(scsi_2btoul(&flexpage->bytes_s_1)) - 8;*/
+ fdt->datalen = 0; /* XXX: Gross assumption */
+ fdt->gap = 0; /* XXX: Gross assumption */
+ fdt->tracks = scsi_2btoul((u_int8_t *)&flexpage->ncyl_1);
+ fdt->size = scsi_4btoul((u_int8_t *)&fcd->nblocks); /* # LBAs */
+ fdt->trans = FDC_500KBPS; /* XXX: Gross assumption */
+ /*scsi_2btoul(&flexpage->xfr_rate_1);*/
+ fdt->heads = flexpage->nheads;
+ fdt->f_gap = 0; /* XXX */
+ fdt->f_inter = 0; /* XXX */
+ fdt->offset_side2 = 0; /* XXX */
+ fdt->flags = FL_MFM; /* not specified within UFI */
+}
+
+/*
+ * Fill-out the additional parameter data required by UFI/SFF8070i
+ * for the 12-byte FORMAT_UNIT command.
+ *
+ * Notes:
+ * ufid points to the structure to be filled out.
+ * cap points to the disk format to be used, as returned by the
+ * GET_FORMAT_CAPACITIES command.
+ * track is the current track to be formatted, or FUFI_ALL_TRACKS
+ * for a complete format of the unit.
+ * side is the current side to be formatted, or FUFI_SIDE_NONE for
+ * a complete format of the unit.
+ */
+void
+scsi_fillout_format_ufi_data(struct format_ufi_data *ufid,
+ u_int8_t track, u_int8_t side,
+ struct format_capacity_descriptor *cap)
+{
+
+ bzero(ufid, sizeof(*ufid));
+
+ /*
+ * Always set the Format Options Valid (FOV) and Disable
+ * CeRTification bits. All other bits should be cleared.
+ *
+ * Set the single track bit if a track-by-track format
+ * was specified.
+ */
+ ufid->fdh.byte2 = FU_DLH_FOV | FU_DLH_DCRT;
+ ufid->fdh.byte2 |= (track == FUFI_ALL_TRACKS) ? 0 : FU_DLH_STPF;
+
+ /*
+ * Set the 'upper side' bit if both a track-by-track forat
+ * and a side were specified.
+ * Specifies which side if it's a track-by-track format;
+ * 0 is the bottom side (lower LBA), 1 is the upper side.
+ */
+ if (track != FUFI_ALL_TRACKS && side == FUFI_SIDE_UPPER)
+ ufid->fdh.byte2 |= FU_DLH_VS;
+
+ /* Fillout format_capacity_descriptor with chosen LBA format. */
+ bcopy(cap, &ufid->fcd, sizeof(*cap));
+ ufid->fcd.byte4 = 0x00;
+
+ /* Fillout defect_list_length. */
+ scsi_ulto2b(sizeof(ufid->fcd), ufid->fdh.defect_list_length);
+}
+
+/*
+ * 12-byte version of FORMAT_UNIT, for use with UFI and SFF8070i devices.
+ *
+ * Notes:
+ * The track number will come from the unit's flexible disk geometry
+ * according to the current position in the format.
+ * The interleave should normally be set to 0.
+ * The LUN doesn't get filled out here.
+ * The param_buf is a struct format_unit_ufi_data which was previously
+ * filled out by scsi_format_unit_ufi_data().
+ */
+void
+scsi_format_unit_12(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ u_int8_t tag_action, u_int8_t byte2, u_int8_t track,
+ u_int16_t interleave, u_int8_t *param_buf, u_int32_t param_len,
+ u_int8_t sense_len, u_int32_t timeout)
+{
+ struct scsi_format_unit_12 *scsi_cmd;
+
+ scsi_cmd = (struct scsi_format_unit_12 *)&csio->cdb_io.cdb_bytes;
+
+ bzero(scsi_cmd, sizeof(*scsi_cmd));
+ scsi_cmd->opcode = FORMAT_UNIT;
+ scsi_cmd->byte2 = byte2 | FU_FMT_DATA | 0x07; /* LUN etc */
+ scsi_cmd->track = track;
+ scsi_ulto2b(interleave, scsi_cmd->interleave);
+ scsi_ulto2b(param_len, scsi_cmd->param_len);
+
+ cam_fill_csio(csio,
+ retries,
+ cbfcnp,
+ CAM_DIR_OUT,
+ tag_action,
+ param_buf,
+ param_len,
+ sense_len,
+ sizeof(*scsi_cmd),
+ timeout);
+}
+
+/*
+ * Prepare a CDB which will return the result of the READ_FORMAT_CAPACITIES
+ * command into the user-provided buffer fmt_buf, with length fmt_len,
+ * once executed.
+ *
+ * XXX: Move this to kernel headers when ready.
+ */
+void
+scsi_read_format_capacities(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ u_int8_t tag_action, u_int8_t byte2, u_int8_t *fmt_buf,
+ u_int32_t fmt_len, u_int8_t sense_len, u_int32_t timeout)
+{
+ struct scsi_read_format_capacities *scsi_cmd;
+
+ cam_fill_csio(csio,
+ retries,
+ cbfcnp,
+ CAM_DIR_IN,
+ tag_action,
+ fmt_buf,
+ fmt_len,
+ sense_len,
+ sizeof(*scsi_cmd),
+ timeout);
+
+ scsi_cmd = (struct scsi_read_format_capacities *)
+ &csio->cdb_io.cdb_bytes;
+ bzero(scsi_cmd, sizeof(*scsi_cmd));
+ scsi_cmd->opcode = READ_FORMAT_CAPACITIES;
+ scsi_cmd->byte2 = byte2; /* LUN */
+ scsi_ulto2b(fmt_len, scsi_cmd->alloc_length);
+}
+
+/*
+ * Execute and return the result of the READ_FORMAT_CAPACITIES command.
+ */
+int
+scsi_get_format_capacities(struct cam_device *device, int retry_count,
+ int timeout, u_int8_t *fmt_buf, u_int32_t fmt_len)
+{
+ union ccb *ccb;
+ int error = 0;
+
+ ccb = cam_getccb(device);
+ if (ccb == NULL) {
+ warnx("couldn't allocate CCB");
+ return (1);
+ }
+
+ bzero(&(&ccb->ccb_h)[1],
+ sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
+ bzero(fmt_buf, fmt_len);
+
+ scsi_read_format_capacities(&ccb->csio,
+ retry_count,
+ NULL,
+ MSG_SIMPLE_Q_TAG,
+ 0, /* XXX: byte2 should contain the LUN */
+ fmt_buf,
+ fmt_len,
+ SSD_FULL_SIZE,
+ timeout ? timeout : 5000);
+
+ /* Disable freezing the device queue */
+ ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
+#if 0
+ if (arglist & CAM_ARG_ERR_RECOVER)
+ ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
+#endif
+ if (cam_send_ccb(device, ccb) < 0) {
+ perror("error sending SCSI get_format_capacities");
+ if (camverbose)
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ cam_freeccb(ccb);
+ return (1);
+ }
+
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ error = 1;
+ if (camverbose)
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ }
+
+ cam_freeccb(ccb);
+ return (0);
+}
+
+/*
+ * Perform a SCSI INQUIRY command and return the results in the user
+ * provided buffer inq_buf.
+ */
+int
+scsi_get_inquiry(struct cam_device *device, int retry_count,
+ int timeout, struct scsi_inquiry_data *inq_buf)
+{
+ union ccb *ccb;
+ int error = 0;
+
+ ccb = cam_getccb(device);
+ if (ccb == NULL) {
+ warnx("couldn't allocate CCB");
+ return (1);
+ }
+
+ bzero(&(&ccb->ccb_h)[1],
+ sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
+ bzero(inq_buf, sizeof(*inq_buf));
+
+ scsi_inquiry(&ccb->csio,
+ /* retries */ retry_count,
+ /* cbfcnp */ NULL,
+ /* tag_action */ MSG_SIMPLE_Q_TAG,
+ /* inq_buf */ (u_int8_t *)inq_buf,
+ /* inq_len */ SHORT_INQUIRY_LENGTH,
+ /* evpd */ 0,
+ /* page_code */ 0,
+ /* sense_len */ SSD_FULL_SIZE,
+ /* timeout */ timeout ? timeout : 5000);
+
+ /* Disable freezing the device queue */
+ ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
+#if 0
+ if (arglist & CAM_ARG_ERR_RECOVER)
+ ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
+#endif
+ if (cam_send_ccb(device, ccb) < 0) {
+ perror("error sending SCSI inquiry");
+ if (camverbose)
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ cam_freeccb(ccb);
+ return (1);
+ }
+
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ error = 1;
+ if (camverbose)
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ }
+
+ cam_freeccb(ccb);
+ return (error);
+}
+
+/*
+ * Return the results of MODE_SENSE for the SMS_FLEXIBLE_GEOMETRY_PAGE
+ * into the buffer page_data, but don't attempt to parse it.
+ */
+int
+scsi_get_flexible_disk_page(struct cam_device *cam_dev,
+ struct flexible_disk_page *page_data,
+ int min_mode_cmd_size, int timeout)
+{
+ struct scsi_mode_header_6 *mh6;
+ struct scsi_mode_header_10 *mh10;
+ union disk_pages *mode_pars; /* embeds the scsi_mode_page_header */
+ u_int8_t *data;
+ size_t data_len;
+ int retval;
+
+ data_len = sizeof(union disk_pages);
+ data_len += (min_mode_cmd_size < 10) ?
+ sizeof(struct scsi_mode_header_6) :
+ sizeof(struct scsi_mode_header_10);
+
+ data = malloc(data_len);
+ if (data == NULL)
+ errx(EX_OSERR, "error allocating mode sense buffer");
+
+ retval = scsi_get_mode_sense(cam_dev, SMS_FLEXIBLE_GEOMETRY_PAGE,
+ SMS_PAGE_CTRL_CURRENT, 0, 0, timeout,
+ (u_int8_t *)data, data_len, min_mode_cmd_size);
+ if (retval != 0) {
+ free(data);
+ errx(EX_OSERR, "error sending mode sense command");
+ }
+
+ mh6 = (struct scsi_mode_header_6 *)data;
+ mh10 = (struct scsi_mode_header_10 *)data;
+ mode_pars = (union disk_pages *)((min_mode_cmd_size < 10) ?
+ MODE_PAGE_HEADER_6(mh6) : MODE_PAGE_HEADER_10(mh10));
+ bcopy(&mode_pars->flexible_disk, page_data,
+ sizeof(struct flexible_disk_page));
+ free(data);
+
+ return (retval);
+}
+
+/*
+ * Return the result of the MODE SENSE command into the user-provided
+ * buffer 'data'.
+ */
+int
+scsi_get_mode_sense(struct cam_device *device,
+ int mode_page, int page_control,
+ int dbd, int retry_count, int timeout,
+ u_int8_t *data, int datalen, int min_mode_cmd_size)
+{
+ union ccb *ccb;
+ int retval;
+
+ ccb = cam_getccb(device);
+
+ if (ccb == NULL)
+ errx(1, "mode_sense: couldn't allocate CCB");
+
+ bzero(&(&ccb->ccb_h)[1],
+ sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
+ bzero(data, datalen);
+
+ scsi_mode_sense_len(&ccb->csio,
+ /* retries */ retry_count,
+ /* cbfcnp */ NULL,
+ /* tag_action */ MSG_SIMPLE_Q_TAG,
+ /* dbd */ dbd,
+ /* page_code */ page_control << 6,
+ /* page */ mode_page,
+ /* param_buf */ data,
+ /* param_len */ datalen,
+ /* minimum_cmd_size */ min_mode_cmd_size,
+ /* sense_len */ SSD_FULL_SIZE,
+ /* timeout */ timeout ? timeout : 5000);
+
+ /* Disable freezing the device queue */
+ ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
+
+ if (((retval = cam_send_ccb(device, ccb)) < 0)
+ || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
+ if (camverbose)
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ retval = 1;
+ }
+
+ cam_freeccb(ccb);
+ return (retval);
+}
+
+void
+sfds_dump_desc(char *hdr, int dump_code_type,
+ struct format_capacity_descriptor *pfd)
+{
+ u_int32_t block_length, nblocks;
+ char *type = "";
+
+ nblocks = scsi_4btoul(pfd->nblocks);
+ block_length = scsi_3btol(pfd->block_length);
+
+ switch (pfd->byte4 & FCD_CODE_MASK) {
+ case FCD_UNFORMATTED:
+ type = "unformatted";
+ break;
+ case FCD_FORMATTED:
+ type = "formatted";
+ break;
+ case FCD_NOMEDIA:
+ type = "no disk present";
+ break;
+ }
+
+ if (dump_code_type) {
+ hdr = ((pfd->byte4 & FCD_CODE_MASK) == FCD_NOMEDIA) ?
+ "maximum" : "current";
+ }
+
+ fprintf(stderr, "%s: %lu blocks, %lu bytes-per-block %s\n", hdr,
+ (unsigned long)nblocks, (unsigned long)block_length, type);
+}
+
+void
+sfds_dump_supported_formats(struct supported_format_descriptors *sfds)
+{
+ char hdr[16];
+ struct format_capacity_descriptor *pfd;
+ int i, cnt, listlen;
+
+ listlen = sfds->fh.capacity_list_length;
+ cnt = listlen / sizeof(sfds->fdsupp[0]) - 1;
+ if ((listlen % sizeof(sfds->fdsupp[0])) > 0) {
+ fprintf(stderr,
+ "WARNING: format capacity list may have been truncated.\n");
+ }
+
+ sfds_dump_desc("currmax", 1, &sfds->fdcurrmax);
+
+ pfd = &sfds->fdsupp[0];
+ for (i = 0; i < cnt; i++, pfd++) {
+ snprintf(hdr, sizeof(hdr), "%d", i);
+ sfds_dump_desc(hdr, 0, pfd);
+ }
+}
+
+int
+scsi_format_track(struct cam_device *cam_dev, union ccb *ccb,
+ int timeout, int cyl, int head, struct format_capacity_descriptor *cap)
+{
+ struct format_ufi_data ufid;
+
+ scsi_fillout_format_ufi_data(&ufid, cyl, head, cap);
+ scsi_format_unit_12(&ccb->csio,
+ 0,
+ NULL,
+ MSG_SIMPLE_Q_TAG,
+ 0, /* XXX: lun */
+ cyl,
+ 0, /* XXX: use default interleave */
+ (u_int8_t *)&ufid,
+ sizeof(ufid),
+ SSD_FULL_SIZE,
+ timeout);
+
+ return (cam_send_ccb(cam_dev, ccb));
+}
+
+void
+scsi_verify(struct ccb_scsiio *csio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ u_int8_t tag_action, u_int8_t byte2, u_int32_t lba_addr,
+ u_int16_t nblocks, u_int8_t sense_len, u_int32_t timeout)
+{
+ struct scsi_verify_12 *scsi_cmd;
+
+ scsi_cmd = (struct scsi_verify_12 *)&csio->cdb_io.cdb_bytes;
+ bzero(scsi_cmd, sizeof(*scsi_cmd));
+ scsi_cmd->opcode = VERIFY;
+ scsi_cmd->byte2 = byte2;
+ scsi_ulto4b(lba_addr, scsi_cmd->addr);
+ scsi_ulto2b(nblocks, scsi_cmd->length);
+
+ cam_fill_csio(csio,
+ retries,
+ cbfcnp,
+ CAM_DIR_NONE,
+ tag_action,
+ NULL,
+ 0,
+ sense_len,
+ sizeof(*scsi_cmd),
+ timeout);
+}
+
+/*
+ * XXX: Makes some assumptions about drive geometry right now.
+ * Assumes 2 heads, 1:1 interleave between heads.
+ */
+int
+scsi_verify_track(struct cam_device *cam_dev, union ccb *ccb,
+ int timeout, int cyl, int head, int spt)
+{
+ u_int32_t lba_addr;
+ u_int16_t nblocks;
+#define NHEADS 2
+
+ lba_addr = cyl * spt * NHEADS;
+ nblocks = spt * NHEADS;
+
+ scsi_verify(&ccb->csio,
+ 0,
+ NULL,
+ MSG_SIMPLE_Q_TAG,
+ 0, /* XXX: byte2, lun */
+ lba_addr,
+ nblocks,
+ SSD_FULL_SIZE,
+ timeout);
+
+ return (cam_send_ccb(cam_dev, ccb));
+#undef NHEADS
+}
Index: usr.sbin/ufdformat/ufdformat.1
===================================================================
--- usr.sbin/ufdformat/ufdformat.1
+++ usr.sbin/ufdformat/ufdformat.1
@@ -0,0 +1,142 @@
+.\"
+.\" Copyright (c) 2004 by Bruce M. Simpson.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
+.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
+.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 12, 2004
+.Os
+.Dt UFDFORMAT 1
+.Sh NAME
+.Nm ufdformat
+.Nd format USB floppy disks
+.Sh SYNOPSIS
+.Nm
+.Op Fl f Ar fmt
+.Op Fl nqvy
+.Ar device
+.Sh DESCRIPTION
+The
+.Nm
+utility formats a floppy disk at
+.Ar device ,
+where
+.Ar device
+may either be given as a full path
+name of a device node for a USB floppy disk drive
+(e.g.\&
+.Pa /dev/da0 ) ,
+or using an abbreviated name that will be looked up
+under
+.Pa /dev
+(e.g.\&
+.Dq Li da0 ) .
+.Pp
+The options are as follows:
+.Bl -tag -width ".Fl s Ar fmtstr"
+.It Fl f Ar fmt
+Specify the density settings for a
+.Ar fmt
+kilobyte format, as described in
+.Xr fdcontrol 8 ;
+1.44MB is assumed as the default.
+.It Fl n
+Do not verify floppy after formatting.
+.It Fl q
+Suppress any normal output from the command, and do not ask the
+user for a confirmation whether to format the floppy disk at
+.Ar device .
+.It Fl v
+Do not format, verify only.
+.It Fl y
+Do not ask for confirmation whether to format the floppy disk but
+still report formatting status.
+.El
+.Pp
+If the
+.Fl q
+flag has not been specified, the user is asked for a confirmation
+of the intended formatting process.
+In order to continue, an answer
+of
+.Ql y
+must be given.
+.Pp
+Note that
+.Nm
+only performs low-level formatting.
+In order to create
+a file system on the medium, see the commands
+.Xr newfs 8
+for a
+.Tn UFS
+file system, or
+.Xr newfs_msdos 8
+for an
+.Tn MS-DOS
+(FAT)
+file system.
+.Sh DIAGNOSTICS
+Unless
+.Fl q
+has been specified, a single letter is printed to standard output
+to inform the user about the progress of work.
+First, an
+.Ql F
+is printed when the track is being formatted, then a
+.Ql V
+while it is being verified, and if an error has been detected, it
+will finally change to
+.Ql E .
+Detailed status information (cylinder, head and sector number, and the
+exact cause of the error) will be printed for up to 10 errors after the
+entire formatting process has completed.
+.Pp
+An exit status of 0 is returned upon successful operation.
+Exit status
+1 is returned on any errors during floppy formatting, and an exit status
+of 2 reflects invalid arguments given to the program (along with an
+appropriate information written to diagnostic output).
+.Sh SEE ALSO
+.Xr fdformat 1 ,
+.Xr fdcontrol 8 ,
+.Xr umass 4 ,
+.Xr newfs 8 ,
+.Xr newfs_msdos 8
+.Rs
+.%T UFI Command Specification
+.%Q "USB Implementers Forum, Inc."
+.%N "Revision 1.0"
+.%D "December 1998"
+.Re
+.Sh HISTORY
+The
+.Nm
+utility
+first appeared in
+.Fx 6.0 .
+.Sh AUTHORS
+.An -nosplit
+The program has been contributed by
+.An Bruce M. Simpson .
Index: usr.sbin/ufdformat/ufdformat.c
===================================================================
--- usr.sbin/ufdformat/ufdformat.c
+++ usr.sbin/ufdformat/ufdformat.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2004 by Bruce M. Simpson.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stdint.h>
+#include <sys/ioctl.h>
+#include <sys/fdcio.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <sysexits.h>
+
+#include <cam/cam.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_ccb.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_da.h>
+#include <cam/scsi/scsi_pass.h>
+#include <cam/scsi/scsi_message.h>
+#include <camlib.h>
+
+#include "scsi_util.h"
+
+#define SIMULATED_FORMAT_DELAY (200 * 1000) /* 0.2 seconds per cyl/side */
+#define MAXPRINTERRS 10
+#define UFI_MODE_SENSE_LEN 10
+#define UFI_MODE_SENSE_TIMEOUT 5
+
+static int
+cvtnum(const char *strng)
+{
+ /* cses */
+ char *endp;
+
+ errno = 0;
+ long longnum = strtoul(strng, &endp, 0);
+ if (strng == endp || *endp != '\0' || errno == ERANGE)
+ return (-1);
+
+ return ((int)longnum);
+}
+
+static void
+usage(void)
+{
+
+ errx(EX_USAGE, "usage: ufdformat [-f fmt] [-nqvy] device");
+}
+
+static int
+yes(void)
+{
+ char reply[256], *p;
+
+ reply[sizeof(reply) - 1] = 0;
+ for (;;) {
+ fflush(stdout);
+ if (!fgets(reply, sizeof(reply) - 1, stdin))
+ return (0);
+ for (p = reply; *p == ' ' || *p == '\t'; ++p)
+ continue;
+ if (*p == 'y' || *p == 'Y')
+ return (1);
+ if (*p == 'n' || *p == 'N' || *p == '\n' || *p == '\r')
+ return (0);
+ printf("Answer `yes' or `no': ");
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ char driver[DEV_IDLEN+1];
+ union ccb *ccb;
+ struct supported_format_descriptors sfds;
+ struct fd_type fdt;
+ struct cam_device *cam_dev;
+ struct scsi_inquiry_data *inq_buf;
+ struct flexible_disk_page *flexpage;
+ int min_mode_cmd_size, min_cmd_timeout;
+ int unit;
+ int format, quiet, verify, verify_only, confirm;
+ int /*fd,*/ c, i, track, error, tracks_per_dot, bytes_per_track, errs;
+ char *devname;
+
+ min_mode_cmd_size = UFI_MODE_SENSE_LEN;
+ min_cmd_timeout = UFI_MODE_SENSE_TIMEOUT;
+ format = quiet = verify_only = confirm = 0;
+ verify = 1;
+
+ while ((c = getopt(argc, argv, "f:nqs:vy")) != -1)
+ switch (c) {
+ case 'f': /* format in kilobytes */
+ if ((format = cvtnum(optarg)) < 0) {
+ fprintf(stderr,
+ "Bad argument %s to -f option; must be numeric\n",
+ optarg);
+ usage();
+ }
+ break;
+
+ case 'n': /* don't verify */
+ verify = 0;
+ break;
+
+ case 'q': /* quiet */
+ quiet = 1;
+ break;
+
+ case 'v': /* verify only */
+ verify = 1;
+ verify_only = 1;
+ break;
+
+ case 'y': /* confirm */
+ confirm = 1;
+ break;
+
+ default:
+ usage();
+ }
+
+ if (optind != argc - 1)
+ usage();
+
+ devname = argv[optind];
+
+ if (cam_get_device(devname, driver, sizeof(driver), &unit) == -1)
+ errx(EX_OSERR, "%s", cam_errbuf);
+
+ if ((cam_dev =
+ cam_open_spec_device(driver, unit, O_RDWR, NULL)) == NULL)
+ errx(EX_OSERR, "cannot open scsi device %s%d", driver, unit);
+
+ /*
+ * Check to see if the device is a removable direct-access
+ * device. If it is not, reject it, and exit.
+ */
+ inq_buf = (struct scsi_inquiry_data *)malloc(
+ sizeof(struct scsi_inquiry_data));
+ error = scsi_get_inquiry(cam_dev, 0, min_cmd_timeout, inq_buf);
+ if (error != 0)
+ errx(EX_OSERR, "error during scsi inquiry");
+ if (SID_TYPE(inq_buf) != T_DIRECT || !SID_IS_REMOVABLE(inq_buf)) {
+ free(inq_buf);
+ errx(EX_OSERR,
+ "device %s%d is not a removable direct-access device",
+ driver, unit);
+ }
+ free(inq_buf);
+
+ /*
+ * Check to see if the device responds to MODE SENSE requests
+ * for the Flexible Disk Page, in order to determine its geometry.
+ */
+ flexpage = malloc(SMS_FLEXIBLE_GEOMETRY_PLEN);
+ error = scsi_get_flexible_disk_page(cam_dev, flexpage,
+ min_mode_cmd_size, min_cmd_timeout);
+ if (error != 0)
+ errx(EX_OSERR, "error during scsi mode sense");
+ if (flexpage->pg_code != SMS_FLEXIBLE_GEOMETRY_PAGE ||
+ flexpage->pg_length != SMS_FLEXIBLE_GEOMETRY_PLEN) {
+ free(flexpage);
+ errx(EX_OSERR,
+ "device %s%d returned an invalid flexible geometry page",
+ driver, unit);
+ }
+
+ /* Obtain supported disk formats. */
+ error = scsi_get_format_capacities(cam_dev, 0, min_cmd_timeout,
+ (u_int8_t *)&sfds, sizeof(sfds));
+ if (error != 0)
+ errx(EX_OSERR, "error reading format capacity list");
+
+ /*
+ * TODO: Determine how long it's going to take to format this disk.
+ * TODO: Stash the track geometry somewhere.
+ * scottl says converting to fdc style is ok.
+ * XXX: Should we just allocate flexpage on the stack or in bss?
+ */
+ dump_flexible_geometry(flexpage);
+ sfds_dump_supported_formats(&sfds);
+
+ /*
+ * Convert UFI floppy geometry to fdc(4) style geometry.
+ * This sort-of replaces the 'format choice' stuff from fdformat.
+ *
+ * TODO: Allow the user to select the format; right now we
+ * just use the current/maximum entry i.e. the first one.
+ */
+ floppy_geom_scsi_to_fdc(&fdt, flexpage, &sfds.fdcurrmax);
+ free(flexpage); /* XXX: We're not likely to be done with this... */
+
+ bytes_per_track = fdt.sectrac * (128 << fdt.secsize);
+
+ /* XXX 20/40 = 0.5 */
+ tracks_per_dot = (fdt.tracks * fdt.heads + 20) / 40;
+
+ if (verify_only) {
+ if (!quiet)
+ printf("Verify %dK floppy `%s%d'.\n",
+ fdt.tracks * fdt.heads * bytes_per_track / 1024,
+ driver, unit);
+ }
+ else if (!quiet && !confirm) {
+ printf ("Format %dK floppy `%s%d'? (y/n): ",
+ fdt.tracks * fdt.heads * bytes_per_track / 1024,
+ driver, unit);
+ if (!yes()) {
+ printf("Not confirmed.\n");
+ return (EX_UNAVAILABLE);
+ }
+ }
+
+ /* Format/verify loop. */
+ if (!quiet) {
+ printf("Processing ");
+ for (i = 0; i < (fdt.tracks * fdt.heads) / tracks_per_dot; i++)
+ putchar('-');
+ printf("\rProcessing ");
+ fflush(stdout);
+ }
+
+ error = errs = 0;
+
+ /* Grab things we need for a SCSI floppy format. */
+ ccb = cam_getccb(cam_dev);
+ if (ccb == NULL)
+ errx(EX_OSERR, "couldn't allocate CCB");
+
+ for (track = 0; track < fdt.tracks * fdt.heads; track++) {
+ if (!verify_only) {
+ (void)scsi_format_track(cam_dev, ccb,
+ min_cmd_timeout,
+ track / fdt.heads, track % fdt.heads,
+ &sfds.fdcurrmax);
+
+ if (!quiet && !((track + 1) % tracks_per_dot)) {
+ putchar('F');
+ fflush(stdout);
+ }
+ }
+ if (verify) {
+ if (scsi_verify_track(cam_dev, ccb, min_cmd_timeout,
+ track / fdt.heads, track % fdt.heads,
+ fdt.sectrac) < 0) {
+ /*
+ * XXX: Need a way of obtaining sense
+ * errors and printing them.
+ */
+ error = 1;
+ errs++;
+ }
+ if (!quiet && !((track + 1) % tracks_per_dot)) {
+ if (!verify_only)
+ putchar('\b');
+ if (error) {
+ putchar('E');
+ error = 0;
+ }
+ else
+ putchar('V');
+ fflush(stdout);
+ }
+ }
+ }
+ if (!quiet)
+ printf(" done.\n");
+
+ if (ccb)
+ cam_freeccb(ccb);
+
+ if (!quiet && errs) {
+ fflush(stdout);
+ if (errs >= MAXPRINTERRS)
+ fprintf(stderr, "(Further errors not printed.)\n");
+ }
+
+ return (errs != 0);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Feb 10, 12:08 AM (16 h, 32 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28607708
Default Alt Text
D13356.diff (34 KB)
Attached To
Mode
D13356: New ufdformat(1) utility
Attached
Detach File
Event Timeline
Log In to Comment