[Midnightbsd-cvs] src: sbin/camcontrol: update camcontrol

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Thu Nov 20 14:24:58 EST 2008


Log Message:
-----------
update camcontrol

Modified Files:
--------------
    src/sbin/camcontrol:
        Makefile (r1.1.1.1 -> r1.2)
        camcontrol.8 (r1.1.1.1 -> r1.2)
        camcontrol.c (r1.1.1.1 -> r1.2)
        camcontrol.h (r1.1.1.1 -> r1.2)
        modeedit.c (r1.1.1.1 -> r1.2)
        util.c (r1.1.1.1 -> r1.2)

-------------- next part --------------
Index: camcontrol.c
===================================================================
RCS file: /home/cvs/src/sbin/camcontrol/camcontrol.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/camcontrol/camcontrol.c -L sbin/camcontrol/camcontrol.c -u -r1.1.1.1 -r1.2
--- sbin/camcontrol/camcontrol.c
+++ sbin/camcontrol/camcontrol.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2005 Kenneth D. Merry
+ * Copyright (c) 1997-2007 Kenneth D. Merry
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,7 +27,8 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sbin/camcontrol/camcontrol.c,v 1.53 2005/03/26 05:34:54 ken Exp $");
+__FBSDID("$FreeBSD: src/sbin/camcontrol/camcontrol.c,v 1.58 2007/09/08 20:24:12 ken Exp $");
+__MBSDID("$MidnightBSD$");
 
 #include <sys/ioctl.h>
 #include <sys/stdint.h>
@@ -40,6 +41,7 @@
 #include <fcntl.h>
 #include <ctype.h>
 #include <err.h>
+#include <libutil.h>
 
 #include <cam/cam.h>
 #include <cam/cam_debug.h>
@@ -69,6 +71,8 @@
 	CAM_CMD_TAG		= 0x0000000e,
 	CAM_CMD_RATE		= 0x0000000f,
 	CAM_CMD_DETACH		= 0x00000010,
+	CAM_CMD_REPORTLUNS	= 0x00000011,
+	CAM_CMD_READCAP		= 0x00000012
 } cam_cmdmask;
 
 typedef enum {
@@ -127,6 +131,8 @@
 	{"stop", CAM_CMD_STARTSTOP, CAM_ARG_NONE, NULL},
 	{"load", CAM_CMD_STARTSTOP, CAM_ARG_START_UNIT | CAM_ARG_EJECT, NULL},
 	{"eject", CAM_CMD_STARTSTOP, CAM_ARG_EJECT, NULL},
+	{"reportluns", CAM_CMD_REPORTLUNS, CAM_ARG_NONE, "clr:"},
+	{"readcapacity", CAM_CMD_READCAP, CAM_ARG_NONE, "bhHNqs"},
 #endif /* MINIMALISTIC */
 	{"rescan", CAM_CMD_RESCAN, CAM_ARG_NONE, NULL},
 	{"reset", CAM_CMD_RESET, CAM_ARG_NONE, NULL},
@@ -203,6 +209,10 @@
 		       int timeout, int argc, char **argv, char *combinedopt);
 static int scsiformat(struct cam_device *device, int argc, char **argv,
 		      char *combinedopt, int retry_count, int timeout);
+static int scsireportluns(struct cam_device *device, int argc, char **argv,
+			  char *combinedopt, int retry_count, int timeout);
+static int scsireadcapacity(struct cam_device *device, int argc, char **argv,
+			    char *combinedopt, int retry_count, int timeout);
 #endif /* MINIMALISTIC */
 
 camcontrol_optret
@@ -845,8 +855,8 @@
 static int
 scsixferrate(struct cam_device *device)
 {
-	u_int32_t freq;
-	u_int32_t speed;
+	u_int32_t freq = 0;
+	u_int32_t speed = 0;
 	union ccb *ccb;
 	u_int mb;
 	int retval = 0;
@@ -862,7 +872,7 @@
 	      sizeof(struct ccb_trans_settings) - sizeof(struct ccb_hdr));
 
 	ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
-	ccb->cts.flags = CCB_TRANS_CURRENT_SETTINGS;
+	ccb->cts.type = CTS_TYPE_CURRENT_SETTINGS;
 
 	if (((retval = cam_send_ccb(device, ccb)) < 0)
 	 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
@@ -883,10 +893,49 @@
 
 	}
 
-	if (((ccb->cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)
-	 && (ccb->cts.sync_offset != 0)) {
-		freq = scsi_calc_syncsrate(ccb->cts.sync_period);
-		speed = freq;
+	if (ccb->cts.transport == XPORT_SPI) {
+		struct ccb_trans_settings_spi *spi =
+		    &ccb->cts.xport_specific.spi;
+
+		if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) {
+			freq = scsi_calc_syncsrate(spi->sync_period);
+			speed = freq;
+		}
+
+		fprintf(stdout, "%s%d: ", device->device_name,
+			device->dev_unit_num);
+
+		if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
+			speed *= (0x01 << spi->bus_width);
+		}
+
+		mb = speed / 1000;
+
+		if (mb > 0) 
+			fprintf(stdout, "%d.%03dMB/s transfers ",
+				mb, speed % 1000);
+		else
+			fprintf(stdout, "%dKB/s transfers ",
+				speed);
+
+		if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)
+		 && (spi->sync_offset != 0))
+			fprintf(stdout, "(%d.%03dMHz, offset %d", freq / 1000,
+				freq % 1000, spi->sync_offset);
+
+		if (((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0)
+		 && (spi->bus_width > 0)) {
+			if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)
+			 && (spi->sync_offset != 0)) {
+				fprintf(stdout, ", ");
+			} else {
+				fprintf(stdout, " (");
+			}
+			fprintf(stdout, "%dbit)", 8 * (0x01 << spi->bus_width));
+		} else if (((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)
+		 && (spi->sync_offset != 0)) {
+			fprintf(stdout, ")");
+		}
 	} else {
 		struct ccb_pathinq cpi;
 
@@ -897,46 +946,27 @@
 
 		speed = cpi.base_transfer_speed;
 		freq = 0;
-	}
-
-	fprintf(stdout, "%s%d: ", device->device_name,
-		device->dev_unit_num);
 
-	if ((ccb->cts.valid & CCB_TRANS_BUS_WIDTH_VALID) != 0)
-		speed *= (0x01 << device->bus_width);
+		mb = speed / 1000;
 
-	mb = speed / 1000;
-
-	if (mb > 0) 
-		fprintf(stdout, "%d.%03dMB/s transfers ",
-			mb, speed % 1000);
-	else
-		fprintf(stdout, "%dKB/s transfers ",
-			speed);
+		if (mb > 0) 
+			fprintf(stdout, "%d.%03dMB/s transfers ",
+				mb, speed % 1000);
+		else
+			fprintf(stdout, "%dKB/s transfers ",
+				speed);
+	}
 
-	if (((ccb->cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)
-	 && (ccb->cts.sync_offset != 0))
-                fprintf(stdout, "(%d.%03dMHz, offset %d", freq / 1000,
-			freq % 1000, ccb->cts.sync_offset);
-
-	if (((ccb->cts.valid & CCB_TRANS_BUS_WIDTH_VALID) != 0)
-	 && (ccb->cts.bus_width > 0)) {
-		if (((ccb->cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)
-		 && (ccb->cts.sync_offset != 0)) {
-			fprintf(stdout, ", ");
-		} else {
-			fprintf(stdout, " (");
+	if (ccb->cts.protocol == PROTO_SCSI) {
+		struct ccb_trans_settings_scsi *scsi =
+		    &ccb->cts.proto_specific.scsi;
+		if (scsi->valid & CTS_SCSI_VALID_TQ) {
+			if (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) {
+				fprintf(stdout, ", Command Queueing Enabled");
+			}
 		}
-		fprintf(stdout, "%dbit)", 8 * (0x01 << ccb->cts.bus_width));
-	} else if (((ccb->cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)
-		&& (ccb->cts.sync_offset != 0)) {
-		fprintf(stdout, ")");
 	}
 
-	if (((ccb->cts.valid & CCB_TRANS_TQ_VALID) != 0)
-	 && (ccb->cts.flags & CCB_TRANS_TAG_ENB))
-                fprintf(stdout, ", Tagged Queueing Enabled");
- 
         fprintf(stdout, "\n");
 
 xferrate_bailout:
@@ -1034,7 +1064,7 @@
 	retval = 0;
 
 	if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
-		warnx("error opening tranport layer device %s", XPT_DEVICE);
+		warnx("error opening transport layer device %s", XPT_DEVICE);
 		warn("%s", XPT_DEVICE);
 		return(1);
 	}
@@ -1220,7 +1250,7 @@
 
 	if (scan) {
 		if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
-			warnx("error opening tranport layer device %s\n",
+			warnx("error opening transport layer device %s\n",
 			    XPT_DEVICE);
 			warn("%s", XPT_DEVICE);
 			return(1);
@@ -2255,36 +2285,51 @@
 
 	cam_path_string(device, pathstr, sizeof(pathstr));
 
-	if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) {
+	if (cts->transport == XPORT_SPI) {
+		struct ccb_trans_settings_spi *spi =
+		    &cts->xport_specific.spi;
 
-		fprintf(stdout, "%ssync parameter: %d\n", pathstr,
-			cts->sync_period);
+		if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) {
 
-		if (cts->sync_offset != 0) {
-			u_int freq;
+			fprintf(stdout, "%ssync parameter: %d\n", pathstr,
+				spi->sync_period);
 
-			freq = scsi_calc_syncsrate(cts->sync_period);
-			fprintf(stdout, "%sfrequency: %d.%03dMHz\n", pathstr,
-				freq / 1000, freq % 1000);
+			if (spi->sync_offset != 0) {
+				u_int freq;
+
+				freq = scsi_calc_syncsrate(spi->sync_period);
+				fprintf(stdout, "%sfrequency: %d.%03dMHz\n",
+					pathstr, freq / 1000, freq % 1000);
+			}
+		}
+
+		if (spi->valid & CTS_SPI_VALID_SYNC_OFFSET) {
+			fprintf(stdout, "%soffset: %d\n", pathstr,
+			    spi->sync_offset);
 		}
-	}
 
-	if (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID)
-		fprintf(stdout, "%soffset: %d\n", pathstr, cts->sync_offset);
+		if (spi->valid & CTS_SPI_VALID_BUS_WIDTH) {
+			fprintf(stdout, "%sbus width: %d bits\n", pathstr,
+				(0x01 << spi->bus_width) * 8);
+		}
 
-	if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID)
-		fprintf(stdout, "%sbus width: %d bits\n", pathstr,
-			(0x01 << cts->bus_width) * 8);
+		if (spi->valid & CTS_SPI_VALID_DISC) {
+			fprintf(stdout, "%sdisconnection is %s\n", pathstr,
+				(spi->flags & CTS_SPI_FLAGS_DISC_ENB) ?
+				"enabled" : "disabled");
+		}
+	}
 
-	if (cts->valid & CCB_TRANS_DISC_VALID)
-		fprintf(stdout, "%sdisconnection is %s\n", pathstr,
-			(cts->flags & CCB_TRANS_DISC_ENB) ? "enabled" :
-			"disabled");
+	if (cts->protocol == PROTO_SCSI) {
+		struct ccb_trans_settings_scsi *scsi=
+		    &cts->proto_specific.scsi;
 
-	if (cts->valid & CCB_TRANS_TQ_VALID)
-		fprintf(stdout, "%stagged queueing is %s\n", pathstr,
-			(cts->flags & CCB_TRANS_TAG_ENB) ? "enabled" :
-			"disabled");
+		if (scsi->valid & CTS_SCSI_VALID_TQ) {
+			fprintf(stdout, "%stagged queueing is %s\n", pathstr,
+				(scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) ?
+				"enabled" : "disabled");
+		}
+	}
 
 }
 
@@ -2496,9 +2541,9 @@
 	ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
 
 	if (user_settings == 0)
-		ccb->cts.flags = CCB_TRANS_CURRENT_SETTINGS;
+		ccb->cts.type = CTS_TYPE_CURRENT_SETTINGS;
 	else
-		ccb->cts.flags = CCB_TRANS_USER_SETTINGS;
+		ccb->cts.type = CTS_TYPE_USER_SETTINGS;
 
 	if (cam_send_ccb(device, ccb) < 0) {
 		perror("error sending XPT_GET_TRAN_SETTINGS CCB");
@@ -2672,16 +2717,27 @@
 		cpi_print(&cpi);
 
 	if (change_settings) {
-		if (disc_enable != -1) {
-			ccb->cts.valid |= CCB_TRANS_DISC_VALID;
+		int didsettings = 0;
+		struct ccb_trans_settings_spi *spi = NULL;
+		struct ccb_trans_settings_scsi *scsi = NULL;
+
+		if (ccb->cts.transport == XPORT_SPI) {
+			spi = &ccb->cts.xport_specific.spi;
+			spi->valid = 0;
+		}
+		if (ccb->cts.protocol == PROTO_SCSI) {
+			scsi = &ccb->cts.proto_specific.scsi;
+			scsi->valid = 0;
+		}
+		if (spi && disc_enable != -1) {
+			spi->valid |= CTS_SPI_VALID_DISC;
 			if (disc_enable == 0)
-				ccb->cts.flags &= ~CCB_TRANS_DISC_ENB;
+				spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
 			else
-				ccb->cts.flags |= CCB_TRANS_DISC_ENB;
-		} else
-			ccb->cts.valid &= ~CCB_TRANS_DISC_VALID;
+				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
+		}
 
-		if (tag_enable != -1) {
+		if (scsi && tag_enable != -1) {
 			if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0) {
 				warnx("HBA does not support tagged queueing, "
 				      "so you cannot modify tag settings");
@@ -2689,16 +2745,16 @@
 				goto ratecontrol_bailout;
 			}
 
-			ccb->cts.valid |= CCB_TRANS_TQ_VALID;
+			scsi->valid |= CTS_SCSI_VALID_TQ;
 
 			if (tag_enable == 0)
-				ccb->cts.flags &= ~CCB_TRANS_TAG_ENB;
+				scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
 			else
-				ccb->cts.flags |= CCB_TRANS_TAG_ENB;
-		} else
-			ccb->cts.valid &= ~CCB_TRANS_TQ_VALID;
+				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
+			didsettings++;
+		}
 
-		if (offset != -1) {
+		if (spi && offset != -1) {
 			if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
 				warnx("HBA at %s%d is not cable of changing "
 				      "offset", cpi.dev_name,
@@ -2706,12 +2762,12 @@
 				retval = 1;
 				goto ratecontrol_bailout;
 			}
-			ccb->cts.valid |= CCB_TRANS_SYNC_OFFSET_VALID;
-			ccb->cts.sync_offset = offset;
-		} else
-			ccb->cts.valid &= ~CCB_TRANS_SYNC_OFFSET_VALID;
+			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
+			spi->sync_offset = offset;
+			didsettings++;
+		}
 
-		if (syncrate != -1) {
+		if (spi && syncrate != -1) {
 			int prelim_sync_period;
 			u_int freq;
 
@@ -2723,7 +2779,7 @@
 				goto ratecontrol_bailout;
 			}
 
-			ccb->cts.valid |= CCB_TRANS_SYNC_RATE_VALID;
+			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
 
 			/*
 			 * The sync rate the user gives us is in MHz.
@@ -2741,12 +2797,12 @@
 			else
 				prelim_sync_period = 10000000 / syncrate;
 
-			ccb->cts.sync_period =
+			spi->sync_period =
 				scsi_calc_syncparam(prelim_sync_period);
 
-			freq = scsi_calc_syncsrate(ccb->cts.sync_period);
-		} else
-			ccb->cts.valid &= ~CCB_TRANS_SYNC_RATE_VALID;
+			freq = scsi_calc_syncsrate(spi->sync_period);
+			didsettings++;
+		}
 
 		/*
 		 * The bus_width argument goes like this:
@@ -2757,7 +2813,7 @@
 		 * command line right by 4, you should get the correct
 		 * number.
 		 */
-		if (bus_width != -1) {
+		if (spi && bus_width != -1) {
 
 			/*
 			 * We might as well validate things here with a
@@ -2783,11 +2839,14 @@
 				goto ratecontrol_bailout;
 			}
 
-			ccb->cts.valid |= CCB_TRANS_BUS_WIDTH_VALID;
-			ccb->cts.bus_width = bus_width >> 4;
-		} else
-			ccb->cts.valid &= ~CCB_TRANS_BUS_WIDTH_VALID;
+			spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
+			spi->bus_width = bus_width >> 4;
+			didsettings++;
+		}
 
+		if  (didsettings == 0) {
+			goto ratecontrol_bailout;
+		}
 		ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
 
 		if (cam_send_ccb(device, ccb) < 0) {
@@ -3152,6 +3211,459 @@
 
 	return(error);
 }
+
+static int
+scsireportluns(struct cam_device *device, int argc, char **argv,
+	       char *combinedopt, int retry_count, int timeout)
+{
+	union ccb *ccb;
+	int c, countonly, lunsonly;
+	struct scsi_report_luns_data *lundata;
+	int alloc_len;
+	uint8_t report_type;
+	uint32_t list_len, i, j;
+	int retval;
+
+	retval = 0;
+	lundata = NULL;
+	report_type = RPL_REPORT_DEFAULT;
+	ccb = cam_getccb(device);
+
+	if (ccb == NULL) {
+		warnx("%s: error allocating ccb", __func__);
+		return (1);
+	}
+
+	bzero(&(&ccb->ccb_h)[1],
+	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
+
+	countonly = 0;
+	lunsonly = 0;
+
+	while ((c = getopt(argc, argv, combinedopt)) != -1) {
+		switch (c) {
+		case 'c':
+			countonly++;
+			break;
+		case 'l':
+			lunsonly++;
+			break;
+		case 'r':
+			if (strcasecmp(optarg, "default") == 0)
+				report_type = RPL_REPORT_DEFAULT;
+			else if (strcasecmp(optarg, "wellknown") == 0)
+				report_type = RPL_REPORT_WELLKNOWN;
+			else if (strcasecmp(optarg, "all") == 0)
+				report_type = RPL_REPORT_ALL;
+			else {
+				warnx("%s: invalid report type \"%s\"",
+				      __func__, optarg);
+				retval = 1;
+				goto bailout;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	if ((countonly != 0)
+	 && (lunsonly != 0)) {
+		warnx("%s: you can only specify one of -c or -l", __func__);
+		retval = 1;
+		goto bailout;
+	}
+	/*
+	 * According to SPC-4, the allocation length must be at least 16
+	 * bytes -- enough for the header and one LUN.
+	 */
+	alloc_len = sizeof(*lundata) + 8;
+
+retry:
+
+	lundata = malloc(alloc_len);
+
+	if (lundata == NULL) {
+		warn("%s: error mallocing %d bytes", __func__, alloc_len);
+		retval = 1;
+		goto bailout;
+	}
+
+	scsi_report_luns(&ccb->csio,
+			 /*retries*/ retry_count,
+			 /*cbfcnp*/ NULL,
+			 /*tag_action*/ MSG_SIMPLE_Q_TAG,
+			 /*select_report*/ report_type,
+			 /*rpl_buf*/ lundata,
+			 /*alloc_len*/ alloc_len,
+			 /*sense_len*/ SSD_FULL_SIZE,
+			 /*timeout*/ timeout ? timeout : 5000);
+
+	/* Disable freezing the device queue */
+	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
+
+	if (arglist & CAM_ARG_ERR_RECOVER)
+		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
+
+	if (cam_send_ccb(device, ccb) < 0) {
+		warn("error sending REPORT LUNS command");
+
+		if (arglist & CAM_ARG_VERBOSE)
+			cam_error_print(device, ccb, CAM_ESF_ALL,
+					CAM_EPF_ALL, stderr);
+
+		retval = 1;
+		goto bailout;
+	}
+
+	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+		cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
+		retval = 1;
+		goto bailout;
+	}
+
+
+	list_len = scsi_4btoul(lundata->length);
+
+	/*
+	 * If we need to list the LUNs, and our allocation
+	 * length was too short, reallocate and retry.
+	 */
+	if ((countonly == 0)
+	 && (list_len > (alloc_len - sizeof(*lundata)))) {
+		alloc_len = list_len + sizeof(*lundata);
+		free(lundata);
+		goto retry;
+	}
+
+	if (lunsonly == 0)
+		fprintf(stdout, "%u LUN%s found\n", list_len / 8,
+			((list_len / 8) > 1) ? "s" : "");
+
+	if (countonly != 0)
+		goto bailout;
+
+	for (i = 0; i < (list_len / 8); i++) {
+		int no_more;
+
+		no_more = 0;
+		for (j = 0; j < sizeof(lundata->luns[i].lundata); j += 2) {
+			if (j != 0)
+				fprintf(stdout, ",");
+			switch (lundata->luns[i].lundata[j] &
+				RPL_LUNDATA_ATYP_MASK) {
+			case RPL_LUNDATA_ATYP_PERIPH:
+				if ((lundata->luns[i].lundata[j] &
+				    RPL_LUNDATA_PERIPH_BUS_MASK) != 0)
+					fprintf(stdout, "%d:", 
+						lundata->luns[i].lundata[j] &
+						RPL_LUNDATA_PERIPH_BUS_MASK);
+				else if ((j == 0)
+				      && ((lundata->luns[i].lundata[j+2] &
+					  RPL_LUNDATA_PERIPH_BUS_MASK) == 0))
+					no_more = 1;
+
+				fprintf(stdout, "%d",
+					lundata->luns[i].lundata[j+1]);
+				break;
+			case RPL_LUNDATA_ATYP_FLAT: {
+				uint8_t tmplun[2];
+				tmplun[0] = lundata->luns[i].lundata[j] &
+					RPL_LUNDATA_FLAT_LUN_MASK;
+				tmplun[1] = lundata->luns[i].lundata[j+1];
+
+				fprintf(stdout, "%d", scsi_2btoul(tmplun));
+				no_more = 1;
+				break;
+			}
+			case RPL_LUNDATA_ATYP_LUN:
+				fprintf(stdout, "%d:%d:%d",
+					(lundata->luns[i].lundata[j+1] &
+					RPL_LUNDATA_LUN_BUS_MASK) >> 5,
+					lundata->luns[i].lundata[j] &
+					RPL_LUNDATA_LUN_TARG_MASK,
+					lundata->luns[i].lundata[j+1] &
+					RPL_LUNDATA_LUN_LUN_MASK);
+				break;
+			case RPL_LUNDATA_ATYP_EXTLUN: {
+				int field_len, field_len_code, eam_code;
+
+				eam_code = lundata->luns[i].lundata[j] &
+					RPL_LUNDATA_EXT_EAM_MASK;
+				field_len_code = (lundata->luns[i].lundata[j] &
+					RPL_LUNDATA_EXT_LEN_MASK) >> 4;
+				field_len = field_len_code * 2;
+		
+				if ((eam_code == RPL_LUNDATA_EXT_EAM_WK)
+				 && (field_len_code == 0x00)) {
+					fprintf(stdout, "%d",
+						lundata->luns[i].lundata[j+1]);
+				} else if ((eam_code ==
+					    RPL_LUNDATA_EXT_EAM_NOT_SPEC)
+					&& (field_len_code == 0x03)) {
+					uint8_t tmp_lun[8];
+
+					/*
+					 * This format takes up all 8 bytes.
+					 * If we aren't starting at offset 0,
+					 * that's a bug.
+					 */
+					if (j != 0) {
+						fprintf(stdout, "Invalid "
+							"offset %d for "
+							"Extended LUN not "
+							"specified format", j);
+						no_more = 1;
+						break;
+					}
+					bzero(tmp_lun, sizeof(tmp_lun));
+					bcopy(&lundata->luns[i].lundata[j+1],
+					      &tmp_lun[1], sizeof(tmp_lun) - 1);
+					fprintf(stdout, "%#jx",
+					       (intmax_t)scsi_8btou64(tmp_lun));
+					no_more = 1;
+				} else {
+					fprintf(stderr, "Unknown Extended LUN"
+						"Address method %#x, length "
+						"code %#x", eam_code,
+						field_len_code);
+					no_more = 1;
+				}
+				break;
+			}
+			default:
+				fprintf(stderr, "Unknown LUN address method "
+					"%#x\n", lundata->luns[i].lundata[0] &
+					RPL_LUNDATA_ATYP_MASK);
+				break;
+			}
+			/*
+			 * For the flat addressing method, there are no
+			 * other levels after it.
+			 */
+			if (no_more != 0)
+				break;
+		}
+		fprintf(stdout, "\n");
+	}
+
+bailout:
+
+	cam_freeccb(ccb);
+
+	free(lundata);
+
+	return (retval);
+}
+
+static int
+scsireadcapacity(struct cam_device *device, int argc, char **argv,
+		 char *combinedopt, int retry_count, int timeout)
+{
+	union ccb *ccb;
+	int blocksizeonly, humanize, numblocks, quiet, sizeonly, baseten;
+	struct scsi_read_capacity_data rcap;
+	struct scsi_read_capacity_data_long rcaplong;
+	uint64_t maxsector;
+	uint32_t block_len;
+	int retval;
+	int c;
+
+	blocksizeonly = 0;
+	humanize = 0;
+	numblocks = 0;
+	quiet = 0;
+	sizeonly = 0;
+	baseten = 0;
+	retval = 0;
+
+	ccb = cam_getccb(device);
+
+	if (ccb == NULL) {
+		warnx("%s: error allocating ccb", __func__);
+		return (1);
+	}
+
+	bzero(&(&ccb->ccb_h)[1],
+	      sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
+
+	while ((c = getopt(argc, argv, combinedopt)) != -1) {
+		switch (c) {
+		case 'b':
+			blocksizeonly++;
+			break;
+		case 'h':
+			humanize++;
+			baseten = 0;
+			break;
+		case 'H':
+			humanize++;
+			baseten++;
+			break;
+		case 'N':
+			numblocks++;
+			break;
+		case 'q':
+			quiet++;
+			break;
+		case 's':
+			sizeonly++;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if ((blocksizeonly != 0)
+	 && (numblocks != 0)) {
+		warnx("%s: you can only specify one of -b or -N", __func__);
+		retval = 1;
+		goto bailout;
+	}
+
+	if ((blocksizeonly != 0)
+	 && (sizeonly != 0)) {
+		warnx("%s: you can only specify one of -b or -s", __func__);
+		retval = 1;
+		goto bailout;
+	}
+
+	if ((humanize != 0)
+	 && (quiet != 0)) {
+		warnx("%s: you can only specify one of -h/-H or -q", __func__);
+		retval = 1;
+		goto bailout;
+	}
+
+	if ((humanize != 0)
+	 && (blocksizeonly != 0)) {
+		warnx("%s: you can only specify one of -h/-H or -b", __func__);
+		retval = 1;
+		goto bailout;
+	}
+
+	scsi_read_capacity(&ccb->csio,
+			   /*retries*/ retry_count,
+			   /*cbfcnp*/ NULL,
+			   /*tag_action*/ MSG_SIMPLE_Q_TAG,
+			   &rcap,
+			   SSD_FULL_SIZE,
+			   /*timeout*/ timeout ? timeout : 5000);
+
+	/* Disable freezing the device queue */
+	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
+
+	if (arglist & CAM_ARG_ERR_RECOVER)
+		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
+
+	if (cam_send_ccb(device, ccb) < 0) {
+		warn("error sending READ CAPACITY command");
+
+		if (arglist & CAM_ARG_VERBOSE)
+			cam_error_print(device, ccb, CAM_ESF_ALL,
+					CAM_EPF_ALL, stderr);
+
+		retval = 1;
+		goto bailout;
+	}
+
+	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+		cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
+		retval = 1;
+		goto bailout;
+	}
+
+	maxsector = scsi_4btoul(rcap.addr);
+	block_len = scsi_4btoul(rcap.length);
+
+	/*
+	 * A last block of 2^32-1 means that the true capacity is over 2TB,
+	 * and we need to issue the long READ CAPACITY to get the real
+	 * capacity.  Otherwise, we're all set.
+	 */
+	if (maxsector != 0xffffffff)
+		goto do_print;
+
+	scsi_read_capacity_16(&ccb->csio,
+			      /*retries*/ retry_count,
+			      /*cbfcnp*/ NULL,
+			      /*tag_action*/ MSG_SIMPLE_Q_TAG,
+			      /*lba*/ 0,
+			      /*reladdr*/ 0,
+			      /*pmi*/ 0,
+			      &rcaplong,
+			      /*sense_len*/ SSD_FULL_SIZE,
+			      /*timeout*/ timeout ? timeout : 5000);
+
+	/* Disable freezing the device queue */
+	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
+
+	if (arglist & CAM_ARG_ERR_RECOVER)
+		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
+
+	if (cam_send_ccb(device, ccb) < 0) {
+		warn("error sending READ CAPACITY (16) command");
+
+		if (arglist & CAM_ARG_VERBOSE)
+			cam_error_print(device, ccb, CAM_ESF_ALL,
+					CAM_EPF_ALL, stderr);
+
+		retval = 1;
+		goto bailout;
+	}
+
+	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+		cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
+		retval = 1;
+		goto bailout;
+	}
+
+	maxsector = scsi_8btou64(rcaplong.addr);
+	block_len = scsi_4btoul(rcaplong.length);
+
+do_print:
+	if (blocksizeonly == 0) {
+		/*
+		 * Humanize implies !quiet, and also implies numblocks.
+		 */
+		if (humanize != 0) {
+			char tmpstr[6];
+			int64_t tmpbytes;
+			int ret;
+
+			tmpbytes = (maxsector + 1) * block_len;
+			ret = humanize_number(tmpstr, sizeof(tmpstr),
+					      tmpbytes, "", HN_AUTOSCALE,
+					      HN_B | HN_DECIMAL |
+					      ((baseten != 0) ?
+					      HN_DIVISOR_1000 : 0));
+			if (ret == -1) {
+				warnx("%s: humanize_number failed!", __func__);
+				retval = 1;
+				goto bailout;
+			}
+			fprintf(stdout, "Device Size: %s%s", tmpstr,
+				(sizeonly == 0) ?  ", " : "\n");
+		} else if (numblocks != 0) {
+			fprintf(stdout, "%s%ju%s", (quiet == 0) ?
+				"Blocks: " : "", (uintmax_t)maxsector + 1,
+				(sizeonly == 0) ? ", " : "\n");
+		} else {
+			fprintf(stdout, "%s%ju%s", (quiet == 0) ?
+				"Last Block: " : "", (uintmax_t)maxsector,
+				(sizeonly == 0) ? ", " : "\n");
+		}
+	}
+	if (sizeonly == 0)
+		fprintf(stdout, "%s%u%s\n", (quiet == 0) ?
+			"Block Length: " : "", block_len, (quiet == 0) ?
+			" bytes" : "");
+bailout:
+	cam_freeccb(ccb);
+
+	return (retval);
+}
+
 #endif /* MINIMALISTIC */
 
 void 
@@ -3164,6 +3676,9 @@
 "        camcontrol periphlist [dev_id][-n dev_name] [-u unit]\n"
 "        camcontrol tur        [dev_id][generic args]\n"
 "        camcontrol inquiry    [dev_id][generic args] [-D] [-S] [-R]\n"
+"        camcontrol reportluns [dev_id][generic args] [-c] [-l] [-r report]\n"
+"        camcontrol readcap    [dev_id][generic args] [-b] [-h] [-H] [-N]\n"
+"                              [-q] [-s]\n"
 "        camcontrol start      [dev_id][generic args]\n"
 "        camcontrol stop       [dev_id][generic args]\n"
 "        camcontrol load       [dev_id][generic args]\n"
@@ -3196,6 +3711,8 @@
 "periphlist  list all CAM peripheral drivers attached to a device\n"
 "tur         send a test unit ready to the named device\n"
 "inquiry     send a SCSI inquiry command to the named device\n"
+"reportluns  send a SCSI report luns command to the device\n"
+"readcap     send a SCSI read capacity command to the device\n"
 "start       send a Start Unit command to the device\n"
 "stop        send a Stop Unit command to the device\n"
 "load        send a Start Unit command to the device with the load bit set\n"
@@ -3236,6 +3753,17 @@
 "-D                get the standard inquiry data\n"
 "-S                get the serial number\n"
 "-R                get the transfer rate, etc.\n"
+"reportluns arguments:\n"
+"-c                only report a count of available LUNs\n"
+"-l                only print out luns, and not a count\n"
+"-r <reporttype>   specify \"default\", \"wellknown\" or \"all\"\n"
+"readcap arguments\n"
+"-b                only report the blocksize\n"
+"-h                human readable device size, base 2\n"
+"-H                human readable device size, base 10\n"
+"-N                print the number of blocks instead of last block\n"
+"-q                quiet, print numbers only\n"
+"-s                only report the last block/device size\n"
 "cmd arguments:\n"
 "-c cdb [args]     specify the SCSI CDB\n"
 "-i len fmt        specify input data and input data format\n"
@@ -3547,6 +4075,16 @@
 			error = scsiformat(cam_dev, argc, argv,
 					   combinedopt, retry_count, timeout);
 			break;
+		case CAM_CMD_REPORTLUNS:
+			error = scsireportluns(cam_dev, argc, argv,
+					       combinedopt, retry_count,
+					       timeout);
+			break;
+		case CAM_CMD_READCAP:
+			error = scsireadcapacity(cam_dev, argc, argv,
+						 combinedopt, retry_count,
+						 timeout);
+			break;
 #endif /* MINIMALISTIC */
 		case CAM_CMD_USAGE:
 			usage(1);
Index: util.c
===================================================================
RCS file: /home/cvs/src/sbin/camcontrol/util.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/camcontrol/util.c -L sbin/camcontrol/util.c -u -r1.1.1.1 -r1.2
--- sbin/camcontrol/util.c
+++ sbin/camcontrol/util.c
@@ -45,6 +45,7 @@
  */
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/sbin/camcontrol/util.c,v 1.10 2003/08/05 09:19:07 johan Exp $");
+__MBSDID("$MidnightBSD$");
 
 #include <sys/stdint.h>
 #include <sys/types.h>
Index: camcontrol.h
===================================================================
RCS file: /home/cvs/src/sbin/camcontrol/camcontrol.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/camcontrol/camcontrol.h -L sbin/camcontrol/camcontrol.h -u -r1.1.1.1 -r1.2
--- sbin/camcontrol/camcontrol.h
+++ sbin/camcontrol/camcontrol.h
@@ -25,6 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
+ * $MidnightBSD$
  * $FreeBSD: src/sbin/camcontrol/camcontrol.h,v 1.4 2000/08/08 06:24:15 kbyanc Exp $
  */
 
Index: camcontrol.8
===================================================================
RCS file: /home/cvs/src/sbin/camcontrol/camcontrol.8,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/camcontrol/camcontrol.8 -L sbin/camcontrol/camcontrol.8 -u -r1.1.1.1 -r1.2
--- sbin/camcontrol/camcontrol.8
+++ sbin/camcontrol/camcontrol.8
@@ -1,5 +1,5 @@
 .\"
-.\" Copyright (c) 1998, 1999, 2000, 2002, 2005 Kenneth D. Merry.
+.\" Copyright (c) 1998, 1999, 2000, 2002, 2005, 2006, 2007 Kenneth D. Merry.
 .\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
@@ -25,9 +25,10 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: src/sbin/camcontrol/camcontrol.8,v 1.41 2005/06/14 11:24:55 ru Exp $
+.\" $MidnightBSD$
+.\" $FreeBSD: src/sbin/camcontrol/camcontrol.8,v 1.44 2007/09/08 20:24:12 ken Exp $
 .\"
-.Dd September 14, 1998
+.Dd August 21, 2006
 .Dt CAMCONTROL 8
 .Os
 .Sh NAME
@@ -59,6 +60,23 @@
 .Op Fl S
 .Op Fl R
 .Nm
+.Ic reportluns
+.Op device id
+.Op generic args
+.Op Fl c
+.Op Fl l
+.Op Fl r Ar reporttype
+.Nm
+.Ic readcap
+.Op device id
+.Op generic args
+.Op Fl b
+.Op Fl h
+.Op Fl H
+.Op Fl N
+.Op Fl q
+.Op Fl s
+.Nm
 .Ic start
 .Op device id
 .Op generic args
@@ -266,6 +284,77 @@
 .It Fl R
 Print out transfer rate information.
 .El
+.It Ic reportluns
+Send the SCSI REPORT LUNS (0xA0) command to the given device.
+By default,
+.Nm
+will print out the list of logical units (LUNs) supported by the target device.
+There are a couple of options to modify the output:
+.Bl -tag -width 14n
+.It Fl c
+Just print out a count of LUNs, not the actual LUN numbers.
+.It Fl l
+Just print out the LUNs, and don't print out the count.
+.It Fl r Ar reporttype
+Specify the type of report to request from the target:
+.Bl -tag -width 012345678
+.It default
+Return the default report.
+This is the
+.Nm
+default.
+Most targets will support this report if they support the REPORT LUNS
+command.
+.It wellknown
+Return only well known LUNs.
+.It all
+Return all available LUNs.
+.El
+.El
+.Pp
+.Nm
+will try to print out LUN numbers in a reasonable format.
+It can understand the peripheral, flat, LUN and extended LUN formats.
+.It Ic readcap
+Send the SCSI READ CAPACITY command to the given device and display
+the results.
+If the device is larger than 2TB, the SCSI READ CAPACITY (16) service
+action will be sent to obtain the full size of the device.
+By default,
+.Nm
+will print out the last logical block of the device, and the blocksize of
+the device in bytes.
+To modify the output format, use the following options:
+.Bl -tag -width 5n
+.It Fl b
+Just print out the blocksize, not the last block or device size.
+This cannot be used with
+.Fl N
+or
+.Fl s .
+.It Fl h
+Print out the device size in human readable (base 2, 1K == 1024) format.
+This implies
+.Fl N
+and cannot be used with
+.Fl q
+or
+.Fl b .
+.It Fl H
+Print out the device size in human readable (base 10, 1K == 1000) format.
+.It Fl N
+Print out the number of blocks in the device instead of the last logical
+block.
+.It Fl q
+Quiet, print out the numbers only (separated by a comma if
+.Fl b
+or
+.Fl s
+are not specified).
+.It Fl s
+Print out the last logical block or the size of the device only, and omit
+the blocksize.
+.El
 .It Ic start
 Send the SCSI Start/Stop Unit (0x1B) command to the given device with the
 start bit set.
Index: modeedit.c
===================================================================
RCS file: /home/cvs/src/sbin/camcontrol/modeedit.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/camcontrol/modeedit.c -L sbin/camcontrol/modeedit.c -u -r1.1.1.1 -r1.2
--- sbin/camcontrol/modeedit.c
+++ sbin/camcontrol/modeedit.c
@@ -28,6 +28,7 @@
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/sbin/camcontrol/modeedit.c,v 1.17 2004/01/22 07:23:35 grehan Exp $");
+__MBSDID("$MidnightBSD$");
 
 #include <sys/queue.h>
 #include <sys/types.h>
Index: Makefile
===================================================================
RCS file: /home/cvs/src/sbin/camcontrol/Makefile,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/camcontrol/Makefile -L sbin/camcontrol/Makefile -u -r1.1.1.1 -r1.2
--- sbin/camcontrol/Makefile
+++ sbin/camcontrol/Makefile
@@ -1,4 +1,5 @@
-# $FreeBSD: src/sbin/camcontrol/Makefile,v 1.16 2004/05/14 13:31:21 cognet Exp $
+# $MidnightBSD$
+# $FreeBSD: src/sbin/camcontrol/Makefile,v 1.17 2007/09/08 20:24:12 ken Exp $
 
 PROG=	camcontrol
 SRCS=	camcontrol.c util.c
@@ -7,13 +8,9 @@
 .else
 CFLAGS+= -DMINIMALISTIC
 .endif
-.if ${MACHINE_ARCH} == "arm"
-WARNS?= 3
-.else
 WARNS?=	6
-.endif
-DPADD=	${LIBCAM} ${LIBSBUF}
-LDADD=	-lcam -lsbuf
+DPADD=	${LIBCAM} ${LIBSBUF} ${LIBUTIL}
+LDADD=	-lcam -lsbuf -lutil
 MAN=	camcontrol.8
 
 .include <bsd.prog.mk>


More information about the Midnightbsd-cvs mailing list