ctlr_scsi.c revision 8007dbcdc98ad962c25a154429c45edfa5cc842b
0N/A * The contents of this file are subject to the terms of the 0N/A * Common Development and Distribution License, Version 1.0 only 0N/A * (the "License"). You may not use this file except in compliance 0N/A * See the License for the specific language governing permissions 0N/A * and limitations under the License. 0N/A * When distributing Covered Code, include this CDDL HEADER in each 0N/A * If applicable, add the following below this CDDL HEADER, with the 0N/A * fields enclosed by brackets "[]" replaced with your own identifying 0N/A * information: Portions Copyright [yyyy] [name of copyright owner] * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. #
pragma ident "%Z%%M% %I% %E% SMI" * This file contains the routines for embedded scsi disks #
endif /* DAD_MODE_CACHE_CCS *//* format defect header bits */ * Local prototypes for ANSI C compilers * Names of commands. Must have SCMD_UNKNOWN at end of list. * Strings for printing mode sense page control values * Strings for printing the mode select options * READ DEFECT DATA commands is optional as per SCSI-2 spec. * Hence check if the read_defect_data command fails with * Invalid Opcode so that we can give a more meaningful message * Read or write the disk. * If the max xfercnt hasn't been determined start with BUF_SECTS * (currently 126 == 63K), otherwise use the xfercnt value * my caller saved from the previous invocation. * Build and execute the uscsi ioctl. We build a group0 * or group1 command as necessary, since some targets * do not support group1 commands. if (
blkno >
0xffffffff) {
* check if partial DMA breakup required * if so, reduce the request size by half and retry * If the xfercnt wasn't previously saved or if the * new value is smaller than the old value, save the * current value in my caller's save area. * Check to see if the disk has been formatted. * If we are able to read the first track, we conclude that * the disk has been formatted. * Try to read the first four blocks. * Format the disk, the whole disk, and nothing but the disk. * Determine if the target appears to be SCSI-2 * compliant. We handle mode sense/mode selects * a little differently, depending upon CCS/SCSI-2 * Reserve the scsi disk before performing mode select and * format operations. This will keep other hosts, if any, from * touching the disk while we are here. * Set up the various SCSI parameters specified before * formatting the disk. Each routine handles the * parameters relevent to a particular page. * If no parameters are specified for a page, there's * no need to do anything. Otherwise, issue a mode * sense for that page. If a specified parameter * differs from the drive's default value, and that * parameter is not fixed, then issue a mode select to * set the default value for the disk as specified * If we're debugging the drive, dump every page * the device supports, for thorough analysis. * Construct the uscsi format ioctl. The form depends * upon the defect list the user extracted. If s/he * extracted the "original" list, we format with only * the P (manufacturer's defect) list. Otherwise, we * format with both the P and the G (grown) list. * To format with the P and G list, we set the fmtData * bit, and send an empty list. To format with the * P list only, we also set the cmpLst bit, meaning * that the (empty) list we send down is the complete * G list, thereby discarding the old G list.. * No G list. The empty list we send down /* check if format with immed was successfully accepted */ /* immed accepted pool to completion */ /* clear defect header and try basecase format */ /* format failure check */ * formatting failed with fmtdata = 1. * Check if defects list command is supported, if it * is not supported then use fmtdata = 0. * A FmtData bit of zero indicates, the * source of defect information is not specified. * proceed to format using with mode selects. * Format without any of the standard mode selects ignoring Grown defects list. "Retry of formatting operation without any of the standard\n" "mode selects and ignoring disk's Grown Defects list. The\n" "disk may be able to be reformatted this way if an earlier\n" "formatting operation was interrupted by a power failure or\n" "SCSI bus reset. The Grown Defects list will be recreated\n" "by format verification and surface analysis.\n\n");
if (
check(
"Retry format without mode selects and Grown Defects list")
* Construct the uscsi format ioctl. * To format with the P and G list, we set the fmtData * and cmpLst bits to zero. To format with just the * P list, we set the fmtData bit (meaning that we will * send down a defect list in the data phase) and the * cmpLst bit (meaning that the list we send is the * complete G list), and a defect list header with * a defect list length of zero. /* No G list. Send empty defect list to replace it */ /* check if format with immed was successfully accepted */ /* immed accepted pool to completion */ /* clear defect header and try basecase format */ /* fmt_print(status ? "Format failed\n\n" : "Format ok\n\n"); */ * Estimate the time required for format operation (See 1163770). * format time = (5_revs * p4_heads * p4_cylinders) / p4_rpm * 5 revolutions (correspond to format_time keyword in format.dat file) are: * 2 rev. for writing the track * 1 rev. for cerifying the data integrity of the track * The return value is a good estimate on the formatting time in minutes. * Caller should add 50% margin to cover defect management overhead. * Issue a mode sense to determine the default parameters * If it fail, try to use the saved or current instead. * We only need the common subset between the CCS * and SCSI-2 structures, so we can treat both * Some drives report 0 for page4->rpm, adjust it to AVG_RPM, 3600. err_print(
"Mode sense page(4) reports rpm value as %d," * Check disk error recovery parameters via mode sense. * Issue a mode select if we need to change something. * If debugging, issue mode senses on the default and * Issue a mode sense to determine the saved parameters * If the saved values fail, use the current instead. * We only need the common subset between the CCS * and SCSI-2 structures, so we can treat both * cases identically. Whatever the drive gives * us, we return to the drive in the mode select, * delta'ed by whatever we want to change. * Ask for changeable parameters. * We need to issue a mode select only if one or more * parameters need to be changed, and those parameters * are flagged by the drive as changeable. * Report any changes so far... "PAGE 1: read retries= %d (%d) write retries= %d (%d)\n",
* Apply any changes requested via the change list method * If no changes required, do not issue a mode select * We always want to set the Page Format bit for mode * selects. Set the Save Page bit if the drive indicates * that it can save this page via the mode sense. /* If failed, try not saving mode select params. */ Warning: Using default error recovery parameters.\n\n");
* If debugging, issue mode senses on the current and * saved values, so we can see the result of the mode * Issue a mode select if we need to change something. * If debugging, issue mode senses on the default and * Issue a mode sense to determine the saved parameters * If the saved values fail, use the current instead. * We only need the common subset between the CCS * and SCSI-2 structures, so we can treat both * cases identically. Whatever the drive gives * us, we return to the drive in the mode select, * delta'ed by whatever we want to change. * Ask for changeable parameters. * We need to issue a mode select only if one or more * parameters need to be changed, and those parameters * are flagged by the drive as changeable. * Apply any changes requested via the change list method * If no changes required, do not issue a mode select * We always want to set the Page Format bit for mode * selects. Set the Save Page bit if the drive indicates * that it can save this page via the mode sense. /* If failed, try not saving mode select params. */ * If debugging, issue mode senses on the current and * saved values, so we can see the result of the mode * Check disk format parameters via mode sense. * Issue a mode select if we need to change something. * If debugging, issue mode senses on the default and * Issue a mode sense to determine the saved parameters * If the saved values fail, use the current instead. * We only need the common subset between the CCS * and SCSI-2 structures, so we can treat both * cases identically. Whatever the drive gives * us, we return to the drive in the mode select, * delta'ed by whatever we want to change. * Ask for changeable parameters. * We need to issue a mode select only if one or more * parameters need to be changed, and those parameters * are flagged by the drive as changeable. * Notify user of any changes so far fmt_print(
"PAGE 3: trk skew= %d (%d) cyl skew= %d (%d) ",
* Apply any changes requested via the change list method * If no changes required, do not issue a mode select * We always want to set the Page Format bit for mode * selects. Set the Save Page bit if the drive indicates * that it can save this page via the mode sense. /* If failed, try not saving mode select params. */ err_print(
"Warning: Using default drive format parameters.\n");
err_print(
"Warning: Drive format may not be correct.\n\n");
* If debugging, issue mode senses on the current and * saved values, so we can see the result of the mode * Check disk geometry parameters via mode sense. * Issue a mode select if we need to change something. * If debugging, issue mode senses on the default and * Issue a mode sense to determine the saved parameters * If the saved values fail, use the current instead. * We only need the common subset between the CCS * and SCSI-2 structures, so we can treat both * cases identically. Whatever the drive gives * us, we return to the drive in the mode select, * delta'ed by whatever we want to change. * Ask for changeable parameters. * We need to issue a mode select only if one or more * parameters need to be changed, and those parameters * are flagged by the drive as changeable. * Notify user of changes so far fmt_print(
"PAGE 4: cylinders= %d heads= %d (%d)\n",
* Apply any changes requested via the change list method * If no changes required, do not issue a mode select * We always want to set the Page Format bit for mode * selects. Set the Save Page bit if the drive indicates * that it can save this page via the mode sense. /* If failed, try not saving mode select params. */ err_print(
"Warning: Using default drive geometry.\n\n");
* If debugging, issue mode senses on the current and * saved values, so we can see the result of the mode * Check SCSI-2 disk cache parameters via mode sense. * Issue a mode select if we need to change something. * Only SCSI-2 devices support this page * If debugging, issue mode senses on the default and * Issue a mode sense to determine the saved parameters * If the saved values fail, use the current instead. * We only need the common subset between the CCS * and SCSI-2 structures, so we can treat both * cases identically. Whatever the drive gives * us, we return to the drive in the mode select, * delta'ed by whatever we want to change. * Ask for changeable parameters. * We need to issue a mode select only if one or more * parameters need to be changed, and those parameters * are flagged by the drive as changeable. * Apply any changes requested via the change list method * If no changes required, do not issue a mode select * We always want to set the Page Format bit for mode * selects. Set the Save Page bit if the drive indicates * that it can save this page via the mode sense. /* If failed, try not saving mode select params. */ Warning: Using default SCSI-2 cache parameters.\n\n");
* If debugging, issue mode senses on the current and * saved values, so we can see the result of the mode * Check CCS disk cache parameters via mode sense. * Issue a mode select if we need to change something. * First, determine if we need to look at page 38 at all. * Not all devices support it. * If debugging, issue mode senses on the default and * Issue a mode sense to determine the saved parameters * If the saved values fail, use the current instead. * We only need the common subset between the CCS * and SCSI-2 structures, so we can treat both * cases identically. Whatever the drive gives * us, we return to the drive in the mode select, * delta'ed by whatever we want to change. * Ask for changeable parameters. * We need to issue a mode select only if one or more * parameters need to be changed, and those parameters * are flagged by the drive as changeable. * Notify the user of changes up to this point fmt_print(
"PAGE 38: cache mode= 0x%x (0x%x)\n",
* Apply any changes requested via the change list method * If no changes required, do not issue a mode select * We always want to set the Page Format bit for mode * selects. Set the Save Page bit if the drive indicates * that it can save this page via the mode sense. /* If failed, try not saving mode select params. */ err_print(
"Warning: Using default CCS cache parameters.\n\n");
* If debugging, issue mode senses on the current and * saved values, so we can see the result of the mode * Extract the manufacturer's defect list. * Extract the current defect list. * For embedded scsi drives, this means both the manufacturer's (P) * and the grown (G) lists. * Extract the grown list only int len;
/* returned defect list length */ * First get length of list by asking for the header only. * Build and execute the uscsi ioctl * check if read_defect_list_is_supported. err_print(
"\nWARNING: Current Disk does not support" "grown" :
"manufacturer's");
* Read the full list the second time err_print(
"can't read defect list 2nd time");
* Build and execute the uscsi ioctl * Convert a SCSI-style defect list to our generic format. * We can handle different format lists. * Allocate space for the rest of the list. * Since we reached the end of the list, old_defect * now points to an invalid reference, since it got * incremented in the above operation. So we don't * need to proceed further. new_len needs to be * incremented to account for the last element. * Merge adjacent contiguous defect entries into one * and update the length of the defect err_print(
"scsi_convert_list_to_new: can't deal with it\n");
* Execute a command and determine the result. * Uses the "uscsi" ioctl interface, which is * If the user wants request sense data to be returned * in case of error then , the "uscsi_cmd" structure * should have the request sense buffer allocated in * Set function flags for driver. * If this command will perform a read, set the USCSI_READ flag * uscsi_cdb is declared as a caddr_t, so any CDB * command byte with the MSB set will result in a * compiler error unless we cast to an unsigned value. * Set timeout: 30 seconds for all commands except format * Get the timeout value computed using page4 geometry. * add 50% margin to cover defect management overhead. * add another 50% margin to have a safe timeout. * If it exceeds 2 hours then use this value. timeout *=
60;
/* convert to seconds */ * formatting drives with huge capacity * will cause these heuristics to come * up with times that overflow ~9 hours err_print(
"format_timeout set to %d seconds, %d" * Set up Request Sense buffer * Clear global error state * Check the status and return appropriate errors if the disk is * unavailable (could be formatting) or reserved (by other host). * In either case we can not talk to the disk now. * Check for physically removed or completely unresponsive drive * If an automatic Request Sense gave us valid * info about the error, we may be able to use * that to print a reasonable error msg. err_print(
"No request sense for command %s\n",
err_print(
"Request sense status for command %s: 0x%x\n",
err_print(
"Request sense for command %s failed\n",
* If the failed command is a Mode Select, and the * target is indicating that it has rounded one of * the mode select parameters, as defined in the SCSI-2 * specification, then we should accept the command * Execute a uscsi mode sense command. * This can only be used to return one page at a time. * Return the mode header/block descriptor and the actual * page data separately - this allows us to support * devices which return either 0 or 1 block descriptors. * Whatever a device gives us in the mode header/block descriptor * will be returned to it upon subsequent mode selects. int fd;
/* file descriptor */ * Allocate a buffer for the mode sense headers * and mode sense data itself. * Build and execute the uscsi ioctl * Verify that the returned data looks reasonabled, * find the actual page data, and copy it into the * user's buffer. Copy the mode_header and block_descriptor * into the header structure, which can then be used to * return the same data to the drive when issuing a mode select. \nMode sense page 0x%x: block descriptor length %d incorrect\n",
\nMode sense page 0x%x: incorrect page code 0x%x\n",
* Accept up to "page_size" bytes of mode sense data. * This allows us to accept both CCS and SCSI-2 * structures, as long as we request the greater Mode sense page 0x%x: incorrect page length %d - expected max %d\n",
* Execute a uscsi mode select command. int fd;
/* file descriptor */ * Allocate a buffer for the mode select header and data * Build the mode select data out of the header and page data * This allows us to support devices which return either * 0 or 1 block descriptors. * Dump the structures if anyone's interested * Fix the code for byte ordering * Put the header and data together * Build and execute the uscsi ioctl * Execute a uscsi inquiry command and return the * Build and execute the uscsi ioctl * Dump the inquiry data if anyone's interested * Return the Read Capacity information * Build and execute the uscsi ioctl * A capacity of 0xffffffff in response to a * READ CAPACITY 10 indicates that the lun * is too large to report the size in a 32 bit * value, and a READ CAPACITY 16 is required * to get the correct size. * Read Capacity (16) is a Service Action In command. One * command byte (0x9E) is overloaded for multiple operations, * with the second CDB byte specifying the desired operation * Fill in allocation length field * Indicate which of the commands failed * Dump the capacity data if anyone's interested * Reserve the current disk * Build and execute the uscsi ioctl * Allocate memory for the mode sense buffer. * Build and execute the uscsi ioctl err_print(
"\nMode sense page 0x3f (%s) failed\n",
err_print(
" Sense data formatted incorrectly:\n");
* Get asc, ascq and info field from sense data. There are two * possible formats (fixed sense data and descriptor sense data) * depending on the value of es_code. * Retrieve "information" field from descriptor format * sense data. Iterates through each sense descriptor * looking for the information descriptor and returns * the information field from that descriptor. * Initialize result to -1 indicating there is no information * The first descriptor will immediately follow the header * Calculate the amount of valid sense data * Iterate through the list of descriptors, stopping when we * Check if this is an information descriptor. We can * use the scsi_information_sense_descr structure as a * template sense the first two fields are always the * Found an information descriptor. Copy the * information field. There will only be one * information descriptor so we can stop looking. * Get pointer to the next descriptor. The "additional * length" field holds the length of the descriptor except * for the "type" and "additional length" fields, so * we need to add 2 to get the total length. * Return a pointer to a string telling us the name of the command. * Return true if we support a particular mode page * Figure out which bits changed, and * are marked as changeable. If this * result actually differs from the * current value, update the current * value, and note that a mode select for (m =
0x01; m <
0x100; m <<=
1) {
* Return whether a given page is affected by an item on * Labels for the various fields of the scsi_extended_sense structure "Error class and code: ",
"Incorrect length indicator: ",
"Additional sense length: ",
"Command-specific information: ",
"Additional sense code: ",
"Additional sense code qualifier: ",
"Field replaceable unit code: ",
"Additional sense bytes: " * Display the full scsi_extended_sense as returned by the device * target should be capable of returning at least 18 * bytes of data, i.e upto rq->es_skey_specific field. * The additional sense bytes (2 or more ...) are optional. * Labels for the various fields of the scsi_descr_sense_hdr structure "Error class and code: ",
"Additional sense length: ",
"Additional sense code: ",
"Additional sense code qualifier: ",
"Additional sense bytes: " * Display the full descriptor sense data as returned by the device * target must return at least 8 bytes of data /* Print descriptor sense header */ * Now print any sense descriptors. The first descriptor will * immediately follow the header * Calculate the amount of valid sense data * Iterate through the list of descriptors, stopping when we * run out of sense data. Descriptor format is: * <Descriptor type> <Descriptor length> <Descriptor data> ... * Determine descriptor type. We can use the * scsi_information_sense_descr structure as a * template since the first two fields are always the * Get pointer to the next descriptor. The "additional * length" field holds the length of the descriptor except * for the "type" and "additional length" fields, so * we need to add 2 to get the total length. * Function checks if READ DEFECT DATA command is supported * First get length of list by asking for the header only. * Build and execute the uscsi ioctl * check if read_defect_list_is_supported. * Format the disk, the whole disk, and nothing but the disk. * Function will be called only for disks * which do not support read defect list command. * Construct the uscsi format ioctl. * Use fmtdata = 0 , indicating the no source of * defects information is provided . * Function will be called only for disks * which do not support read defect list command. * Description: This function is used by scsi_format and * scsi_format_raw to poll the device while the FORMAT * UNIT cdb in in progress. * file descriptor to poll /* Loop sending TEST UNIT READY until format is complete */ /* clear last request sense data */ /* issue test unit ready */ /* If device returns not ready we get EIO */ /* Check SKSV if progress indication is avail */ /* Store progress indication */ * check to see if we can estimate * time remaining - wait until the format * is at least 5 percent complete to avoid * wildly-fluctuating time estimates /* display with estimated time */ "(%02d:%02d:%02d remaining) ",
/* flush or the screen will not update */ /* format not in progress */ fmt_print(
"\nRequest Sense ASC=0x%x ASCQ=0x%x",
/* delay so we don't waste cpu time */