/*
* 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
*/
/*
*/
#include <fcntl.h>
#include <libdevinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stropts.h>
#include <unistd.h>
#include <kstat.h>
#include <errno.h>
#include <devid.h>
#include <dirent.h>
#include <sys/efi_partition.h>
/* included for uscsi */
#include <strings.h>
#include <sys/byteorder.h>
#include "libdiskmgt.h"
#include "disks_private.h"
/*
* Reduce SCSIBUFLEN to 0xfffc to ensure its 2 byte and 4 byte aligned
* since some HBAs on x86 architecture require 4 byte alignment.
* SCSI command get_configuration can return 64K -2 bytes of data.
* But the spec adds a comment that says current usage is only 1K.
*/
/* byte get macros */
static char *kstat_err_names[] = {
"Soft Errors",
"Hard Errors",
"Transport Errors",
"Media Error",
"Device Not Ready",
"No Device",
"Recoverable",
"Illegal Request",
"Predictive Failure Analysis",
};
static char *err_attr_names[] = {
};
/*
* **************** begin uscsi stuff ****************
*/
#if defined(_BIT_FIELDS_LTOH)
#elif defined(_BIT_FIELDS_HTOL)
#else
#endif
struct conf_feature {
#if defined(_BIT_FIELDS_LTOH)
#else
#endif /* _BIT_FIELDS_LTOH */
union features {
struct generic {
} gen;
struct profile_list {
#if defined(_BIT_FIELDS_LTOH)
#else
#endif /* _BIT_FIELDS_LTOH */
struct core {
} core;
struct morphing {
#if defined(_BIT_FIELDS_LTOH)
#else
#endif /* _BIT_FIELDS_LTOH */
} morphing;
struct removable {
#if defined(_BIT_FIELDS_LTOH)
#else
#endif /* _BIT_FIELDS_LTOH */
} removable;
struct random_readable {
#if defined(_BIT_FIELDS_LTOH)
#else
#endif /* _BIT_FIELDS_LTOH */
} rread;
struct cd_read {
#if defined(_BIT_FIELDS_LTOH)
#else
#endif /* _BIT_FIELDS_LTOH */
} cdread;
struct cd_audio {
#if defined(_BIT_FIELDS_LTOH)
#else
#endif /* _BIT_FIELDS_LTOH */
} audio;
struct dvd_css {
} dvdcss;
} features;
};
struct get_configuration {
};
struct capabilities {
#if defined(_BIT_FIELDS_LTOH)
#else
#endif /* _BIT_FIELDS_LTOH */
#if defined(_BIT_FIELDS_LTOH)
/* read capabilities */
#else
#endif /* _BIT_FIELDS_LTOH */
#if defined(_BIT_FIELDS_LTOH)
/* write capabilities */
#else
/* write capabilities */
#endif /* _BIT_FIELDS_LTOH */
/* there is more to this page, but nothing we care about */
};
struct mode_header_g2 {
};
/*
*/
struct scsi_ms_header {
};
sizeof (struct mode_page))
/*
* ********** end of uscsi stuff ************
*/
int *errp);
static int check_atapi(int fd);
static int get_cdrom_drvtype(int fd);
static char *get_err_attr_name(char *kstat_name);
struct scsi_ms_header *header);
descriptor_t **
int *errp)
{
switch (type) {
case DM_CONTROLLER:
case DM_PATH:
case DM_ALIAS:
case DM_MEDIA:
}
return (NULL);
}
/*
*/
descriptor_t **
{
/* at most one drive is associated with these descriptors */
return (NULL);
}
if (*errp != 0) {
return (NULL);
}
return (drives);
}
nvlist_t *
{
int fd;
return (NULL);
}
opath[0] = 0;
}
if (fd >= 0) {
}
return (attrs);
}
/*
* Check if we have the drive in our list, based upon the device id.
* We got the device id from the dev tree walk. This is encoded
* using devid_str_encode(3DEVID). In order to check the device ids we need
* to use the devid_compare(3DEVID) function, so we need to decode the
* string representation of the device id.
*/
{
int i;
return (NULL);
}
if (*errp != 0) {
return (NULL);
}
/*
* We have to loop through all of them, freeing the ones we don't
* want. Once drive is set, we don't need to compare any more.
*/
for (i = 0; drives[i]; i++) {
} else {
/* clean up the unused descriptor */
}
}
}
return (drive);
}
descriptor_t **
{
if (*errp != 0) {
return (NULL);
}
if (*errp != 0) {
} else {
}
}
return (drives);
}
char *
{
}
nvlist_t *
{
return (NULL);
}
if (stat_type == DM_DRV_STAT_PERFORMANCE ||
return (NULL);
}
return (NULL);
}
int status;
continue;
}
if (stat_type == DM_DRV_STAT_PERFORMANCE) {
} else {
}
if (status != 0) {
(void) kstat_close(kc);
return (NULL);
}
}
(void) kstat_close(kc);
*errp = 0;
return (stats);
}
if (stat_type == DM_DRV_STAT_TEMPERATURE) {
int fd;
temp.dkt_cur_temp) != 0) {
return (NULL);
}
} else {
return (NULL);
}
} else {
return (NULL);
}
*errp = 0;
return (stats);
}
return (NULL);
}
int
{
int status;
int fd;
return (part_format);
}
return (part_format);
}
/*
* Find the partition format.
*/
} else if ((status == VT_ENOTSUP) &&
}
return (part_format);
}
int
{
int error = 0;
int locked;
dp = cache_get_disklist();
}
return (error);
}
/*
* This function opens the disk generically (any slice).
*/
int
{
/*
* Just open the first devpath.
*/
}
}
return (-1);
}
static descriptor_t **
{
int i;
int cnt;
int pos;
/* count the number of drives in the snapshot */
return (NULL);
}
pos = 0;
for (i = 0; drives[i]; i++) {
int j;
int match;
/* Make sure the drive type is set */
match = 0;
for (j = 0; filter[j] != DM_FILTER_END; j++) {
match = 1;
break;
}
}
if (!match) {
}
}
*errp = 0;
return (found);
}
static int
{
switch (drive_type) {
case DK_UNKNOWN:
return (DM_DT_UNKNOWN);
case DK_MO_ERASABLE:
return (DM_DT_MO_ERASABLE);
case DK_MO_WRITEONCE:
return (DM_DT_MO_WRITEONCE);
case DK_AS_MO:
return (DM_DT_AS_MO);
case DK_CDROM:
return (DM_DT_CDROM);
case DK_CDR:
return (DM_DT_CDR);
case DK_CDRW:
return (DM_DT_CDRW);
case DK_DVDROM:
return (DM_DT_DVDROM);
case DK_DVDR:
return (DM_DT_DVDR);
case DK_DVDRAM:
return (DM_DT_DVDRAM);
case DK_FIXED_DISK:
return (DM_DT_FIXED);
case DK_FLOPPY:
return (DM_DT_FLOPPY);
case DK_ZIP:
return (DM_DT_ZIP);
case DK_JAZ:
return (DM_DT_JAZ);
default:
return (DM_DT_UNKNOWN);
}
}
static descriptor_t **
{
int pos;
*errp = 0;
cnt = 0;
cnt++;
}
cnt++;
}
}
/* set up the new array */
return (NULL);
}
pos = 0;
if (*errp != 0) {
return (NULL);
}
}
if (*errp != 0) {
return (NULL);
}
}
}
return (out_array);
}
static descriptor_t **
{
int cnt;
int i;
/* Count how many we have. */
/* make the snapshot */
if (controllers == NULL) {
return (NULL);
}
for (i = 0; diskp->controllers[i]; i++) {
if (*errp != 0) {
return (NULL);
}
}
controllers[i] = NULL;
*errp = 0;
return (controllers);
}
static descriptor_t **
{
int cnt;
int i;
/* Count how many we have. */
cnt = 0;
}
/* make the snapshot */
return (NULL);
}
/*
* We fill in the name field of the descriptor with the device_id
* when we deal with path descriptors originating from a drive.
* In that way we can use the device id within the path code to
* lookup the path state for this drive.
*/
for (i = 0; i < cnt; i++) {
if (*errp != 0) {
return (NULL);
}
}
*errp = 0;
return (paths);
}
static int
{
return (ENOMEM);
}
/* Make sure media is inserted and spun up. */
return (ENOMEM);
}
}
/* can't tell diff between dead & no media on removable drives */
return (ENOMEM);
}
} else {
/* check if the fixed drive is up or not */
return (ENOMEM);
}
} else {
return (ENOMEM);
}
}
}
return (ENOMEM);
}
!= 0) {
return (ENOMEM);
}
}
return (ENOMEM);
}
}
!= 0) {
return (ENOMEM);
}
}
return (ENOMEM);
}
}
}
return (ENOMEM);
}
}
return (ENOMEM);
}
}
return (ENOMEM);
}
}
return (0);
}
static int
{
int err = 0;
/* names are format: "sd0,err" - copy chars up to comma */
}
break;
}
}
}
return (err);
}
/*
* Getting the drive type depends on if the dev tree walk indicated that the
* drive was a CD-ROM or not. The kernal lumps all of the removable multi-media
* drives (e.g. CD, DVD, MO, etc.) together as CD-ROMS, so we need to use
* a uscsi cmd to check the drive type.
*/
static void
{
int opened_here = 0;
/* We may have already opened the device. */
if (fd < 0) {
opened_here = 1;
}
if (fd >= 0) {
/* use uscsi to determine drive type */
/* if uscsi fails, just call it a cd-rom */
}
} else {
}
}
if (opened_here) {
}
} else {
/* couldn't open */
}
}
}
}
static char *
{
int i;
for (i = 0; kstat_err_names[i] != NULL; i++) {
return (err_attr_names[i]);
}
}
return (NULL);
}
static int
{
}
static int
{
}
static int
{
return (ENOMEM);
}
return (ENOMEM);
}
return (ENOMEM);
}
return (ENOMEM);
}
int i;
char *attr_name;
continue;
continue;
}
case KSTAT_DATA_UINT32:
!= 0) {
return (ENOMEM);
}
break;
default:
/* Right now all of the error types are uint32 */
break;
}
}
}
return (0);
}
static int
{
}
}
/*
* There can be more than one kstat value when we have multi-path drives
* that are not under mpxio (since there is more than one kstat name for
* the drive in this case). So, we may have merge all of the kstat values
* to give an accurate set of stats for the drive.
*/
static int
{
}
}
/*
* uscsi function to get the rpm of the drive
*/
static int
{
int opened_here = 0;
/* We may have already opened the device. */
if (fd < 0) {
opened_here = 1;
}
if (fd >= 0) {
int status;
union {
} u_page4;
&header);
if (status) {
&header);
}
if (status) {
&header);
}
if (!status) {
#ifdef _LITTLE_ENDIAN
#endif /* _LITTLE_ENDIAN */
}
if (opened_here) {
}
}
return (rpm);
}
/*
* ******** the rest of this is uscsi stuff for the drv type ********
*/
/*
* We try a get_configuration uscsi cmd. If that fails, try a
* atapi_capabilities cmd. If both fail then this is an older CD-ROM.
*/
static int
{
int flen;
/* The first profile is the preferred one for the drive. */
if (flen > 0) {
int prof_num;
if (dm_debug > 1) {
prof_num);
}
switch (prof_num) {
case PROF_MAGNETO_OPTICAL:
return (DM_DT_MO_ERASABLE);
case PROF_OPTICAL_WO:
return (DM_DT_MO_WRITEONCE);
case PROF_OPTICAL_ASMO:
return (DM_DT_AS_MO);
case PROF_CDROM:
return (DM_DT_CDROM);
case PROF_CDR:
return (DM_DT_CDR);
case PROF_CDRW:
return (DM_DT_CDRW);
case PROF_DVDROM:
return (DM_DT_DVDROM);
case PROF_DVDRAM:
return (DM_DT_DVDRAM);
case PROF_DVDRW_REST:
return (DM_DT_DVDRW);
case PROF_DVDRW_SEQ:
return (DM_DT_DVDRW);
case PROF_DVDRW:
return (DM_DT_DVDRW);
case PROF_DDCD_ROM:
return (DM_DT_DDCDROM);
case PROF_DDCD_R:
return (DM_DT_DDCDR);
case PROF_DDCD_RW:
return (DM_DT_DDCDRW);
}
}
}
/* see if the atapi capabilities give anything */
return (check_atapi(fd));
}
static int
{
int bdesclen;
cap = (struct capabilities *)
if (dm_debug > 1) {
}
/* These are in order of how we want to report the drv type. */
if (cap->dvdram_write) {
return (DM_DT_DVDRAM);
}
if (cap->dvdr_write) {
return (DM_DT_DVDR);
}
if (cap->dvdrom_read) {
return (DM_DT_DVDROM);
}
if (cap->cdrw_write) {
return (DM_DT_CDRW);
}
return (DM_DT_CDR);
}
return (DM_DT_CDROM);
}
}
/* everything failed, so this is an older CD-ROM */
if (dm_debug > 1) {
}
return (DM_DT_CDROM);
}
static uint64_t
{
return (value);
}
static void
{
}
static void
{
}
static void
{
/* group 1 mode page */
}
static int
{
int nbytes;
int status;
int maximum;
/*
* Allocate a buffer for the mode sense headers
* and mode sense data itself.
*/
nbytes = sizeof (struct block_descriptor) +
sizeof (struct mode_header) + page_size;
return (-1);
}
/*
* Build and execute the uscsi ioctl
*/
}
return (-1);
}
/*
* 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.
*/
hdr->bdesc_length != 0) {
return (-1);
}
return (-1);
}
/*
* 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
* of the two.
*/
return (-1);
}
return (0);
}