svn commit: r237740 - stable/9/sbin/camcontrol

Scott Long scottl at FreeBSD.org
Fri Jun 29 03:37:24 UTC 2012


Author: scottl
Date: Fri Jun 29 03:37:23 2012
New Revision: 237740
URL: http://svn.freebsd.org/changeset/base/237740

Log:
  Merge the firmware download functionality into camcontrol, as well as
  several other minor code changes.
  
  Obtained from:	Netflix, Inc.

Added:
  stable/9/sbin/camcontrol/fwdownload.c
     - copied, changed from r227961, head/sbin/camcontrol/fwdownload.c
  stable/9/sbin/camcontrol/progress.c
     - copied unchanged from r237285, head/sbin/camcontrol/progress.c
  stable/9/sbin/camcontrol/progress.h
     - copied unchanged from r237285, head/sbin/camcontrol/progress.h
Modified:
  stable/9/sbin/camcontrol/Makefile
  stable/9/sbin/camcontrol/camcontrol.8
  stable/9/sbin/camcontrol/camcontrol.c
  stable/9/sbin/camcontrol/camcontrol.h
  stable/9/sbin/camcontrol/modeedit.c
  stable/9/sbin/camcontrol/util.c
Directory Properties:
  stable/9/sbin/camcontrol/   (props changed)

Modified: stable/9/sbin/camcontrol/Makefile
==============================================================================
--- stable/9/sbin/camcontrol/Makefile	Fri Jun 29 03:03:42 2012	(r237739)
+++ stable/9/sbin/camcontrol/Makefile	Fri Jun 29 03:37:23 2012	(r237740)
@@ -3,7 +3,7 @@
 PROG=	camcontrol
 SRCS=	camcontrol.c util.c
 .if !defined(RELEASE_CRUNCH)
-SRCS+=	modeedit.c
+SRCS+=	fwdownload.c modeedit.c progress.c
 .else
 CFLAGS+= -DMINIMALISTIC
 .endif

Modified: stable/9/sbin/camcontrol/camcontrol.8
==============================================================================
--- stable/9/sbin/camcontrol/camcontrol.8	Fri Jun 29 03:03:42 2012	(r237739)
+++ stable/9/sbin/camcontrol/camcontrol.8	Fri Jun 29 03:37:23 2012	(r237740)
@@ -221,6 +221,13 @@
 .Op device id
 .Op generic args
 .Nm
+.Ic fwdownload
+.Op device id
+.Op generic args
+.Aq Fl f Ar fw_image
+.Op Fl y
+.Op Fl s
+.Nm
 .Ic help
 .Sh DESCRIPTION
 The
@@ -1063,6 +1070,54 @@ specifies automatic standby timer value 
 .It Ic sleep
 Put ATA device into SLEEP state. Note that the only way get device out of
 this state may be reset.
+.It Ic fwdownload
+Program firmware of the named SCSI device using the image file provided.
+.Pp
+Current list of supported vendors:
+.Bl -bullet -offset indent -compact
+.It
+HITACHI
+.It
+HP
+.It
+IBM
+.It
+PLEXTOR
+.It
+QUANTUM
+.It
+SEAGATE
+.El
+.Pp
+.Em WARNING! WARNING! WARNING!
+.Pp
+Little testing has been done to make sure that different device models from
+each vendor work correctly with the fwdownload command.
+A vendor name appearing in the supported list means only that firmware of at
+least one device type from that vendor has successfully been programmed with
+the fwdownload command.
+Extra caution should be taken when using this command since there is no
+guarantee it will not break a device from the listed vendors.
+Ensure that you have a recent backup of the data on the device before
+performing a firmware update.
+.Bl -tag -width 11n
+.It Fl f Ar fw_image
+Path to the firmware image file to be downloaded to the specified device.
+.It Fl y
+Do not ask for confirmation.
+.It Fl s
+Run in simulation mode.
+Packet sizes that will be sent are shown, but no actual packet is sent to the
+device.
+No confimation is asked in simulation mode.
+.It Fl v
+Besides showing sense information in case of a failure, the verbose option
+causes
+.Nm
+to output a line for every firmware segment that is sent to the device by the
+fwdownload command
+-- the same as the ones shown in simulation mode.
+.El
 .It Ic help
 Print out verbose usage information.
 .El
@@ -1176,7 +1231,6 @@ camcontrol negotiate -n da -u 3 -R 20.00
 Negotiate a sync rate of 20MHz and an offset of 15 with da3.
 Then send a
 Test Unit Ready command to make the settings take effect.
-.Pp
 .Bd -literal -offset indent
 camcontrol smpcmd ses0 -v -r 4 "40 0 00 0" -R 1020 "s9 i1"
 .Ed

Modified: stable/9/sbin/camcontrol/camcontrol.c
==============================================================================
--- stable/9/sbin/camcontrol/camcontrol.c	Fri Jun 29 03:03:42 2012	(r237739)
+++ stable/9/sbin/camcontrol/camcontrol.c	Fri Jun 29 03:37:23 2012	(r237740)
@@ -86,7 +86,8 @@ typedef enum {
 	CAM_CMD_SMP_RG		= 0x00000018,
 	CAM_CMD_SMP_PC		= 0x00000019,
 	CAM_CMD_SMP_PHYLIST	= 0x0000001a,
-	CAM_CMD_SMP_MANINFO	= 0x0000001b
+	CAM_CMD_SMP_MANINFO	= 0x0000001b,
+	CAM_CMD_DOWNLOAD_FW	= 0x0000001c
 } cam_cmdmask;
 
 typedef enum {
@@ -181,6 +182,7 @@ struct camcontrol_opts option_table[] = 
 	{"idle", CAM_CMD_IDLE, CAM_ARG_NONE, "t:"},
 	{"standby", CAM_CMD_STANDBY, CAM_ARG_NONE, "t:"},
 	{"sleep", CAM_CMD_SLEEP, CAM_ARG_NONE, ""},
+	{"fwdownload", CAM_CMD_DOWNLOAD_FW, CAM_ARG_NONE, "f:ys"},
 #endif /* MINIMALISTIC */
 	{"help", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
 	{"-?", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
@@ -223,8 +225,6 @@ static int testunitready(struct cam_devi
 			 int timeout, int quiet);
 static int scsistart(struct cam_device *device, int startstop, int loadeject,
 		     int retry_count, int timeout);
-static int scsidoinquiry(struct cam_device *device, int argc, char **argv,
-			 char *combinedopt, int retry_count, int timeout);
 static int scsiinquiry(struct cam_device *device, int retry_count, int timeout);
 static int scsiserial(struct cam_device *device, int retry_count, int timeout);
 static int camxferrate(struct cam_device *device);
@@ -703,7 +703,7 @@ scsistart(struct cam_device *device, int
 	return(error);
 }
 
-static int
+int
 scsidoinquiry(struct cam_device *device, int argc, char **argv,
 	      char *combinedopt, int retry_count, int timeout)
 {
@@ -3071,6 +3071,26 @@ get_cgd_bailout:
 	return(retval);
 }
 
+/* return the type of disk (really the command type) */
+static const char *
+get_disk_type(struct cam_device *device)
+{
+	struct ccb_getdev	cgd;
+
+	(void) memset(&cgd, 0x0, sizeof(cgd));
+	get_cgd(device, &cgd);
+	switch(cgd.protocol) {
+	case PROTO_SCSI:
+		return "scsi";
+	case PROTO_ATA:
+	case PROTO_ATAPI:
+	case PROTO_SATAPM:
+		return "ata";
+	default:
+		return "unknown";
+	}
+}
+
 static void
 cpi_print(struct ccb_pathinq *cpi)
 {
@@ -3644,7 +3664,7 @@ scsiformat(struct cam_device *device, in
 	union ccb *ccb;
 	int c;
 	int ycount = 0, quiet = 0;
-	int error = 0, response = 0, retval = 0;
+	int error = 0, retval = 0;
 	int use_timeout = 10800 * 1000;
 	int immediate = 1;
 	struct format_defect_list_header fh;
@@ -3698,27 +3718,7 @@ scsiformat(struct cam_device *device, in
 	}
 
 	if (ycount == 0) {
-
-		do {
-			char str[1024];
-
-			fprintf(stdout, "Are you SURE you want to do "
-				"this? (yes/no) ");
-
-			if (fgets(str, sizeof(str), stdin) != NULL) {
-
-				if (strncasecmp(str, "yes", 3) == 0)
-					response = 1;
-				else if (strncasecmp(str, "no", 2) == 0)
-					response = -1;
-				else {
-					fprintf(stdout, "Please answer"
-						" \"yes\" or \"no\"\n");
-				}
-			}
-		} while (response == 0);
-
-		if (response == -1) {
+		if (!get_confirmation()) {
 			error = 1;
 			goto scsiformat_bailout;
 		}
@@ -5765,6 +5765,7 @@ usage(int verbose)
 "        camcontrol idle       [dev_id][generic args][-t time]\n"
 "        camcontrol standby    [dev_id][generic args][-t time]\n"
 "        camcontrol sleep      [dev_id][generic args]\n"
+"        camcontrol fwdownload [dev_id][generic args] <-f fw_image> [-y][-s]\n"
 #endif /* MINIMALISTIC */
 "        camcontrol help\n");
 	if (!verbose)
@@ -5800,6 +5801,7 @@ usage(int verbose)
 "idle        send the ATA IDLE command to the named device\n"
 "standby     send the ATA STANDBY command to the named device\n"
 "sleep       send the ATA SLEEP command to the named device\n"
+"fwdownload  program firmware of the named device with the given image"
 "help        this message\n"
 "Device Identifiers:\n"
 "bus:target        specify the bus and target, lun defaults to 0\n"
@@ -5891,7 +5893,12 @@ usage(int verbose)
 "-w                don't send immediate format command\n"
 "-y                don't ask any questions\n"
 "idle/standby arguments:\n"
-"-t <arg>          number of seconds before respective state.\n");
+"-t <arg>          number of seconds before respective state.\n"
+"fwdownload arguments:\n"
+"-f fw_image       path to firmware image file\n"
+"-y                don't ask any questions\n"
+"-s                run in simulation mode\n"
+"-v                print info for every firmware segment sent to device\n");
 #endif /* MINIMALISTIC */
 }
 
@@ -6207,6 +6214,11 @@ main(int argc, char **argv)
 						 combinedopt, retry_count,
 						 timeout);
 			break;
+		case CAM_CMD_DOWNLOAD_FW:
+			error = fwdownload(cam_dev, argc, argv, combinedopt,
+			    arglist & CAM_ARG_VERBOSE, retry_count, timeout,
+			    get_disk_type(cam_dev));
+			break;
 #endif /* MINIMALISTIC */
 		case CAM_CMD_USAGE:
 			usage(1);

Modified: stable/9/sbin/camcontrol/camcontrol.h
==============================================================================
--- stable/9/sbin/camcontrol/camcontrol.h	Fri Jun 29 03:03:42 2012	(r237739)
+++ stable/9/sbin/camcontrol/camcontrol.h	Fri Jun 29 03:37:23 2012	(r237740)
@@ -40,6 +40,9 @@ struct get_hook
 	int got;
 };
 
+int fwdownload(struct cam_device *device, int argc, char **argv,
+	       char *combinedopt, int verbose, int retry_count, int timeout,
+	       const char */*type*/);
 void 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);
@@ -49,8 +52,11 @@ void mode_edit(struct cam_device *device
 	       int edit, int binary, int retry_count, int timeout);
 void mode_list(struct cam_device *device, int page_control, int dbd,
 	       int retry_count, int timeout);
+int scsidoinquiry(struct cam_device *device, int argc, char **argv,
+		  char *combinedopt, int retry_count, int timeout);
 char *cget(void *hook, char *name);
 int iget(void *hook, char *name);
 void arg_put(void *hook, int letter, void *arg, int count, char *name);
+int get_confirmation(void);
 void usage(int verbose);
 #endif /* _CAMCONTROL_H */

Copied and modified: stable/9/sbin/camcontrol/fwdownload.c (from r227961, head/sbin/camcontrol/fwdownload.c)
==============================================================================
--- head/sbin/camcontrol/fwdownload.c	Fri Nov 25 04:03:37 2011	(r227961, copy source)
+++ stable/9/sbin/camcontrol/fwdownload.c	Fri Jun 29 03:37:23 2012	(r237740)
@@ -26,6 +26,15 @@
  */
 
 /*
+ * This software is derived from Andre Albsmeier's fwprog.c which contained
+ * the following note:
+ *
+ * Many thanks goes to Marc Frajola <marc at terasolutions.com> from
+ * TeraSolutions for the initial idea and his programme for upgrading
+ * the firmware of I*M DDYS drives.
+ */
+
+/*
  * BEWARE:
  *
  * The fact that you see your favorite vendor listed below does not
@@ -55,6 +64,8 @@ __FBSDID("$FreeBSD$");
 #include <cam/scsi/scsi_message.h>
 #include <camlib.h>
 
+#include "progress.h"
+
 #include "camcontrol.h"
 
 #define	CMD_TIMEOUT 50000	/* 50 seconds */
@@ -64,6 +75,7 @@ typedef enum {
 	VENDOR_HP,
 	VENDOR_IBM,
 	VENDOR_PLEXTOR,
+	VENDOR_QUALSTAR,
 	VENDOR_QUANTUM,
 	VENDOR_SEAGATE,
 	VENDOR_UNKNOWN
@@ -79,32 +91,58 @@ struct fw_vendor {
 	int inc_cdb_offset;
 };
 
-struct fw_vendor vendors_list[] = {
+static const struct fw_vendor vendors_list[] = {
 	{VENDOR_HITACHI,	"HITACHI",	0x8000, 0x05, 0x05, 1, 0},
 	{VENDOR_HP,		"HP",		0x8000, 0x07, 0x07, 0, 1},
 	{VENDOR_IBM,		"IBM",		0x8000, 0x05, 0x05, 1, 0},
 	{VENDOR_PLEXTOR,	"PLEXTOR",	0x2000, 0x04, 0x05, 0, 1},
+	{VENDOR_QUALSTAR,	"QUALSTAR",	0x2030, 0x05, 0x05, 0, 0},
 	{VENDOR_QUANTUM,	"QUANTUM",	0x2000, 0x04, 0x05, 0, 1},
 	{VENDOR_SEAGATE,	"SEAGATE",	0x8000, 0x07, 0x07, 0, 1},
+	/* the next 2 are SATA disks going through SAS HBA */
+	{VENDOR_SEAGATE,	"ATA ST",	0x8000, 0x07, 0x07, 0, 1},
+	{VENDOR_HITACHI,	"ATA HDS",	0x8000, 0x05, 0x05, 1, 0},
 	{VENDOR_UNKNOWN,	NULL,		0x0000, 0x00, 0x00, 0, 0}
 };
 
-static struct fw_vendor *fw_get_vendor(struct cam_device *cam_dev);
-static char	*fw_read_img(char *fw_img_path, struct fw_vendor *vp,
-		    int *num_bytes);
+#ifndef ATA_DOWNLOAD_MICROCODE
+#define ATA_DOWNLOAD_MICROCODE	0x92
+#endif
+
+#define USE_OFFSETS_FEATURE	0x3
+
+#ifndef LOW_SECTOR_SIZE
+#define LOW_SECTOR_SIZE		512
+#endif
+
+#define ATA_MAKE_LBA(o, p)	\
+	((((((o) / LOW_SECTOR_SIZE) >> 8) & 0xff) << 16) | \
+	  ((((o) / LOW_SECTOR_SIZE) & 0xff) << 8) | \
+	  ((((p) / LOW_SECTOR_SIZE) >> 8) & 0xff))
+
+#define ATA_MAKE_SECTORS(p)	(((p) / 512) & 0xff)
+
+#ifndef UNKNOWN_MAX_PKT_SIZE
+#define UNKNOWN_MAX_PKT_SIZE	0x8000
+#endif
+
+static const struct fw_vendor *fw_get_vendor(struct cam_device *cam_dev);
+static char	*fw_read_img(const char *fw_img_path,
+		    const struct fw_vendor *vp, int *num_bytes);
 static int	 fw_download_img(struct cam_device *cam_dev,
-		    struct fw_vendor *vp, char *buf, int img_size,
-		    int sim_mode, int verbose, int retry_count, int timeout);
+		    const struct fw_vendor *vp, char *buf, int img_size,
+		    int sim_mode, int verbose, int retry_count, int timeout,
+		    const char */*name*/, const char */*type*/);
 
 /*
  * Find entry in vendors list that belongs to
  * the vendor of given cam device.
  */
-static struct fw_vendor *
+static const struct fw_vendor *
 fw_get_vendor(struct cam_device *cam_dev)
 {
 	char vendor[SID_VENDOR_SIZE + 1];
-	struct fw_vendor *vp;
+	const struct fw_vendor *vp;
 
 	if (cam_dev == NULL)
 		return (NULL);
@@ -124,7 +162,7 @@ fw_get_vendor(struct cam_device *cam_dev
  * in num_bytes.
  */
 static char *
-fw_read_img(char *fw_img_path, struct fw_vendor *vp, int *num_bytes)
+fw_read_img(const char *fw_img_path, const struct fw_vendor *vp, int *num_bytes)
 {
 	int fd;
 	struct stat stbuf;
@@ -164,6 +202,9 @@ fw_read_img(char *fw_img_path, struct fw
 		    (img_size % 512 == 80))
 			skip_bytes = 80;
 		break;
+	case VENDOR_QUALSTAR:
+		skip_bytes = img_size % 1030;
+		break;
 	default:
 		break;
 	}
@@ -196,28 +237,59 @@ bailout1:
  * device but do not sent any actual packets
  */
 static int
-fw_download_img(struct cam_device *cam_dev, struct fw_vendor *vp,
+fw_download_img(struct cam_device *cam_dev, const struct fw_vendor *vp,
     char *buf, int img_size, int sim_mode, int verbose, int retry_count,
-    int timeout)
+    int timeout, const char *imgname, const char *type)
 {
 	struct scsi_write_buffer cdb;
+	progress_t progress;
+	int size;
 	union ccb *ccb;
 	int pkt_count = 0;
+	int max_pkt_size;
 	u_int32_t pkt_size = 0;
 	char *pkt_ptr = buf;
 	u_int32_t offset;
 	int last_pkt = 0;
+	int16_t *ptr;
 
 	if ((ccb = cam_getccb(cam_dev)) == NULL) {
 		warnx("Could not allocate CCB");
 		return (1);
 	}
-	scsi_test_unit_ready(&ccb->csio, 0, NULL, MSG_SIMPLE_Q_TAG,
-	    SSD_FULL_SIZE, 5000);
+	if (strcmp(type, "scsi") == 0) {
+		scsi_test_unit_ready(&ccb->csio, 0, NULL, MSG_SIMPLE_Q_TAG,
+		    SSD_FULL_SIZE, 5000);
+	} else if (strcmp(type, "ata") == 0) {
+		/* cam_getccb cleans up the header, caller has to zero the payload */
+		bzero(&(&ccb->ccb_h)[1],
+		      sizeof(struct ccb_ataio) - sizeof(struct ccb_hdr));
+
+		ptr = (uint16_t *)malloc(sizeof(struct ata_params));
+
+		if (ptr == NULL) {
+			cam_freeccb(ccb);
+			warnx("can't malloc memory for identify\n");
+			return(1);
+		}
+		bzero(ptr, sizeof(struct ata_params));
+		cam_fill_ataio(&ccb->ataio,
+                      1,
+                      NULL,
+                      /*flags*/CAM_DIR_IN,
+                      MSG_SIMPLE_Q_TAG,
+                      /*data_ptr*/(uint8_t *)ptr,
+                      /*dxfer_len*/sizeof(struct ata_params),
+                      timeout ? timeout : 30 * 1000);
+		ata_28bit_cmd(&ccb->ataio, ATA_ATA_IDENTIFY, 0, 0, 0);
+	} else {
+		warnx("weird disk type '%s'", type);
+		return 1;
+	}
 	/* Disable freezing the device queue. */
 	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
 	if (cam_send_ccb(cam_dev, ccb) < 0) {
-		warnx("Error sending test unit ready");
+		warnx("Error sending identify/test unit ready");
 		if (verbose)
 			cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
 			    CAM_EPF_ALL, stderr);
@@ -232,85 +304,104 @@ fw_download_img(struct cam_device *cam_d
 		cam_freeccb(ccb);
 		return (1);
 	}
-	pkt_size = vp->max_pkt_size;
-	if (verbose || sim_mode) {
-		fprintf(stdout,
-		    "--------------------------------------------------\n");
-		fprintf(stdout,
-		    "PktNo.	PktSize	       BytesRemaining	LastPkt\n");
-		fprintf(stdout,
-		    "--------------------------------------------------\n");
+	max_pkt_size = vp->max_pkt_size;
+	if (vp->max_pkt_size == 0 && strcmp(type, "ata") == 0) {
+		max_pkt_size = UNKNOWN_MAX_PKT_SIZE;
 	}
+	pkt_size = vp->max_pkt_size;
+	progress_init(&progress, imgname, size = img_size);
 	/* Download single fw packets. */
 	do {
-		if (img_size <= vp->max_pkt_size) {
+		if (img_size <= max_pkt_size) {
 			last_pkt = 1;
 			pkt_size = img_size;
 		}
-		if (verbose || sim_mode)
-			fprintf(stdout, "%3u   %5u (0x%05X)   %7u (0x%06X)   "
-			    "%d\n", pkt_count, pkt_size, pkt_size,
-			    img_size - pkt_size, img_size - pkt_size,
-			    last_pkt);
+		progress_update(&progress, size - img_size);
+		progress_draw(&progress);
 		bzero(&cdb, sizeof(cdb));
-		cdb.opcode  = WRITE_BUFFER;
-		cdb.control = 0;
-		/* Parameter list length. */
-		scsi_ulto3b(pkt_size, &cdb.length[0]);
-		offset = vp->inc_cdb_offset ? (pkt_ptr - buf) : 0;
-		scsi_ulto3b(offset, &cdb.offset[0]);
-		cdb.byte2 = last_pkt ? vp->cdb_byte2_last : vp->cdb_byte2;
-		cdb.buffer_id = vp->inc_cdb_buffer_id ? pkt_count : 0;
-		/* Zero out payload of ccb union after ccb header. */
-		bzero((u_char *)ccb + sizeof(struct ccb_hdr),
-		    sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
-		/* Copy previously constructed cdb into ccb_scsiio struct. */
-		bcopy(&cdb, &ccb->csio.cdb_io.cdb_bytes[0],
-		    sizeof(struct scsi_write_buffer));
-		/* Fill rest of ccb_scsiio struct. */
+		if (strcmp(type, "scsi") == 0) {
+			cdb.opcode  = WRITE_BUFFER;
+			cdb.control = 0;
+			/* Parameter list length. */
+			scsi_ulto3b(pkt_size, &cdb.length[0]);
+			offset = vp->inc_cdb_offset ? (pkt_ptr - buf) : 0;
+			scsi_ulto3b(offset, &cdb.offset[0]);
+			cdb.byte2 = last_pkt ? vp->cdb_byte2_last : vp->cdb_byte2;
+			cdb.buffer_id = vp->inc_cdb_buffer_id ? pkt_count : 0;
+			/* Zero out payload of ccb union after ccb header. */
+			bzero((u_char *)ccb + sizeof(struct ccb_hdr),
+			    sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
+			/* Copy previously constructed cdb into ccb_scsiio struct. */
+			bcopy(&cdb, &ccb->csio.cdb_io.cdb_bytes[0],
+			    sizeof(struct scsi_write_buffer));
+			/* Fill rest of ccb_scsiio struct. */
+			if (!sim_mode) {
+				cam_fill_csio(&ccb->csio,		/* ccb_scsiio	*/
+				    retry_count,			/* retries	*/
+				    NULL,				/* cbfcnp	*/
+				    CAM_DIR_OUT | CAM_DEV_QFRZDIS,	/* flags	*/
+				    CAM_TAG_ACTION_NONE,		/* tag_action	*/
+				    (u_char *)pkt_ptr,			/* data_ptr	*/
+				    pkt_size,				/* dxfer_len	*/
+				    SSD_FULL_SIZE,			/* sense_len	*/
+				    sizeof(struct scsi_write_buffer),	/* cdb_len	*/
+				    timeout ? timeout : CMD_TIMEOUT);	/* timeout	*/
+			}
+		} else if (strcmp(type, "ata") == 0) {
+			bzero(&(&ccb->ccb_h)[1],
+			      sizeof(struct ccb_ataio) - sizeof(struct ccb_hdr));
+			if (!sim_mode) {
+				uint32_t	off;
+
+				cam_fill_ataio(&ccb->ataio,
+					(last_pkt) ? 256 : retry_count,
+					NULL,
+					/*flags*/CAM_DIR_OUT | CAM_DEV_QFRZDIS,
+					CAM_TAG_ACTION_NONE,
+					/*data_ptr*/(uint8_t *)pkt_ptr,
+					/*dxfer_len*/pkt_size,
+					timeout ? timeout : 30 * 1000);
+				off = (uint32_t)(pkt_ptr - buf);
+				ata_28bit_cmd(&ccb->ataio, ATA_DOWNLOAD_MICROCODE,
+					USE_OFFSETS_FEATURE,
+					ATA_MAKE_LBA(off, pkt_size),
+					ATA_MAKE_SECTORS(pkt_size));
+			}
+		}
 		if (!sim_mode) {
-			cam_fill_csio(&ccb->csio,		/* ccb_scsiio	*/
-			    retry_count,			/* retries	*/
-			    NULL,				/* cbfcnp	*/
-			    CAM_DIR_OUT | CAM_DEV_QFRZDIS,	/* flags	*/
-			    CAM_TAG_ACTION_NONE,		/* tag_action	*/
-			    (u_char *)pkt_ptr,			/* data_ptr	*/
-			    pkt_size,				/* dxfer_len	*/
-			    SSD_FULL_SIZE,			/* sense_len	*/
-			    sizeof(struct scsi_write_buffer),	/* cdb_len	*/
-			    timeout ? timeout : CMD_TIMEOUT);	/* timeout	*/
 			/* Execute the command. */
 			if (cam_send_ccb(cam_dev, ccb) < 0) {
 				warnx("Error writing image to device");
 				if (verbose)
 					cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
-					    CAM_EPF_ALL, stderr);
+						   CAM_EPF_ALL, stderr);
 				goto bailout;
 			}
+			if (ccb->ataio.res.status != 0 /*&& !last_pkt*/) {
+				cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
+					   CAM_EPF_ALL, stderr);
+			}
 		}
 		/* Prepare next round. */
 		pkt_count++;
 		pkt_ptr += pkt_size;
 		img_size -= pkt_size;
 	} while(!last_pkt);
-	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
-		if (verbose)
-			cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
-			    CAM_EPF_ALL, stderr);
-		goto bailout;
-	}
+	progress_complete(&progress, size - img_size);
 	cam_freeccb(ccb);
 	return (0);
 bailout:
+	progress_complete(&progress, size - img_size);
 	cam_freeccb(ccb);
 	return (1);
 }
 
 int
 fwdownload(struct cam_device *device, int argc, char **argv,
-    char *combinedopt, int verbose, int retry_count, int timeout)
+    char *combinedopt, int verbose, int retry_count, int timeout,
+    const char *type)
 {
-	struct fw_vendor *vp;
+	const struct fw_vendor *vp;
 	char *fw_img_path = NULL;
 	char *buf;
 	int img_size;
@@ -336,12 +427,13 @@ fwdownload(struct cam_device *device, in
 	}
 
 	if (fw_img_path == NULL)
-		errx(1,
-		    "you must specify a firmware image file using -f option");
+		errx(1, "you must specify a firmware image file using -f option");
 
 	vp = fw_get_vendor(device);
-	if (vp == NULL || vp->type == VENDOR_UNKNOWN)
-		errx(1, "Unsupported device");
+	if (vp == NULL)
+		errx(1, "NULL vendor");
+	if (vp->type == VENDOR_UNKNOWN)
+		warnx("Unsupported device - flashing through an HBA?");
 
 	buf = fw_read_img(fw_img_path, vp, &img_size);
 	if (buf == NULL)
@@ -351,11 +443,6 @@ fwdownload(struct cam_device *device, in
 		fprintf(stdout, "You are about to download firmware image (%s)"
 		    " into the following device:\n",
 		    fw_img_path);
-		if (scsidoinquiry(device, argc, argv, combinedopt, 0,
-		    5000) != 0) {
-			warnx("Error sending inquiry");
-			goto fail;
-		}
 		fprintf(stdout, "\nIt may damage your drive. ");
 		if (!get_confirmation())
 			goto fail;
@@ -364,10 +451,11 @@ fwdownload(struct cam_device *device, in
 		fprintf(stdout, "Running in simulation mode\n");
 
 	if (fw_download_img(device, vp, buf, img_size, sim_mode, verbose,
-	    retry_count, timeout) != 0) {
+	    retry_count, timeout, fw_img_path, type) != 0) {
 		fprintf(stderr, "Firmware download failed\n");
 		goto fail;
-	} else 
+	}
+	else 
 		fprintf(stdout, "Firmware download successful\n");
 
 	free(buf);

Modified: stable/9/sbin/camcontrol/modeedit.c
==============================================================================
--- stable/9/sbin/camcontrol/modeedit.c	Fri Jun 29 03:03:42 2012	(r237739)
+++ stable/9/sbin/camcontrol/modeedit.c	Fri Jun 29 03:37:23 2012	(r237740)
@@ -83,15 +83,15 @@ struct editentry {
 		char	*svalue;
 	} value;
 };
-STAILQ_HEAD(, editentry) editlist;	/* List of page entries. */
-int editlist_changed = 0;		/* Whether any entries were changed. */
+static STAILQ_HEAD(, editentry) editlist; /* List of page entries. */
+static int editlist_changed = 0;	/* Whether any entries were changed. */
 
 struct pagename {
 	SLIST_ENTRY(pagename) link;
 	int pagenum;
 	char *name;
 };
-SLIST_HEAD(, pagename) namelist;	/* Page number to name mappings. */
+static SLIST_HEAD(, pagename) namelist;	/* Page number to name mappings. */
 
 static char format[MAX_FORMAT_SPEC];	/* Buffer for scsi cdb format def. */
 

Copied: stable/9/sbin/camcontrol/progress.c (from r237285, head/sbin/camcontrol/progress.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/9/sbin/camcontrol/progress.c	Fri Jun 29 03:37:23 2012	(r237740, copy of r237285, head/sbin/camcontrol/progress.c)
@@ -0,0 +1,186 @@
+/*	$NetBSD: progressbar.c,v 1.21 2009/04/12 10:18:52 lukem Exp $	*/
+
+/*-
+ * Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "progress.h"
+
+static const char * const suffixes[] = {
+	"",	/* 2^0  (byte) */
+	"KiB",	/* 2^10 Kibibyte */
+	"MiB",	/* 2^20 Mebibyte */
+	"GiB",	/* 2^30 Gibibyte */
+	"TiB",	/* 2^40 Tebibyte */
+	"PiB",	/* 2^50 Pebibyte */
+	"EiB",	/* 2^60 Exbibyte */
+};
+
+#define NSUFFIXES	(sizeof(suffixes) / sizeof(suffixes[0]))
+#define SECSPERHOUR	(60 * 60)
+#define DEFAULT_TTYWIDTH	80
+
+/* initialise progress meter structure */
+int
+progress_init(progress_t *prog, const char *prefix, uint64_t total)
+{
+        struct winsize	winsize;
+        int		oerrno = errno;
+
+	(void) memset(prog, 0x0, sizeof(*prog));
+	prog->size = total;
+	prog->prefix = strdup(prefix);
+	prog->start = time(NULL);
+        if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) != -1 &&
+            winsize.ws_col != 0) {
+                prog->ttywidth = winsize.ws_col;
+        } else {
+                prog->ttywidth = DEFAULT_TTYWIDTH;
+	}
+        errno = oerrno;
+	return 1;
+}
+
+/* update the values in the progress meter */
+int
+progress_update(progress_t *prog, uint64_t done)
+{
+	prog->done = done;
+	prog->percent = (prog->done * 100) / prog->size;
+	prog->now = time(NULL);
+	prog->elapsed = prog->now - prog->start;
+	if (done == 0 || prog->elapsed == 0 || prog->done / prog->elapsed == 0) {
+		prog->eta = 0;
+	} else {
+		prog->eta = prog->size / (prog->done / prog->elapsed) - prog->elapsed;
+	}
+	return 1;
+}
+
+/* update the values in the progress meter */
+int
+progress_reset_size(progress_t *prog, uint64_t size)
+{
+	prog->size = size;
+	return 1;
+}
+
+/* make it look pretty at the end - display done bytes (usually total) */
+int
+progress_complete(progress_t *prog, uint64_t done)
+{
+	progress_update(prog, done);
+	progress_draw(prog);
+	printf("\n");
+	return 1;
+}
+
+/* draw the progress meter */
+int
+progress_draw(progress_t *prog)
+{
+#define	BAROVERHEAD	45		/* non `*' portion of progress bar */
+					/*
+					 * stars should contain at least
+					 * sizeof(buf) - BAROVERHEAD entries
+					 */
+	static const char	stars[] =
+"*****************************************************************************"
+"*****************************************************************************"
+"*****************************************************************************";
+	unsigned		bytesabbrev;
+	unsigned		bpsabbrev;
+	int64_t			secs;
+	uint64_t		bytespersec;
+	uint64_t		abbrevsize;
+	int64_t			secsleft;
+	size_t			barlength;
+	size_t			starc;
+	char			hours[12];
+	char			buf[256];
+	int			len;
+
+	barlength = MIN(sizeof(buf) - 1, (unsigned)prog->ttywidth) - BAROVERHEAD - strlen(prog->prefix);
+	starc = (barlength * prog->percent) / 100;
+	abbrevsize = prog->done;
+	for (bytesabbrev = 0; abbrevsize >= 100000 && bytesabbrev < NSUFFIXES; bytesabbrev++) {
+		abbrevsize >>= 10;
+	}
+	if (bytesabbrev == NSUFFIXES) {
+		bytesabbrev--;
+	}
+	bytespersec = 0;
+	if (prog->done > 0) {
+		bytespersec = prog->done;
+		if (prog->elapsed > 0) {
+			bytespersec /= prog->elapsed;
+		}
+	}
+	for (bpsabbrev = 1; bytespersec >= 1024000 && bpsabbrev < NSUFFIXES; bpsabbrev++) {
+		bytespersec >>= 10;
+	}
+	if (prog->done == 0 || prog->elapsed <= 0 || prog->done > prog->size) {
+		secsleft = 0;
+	} else {
+		secsleft = prog->eta;
+	}
+	if ((secs = secsleft / SECSPERHOUR) > 0) {
+		(void) snprintf(hours, sizeof(hours), "%2lld:", (long long)secs);
+	} else {
+		(void) snprintf(hours, sizeof(hours), "   ");
+	}
+	secs = secsleft % SECSPERHOUR;
+	len = snprintf(buf, sizeof(buf),
+		"\r%s %3lld%% |%.*s%*s| %5lld %-3s %3lld.%02d %.2sB/s %s%02d:%02d ETA",
+		(prog->prefix) ? prog->prefix : "",
+		(long long)prog->percent,
+		(int)starc, stars, (int)(barlength - starc), "",
+		(long long)abbrevsize,
+		suffixes[bytesabbrev],
+		(long long)(bytespersec / 1024),
+		(int)((bytespersec % 1024) * 100 / 1024),
+		suffixes[bpsabbrev],
+		hours,
+		(int)secs / 60, (int)secs % 60);
+	return (int)write(STDOUT_FILENO, buf, len);
+}

Copied: stable/9/sbin/camcontrol/progress.h (from r237285, head/sbin/camcontrol/progress.h)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/9/sbin/camcontrol/progress.h	Fri Jun 29 03:37:23 2012	(r237740, copy of r237285, head/sbin/camcontrol/progress.h)
@@ -0,0 +1,60 @@
+/*	$NetBSD: progressbar.c,v 1.21 2009/04/12 10:18:52 lukem Exp $	*/
+
+/*-
+ * Copyright (c) 1997-2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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 PROGRESS_H_
+#define PROGRESS_H_	20100228
+
+#include <sys/types.h>
+
+#include <inttypes.h>
+
+/* structure used to display a progress meter */
+typedef struct progress_t {
+	char		*prefix;	/* any prefix explanation */
+	uint64_t	 size;		/* total of bytes/units to be counted */
+	uint64_t	 done;		/* number of units counted to date */
+	uint64_t	 percent;	/* cache the percentage complete */
+	time_t		 start;		/* time we started this */
+	time_t		 now;		/* time now */
+	time_t		 eta;		/* estimated # of secs until completion */
+	int64_t		 elapsed;	/* cached # of elapsed seconds */
+	int32_t		 ttywidth;	/* width of tty in columns */
+} progress_t;
+
+int progress_init(progress_t */*meter*/, const char */*prefix*/, uint64_t /*size*/);
+int progress_update(progress_t */*meter*/, uint64_t /*done*/);
+int progress_draw(progress_t */*meter*/);
+int progress_reset_size(progress_t */*meter*/, uint64_t /*size*/);
+int progress_complete(progress_t */*meter*/, uint64_t /*done*/);
+
+#endif

Modified: stable/9/sbin/camcontrol/util.c
==============================================================================
--- stable/9/sbin/camcontrol/util.c	Fri Jun 29 03:03:42 2012	(r237739)
+++ stable/9/sbin/camcontrol/util.c	Fri Jun 29 03:37:23 2012	(r237740)
@@ -154,3 +154,31 @@ arg_put(void *hook __unused, int letter,
 	if (verbose)
 		putchar('\n');
 }
+
+/*
+ * Get confirmation from user
+ * Return values:
+ *    1: confirmed
+ *    0: unconfirmed
+ */
+int
+get_confirmation(void)
+{
+	char str[1024];
+	int response = -1;
+
+	do {
+		fprintf(stdout, "Are you SURE you want to do this? (yes/no) ");
+		if (fgets(str, sizeof(str), stdin) != NULL) {
+			if (strncasecmp(str, "yes", 3) == 0)
+				response = 1;
+			else if (strncasecmp(str, "no", 2) == 0)
+				response = 0;
+			else
+				fprintf(stdout,
+				    "Please answer \"yes\" or \"no\"\n");
+		} else
+			response = 0;
+	} while (response == -1);
+	return (response);
+}


More information about the svn-src-all mailing list