==== //depot/FreeBSD-ken/src/lib/libcam/Makefile#2 - /a/ken/perforce2/FreeBSD-ken/src/lib/libcam/Makefile ==== *** /tmp/tmp.63018.0 Sun Jan 16 23:51:11 2000 --- /a/ken/perforce2/FreeBSD-ken/src/lib/libcam/Makefile Sun Jan 16 23:45:01 2000 *************** *** 3,9 **** MAINTAINER=ken@FreeBSD.ORG LIB= cam ! SRCS= camlib.c scsi_cmdparse.c scsi_all.c scsi_sa.c cam.c INCS= camlib.h MAN3= cam.3 cam_cdbparse.3 --- 3,9 ---- MAINTAINER=ken@FreeBSD.ORG LIB= cam ! SRCS= camlib.c scsi_cmdparse.c scsi_all.c scsi_da.c scsi_sa.c cam.c INCS= camlib.h MAN3= cam.3 cam_cdbparse.3 ==== //depot/FreeBSD-ken/src/sbin/camcontrol/camcontrol.8#3 - /a/ken/perforce2/FreeBSD-ken/src/sbin/camcontrol/camcontrol.8 ==== *** /tmp/tmp.63018.1 Sun Jan 16 23:51:11 2000 --- /a/ken/perforce2/FreeBSD-ken/src/sbin/camcontrol/camcontrol.8 Sun Jan 16 23:45:55 2000 *************** *** 1,5 **** .\" ! .\" Copyright (c) 1998, 1999 Kenneth D. Merry. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without --- 1,5 ---- .\" ! .\" Copyright (c) 1998, 1999, 2000 Kenneth D. Merry. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without *************** *** 128,133 **** --- 128,140 ---- .Op Fl W Ar bus_width .Op Fl v .Nm camcontrol + format + .Op device id + .Op generic args + .Op Fl q + .Op Fl w + .Op Fl y + .Nm camcontrol help .Sh DESCRIPTION .Nm camcontrol *************** *** 172,178 **** .Fl u arguments will .Em not ! override a specified bus:target or bus:target:lun, howevever. .Pp Most of the .Nm camcontrol --- 179,185 ---- .Fl u arguments will .Em not ! override a specified bus:target or bus:target:lun, however. .Pp Most of the .Nm camcontrol *************** *** 332,338 **** argument to specify the CDB. Other arguments are optional, depending on the command type. The command and data specification syntax is documented in ! .Xr cam 3 . NOTE: If the CDB specified causes data to be transfered to or from the SCSI device in question, you MUST specify either .Fl i --- 339,345 ---- argument to specify the CDB. Other arguments are optional, depending on the command type. The command and data specification syntax is documented in ! .Xr cam_cdbparse 3 . NOTE: If the CDB specified causes data to be transfered to or from the SCSI device in question, you MUST specify either .Fl i *************** *** 509,514 **** --- 516,585 ---- .Fl a switch above will automatically send a Test Unit Ready to the device so negotiation parameters will take effect. + .It format + Issue the + .Tn SCSI + FORMAT UNIT command to the named device. + .Pp + .Em WARNING! WARNING! WARNING! + .Pp + Low level formatting a disk will destroy ALL data on the disk. Use + extreme caution when issuing this command. Many users low-level format + disks that do not really need to be low-level formatted. There are + relatively few scenarios that call for low-level formatting a disk. + One reason for + low-level formatting a disk is if you want to change the physical sector + size of the disk. Another reason for low-level formatting a disk is to + revive the disk if you are getting "medium format corrupted" errors from the + disk in response to read and write requests. + .Pp + Some disks take longer than others to format. Users should specify a + timeout long enough to allow the format to complete. The default format + timeout is 3 hours, which should be long enough for most disks. Some hard + disks will complete a format operation in a very short period of time + (on the order of 5 minutes or less). This is often because the drive + doesn't really support the FORMAT UNIT command -- it just accepts the + command, waits a few minutes and then returns it. + .Pp + The + .Sq format + subcommand takes several arguments that modify its default behavior. The + .Fl q + and + .Fl y + arguments can be useful for scripts. + .Pp + .Bl -tag -width 123456 + .It Fl q + Be quiet, don't print any status messages. This option will not disable + the questions, however. To disable questions, use the + .Fl y + argument, below. + .It Fl w + Issue a non-immediate format command. By default, + .Nm camcontrol + issues the FORMAT UNIT command with the immediate bit set. This tells the + device to immediately return the format command, before the format has + actually completed. Then, + .Nm camcontrol + gathers + .Tn SCSI + sense information from the device every second to determine how far along + in the format process it is. If the + .Fl w + argument is specified, + .Nm camcontrol + will issue a non-immediate format command, and will be unable to print any + information to let the user know what percentage of the disk has been + formatted. + .It Fl y + Don't ask any questions. By default, + .Nm camcontrol + will ask the user if he/she really wants to format the disk in question, + and also if the default format command timeout is acceptable. The user + will not be asked about the timeout if a timeout is specified on the + command line. + .El .It help Print out verbose usage information. .El *************** *** 610,642 **** .Pp 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 foobar - camcontrol cmd -n da -u 3 -v -t 7200 -c "4 0 0 0 0 0" - .Ed - .Pp - Send the FORMAT UNIT (0x04) command to da3. This will low-level format the - disk. Print sense information if the command fails, and set the timeout to - two hours (or 7200 seconds). - .Pp - .Em WARNING! WARNING! WARNING! - .Pp - Low level formatting a disk will destroy ALL data on the disk. Use - extreme caution when issuing this command. Many users low-level format - disks that do not really need to be low-level formatted. There are - relatively few scenarios that call for low-level formatting a disk. - One reason for - low-level formatting a disk is if you want to change the physical sector - size of the disk. Another reason for low-level formatting a disk is to - revive the disk if you are getting "medium format corrupted" errors from the - disk in response to read and write requests. - .Pp - Some disks take longer than others to format. Users should specify a - timeout long enough to allow the format to complete. Some hard disks - will complete a format operation in a very short period of time (on the - order of 5 minutes or less). This is often because the drive doesn't - really support the FORMAT UNIT command -- it just accepts the command, - waits a few minutes and then returns it. .Sh SEE ALSO .Xr cam 3 , .Xr cam_cdbparse 3 , --- 681,686 ---- ==== //depot/FreeBSD-ken/src/sbin/camcontrol/camcontrol.c#6 - /a/ken/perforce2/FreeBSD-ken/src/sbin/camcontrol/camcontrol.c ==== *** /tmp/tmp.63018.2 Sun Jan 16 23:51:11 2000 --- /a/ken/perforce2/FreeBSD-ken/src/sbin/camcontrol/camcontrol.c Sun Jan 16 23:45:28 2000 *************** *** 1,5 **** /* ! * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry * All rights reserved. * * Redistribution and use in source and binary forms, with or without --- 1,5 ---- /* ! * Copyright (c) 1997, 1998, 1999, 2000 Kenneth D. Merry * All rights reserved. * * Redistribution and use in source and binary forms, with or without *************** *** 132,137 **** --- 132,138 ---- {"negotiate", CAM_ARG_RATE, negotiate_opts}, {"rate", CAM_ARG_RATE, negotiate_opts}, {"debug", CAM_ARG_DEBUG, "ITSc"}, + {"format", CAM_ARG_FORMAT, "qwy"}, {"help", CAM_ARG_USAGE, NULL}, {"-?", CAM_ARG_USAGE, NULL}, {"-h", CAM_ARG_USAGE, NULL}, *************** *** 181,186 **** --- 182,189 ---- int quiet, struct ccb_trans_settings *cts); static int ratecontrol(struct cam_device *device, int retry_count, 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); camcontrol_optret getoption(char *arg, cam_argmask *argnum, char **subopt) *************** *** 2619,2624 **** --- 2622,2919 ---- return(retval); } + static int + scsiformat(struct cam_device *device, int argc, char **argv, + char *combinedopt, int retry_count, int timeout) + { + union ccb *ccb; + int c; + int ycount = 0, quiet = 0; + int error = 0, response = 0, retval = 0; + int use_timeout = 10800 * 1000; + int immediate = 1; + struct format_defect_list_header fh; + u_int8_t *data_ptr = NULL; + u_int32_t dxfer_len = 0; + u_int8_t byte2 = 0; + + ccb = cam_getccb(device); + + if (ccb == NULL) { + warnx("scsiformat: error allocating ccb"); + 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 'q': + quiet++; + break; + case 'w': + immediate = 0; + break; + case 'y': + ycount++; + break; + } + } + + if (quiet == 0) { + fprintf(stdout, "You are about to REMOVE ALL DATA from the " + "following device:\n"); + + error = scsidoinquiry(device, argc, argv, combinedopt, + retry_count, timeout); + + if (error != 0) { + warnx("scsiformat: error sending inquiry"); + goto scsiformat_bailout; + } + } + + 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) { + error = 1; + goto scsiformat_bailout; + } + } + + if (timeout != 0) + use_timeout = timeout; + + if (quiet == 0) { + fprintf(stdout, "Current format timeout is %d seconds\n", + use_timeout / 1000); + } + + /* + * If the user hasn't disabled questions and didn't specify a + * timeout on the command line, ask them if they want the current + * timeout. + */ + if ((ycount == 0) + && (timeout == 0)) { + char str[1024]; + int new_timeout = 0; + + fprintf(stdout, "Enter new timeout in seconds or press\n" + "return to keep the current timeout [%d] ", + use_timeout / 1000); + + if (fgets(str, sizeof(str), stdin) != NULL) { + if (str[0] != '\0') + new_timeout = atoi(str); + } + + if (new_timeout != 0) { + use_timeout = new_timeout * 1000; + fprintf(stdout, "Using new timeout value %d\n", + use_timeout / 1000); + } + } + + /* + * Keep this outside the if block below to silence any unused + * variable warnings. + */ + bzero(&fh, sizeof(fh)); + + /* + * If we're in immediate mode, we've got to include the format + * header + */ + if (immediate != 0) { + fh.byte2 = FU_DLH_IMMED; + data_ptr = (u_int8_t *)&fh; + dxfer_len = sizeof(fh); + byte2 = FU_FMT_DATA; + } else if (quiet == 0) { + fprintf(stdout, "Formatting..."); + fflush(stdout); + } + + scsi_format_unit(&ccb->csio, + /* retries */ retry_count, + /* cbfcnp */ NULL, + /* tag_action */ MSG_SIMPLE_Q_TAG, + /* byte2 */ byte2, + /* ileave */ 0, + /* data_ptr */ data_ptr, + /* dxfer_len */ dxfer_len, + /* sense_len */ SSD_FULL_SIZE, + /* timeout */ use_timeout); + + /* 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 (((retval = cam_send_ccb(device, ccb)) < 0) + || ((immediate == 0) + && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP))) { + char *errstr = "error sending format command"; + + if (retval < 0) + warn(errstr); + else + warnx(errstr); + + if (arglist & CAM_ARG_VERBOSE) { + if ((ccb->ccb_h.status & CAM_STATUS_MASK) == + CAM_SCSI_STATUS_ERROR) + scsi_sense_print(device, &ccb->csio, stderr); + else + fprintf(stderr, "CAM status is %#x\n", + ccb->ccb_h.status); + } + error = 1; + goto scsiformat_bailout; + } + + /* + * If we ran in non-immediate mode, we already checked for errors + * above and printed out any necessary information. If we're in + * immediate mode, we need to loop through and get status + * information periodically. + */ + if (immediate == 0) { + if (quiet == 0) { + fprintf(stdout, "Format Complete\n"); + } + goto scsiformat_bailout; + } + + do { + cam_status status; + + bzero(&(&ccb->ccb_h)[1], + sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); + + /* + * There's really no need to do error recovery or + * retries here, since we're just going to sit in a + * loop and wait for the device to finish formatting. + */ + scsi_test_unit_ready(&ccb->csio, + /* retries */ 0, + /* cbfcnp */ NULL, + /* tag_action */ MSG_SIMPLE_Q_TAG, + /* sense_len */ SSD_FULL_SIZE, + /* timeout */ 5000); + + /* Disable freezing the device queue */ + ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; + + retval = cam_send_ccb(device, ccb); + + /* + * If we get an error from the ioctl, bail out. SCSI + * errors are expected. + */ + if (retval < 0) { + warn("error sending CAMIOCOMMAND ioctl"); + if (arglist & CAM_ARG_VERBOSE) { + if ((ccb->ccb_h.status & CAM_STATUS_MASK) == + CAM_SCSI_STATUS_ERROR) + scsi_sense_print(device, &ccb->csio, + stderr); + else + fprintf(stderr, "CAM status is %#x\n", + ccb->ccb_h.status); + } + error = 1; + goto scsiformat_bailout; + } + + status = ccb->ccb_h.status & CAM_STATUS_MASK; + + if ((status != CAM_REQ_CMP) + && (status == CAM_SCSI_STATUS_ERROR)) { + struct scsi_sense_data *sense; + int error_code, sense_key, asc, ascq; + + sense = &ccb->csio.sense_data; + scsi_extract_sense(sense, &error_code, &sense_key, + &asc, &ascq); + + /* + * According to the SCSI-2 and SCSI-3 specs, a + * drive that is in the middle of a format should + * return NOT READY with an ASC of "logical unit + * not ready, format in progress". The sense key + * specific bytes will then be a progress indicator. + */ + if ((sense_key == SSD_KEY_NOT_READY) + && (asc == 0x04) && (ascq == 0x04)) { + if ((sense->extra_len >= 10) + && ((sense->sense_key_spec[0] & + SSD_SCS_VALID) != 0) + && (quiet == 0)) { + int val; + u_int64_t percentage; + + val = scsi_2btoul( + &sense->sense_key_spec[1]); + percentage = 10000 * val; + + fprintf(stdout, + "\rFormatting: %qd.%02qd %% " + "(%d/%d) done", + percentage / (0x10000 * 100), + (percentage / 0x10000) % 100, + val, 0x10000); + fflush(stdout); + } + sleep(1); + } else { + warnx("Unexpected SCSI error during format"); + scsi_sense_print(device, &ccb->csio, stderr); + error = 1; + goto scsiformat_bailout; + } + + } else if (status != CAM_REQ_CMP) { + warnx("Unexpected CAM status %#x", status); + error = 1; + goto scsiformat_bailout; + } + + } while((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP); + + if (quiet == 0) + fprintf(stdout, "\nFormat Complete\n"); + + scsiformat_bailout: + + cam_freeccb(ccb); + + return(error); + } + void usage(int verbose) { *************** *** 2644,2649 **** --- 2939,2945 ---- " [-D ][-O offset][-q]\n" " [-R syncrate][-v][-T ]\n" " [-U][-W bus_width]\n" + " camcontrol format [dev_id][generic args][-q][-w][-y]\n" " camcontrol help\n"); if (!verbose) return; *************** *** 2664,2669 **** --- 2960,2966 ---- "debug turn debugging on/off for a bus, target, or lun, or all devices\n" "tags report or set the number of transaction slots for a device\n" "negotiate report or set device negotiation parameters\n" + "format send the SCSI FORMAT UNIT command to the named device\n" "help this message\n" "Device Identifiers:\n" "bus:target specify the bus and target, lun defaults to 0\n" *************** *** 2712,2718 **** "-T \"enable\" or \"disable\" tagged queueing\n" "-U report/set user negotiation settings\n" "-W bus_width set the bus width in bits (8, 16 or 32)\n" ! "-v also print a Path Inquiry CCB for the controller\n", DEFAULT_DEVICE, DEFAULT_UNIT); } --- 3009,3019 ---- "-T \"enable\" or \"disable\" tagged queueing\n" "-U report/set user negotiation settings\n" "-W bus_width set the bus width in bits (8, 16 or 32)\n" ! "-v also print a Path Inquiry CCB for the controller\n" ! "format arguments:\n" ! "-q be quiet, don't print status messages\n" ! "-w don't send immediate format command\n" ! "-y don't ask any questions\n", DEFAULT_DEVICE, DEFAULT_UNIT); } *************** *** 2971,2976 **** --- 3272,3281 ---- case CAM_ARG_RATE: error = ratecontrol(cam_dev, retry_count, timeout, argc, argv, combinedopt); + break; + case CAM_ARG_FORMAT: + error = scsiformat(cam_dev, argc, argv, + combinedopt, retry_count, timeout); break; case CAM_ARG_USAGE: usage(1); ==== //depot/FreeBSD-ken/src/sys/cam/scsi/scsi_da.c#4 - /a/ken/perforce2/FreeBSD-ken/src/sys/cam/scsi/scsi_da.c ==== *** /tmp/tmp.63018.3 Sun Jan 16 23:51:11 2000 --- /a/ken/perforce2/FreeBSD-ken/src/sys/cam/scsi/scsi_da.c Sun Jan 16 23:50:09 2000 *************** *** 28,38 **** --- 28,44 ---- * $FreeBSD: src/sys/cam/scsi/scsi_da.c,v 1.41 1999/12/08 04:45:13 ken Exp $ */ + #ifdef _KERNEL #include "opt_hw_wdog.h" + #endif /* _KERNEL */ #include + + #ifdef _KERNEL #include #include + #endif /* _KERNEL */ + #include #include #include *************** *** 46,51 **** --- 52,62 ---- #include #include + #ifndef _KERNEL + #include + #include + #endif /* _KERNEL */ + #include #include #include *************** *** 54,59 **** --- 65,75 ---- #include + #ifndef _KERNEL + #include + #endif /* !_KERNEL */ + + #ifdef _KERNEL typedef enum { DA_STATE_PROBE, DA_STATE_NORMAL *************** *** 1539,1541 **** --- 1555,1592 ---- } } + + #else /* !_KERNEL */ + + /* + * XXX This is only left out of the kernel build to silence warnings. If, + * for some reason this function is used in the kernel, the ifdefs should + * be moved so it is included both in the kernel and userland. + */ + void + scsi_format_unit(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_int16_t ileave, + u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len, + u_int32_t timeout) + { + struct scsi_format_unit *scsi_cmd; + + scsi_cmd = (struct scsi_format_unit *)&csio->cdb_io.cdb_bytes; + scsi_cmd->opcode = FORMAT_UNIT; + scsi_cmd->byte2 = byte2; + scsi_ulto2b(ileave, scsi_cmd->interleave); + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/ (dxfer_len > 0) ? CAM_DIR_OUT : CAM_DIR_NONE, + tag_action, + data_ptr, + dxfer_len, + sense_len, + sizeof(*scsi_cmd), + timeout); + } + + #endif /* _KERNEL */ ==== //depot/FreeBSD-ken/src/sys/cam/scsi/scsi_da.h#1 - /a/ken/perforce2/FreeBSD-ken/src/sys/cam/scsi/scsi_da.h ==== *** /tmp/tmp.63018.4 Sun Jan 16 23:51:11 2000 --- /a/ken/perforce2/FreeBSD-ken/src/sys/cam/scsi/scsi_da.h Sun Jan 16 23:50:26 2000 *************** *** 63,68 **** --- 63,87 ---- u_int8_t control; }; + /* + * NOTE: The lower three bits of byte2 of the format CDB are the same as + * the lower three bits of byte2 of the read defect data CDB, below. + */ + struct scsi_format_unit + { + u_int8_t opcode; + u_int8_t byte2; + #define FU_FORMAT_MASK SRDD10_DLIST_FORMAT_MASK + #define FU_BLOCK_FORMAT SRDD10_BLOCK_FORMAT + #define FU_BFI_FORMAT SRDD10_BYTES_FROM_INDEX_FORMAT + #define FU_PHYS_FORMAT SRDD10_PHYSICAL_SECTOR_FORMAT + #define FU_CMPLST 0x08 + #define FU_FMT_DATA 0x10 + u_int8_t vendor_specific; + u_int8_t interleave[2]; + u_int8_t control; + }; + struct scsi_reassign_blocks { u_int8_t opcode; *************** *** 128,139 **** --- 147,186 ---- * Opcodes */ #define REZERO_UNIT 0x01 + #define FORMAT_UNIT 0x04 #define REASSIGN_BLOCKS 0x07 #define MODE_SELECT 0x15 #define MODE_SENSE 0x1a #define READ_DEFECT_DATA_10 0x37 #define READ_DEFECT_DATA_12 0xb7 + struct format_defect_list_header + { + u_int8_t reserved; + u_int8_t byte2; + #define FU_DLH_VS 0x01 + #define FU_DLH_IMMED 0x02 + #define FU_DLH_DSP 0x04 + #define FU_DLH_IP 0x08 + #define FU_DLH_STPF 0x10 + #define FU_DLH_DCRT 0x20 + #define FU_DLH_DPRY 0x40 + #define FU_DLH_FOV 0x80 + u_int8_t defect_list_length[2]; + }; + + struct format_ipat_descriptor + { + u_int8_t byte1; + #define FU_INIT_NO_HDR 0x00 + #define FU_INIT_LBA_MSB 0x40 + #define FU_INIT_LBA_EACH 0x80 + #define FU_INIT_SI 0x20 + u_int8_t pattern_type; + #define FU_INIT_PAT_DEFAULT 0x00 + #define FU_INIT_PAT_REPEAT 0x01 + u_int8_t pat_length[2]; + }; struct scsi_reassign_blocks_data { *************** *** 317,321 **** --- 364,384 ---- u_int8_t reserved2; u_int8_t recovery_time_limit[2]; }; + + __BEGIN_DECLS + /* + * XXX This is only left out of the kernel build to silence warnings. If, + * for some reason this function is used in the kernel, the ifdefs should + * be moved so it is included both in the kernel and userland. + */ + #ifndef _KERNEL + void scsi_format_unit(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_int16_t ileave, + u_int8_t *data_ptr, u_int32_t dxfer_len, + u_int8_t sense_len, u_int32_t timeout); + + #endif /* !_KERNEL */ + __END_DECLS #endif /* _SCSI_SCSI_DA_H */