/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2011 Gary Mills
*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
*/
/*
* This file contains functions to implement automatic configuration
* of scsi disks.
*/
#include "global.h"
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <ctype.h>
#include "misc.h"
#include "param.h"
#include "ctlr_scsi.h"
#include "auto_sense.h"
#include "partition.h"
#include "label.h"
#include "startup.h"
#include "analyze.h"
#include "io.h"
#include "hardware_structs.h"
#include "menu_fdisk.h"
extern int nctypes;
extern struct ctlr_type ctlr_types[];
/*
* Marker for free hog partition
*/
/*
* Default partition tables
*
* Disk capacity root swap usr
* ------------- ---- ---- ---
* 0mb to 64mb 0 0 remainder
* 64mb to 180mb 16mb 16mb remainder
* 180mb to 280mb 16mb 32mb remainder
* 280mb to 380mb 24mb 32mb remainder
* 380mb to 600mb 32mb 32mb remainder
* 600mb to 1gb 32mb 64mb remainder
* 1gb to 2gb 64mb 128mb remainder
* 2gb on up 128mb 128mb remainder
*/
struct part_table {
};
{ 0, 0, 0, 0, 0, 0, HOG, 0}
};
};
};
};
};
};
};
};
static struct default_partitions {
} default_partitions[] = {
};
#define DEFAULT_PARTITION_TABLE_SIZE \
(sizeof (default_partitions) / sizeof (struct default_partitions))
/*
* msgs for check()
*/
/*
* Disks on symbios(Hardwire raid controller) return a fixed number
* of heads(64)/cylinders(64) and adjust the cylinders depending
* capacity of the configured lun.
* In such a case we get number of physical cylinders < 3 which
* is the minimum required by solaris(2 reserved + 1 data cylinders).
*
*/
/*
* assuming a minimum of 32 block cylinders.
*/
#if defined(_SUNOS_VTOC_8)
/* These are 16-bit fields */
#endif /* defined(_SUNOS_VTOC_8) */
/*
* minimum number of cylinders required by Solaris.
*/
/*
* ANSI prototypes for local static functions
*/
static struct disk_type *generic_disk_sense(
int fd,
int can_prompt,
struct scsi_inquiry *inquiry,
struct scsi_capacity_16 *capacity,
char *disk_name);
static int use_existing_disk_type(
int fd,
int can_prompt,
struct scsi_inquiry *inquiry,
struct scsi_capacity_16 *capacity);
int ctrl_type);
static struct disk_type *find_scsi_disk_type(
char *disk_name,
static struct disk_type *find_scsi_disk_by_name(
char *disk_name);
static struct ctlr_type *find_scsi_ctlr_type(void);
static struct ctlr_info *find_scsi_ctlr_info(
static struct disk_type *new_scsi_disk_type(
int fd,
char *disk_name,
static struct disk_info *find_scsi_disk_info(
static char *get_sun_disk_name(
char *disk_name,
struct scsi_inquiry *inquiry);
static char *strcopy(
char *dst,
char *src,
int n);
#if defined(_SUNOS_VTOC_8)
static diskaddr_t square_box(
#endif /* defined(_SUNOS_VTOC_8) */
/*
* We need to get information necessary to construct a *new* efi
* label type
*/
struct disk_type *
{
int i;
if (option_msg && diag_msg) {
err_print("DKIOCINFO failed\n");
}
return (NULL);
}
} else {
}
/*
* get vendor, product, revision and capacity info.
*/
}
/*
* Now build the default partition table
*/
err_print("efi_alloc_and_init failed. \n");
}
/*
* Create a whole hog EFI partition table:
* S0 takes the whole disk except the primary EFI label,
* backup EFI label, and the reserved partition.
*/
- EFI_MIN_RESV_SIZE + 1;
/*
* S1-S6 are unassigned slices.
*/
}
/*
* The reserved slice
*/
/*
* Now stick all of it into the disk_type struct
*/
} else {
}
}
return (NULL);
}
part = (struct partition_info *)
zalloc(sizeof (struct partition_info));
return (disk);
}
static int
{
int error;
return (error);
}
static struct ctlr_type *
{
type == DKC_BLKDEV);
}
}
impossible("no DIRECT/VBD/BLKDEV controller type");
}
static struct ctlr_info *
{
type == DKC_BLKDEV);
return (ctlr);
}
}
impossible("no DIRECT/VBD/BLKDEV controller info");
/*NOTREACHED*/
}
static struct disk_info *
{
type == DKC_BLKDEV);
return (disk);
}
}
impossible("No DIRECT/VBD/BLKDEV disk info instance\n");
/*NOTREACHED*/
}
/*
* To convert EFI to SMI labels, we need to get label geometry.
* Unfortunately at this time there is no good way to do so.
* DKIOCGGEOM will fail if disk is EFI labeled. So we hack around
* it and clear EFI label, do a DKIOCGGEOM and put the EFI label
* back on disk.
* This routine gets the label geometry and initializes the label
* It uses cur_file as opened device.
* returns 0 if succeeds or -1 if failed.
*/
static int
{
int success = 0;
err_print("auto_label_init: calloc failed\n");
goto auto_label_init_out;
}
err_print("auto_label_init: GETEFI failed\n");
goto auto_label_init_out;
}
err_print("auto_label_init calloc2 failed");
goto auto_label_init_out;
}
/* get the LBA size and capacity */
err_print("auto_label_init: dkiocgmediainfo failed\n");
goto auto_label_init_out;
}
if (disk_info.dki_lbsize == 0) {
if (option_msg && diag_msg) {
err_print("auto_lbal_init: assuming 512 byte"
"block size");
}
}
/*
* back up efi label goes to capacity - 1, we are reading an extra block
* before the back up label.
*/
err_print("auto_label_init: GETEFI backup failed\n");
goto auto_label_init_out;
}
err_print("auto_label_init: SETEFI failed\n");
goto auto_label_init_out;
}
backsigp->efi_gpt_Signature = 0;
err_print("auto_label_init: SETEFI backup failed\n");
}
err_print("auto_label_init: GGEOM failed\n");
else
success = 1;
err_print("auto_label_init: SETEFI revert backup failed\n");
success = 0;
}
err_print("auto_label_init: SETEFI revert failed\n");
success = 0;
}
if (success == 0)
goto auto_label_init_out;
"%s cyl %u alt %u hd %u sec %u",
rval = 0;
#if defined(_FIRMWARE_NEEDS_FDISK)
(void) auto_solaris_part(label);
#endif /* defined(_FIRMWARE_NEEDS_FDISK) */
rval = -1;
}
if (data)
if (databack)
return (rval);
}
static struct disk_type *
int fd,
char *disk_name,
{
int i;
/*
* Get the disk controller info for this disk
*/
if (option_msg && diag_msg) {
err_print("DKIOCINFO failed\n");
}
return (NULL);
}
/*
* Find the ctlr_info for this disk.
*/
/*
* Allocate a new disk type for the direct controller.
*/
/*
* Find the disk_info instance for this disk.
*/
/*
* The controller and the disk should match.
*/
/*
* Link the disk into the list of disks
*/
} else {
}
}
/*
* Allocate and initialize the disk name.
*/
/*
* Initialize disk geometry info
*/
part = (struct partition_info *)
zalloc(sizeof (struct partition_info));
} else {
}
}
/*
* Set up the partition name
*/
/*
* Fill in the partition info from the label
*/
for (i = 0; i < NDKMAP; i++) {
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
#else
#endif /* defined(_SUNOS_VTOC_8) */
}
/*
* Use the VTOC if valid, or install a default
*/
} else {
}
/*
* Link the disk to the partition map
*/
return (disk);
}
/*
* Get a disk type that has label info. This is used to convert
* EFI label to SMI label
*/
struct disk_type *
{
if (auto_label_init(label) != 0) {
err_print("auto_direct_get_geom_label: failed to get label"
"geometry");
return (NULL);
} else {
return (disk_type);
}
}
/*
* Auto-sense a scsi disk configuration, ie get the information
* necessary to construct a label. We have two different
* ways to auto-sense a scsi disk:
* - format.dat override, via inquiry name
* - generic scsi, via standard mode sense and inquiry
* change geometry and reformat.
*/
struct disk_type *
int fd,
int can_prompt,
{
int force_format_dat = 0;
int force_generic = 0;
int deflt;
char *buf;
/*
* First, if expert mode, find out if the user
* wants to override any of the standard methods.
*/
if (can_prompt && expert_mode) {
deflt = 1;
&deflt, DATA_INPUT) == 0) {
force_format_dat = 1;
&deflt, DATA_INPUT) == 0) {
force_generic = 1;
}
}
/*
* Get the Inquiry data. If this fails, there's
* no hope for this disk, so give up.
*/
}
if (option_msg && diag_msg) {
err_print("Product id: ");
err_print("\n");
}
/*
* Get the Read Capacity
*/
}
/*
* If the reported capacity is set to zero, then the disk
* is not usable. If the reported capacity is set to all
* 0xf's, then this disk is too large. These could only
* happen with a device that supports LBAs larger than 64
* bits which are not defined by any current T10 standards
* or by error responding from target.
*/
if ((capacity.sc_capacity == 0) ||
if (option_msg && diag_msg) {
err_print("Invalid capacity\n");
}
}
if (option_msg && diag_msg) {
err_print("blocks: %llu (0x%llx)\n",
}
/*
* Extract the disk name for the format.dat override
*/
if (option_msg && diag_msg) {
}
}
/*
* Figure out which method we use for auto sense.
* If a particular method fails, we fall back to
* the next possibility.
*/
if (force_generic) {
}
/*
* Try for an existing format.dat first
*/
return (disk_type);
}
if (force_format_dat) {
return (NULL);
}
}
/*
* Otherwise, try using generic SCSI-2 sense and inquiry.
*/
}
/*ARGSUSED*/
static struct disk_type *
int fd,
int can_prompt,
struct scsi_inquiry *inquiry,
struct scsi_capacity_16 *capacity,
char *disk_name)
{
int setdefault = 0;
int rpm = 0;
union {
} u_page3;
union {
} u_page4;
/*
* If the name of this disk appears to be "SUN", use it,
* otherwise construct a name out of the generic
* Inquiry info. If it turns out that we already
* have a SUN disk type of this name that differs
* in geometry, we will revert to the generic name
* anyway.
*/
}
/*
* Get the number of blocks from Read Capacity data. Note that
* the logical block address range from 0 to capacity->sc_capacity.
* Limit the size to 2 TB (UINT32_MAX) to use with SMI labels.
*/
if (tblocks > UINT32_MAX)
else
/*
* Get current Page 3 - Format Parameters page
*/
setdefault = 1;
}
/*
* Get current Page 4 - Drive Geometry page
*/
setdefault = 1;
}
if (setdefault != 1) {
/* The inquiry of mode page 3 & page 4 are successful */
/*
* Correct for byte order if necessary
*/
/*
* Construct a new label out of the sense data,
* Inquiry and Capacity.
*
* If the disk capacity is > 1TB then simply compute
* the CHS values based on the total disk capacity and
* not use the values from mode-sense data.
*/
&nsect);
} else {
}
/*
* If the number of physical cylinders reported is less
* the SUN_MIN_CYL(3) then try to adjust the geometry so that
* we have atleast SUN_MIN_CYL cylinders.
*/
if (pcyl < SUN_MIN_CYL) {
setdefault = 1;
} else if (adjust_disk_geometry(
setdefault = 1;
}
}
}
/*
* Mode sense page 3 and page 4 are obsolete in SCSI-3. For
* newly developed large sector size disk, we will not rely on
* those two pages but compute geometry directly.
*/
/*
* If the number of cylinders or the number of heads reported
* is zero, we think the inquiry of page 3 and page 4 failed.
* We will set the geometry infomation by ourselves.
*/
}
/*
* The sd driver reserves 2 cylinders the backup disk label and
* the deviceid. Set the number of data cylinders to pcyl-acyl.
*/
if (option_msg && diag_msg) {
err_print("Geometry:\n");
#if defined(_SUNOS_VTOC_16)
#endif /* defined(_SUNOS_VTOC_16) */
}
/*
* Some drives do not support page4 or report 0 for page4->rpm,
* adjust it to AVG_RPM, 3600.
*/
if (option_msg && diag_msg)
err_print("The current rpm value %d is invalid,"
}
/*
* Some drives report 0 for nsect (page 3, byte 10 and 11) if they
* have variable number of sectors per track. So adjust nsect.
* Also the value is defined as vendor specific, hence check if
* it is in a tolerable range. The values (32 and 4 below) are
* chosen so that this change below does not generate a different
* geometry for currently supported sun disks.
*/
if ((nsect == 0) ||
err_print("Mode sense page(3) reports nsect value"
" as %d, adjusting it to %llu\n",
} else {
/* convert capacity to nsect * nhead * pcyl */
err_print("\nWARNING: Disk geometry is based on "
"capacity data.\n\n");
&nsect);
if (option_msg && diag_msg) {
err_print("Geometry:(after adjustment)\n");
#if defined(_SUNOS_VTOC_16)
#endif
}
}
}
/*
* Some drives report their physical geometry such that
* it is greater than the actual capacity. Adjust the
* geometry to allow for this, so we don't run off
* the end of the disk.
*/
if (option_msg && diag_msg) {
err_print("Computed capacity (%llu) exceeds actual "
"disk capacity (%llu)\n",
}
do {
pcyl--;
/*
* Try to adjust nsect instead of pcyl to see if we
* can optimize. For compatability reasons do this
* only in expert mode (refer to bug 1144812).
*/
do {
n--;
if (((diskaddr_t)p * nhead * n) >
/*
* Ask the user for a choice here.
*/
err_print("1. Capacity = %llu, with pcyl = %u "
"nhead = %u nsect = %u\n",
err_print("2. Capacity = %llu, with pcyl = %u "
"nhead = %u nsect = %u\n",
((diskaddr_t)p * nhead * n),
p, nhead, n);
pcyl = p;
nsect = n;
}
}
}
}
#if defined(_SUNOS_VTOC_8)
/*
* Finally, we need to make sure we don't overflow any of the
* fields in our disk label. To do this we need to `square
* the box' so to speak. We will lose bits here.
*/
if ((pcyl > MAXIMUM_NO_CYLINDERS &&
((nsect > MAXIMUM_NO_SECTORS) ||
(nhead > MAXIMUM_NO_HEADS))) ||
((nsect > MAXIMUM_NO_SECTORS) &&
(nhead > MAXIMUM_NO_HEADS))) {
err_print("This disk is too big to label. "
" You will lose some blocks.\n");
}
if ((pcyl > MAXIMUM_NO_CYLINDERS) ||
(nsect > MAXIMUM_NO_SECTORS) ||
(nhead > MAXIMUM_NO_HEADS)) {
int order;
switch (order) {
case 0x7: /* pcyl > nhead > nsect */
nblocks =
break;
case 0x6: /* pcyl > nsect > nhead */
nblocks =
break;
case 0x4: /* nsect > pcyl > nhead */
nblocks =
break;
case 0x0: /* nsect > nhead > pcyl */
nblocks =
break;
case 0x3: /* nhead > pcyl > nsect */
nblocks =
break;
case 0x1: /* nhead > nsect > pcyl */
nblocks =
break;
default:
/* How did we get here? */
impossible("label overflow adjustment");
/* Do something useful */
nblocks =
break;
}
if (option_msg && diag_msg &&
err_print("After adjusting geometry you lost"
" %llu of %llu blocks.\n",
}
/*
* Allow user to modify this by hand if desired.
*/
"\nGeometry: %u heads, %u sectors %u cylinders"
" result in %llu out of %llu blocks.\n"
"Do you want to modify the device geometry",
&deflt, DATA_INPUT) != 0)
break;
"Number of sectors per track",
err_print("Warning: %llu blocks exceeds "
"disk capacity of %llu blocks\n",
}
}
}
#endif /* defined(_SUNOS_VTOC_8) */
if (option_msg && diag_msg) {
err_print("\nGeometry after adjusting for capacity:\n");
}
"%s cyl %u alt %u hd %u sec %u",
#if defined(_FIRMWARE_NEEDS_FDISK)
goto err;
#endif /* defined(_FIRMWARE_NEEDS_FDISK) */
goto err;
}
/*
* Find an existing disk type defined for this disk.
* For this to work, both the name and geometry must
* match. If there is no such type, but there already
* is a disk defined with that name, but with a different
* geometry, construct a new generic disk name out of
* the inquiry information. Whatever name we're
* finally using, if there's no such disk type defined,
* build a new disk definition.
*/
(void) get_generic_disk_name(disk_name,
inquiry);
if (option_msg && diag_msg) {
}
sizeof (label->dkl_asciilabel),
"%s cyl %u alt %u hd %u sec %u",
}
goto err;
}
}
return (disk);
err:
if (option_msg && diag_msg) {
"Configuration via generic SCSI-2 information failed\n");
}
return (NULL);
}
/*ARGSUSED*/
static int
int fd,
int can_prompt,
struct scsi_inquiry *inquiry,
struct scsi_capacity_16 *capacity)
{
int pcyl;
int acyl;
int nhead;
int nsect;
int rpm;
/*
* Construct a new label out of the format.dat
*/
if (option_msg && diag_msg) {
err_print("Format.dat geometry:\n");
}
"%s cyl %u alt %u hd %u sec %u",
goto err;
}
return (1);
err:
if (option_msg && diag_msg) {
"Configuration via format.dat geometry failed\n");
}
return (0);
}
int
int ctrl_type)
{
int i;
int cyl;
int freecyls;
int blks_per_cyl;
int ncyl;
#ifdef lint
#endif
/*
* Install a default vtoc
*/
for (i = 0; i < NDKMAP; i++) {
}
/*
* Find a partition that matches this disk. Capacity
* is in integral number of megabytes.
*/
for (i = 0; i < DEFAULT_PARTITION_TABLE_SIZE; i++, dpt++) {
break;
}
}
if (i == DEFAULT_PARTITION_TABLE_SIZE) {
if (option_msg && diag_msg) {
err_print("No matching default partition (%llu)\n",
capacity);
}
return (0);
}
/*
* Go through default partition table, finding fixed
* sized entries.
*/
for (i = 0; i < NDKMAP; i++) {
ncyls[i] = 0;
} else {
/*
* Calculate number of cylinders necessary
* for specified size, rounding up to
* the next greatest integral number of
* cylinders. Always give what they
* asked or more, never less.
*/
}
}
if (freecyls < 0) {
if (option_msg && diag_msg) {
for (i = 0; i < NDKMAP; i++) {
if (ncyls[i] == 0)
continue;
err_print("Partition %d: %u cyls\n",
i, ncyls[i]);
}
err_print("Free cylinders exhausted (%d)\n",
freecyls);
}
return (0);
}
#if defined(i386)
/*
* Set the default boot partition to 1 cylinder
*/
freecyls -= 1;
/*
* If current disk type is not a SCSI disk,
* set the default alternates partition to 2 cylinders
*/
if (ctrl_type != DKC_SCSI_CCS) {
freecyls -= 2;
}
#endif /* defined(i386) */
/*
* Set the free hog partition to whatever space remains.
* It's an error to have more than one HOG partition,
* but we don't verify that here.
*/
for (i = 0; i < NDKMAP; i++) {
break;
}
}
/*
* Error checking
*/
ncyl = 0;
for (i = 0; i < NDKMAP; i++) {
}
/*
* Finally, install the partition in the label.
*/
cyl = 0;
#if defined(_SUNOS_VTOC_16)
if (i == 2 || ncyls[i] == 0)
continue;
}
for (i = 0; i < NDKMAP/2; i++) {
#elif defined(_SUNOS_VTOC_8)
for (i = 0; i < NDKMAP; i++) {
#else
#endif /* defined(_SUNOS_VTOC_16) */
if (i == 2 || ncyls[i] == 0) {
#if defined(_SUNOS_VTOC_8)
if (i != 2) {
}
#endif
continue;
}
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
#else
#endif /* defined(_SUNOS_VTOC_8) */
}
/*
* Set the whole disk partition
*/
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
#else
#endif /* defined(_SUNOS_VTOC_8) */
if (option_msg && diag_msg) {
float scaled;
err_print("\n");
for (i = 0; i < NDKMAP; i++) {
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
#else
#endif /* defined(_SUNOS_VTOC_8) */
continue;
err_print("Partition %d: ", i);
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
#else
#endif /* defined(_SUNOS_VTOC_8) */
if (scaled > 1024.0) {
} else {
}
#if defined(_SUNOS_VTOC_8)
err_print(" %6d cylinders\n",
#elif defined(_SUNOS_VTOC_16)
err_print(" %6d cylinders\n",
#else
#endif /* defined(_SUNOS_VTOC_8) */
}
err_print("\n");
}
return (1);
}
/*
* Find an existing scsi disk definition by this name,
* if possible.
*/
static struct disk_type *
char *disk_name,
{
ctlr = find_scsi_ctlr_type();
if (dp->dtype_asciilabel) {
return (dp);
}
}
}
}
/*
* Find an existing scsi disk definition by this name,
* if possible.
*/
static struct disk_type *
char *disk_name)
{
ctlr = find_scsi_ctlr_type();
if (dp->dtype_asciilabel) {
return (dp);
}
}
}
}
/*
* Return a pointer to the ctlr_type structure for SCSI
* disks. This list is built into the program, so there's
* no chance of not being able to find it, unless someone
* totally mangles the code.
*/
static struct ctlr_type *
{
}
}
impossible("no SCSI controller type");
}
/*
* Return a pointer to the scsi ctlr_info structure. This
* structure is allocated the first time format sees a
* disk on this controller, so it must be present.
*/
static struct ctlr_info *
{
return (NULL);
}
return (ctlr);
}
}
impossible("no SCSI controller info");
}
static struct disk_type *
int fd,
char *disk_name,
{
int i;
/*
* Get the disk controller info for this disk
*/
if (option_msg && diag_msg) {
err_print("DKIOCINFO failed\n");
}
return (NULL);
}
/*
* Find the ctlr_info for this disk.
*/
/*
* Allocate a new disk type for the SCSI controller.
*/
/*
* Find the disk_info instance for this disk.
*/
/*
* The controller and the disk should match.
*/
/*
* Link the disk into the list of disks
*/
} else {
}
}
/*
* Allocate and initialize the disk name.
*/
/*
* Initialize disk geometry info
*/
/*
* Attempt to match the partition map in the label
* with a know partition for this disk type.
*/
break;
}
}
/*
* If no match was made, we need to create a partition
* map for this disk.
*/
part = (struct partition_info *)
zalloc(sizeof (struct partition_info));
} else {
}
}
/*
* Set up the partition name
*/
/*
* Fill in the partition info from the label
*/
for (i = 0; i < NDKMAP; i++) {
#if defined(_SUNOS_VTOC_8)
#elif defined(_SUNOS_VTOC_16)
#else
#endif /* defined(_SUNOS_VTOC_8) */
}
}
/*
* Use the VTOC if valid, or install a default
*/
} else {
}
/*
* Link the disk to the partition map
*/
return (disk);
}
/*
* Delete a disk type from disk type list.
*/
int
{
else
ctlr = find_scsi_ctlr_type();
return (-1);
}
if (cur_label == L_TYPE_EFI)
return (0);
} else {
if (cur_label == L_TYPE_EFI)
return (0);
}
}
return (-1);
}
}
static struct disk_info *
{
return (disk);
}
}
impossible("No SCSI disk info instance\n");
}
static char *
char *disk_name,
struct scsi_inquiry *inquiry)
{
/*
* Extract the sun name of the disk
*/
return (disk_name);
}
char *
char *disk_name,
struct scsi_inquiry *inquiry)
{
char *p;
*p++ = '-';
*p++ = '-';
sizeof (inquiry->inq_revision));
return (disk_name);
}
/*
* Copy a string of characters from src to dst, for at
* most n bytes. Strip all leading and trailing spaces,
* and stop if there are any non-printable characters.
* Return ptr to the next character to be filled.
*/
static char *
char *dst,
char *src,
int n)
{
int i;
while (*src == ' ' && n > 0) {
src++;
n--;
}
if (*src == ' ') {
i++;
} else {
while (i-- > 0)
*dst++ = ' ';
}
}
*dst = 0;
return (dst);
}
/*
* adjust disk geometry.
* This is used when disk reports a disk geometry page having
* no of physical cylinders is < 3 which is the minimum required
* by Solaris (2 for storing labels and at least one as a data
* cylinder )
*/
int
{
/*
* reduce nsect by 2 for each iteration and re-calculate
* the number of cylinders.
*/
while (lnsect > MINIMUM_NO_SECTORS &&
lcyl < MINIMUM_NO_CYLINDERS) {
/*
* make sure that we do not go below MINIMUM_NO_SECTORS.
*/
}
/*
* If the geometry still does not satisfy
* MINIMUM_NO_CYLINDERS then try to reduce the
* no of heads.
*/
while (lnhead > MINIMUM_NO_HEADS &&
lcyl < MINIMUM_NO_CYLINDERS) {
}
/*
* now we should have atleast SUN_MIN_CYL cylinders.
* If we still do not get SUN_MIN_CYL with MINIMUM_NO_HEADS
* and MINIMUM_NO_HEADS then return error.
*/
if (lcyl < SUN_MIN_CYL)
return (1);
else {
return (0);
}
}
#if defined(_SUNOS_VTOC_8)
/*
* Reduce the size of one dimention below a specified
* limit with a minimum loss of volume. Dimenstions are
* assumed to be passed in form the largest value (the one
* that needs to be reduced) to the smallest value. The
* values will be twiddled until they are all less than or
* equal to their limit. Returns the number in the new geometry.
*/
static diskaddr_t
{
uint_t i;
/*
* Although the routine should work with any ordering of
* parameters, it's most efficient if they are passed in
* in decreasing magnitude.
*/
/*
* This is done in a very arbitrary manner. We could try to
* find better values but I can't come up with a method that
* would run in a reasonable amount of time. That could take
* approximately 65535 * 65535 iterations of a dozen flops each
* or well over 4G flops.
*
* First:
*
* Let's see how far we can go with bitshifts w/o losing
* any blocks.
*/
;
if (i) {
}
double d[4];
/*
* Second:
*
* Set the highest value at its limit then calculate errors,
* adjusting the 2nd highest value (we get better resolution
* that way).
*/
d[1] = lim1;
d[3] = *dim3;
/*
* If we overflowed the middle term, set it to its limit and
* chose a new low term.
*/
if (d[2] > lim2) {
d[2] = lim2;
}
/*
* Convert to integers.
*/
*dim1 = (int)d[1];
*dim2 = (int)d[2];
*dim3 = (int)d[3];
}
/*
* Fixup any other possible problems.
* If this happens, we need a new disklabel format.
*/
}
#endif /* defined(_SUNOS_VTOC_8) */
/*
* Calculate CHS values based on the capacity data.
*
* NOTE: This function is same as cmlb_convert_geomerty() function in
* cmlb kernel module.
*/
static void
{
/* Unlabeled SCSI floppy device */
if (total_capacity < 160) {
/* Less than 80K */
*nheadp = 1;
*pcylp = total_capacity;
*nsectp = 1;
return;
} else if (total_capacity <= 0x1000) {
*nheadp = 2;
*pcylp = 80;
return;
}
/*
* For all devices we calculate cylinders using the heads and sectors
* we assign based on capacity of the device. The algorithm is
* designed to be compatible with the way other operating systems
* lay out fdisk tables for X86 and to insure that the cylinders never
* exceed 65535 to prevent problems with X86 ioctls that report
* geometry.
* For some smaller disk sizes we report geometry that matches those
* used by X86 BIOS usage. For larger disks, we use SPT that are
* multiples of 63, since other OSes that are not limited to 16-bits
* for cylinders stop at 63 SPT we make do by using multiples of 63 SPT.
*
* The following table (in order) illustrates some end result
* calculations:
*
* Maximum number of blocks nhead nsect
*
* 2097152 (1GB) 64 32
* 16777216 (8GB) 128 32
* 1052819775 (502.02GB) 255 63
* 2105639550 (0.98TB) 255 126
* 3158459325 (1.47TB) 255 189
* 4211279100 (1.96TB) 255 252
* 5264098875 (2.45TB) 255 315
* ...
*/
if (total_capacity <= 0x200000) {
*nheadp = 64;
*nsectp = 32;
} else if (total_capacity <= 0x01000000) {
*nheadp = 128;
*nsectp = 32;
} else {
*nheadp = 255;
/* make nsect be smallest multiple of 63 */
*nsectp = ((total_capacity +
if (*nsectp == 0)
}
if (usable_capacity < total_capacity)
else
}