Page MenuHomeFreeBSD

D13356.diff
No OneTemporary

D13356.diff

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

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)

Event Timeline