Permalink
Switch branches/tags
166 20160526 HEAD-2315 OS-3068 OS-4683 OS-5783 OS-6443-final OS-6443 OS-6473 OS-6534 OS-7200 OS-7217 OS-7320 RFD96 arm64-dev backout_9421 dev-bhyve-promisc dev-overlay eu-ams-1 gcc4 ikev2 intrd jclulow_pf libzfs_diff master mdb-union nat-reform netperf openssl release-20120528 release-20120626 release-20120712 release-20120726 release-20120809 release-20120823 release-20120906 release-20120920 release-20121004 release-20121101 release-20121129 release-20121213 release-20121227 release-20130110 release-20130124 release-20130207 release-20130221 release-20130307 release-20130321 release-20130404 release-20130418 release-20130502 release-20130515 release-20130530 release-20130613 release-20130627 release-20130711 release-20130725 release-20130822 release-20130905 release-20130919 release-20131003 release-20131017 release-20131031 release-20131128 release-20131212 release-20140109 release-20140123 release-20140206 release-20140220 release-20140307 release-20140320 release-20140403 release-20140417 release-20140501 release-20140515 release-20140529 release-20140612 release-20140626 release-20140703 release-20140710 release-20140724 release-20140807 release-20140821 release-20140904 release-20140918 release-20141002 release-20141016 release-20141030 release-20141113 release-20141127 release-20141211 release-20141225 release-20150108 release-20150122 release-20150205 release-20150219 release-20150305 release-20150319 release-20150402 release-20150416 release-20150430 release-20150514 release-20150528 release-20150611 release-20150625 release-20150709 release-20150723 release-20150806 release-20150820 release-20150903 release-20150917 release-20151001 release-20151015 release-20151029 release-20151112 release-20151126 release-20151210 release-20151224 release-20160107 release-20160121 release-20160204 release-20160218 release-20160303 release-20160317 release-20160331 release-20160414 release-20160428 release-20160512 release-20160526 release-20160609 release-20160625 release-20160707 release-20160721 release-20160804 release-20160818 release-20160901 release-20160915 release-20160929 release-20161013 release-20161027 release-20161110 release-20161124 release-20161208 release-20161222 release-20170105 release-20170119 release-20170202 release-20170216 release-20170302 release-20170316 release-20170330 release-20170413 release-20170427 release-20170511 release-20170525 release-20170608 release-20170622 release-20170706 release-20170720 release-20170803 release-20170817 release-20170831 release-20170914 release-20170928 release-20171012 release-20171026 release-20171109 release-20171110 release-20171123 release-20171207 release-20171221 release-20180104 release-20180118 release-20180201 release-20180215 release-20180301 release-20180315 release-20180329 release-20180412 release-20180426 release-20180510 release-20180524 release-20180607 release-20180621 release-20180705 release-20180719 release-20180802 release-20180816 release-20180830 release-20180913 release-20180927 release-20181011 release-20181025 release-20181108 release-20181122 release-20181206 rpz-lso smartarray smatch uefi us-west-2 vpc zfs-crypto
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
32291 lines (28505 sloc) 905 KB
/*
* 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
* or http://www.opensolaris.org/os/licensing.
* 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) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Copyright (c) 2011 Bayard G. Bell. All rights reserved.
* Copyright (c) 2012, 2016 by Delphix. All rights reserved.
* Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
* Copyright 2016 Joyent, Inc.
* Copyright 2017 Nexenta Systems, Inc.
*/
/*
* Copyright 2011 cyril.galibern@opensvc.com
*/
/*
* SCSI disk target driver.
*/
#include <sys/scsi/scsi.h>
#include <sys/dkbad.h>
#include <sys/dklabel.h>
#include <sys/dkio.h>
#include <sys/fdio.h>
#include <sys/cdio.h>
#include <sys/mhd.h>
#include <sys/vtoc.h>
#include <sys/dktp/fdisk.h>
#include <sys/kstat.h>
#include <sys/vtrace.h>
#include <sys/note.h>
#include <sys/thread.h>
#include <sys/proc.h>
#include <sys/efi_partition.h>
#include <sys/var.h>
#include <sys/aio_req.h>
#include <sys/dkioc_free_util.h>
#ifdef __lock_lint
#define _LP64
#define __amd64
#endif
#if (defined(__fibre))
/* Note: is there a leadville version of the following? */
#include <sys/fc4/fcal_linkapp.h>
#endif
#include <sys/taskq.h>
#include <sys/uuid.h>
#include <sys/byteorder.h>
#include <sys/sdt.h>
#include "sd_xbuf.h"
#include <sys/scsi/targets/sddef.h>
#include <sys/cmlb.h>
#include <sys/sysevent/eventdefs.h>
#include <sys/sysevent/dev.h>
#include <sys/fm/protocol.h>
/*
* Loadable module info.
*/
#if (defined(__fibre))
#define SD_MODULE_NAME "SCSI SSA/FCAL Disk Driver"
#else /* !__fibre */
#define SD_MODULE_NAME "SCSI Disk Driver"
#endif /* !__fibre */
/*
* Define the interconnect type, to allow the driver to distinguish
* between parallel SCSI (sd) and fibre channel (ssd) behaviors.
*
* This is really for backward compatibility. In the future, the driver
* should actually check the "interconnect-type" property as reported by
* the HBA; however at present this property is not defined by all HBAs,
* so we will use this #define (1) to permit the driver to run in
* backward-compatibility mode; and (2) to print a notification message
* if an FC HBA does not support the "interconnect-type" property. The
* behavior of the driver will be to assume parallel SCSI behaviors unless
* the "interconnect-type" property is defined by the HBA **AND** has a
* value of either INTERCONNECT_FIBRE, INTERCONNECT_SSA, or
* INTERCONNECT_FABRIC, in which case the driver will assume Fibre
* Channel behaviors (as per the old ssd). (Note that the
* INTERCONNECT_1394 and INTERCONNECT_USB types are not supported and
* will result in the driver assuming parallel SCSI behaviors.)
*
* (see common/sys/scsi/impl/services.h)
*
* Note: For ssd semantics, don't use INTERCONNECT_FABRIC as the default
* since some FC HBAs may already support that, and there is some code in
* the driver that already looks for it. Using INTERCONNECT_FABRIC as the
* default would confuse that code, and besides things should work fine
* anyways if the FC HBA already reports INTERCONNECT_FABRIC for the
* "interconnect_type" property.
*
*/
#if (defined(__fibre))
#define SD_DEFAULT_INTERCONNECT_TYPE SD_INTERCONNECT_FIBRE
#else
#define SD_DEFAULT_INTERCONNECT_TYPE SD_INTERCONNECT_PARALLEL
#endif
/*
* The name of the driver, established from the module name in _init.
*/
static char *sd_label = NULL;
/*
* Driver name is unfortunately prefixed on some driver.conf properties.
*/
#if (defined(__fibre))
#define sd_max_xfer_size ssd_max_xfer_size
#define sd_config_list ssd_config_list
static char *sd_max_xfer_size = "ssd_max_xfer_size";
static char *sd_config_list = "ssd-config-list";
#else
static char *sd_max_xfer_size = "sd_max_xfer_size";
static char *sd_config_list = "sd-config-list";
#endif
/*
* Driver global variables
*/
#if (defined(__fibre))
/*
* These #defines are to avoid namespace collisions that occur because this
* code is currently used to compile two separate driver modules: sd and ssd.
* All global variables need to be treated this way (even if declared static)
* in order to allow the debugger to resolve the names properly.
* It is anticipated that in the near future the ssd module will be obsoleted,
* at which time this namespace issue should go away.
*/
#define sd_state ssd_state
#define sd_io_time ssd_io_time
#define sd_failfast_enable ssd_failfast_enable
#define sd_ua_retry_count ssd_ua_retry_count
#define sd_report_pfa ssd_report_pfa
#define sd_max_throttle ssd_max_throttle
#define sd_min_throttle ssd_min_throttle
#define sd_rot_delay ssd_rot_delay
#define sd_retry_on_reservation_conflict \
ssd_retry_on_reservation_conflict
#define sd_reinstate_resv_delay ssd_reinstate_resv_delay
#define sd_resv_conflict_name ssd_resv_conflict_name
#define sd_component_mask ssd_component_mask
#define sd_level_mask ssd_level_mask
#define sd_debug_un ssd_debug_un
#define sd_error_level ssd_error_level
#define sd_xbuf_active_limit ssd_xbuf_active_limit
#define sd_xbuf_reserve_limit ssd_xbuf_reserve_limit
#define sd_tr ssd_tr
#define sd_reset_throttle_timeout ssd_reset_throttle_timeout
#define sd_qfull_throttle_timeout ssd_qfull_throttle_timeout
#define sd_qfull_throttle_enable ssd_qfull_throttle_enable
#define sd_check_media_time ssd_check_media_time
#define sd_wait_cmds_complete ssd_wait_cmds_complete
#define sd_label_mutex ssd_label_mutex
#define sd_detach_mutex ssd_detach_mutex
#define sd_log_buf ssd_log_buf
#define sd_log_mutex ssd_log_mutex
#define sd_disk_table ssd_disk_table
#define sd_disk_table_size ssd_disk_table_size
#define sd_sense_mutex ssd_sense_mutex
#define sd_cdbtab ssd_cdbtab
#define sd_cb_ops ssd_cb_ops
#define sd_ops ssd_ops
#define sd_additional_codes ssd_additional_codes
#define sd_tgops ssd_tgops
#define sd_minor_data ssd_minor_data
#define sd_minor_data_efi ssd_minor_data_efi
#define sd_tq ssd_tq
#define sd_wmr_tq ssd_wmr_tq
#define sd_taskq_name ssd_taskq_name
#define sd_wmr_taskq_name ssd_wmr_taskq_name
#define sd_taskq_minalloc ssd_taskq_minalloc
#define sd_taskq_maxalloc ssd_taskq_maxalloc
#define sd_dump_format_string ssd_dump_format_string
#define sd_iostart_chain ssd_iostart_chain
#define sd_iodone_chain ssd_iodone_chain
#define sd_pm_idletime ssd_pm_idletime
#define sd_force_pm_supported ssd_force_pm_supported
#define sd_dtype_optical_bind ssd_dtype_optical_bind
#define sd_ssc_init ssd_ssc_init
#define sd_ssc_send ssd_ssc_send
#define sd_ssc_fini ssd_ssc_fini
#define sd_ssc_assessment ssd_ssc_assessment
#define sd_ssc_post ssd_ssc_post
#define sd_ssc_print ssd_ssc_print
#define sd_ssc_ereport_post ssd_ssc_ereport_post
#define sd_ssc_set_info ssd_ssc_set_info
#define sd_ssc_extract_info ssd_ssc_extract_info
#endif
#ifdef SDDEBUG
int sd_force_pm_supported = 0;
#endif /* SDDEBUG */
void *sd_state = NULL;
int sd_io_time = SD_IO_TIME;
int sd_failfast_enable = 1;
int sd_ua_retry_count = SD_UA_RETRY_COUNT;
int sd_report_pfa = 1;
int sd_max_throttle = SD_MAX_THROTTLE;
int sd_min_throttle = SD_MIN_THROTTLE;
int sd_rot_delay = 4; /* Default 4ms Rotation delay */
int sd_qfull_throttle_enable = TRUE;
int sd_retry_on_reservation_conflict = 1;
int sd_reinstate_resv_delay = SD_REINSTATE_RESV_DELAY;
_NOTE(SCHEME_PROTECTS_DATA("safe sharing", sd_reinstate_resv_delay))
static int sd_dtype_optical_bind = -1;
/* Note: the following is not a bug, it really is "sd_" and not "ssd_" */
static char *sd_resv_conflict_name = "sd_retry_on_reservation_conflict";
/*
* Global data for debug logging. To enable debug printing, sd_component_mask
* and sd_level_mask should be set to the desired bit patterns as outlined in
* sddef.h.
*/
uint_t sd_component_mask = 0x0;
uint_t sd_level_mask = 0x0;
struct sd_lun *sd_debug_un = NULL;
uint_t sd_error_level = SCSI_ERR_RETRYABLE;
/* Note: these may go away in the future... */
static uint32_t sd_xbuf_active_limit = 512;
static uint32_t sd_xbuf_reserve_limit = 16;
static struct sd_resv_reclaim_request sd_tr = { NULL, NULL, NULL, 0, 0, 0 };
/*
* Timer value used to reset the throttle after it has been reduced
* (typically in response to TRAN_BUSY or STATUS_QFULL)
*/
static int sd_reset_throttle_timeout = SD_RESET_THROTTLE_TIMEOUT;
static int sd_qfull_throttle_timeout = SD_QFULL_THROTTLE_TIMEOUT;
/*
* Interval value associated with the media change scsi watch.
*/
static int sd_check_media_time = 3000000;
/*
* Wait value used for in progress operations during a DDI_SUSPEND
*/
static int sd_wait_cmds_complete = SD_WAIT_CMDS_COMPLETE;
/*
* sd_label_mutex protects a static buffer used in the disk label
* component of the driver
*/
static kmutex_t sd_label_mutex;
/*
* sd_detach_mutex protects un_layer_count, un_detach_count, and
* un_opens_in_progress in the sd_lun structure.
*/
static kmutex_t sd_detach_mutex;
_NOTE(MUTEX_PROTECTS_DATA(sd_detach_mutex,
sd_lun::{un_layer_count un_detach_count un_opens_in_progress}))
/*
* Global buffer and mutex for debug logging
*/
static char sd_log_buf[1024];
static kmutex_t sd_log_mutex;
/*
* Structs and globals for recording attached lun information.
* This maintains a chain. Each node in the chain represents a SCSI controller.
* The structure records the number of luns attached to each target connected
* with the controller.
* For parallel scsi device only.
*/
struct sd_scsi_hba_tgt_lun {
struct sd_scsi_hba_tgt_lun *next;
dev_info_t *pdip;
int nlun[NTARGETS_WIDE];
};
/*
* Flag to indicate the lun is attached or detached
*/
#define SD_SCSI_LUN_ATTACH 0
#define SD_SCSI_LUN_DETACH 1
static kmutex_t sd_scsi_target_lun_mutex;
static struct sd_scsi_hba_tgt_lun *sd_scsi_target_lun_head = NULL;
_NOTE(MUTEX_PROTECTS_DATA(sd_scsi_target_lun_mutex,
sd_scsi_hba_tgt_lun::next sd_scsi_hba_tgt_lun::pdip))
_NOTE(MUTEX_PROTECTS_DATA(sd_scsi_target_lun_mutex,
sd_scsi_target_lun_head))
/*
* "Smart" Probe Caching structs, globals, #defines, etc.
* For parallel scsi and non-self-identify device only.
*/
/*
* The following resources and routines are implemented to support
* "smart" probing, which caches the scsi_probe() results in an array,
* in order to help avoid long probe times.
*/
struct sd_scsi_probe_cache {
struct sd_scsi_probe_cache *next;
dev_info_t *pdip;
int cache[NTARGETS_WIDE];
};
static kmutex_t sd_scsi_probe_cache_mutex;
static struct sd_scsi_probe_cache *sd_scsi_probe_cache_head = NULL;
/*
* Really we only need protection on the head of the linked list, but
* better safe than sorry.
*/
_NOTE(MUTEX_PROTECTS_DATA(sd_scsi_probe_cache_mutex,
sd_scsi_probe_cache::next sd_scsi_probe_cache::pdip))
_NOTE(MUTEX_PROTECTS_DATA(sd_scsi_probe_cache_mutex,
sd_scsi_probe_cache_head))
/*
* Power attribute table
*/
static sd_power_attr_ss sd_pwr_ss = {
{ "NAME=spindle-motor", "0=off", "1=on", NULL },
{0, 100},
{30, 0},
{20000, 0}
};
static sd_power_attr_pc sd_pwr_pc = {
{ "NAME=spindle-motor", "0=stopped", "1=standby", "2=idle",
"3=active", NULL },
{0, 0, 0, 100},
{90, 90, 20, 0},
{15000, 15000, 1000, 0}
};
/*
* Power level to power condition
*/
static int sd_pl2pc[] = {
SD_TARGET_START_VALID,
SD_TARGET_STANDBY,
SD_TARGET_IDLE,
SD_TARGET_ACTIVE
};
/*
* Vendor specific data name property declarations
*/
#if defined(__fibre) || defined(__i386) ||defined(__amd64)
static sd_tunables seagate_properties = {
SEAGATE_THROTTLE_VALUE,
0,
0,
0,
0,
0,
0,
0,
0
};
static sd_tunables fujitsu_properties = {
FUJITSU_THROTTLE_VALUE,
0,
0,
0,
0,
0,
0,
0,
0
};
static sd_tunables ibm_properties = {
IBM_THROTTLE_VALUE,
0,
0,
0,
0,
0,
0,
0,
0
};
static sd_tunables purple_properties = {
PURPLE_THROTTLE_VALUE,
0,
0,
PURPLE_BUSY_RETRIES,
PURPLE_RESET_RETRY_COUNT,
PURPLE_RESERVE_RELEASE_TIME,
0,
0,
0
};
static sd_tunables sve_properties = {
SVE_THROTTLE_VALUE,
0,
0,
SVE_BUSY_RETRIES,
SVE_RESET_RETRY_COUNT,
SVE_RESERVE_RELEASE_TIME,
SVE_MIN_THROTTLE_VALUE,
SVE_DISKSORT_DISABLED_FLAG,
0
};
static sd_tunables maserati_properties = {
0,
0,
0,
0,
0,
0,
0,
MASERATI_DISKSORT_DISABLED_FLAG,
MASERATI_LUN_RESET_ENABLED_FLAG
};
static sd_tunables pirus_properties = {
PIRUS_THROTTLE_VALUE,
0,
PIRUS_NRR_COUNT,
PIRUS_BUSY_RETRIES,
PIRUS_RESET_RETRY_COUNT,
0,
PIRUS_MIN_THROTTLE_VALUE,
PIRUS_DISKSORT_DISABLED_FLAG,
PIRUS_LUN_RESET_ENABLED_FLAG
};
#endif
#if (defined(__sparc) && !defined(__fibre)) || \
(defined(__i386) || defined(__amd64))
static sd_tunables elite_properties = {
ELITE_THROTTLE_VALUE,
0,
0,
0,
0,
0,
0,
0,
0
};
static sd_tunables st31200n_properties = {
ST31200N_THROTTLE_VALUE,
0,
0,
0,
0,
0,
0,
0,
0
};
#endif /* Fibre or not */
static sd_tunables lsi_properties_scsi = {
LSI_THROTTLE_VALUE,
0,
LSI_NOTREADY_RETRIES,
0,
0,
0,
0,
0,
0
};
static sd_tunables symbios_properties = {
SYMBIOS_THROTTLE_VALUE,
0,
SYMBIOS_NOTREADY_RETRIES,
0,
0,
0,
0,
0,
0
};
static sd_tunables lsi_properties = {
0,
0,
LSI_NOTREADY_RETRIES,
0,
0,
0,
0,
0,
0
};
static sd_tunables lsi_oem_properties = {
0,
0,
LSI_OEM_NOTREADY_RETRIES,
0,
0,
0,
0,
0,
0,
1
};
#if (defined(SD_PROP_TST))
#define SD_TST_CTYPE_VAL CTYPE_CDROM
#define SD_TST_THROTTLE_VAL 16
#define SD_TST_NOTREADY_VAL 12
#define SD_TST_BUSY_VAL 60
#define SD_TST_RST_RETRY_VAL 36
#define SD_TST_RSV_REL_TIME 60
static sd_tunables tst_properties = {
SD_TST_THROTTLE_VAL,
SD_TST_CTYPE_VAL,
SD_TST_NOTREADY_VAL,
SD_TST_BUSY_VAL,
SD_TST_RST_RETRY_VAL,
SD_TST_RSV_REL_TIME,
0,
0,
0
};
#endif
/* This is similar to the ANSI toupper implementation */
#define SD_TOUPPER(C) (((C) >= 'a' && (C) <= 'z') ? (C) - 'a' + 'A' : (C))
/*
* Static Driver Configuration Table
*
* This is the table of disks which need throttle adjustment (or, perhaps
* something else as defined by the flags at a future time.) device_id
* is a string consisting of concatenated vid (vendor), pid (product/model)
* and revision strings as defined in the scsi_inquiry structure. Offsets of
* the parts of the string are as defined by the sizes in the scsi_inquiry
* structure. Device type is searched as far as the device_id string is
* defined. Flags defines which values are to be set in the driver from the
* properties list.
*
* Entries below which begin and end with a "*" are a special case.
* These do not have a specific vendor, and the string which follows
* can appear anywhere in the 16 byte PID portion of the inquiry data.
*
* Entries below which begin and end with a " " (blank) are a special
* case. The comparison function will treat multiple consecutive blanks
* as equivalent to a single blank. For example, this causes a
* sd_disk_table entry of " NEC CDROM " to match a device's id string
* of "NEC CDROM".
*
* Note: The MD21 controller type has been obsoleted.
* ST318202F is a Legacy device
* MAM3182FC, MAM3364FC, MAM3738FC do not appear to have ever been
* made with an FC connection. The entries here are a legacy.
*/
static sd_disk_config_t sd_disk_table[] = {
#if defined(__fibre) || defined(__i386) || defined(__amd64)
{ "SEAGATE ST34371FC", SD_CONF_BSET_THROTTLE, &seagate_properties },
{ "SEAGATE ST19171FC", SD_CONF_BSET_THROTTLE, &seagate_properties },
{ "SEAGATE ST39102FC", SD_CONF_BSET_THROTTLE, &seagate_properties },
{ "SEAGATE ST39103FC", SD_CONF_BSET_THROTTLE, &seagate_properties },
{ "SEAGATE ST118273F", SD_CONF_BSET_THROTTLE, &seagate_properties },
{ "SEAGATE ST318202F", SD_CONF_BSET_THROTTLE, &seagate_properties },
{ "SEAGATE ST318203F", SD_CONF_BSET_THROTTLE, &seagate_properties },
{ "SEAGATE ST136403F", SD_CONF_BSET_THROTTLE, &seagate_properties },
{ "SEAGATE ST318304F", SD_CONF_BSET_THROTTLE, &seagate_properties },
{ "SEAGATE ST336704F", SD_CONF_BSET_THROTTLE, &seagate_properties },
{ "SEAGATE ST373405F", SD_CONF_BSET_THROTTLE, &seagate_properties },
{ "SEAGATE ST336605F", SD_CONF_BSET_THROTTLE, &seagate_properties },
{ "SEAGATE ST336752F", SD_CONF_BSET_THROTTLE, &seagate_properties },
{ "SEAGATE ST318452F", SD_CONF_BSET_THROTTLE, &seagate_properties },
{ "FUJITSU MAG3091F", SD_CONF_BSET_THROTTLE, &fujitsu_properties },
{ "FUJITSU MAG3182F", SD_CONF_BSET_THROTTLE, &fujitsu_properties },
{ "FUJITSU MAA3182F", SD_CONF_BSET_THROTTLE, &fujitsu_properties },
{ "FUJITSU MAF3364F", SD_CONF_BSET_THROTTLE, &fujitsu_properties },
{ "FUJITSU MAL3364F", SD_CONF_BSET_THROTTLE, &fujitsu_properties },
{ "FUJITSU MAL3738F", SD_CONF_BSET_THROTTLE, &fujitsu_properties },
{ "FUJITSU MAM3182FC", SD_CONF_BSET_THROTTLE, &fujitsu_properties },
{ "FUJITSU MAM3364FC", SD_CONF_BSET_THROTTLE, &fujitsu_properties },
{ "FUJITSU MAM3738FC", SD_CONF_BSET_THROTTLE, &fujitsu_properties },
{ "IBM DDYFT1835", SD_CONF_BSET_THROTTLE, &ibm_properties },
{ "IBM DDYFT3695", SD_CONF_BSET_THROTTLE, &ibm_properties },
{ "IBM IC35LF2D2", SD_CONF_BSET_THROTTLE, &ibm_properties },
{ "IBM IC35LF2PR", SD_CONF_BSET_THROTTLE, &ibm_properties },
{ "IBM 1724-100", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "IBM 1726-2xx", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "IBM 1726-22x", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "IBM 1726-4xx", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "IBM 1726-42x", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "IBM 1726-3xx", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "IBM 3526", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "IBM 3542", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "IBM 3552", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "IBM 1722", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "IBM 1742", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "IBM 1815", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "IBM FAStT", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "IBM 1814", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "IBM 1814-200", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "IBM 1818", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "DELL MD3000", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "DELL MD3000i", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "LSI INF", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "ENGENIO INF", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "SGI TP", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "SGI IS", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "*CSM100_*", SD_CONF_BSET_NRR_COUNT |
SD_CONF_BSET_CACHE_IS_NV, &lsi_oem_properties },
{ "*CSM200_*", SD_CONF_BSET_NRR_COUNT |
SD_CONF_BSET_CACHE_IS_NV, &lsi_oem_properties },
{ "Fujitsu SX300", SD_CONF_BSET_THROTTLE, &lsi_oem_properties },
{ "LSI", SD_CONF_BSET_NRR_COUNT, &lsi_properties },
{ "SUN T3", SD_CONF_BSET_THROTTLE |
SD_CONF_BSET_BSY_RETRY_COUNT|
SD_CONF_BSET_RST_RETRIES|
SD_CONF_BSET_RSV_REL_TIME,
&purple_properties },
{ "SUN SESS01", SD_CONF_BSET_THROTTLE |
SD_CONF_BSET_BSY_RETRY_COUNT|
SD_CONF_BSET_RST_RETRIES|
SD_CONF_BSET_RSV_REL_TIME|
SD_CONF_BSET_MIN_THROTTLE|
SD_CONF_BSET_DISKSORT_DISABLED,
&sve_properties },
{ "SUN T4", SD_CONF_BSET_THROTTLE |
SD_CONF_BSET_BSY_RETRY_COUNT|
SD_CONF_BSET_RST_RETRIES|
SD_CONF_BSET_RSV_REL_TIME,
&purple_properties },
{ "SUN SVE01", SD_CONF_BSET_DISKSORT_DISABLED |
SD_CONF_BSET_LUN_RESET_ENABLED,
&maserati_properties },
{ "SUN SE6920", SD_CONF_BSET_THROTTLE |
SD_CONF_BSET_NRR_COUNT|
SD_CONF_BSET_BSY_RETRY_COUNT|
SD_CONF_BSET_RST_RETRIES|
SD_CONF_BSET_MIN_THROTTLE|
SD_CONF_BSET_DISKSORT_DISABLED|
SD_CONF_BSET_LUN_RESET_ENABLED,
&pirus_properties },
{ "SUN SE6940", SD_CONF_BSET_THROTTLE |
SD_CONF_BSET_NRR_COUNT|
SD_CONF_BSET_BSY_RETRY_COUNT|
SD_CONF_BSET_RST_RETRIES|
SD_CONF_BSET_MIN_THROTTLE|
SD_CONF_BSET_DISKSORT_DISABLED|
SD_CONF_BSET_LUN_RESET_ENABLED,
&pirus_properties },
{ "SUN StorageTek 6920", SD_CONF_BSET_THROTTLE |
SD_CONF_BSET_NRR_COUNT|
SD_CONF_BSET_BSY_RETRY_COUNT|
SD_CONF_BSET_RST_RETRIES|
SD_CONF_BSET_MIN_THROTTLE|
SD_CONF_BSET_DISKSORT_DISABLED|
SD_CONF_BSET_LUN_RESET_ENABLED,
&pirus_properties },
{ "SUN StorageTek 6940", SD_CONF_BSET_THROTTLE |
SD_CONF_BSET_NRR_COUNT|
SD_CONF_BSET_BSY_RETRY_COUNT|
SD_CONF_BSET_RST_RETRIES|
SD_CONF_BSET_MIN_THROTTLE|
SD_CONF_BSET_DISKSORT_DISABLED|
SD_CONF_BSET_LUN_RESET_ENABLED,
&pirus_properties },
{ "SUN PSX1000", SD_CONF_BSET_THROTTLE |
SD_CONF_BSET_NRR_COUNT|
SD_CONF_BSET_BSY_RETRY_COUNT|
SD_CONF_BSET_RST_RETRIES|
SD_CONF_BSET_MIN_THROTTLE|
SD_CONF_BSET_DISKSORT_DISABLED|
SD_CONF_BSET_LUN_RESET_ENABLED,
&pirus_properties },
{ "SUN SE6330", SD_CONF_BSET_THROTTLE |
SD_CONF_BSET_NRR_COUNT|
SD_CONF_BSET_BSY_RETRY_COUNT|
SD_CONF_BSET_RST_RETRIES|
SD_CONF_BSET_MIN_THROTTLE|
SD_CONF_BSET_DISKSORT_DISABLED|
SD_CONF_BSET_LUN_RESET_ENABLED,
&pirus_properties },
{ "SUN STK6580_6780", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "SUN SUN_6180", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "STK OPENstorage", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "STK OpenStorage", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "STK BladeCtlr", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "STK FLEXLINE", SD_CONF_BSET_NRR_COUNT, &lsi_oem_properties },
{ "SYMBIOS", SD_CONF_BSET_NRR_COUNT, &symbios_properties },
#endif /* fibre or NON-sparc platforms */
#if ((defined(__sparc) && !defined(__fibre)) ||\
(defined(__i386) || defined(__amd64)))
{ "SEAGATE ST42400N", SD_CONF_BSET_THROTTLE, &elite_properties },
{ "SEAGATE ST31200N", SD_CONF_BSET_THROTTLE, &st31200n_properties },
{ "SEAGATE ST41600N", SD_CONF_BSET_TUR_CHECK, NULL },
{ "CONNER CP30540", SD_CONF_BSET_NOCACHE, NULL },
{ "*SUN0104*", SD_CONF_BSET_FAB_DEVID, NULL },
{ "*SUN0207*", SD_CONF_BSET_FAB_DEVID, NULL },
{ "*SUN0327*", SD_CONF_BSET_FAB_DEVID, NULL },
{ "*SUN0340*", SD_CONF_BSET_FAB_DEVID, NULL },
{ "*SUN0424*", SD_CONF_BSET_FAB_DEVID, NULL },
{ "*SUN0669*", SD_CONF_BSET_FAB_DEVID, NULL },
{ "*SUN1.0G*", SD_CONF_BSET_FAB_DEVID, NULL },
{ "SYMBIOS INF-01-00 ", SD_CONF_BSET_FAB_DEVID, NULL },
{ "SYMBIOS", SD_CONF_BSET_THROTTLE|SD_CONF_BSET_NRR_COUNT,
&symbios_properties },
{ "LSI", SD_CONF_BSET_THROTTLE | SD_CONF_BSET_NRR_COUNT,
&lsi_properties_scsi },
#if defined(__i386) || defined(__amd64)
{ " NEC CD-ROM DRIVE:260 ", (SD_CONF_BSET_PLAYMSF_BCD
| SD_CONF_BSET_READSUB_BCD
| SD_CONF_BSET_READ_TOC_ADDR_BCD
| SD_CONF_BSET_NO_READ_HEADER
| SD_CONF_BSET_READ_CD_XD4), NULL },
{ " NEC CD-ROM DRIVE:270 ", (SD_CONF_BSET_PLAYMSF_BCD
| SD_CONF_BSET_READSUB_BCD
| SD_CONF_BSET_READ_TOC_ADDR_BCD
| SD_CONF_BSET_NO_READ_HEADER
| SD_CONF_BSET_READ_CD_XD4), NULL },
#endif /* __i386 || __amd64 */
#endif /* sparc NON-fibre or NON-sparc platforms */
#if (defined(SD_PROP_TST))
{ "VENDOR PRODUCT ", (SD_CONF_BSET_THROTTLE
| SD_CONF_BSET_CTYPE
| SD_CONF_BSET_NRR_COUNT
| SD_CONF_BSET_FAB_DEVID
| SD_CONF_BSET_NOCACHE
| SD_CONF_BSET_BSY_RETRY_COUNT
| SD_CONF_BSET_PLAYMSF_BCD
| SD_CONF_BSET_READSUB_BCD
| SD_CONF_BSET_READ_TOC_TRK_BCD
| SD_CONF_BSET_READ_TOC_ADDR_BCD
| SD_CONF_BSET_NO_READ_HEADER
| SD_CONF_BSET_READ_CD_XD4
| SD_CONF_BSET_RST_RETRIES
| SD_CONF_BSET_RSV_REL_TIME
| SD_CONF_BSET_TUR_CHECK), &tst_properties},
#endif
};
static const int sd_disk_table_size =
sizeof (sd_disk_table)/ sizeof (sd_disk_config_t);
/*
* Emulation mode disk drive VID/PID table
*/
static char sd_flash_dev_table[][25] = {
"ATA MARVELL SD88SA02",
"MARVELL SD88SA02",
"TOSHIBA THNSNV05",
};
static const int sd_flash_dev_table_size =
sizeof (sd_flash_dev_table) / sizeof (sd_flash_dev_table[0]);
#define SD_INTERCONNECT_PARALLEL 0
#define SD_INTERCONNECT_FABRIC 1
#define SD_INTERCONNECT_FIBRE 2
#define SD_INTERCONNECT_SSA 3
#define SD_INTERCONNECT_SATA 4
#define SD_INTERCONNECT_SAS 5
#define SD_IS_PARALLEL_SCSI(un) \
((un)->un_interconnect_type == SD_INTERCONNECT_PARALLEL)
#define SD_IS_SERIAL(un) \
(((un)->un_interconnect_type == SD_INTERCONNECT_SATA) ||\
((un)->un_interconnect_type == SD_INTERCONNECT_SAS))
/*
* Definitions used by device id registration routines
*/
#define VPD_HEAD_OFFSET 3 /* size of head for vpd page */
#define VPD_PAGE_LENGTH 3 /* offset for pge length data */
#define VPD_MODE_PAGE 1 /* offset into vpd pg for "page code" */
static kmutex_t sd_sense_mutex = {0};
/*
* Macros for updates of the driver state
*/
#define New_state(un, s) \
(un)->un_last_state = (un)->un_state, (un)->un_state = (s)
#define Restore_state(un) \
{ uchar_t tmp = (un)->un_last_state; New_state((un), tmp); }
static struct sd_cdbinfo sd_cdbtab[] = {
{ CDB_GROUP0, 0x00, 0x1FFFFF, 0xFF, },
{ CDB_GROUP1, SCMD_GROUP1, 0xFFFFFFFF, 0xFFFF, },
{ CDB_GROUP5, SCMD_GROUP5, 0xFFFFFFFF, 0xFFFFFFFF, },
{ CDB_GROUP4, SCMD_GROUP4, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFF, },
};
/*
* Specifies the number of seconds that must have elapsed since the last
* cmd. has completed for a device to be declared idle to the PM framework.
*/
static int sd_pm_idletime = 1;
/*
* Internal function prototypes
*/
#if (defined(__fibre))
/*
* These #defines are to avoid namespace collisions that occur because this
* code is currently used to compile two separate driver modules: sd and ssd.
* All function names need to be treated this way (even if declared static)
* in order to allow the debugger to resolve the names properly.
* It is anticipated that in the near future the ssd module will be obsoleted,
* at which time this ugliness should go away.
*/
#define sd_log_trace ssd_log_trace
#define sd_log_info ssd_log_info
#define sd_log_err ssd_log_err
#define sdprobe ssdprobe
#define sdinfo ssdinfo
#define sd_prop_op ssd_prop_op
#define sd_scsi_probe_cache_init ssd_scsi_probe_cache_init
#define sd_scsi_probe_cache_fini ssd_scsi_probe_cache_fini
#define sd_scsi_clear_probe_cache ssd_scsi_clear_probe_cache
#define sd_scsi_probe_with_cache ssd_scsi_probe_with_cache
#define sd_scsi_target_lun_init ssd_scsi_target_lun_init
#define sd_scsi_target_lun_fini ssd_scsi_target_lun_fini
#define sd_scsi_get_target_lun_count ssd_scsi_get_target_lun_count
#define sd_scsi_update_lun_on_target ssd_scsi_update_lun_on_target
#define sd_spin_up_unit ssd_spin_up_unit
#define sd_enable_descr_sense ssd_enable_descr_sense
#define sd_reenable_dsense_task ssd_reenable_dsense_task
#define sd_set_mmc_caps ssd_set_mmc_caps
#define sd_read_unit_properties ssd_read_unit_properties
#define sd_process_sdconf_file ssd_process_sdconf_file
#define sd_process_sdconf_table ssd_process_sdconf_table
#define sd_sdconf_id_match ssd_sdconf_id_match
#define sd_blank_cmp ssd_blank_cmp
#define sd_chk_vers1_data ssd_chk_vers1_data
#define sd_set_vers1_properties ssd_set_vers1_properties
#define sd_check_bdc_vpd ssd_check_bdc_vpd
#define sd_check_emulation_mode ssd_check_emulation_mode
#define sd_get_physical_geometry ssd_get_physical_geometry
#define sd_get_virtual_geometry ssd_get_virtual_geometry
#define sd_update_block_info ssd_update_block_info
#define sd_register_devid ssd_register_devid
#define sd_get_devid ssd_get_devid
#define sd_create_devid ssd_create_devid
#define sd_write_deviceid ssd_write_deviceid
#define sd_check_vpd_page_support ssd_check_vpd_page_support
#define sd_setup_pm ssd_setup_pm
#define sd_create_pm_components ssd_create_pm_components
#define sd_ddi_suspend ssd_ddi_suspend
#define sd_ddi_resume ssd_ddi_resume
#define sd_pm_state_change ssd_pm_state_change
#define sdpower ssdpower
#define sdattach ssdattach
#define sddetach ssddetach
#define sd_unit_attach ssd_unit_attach
#define sd_unit_detach ssd_unit_detach
#define sd_set_unit_attributes ssd_set_unit_attributes
#define sd_create_errstats ssd_create_errstats
#define sd_set_errstats ssd_set_errstats
#define sd_set_pstats ssd_set_pstats
#define sddump ssddump
#define sd_scsi_poll ssd_scsi_poll
#define sd_send_polled_RQS ssd_send_polled_RQS
#define sd_ddi_scsi_poll ssd_ddi_scsi_poll
#define sd_init_event_callbacks ssd_init_event_callbacks
#define sd_event_callback ssd_event_callback
#define sd_cache_control ssd_cache_control
#define sd_get_write_cache_enabled ssd_get_write_cache_enabled
#define sd_get_write_cache_changeable ssd_get_write_cache_changeable
#define sd_get_nv_sup ssd_get_nv_sup
#define sd_make_device ssd_make_device
#define sdopen ssdopen
#define sdclose ssdclose
#define sd_ready_and_valid ssd_ready_and_valid
#define sdmin ssdmin
#define sdread ssdread
#define sdwrite ssdwrite
#define sdaread ssdaread
#define sdawrite ssdawrite
#define sdstrategy ssdstrategy
#define sdioctl ssdioctl
#define sd_mapblockaddr_iostart ssd_mapblockaddr_iostart
#define sd_mapblocksize_iostart ssd_mapblocksize_iostart
#define sd_checksum_iostart ssd_checksum_iostart
#define sd_checksum_uscsi_iostart ssd_checksum_uscsi_iostart
#define sd_pm_iostart ssd_pm_iostart
#define sd_core_iostart ssd_core_iostart
#define sd_mapblockaddr_iodone ssd_mapblockaddr_iodone
#define sd_mapblocksize_iodone ssd_mapblocksize_iodone
#define sd_checksum_iodone ssd_checksum_iodone
#define sd_checksum_uscsi_iodone ssd_checksum_uscsi_iodone
#define sd_pm_iodone ssd_pm_iodone
#define sd_initpkt_for_buf ssd_initpkt_for_buf
#define sd_destroypkt_for_buf ssd_destroypkt_for_buf
#define sd_setup_rw_pkt ssd_setup_rw_pkt
#define sd_setup_next_rw_pkt ssd_setup_next_rw_pkt
#define sd_buf_iodone ssd_buf_iodone
#define sd_uscsi_strategy ssd_uscsi_strategy
#define sd_initpkt_for_uscsi ssd_initpkt_for_uscsi
#define sd_destroypkt_for_uscsi ssd_destroypkt_for_uscsi
#define sd_uscsi_iodone ssd_uscsi_iodone
#define sd_xbuf_strategy ssd_xbuf_strategy
#define sd_xbuf_init ssd_xbuf_init
#define sd_pm_entry ssd_pm_entry
#define sd_pm_exit ssd_pm_exit
#define sd_pm_idletimeout_handler ssd_pm_idletimeout_handler
#define sd_pm_timeout_handler ssd_pm_timeout_handler
#define sd_add_buf_to_waitq ssd_add_buf_to_waitq
#define sdintr ssdintr
#define sd_start_cmds ssd_start_cmds
#define sd_send_scsi_cmd ssd_send_scsi_cmd
#define sd_bioclone_alloc ssd_bioclone_alloc
#define sd_bioclone_free ssd_bioclone_free
#define sd_shadow_buf_alloc ssd_shadow_buf_alloc
#define sd_shadow_buf_free ssd_shadow_buf_free
#define sd_print_transport_rejected_message \
ssd_print_transport_rejected_message
#define sd_retry_command ssd_retry_command
#define sd_set_retry_bp ssd_set_retry_bp
#define sd_send_request_sense_command ssd_send_request_sense_command
#define sd_start_retry_command ssd_start_retry_command
#define sd_start_direct_priority_command \
ssd_start_direct_priority_command
#define sd_return_failed_command ssd_return_failed_command
#define sd_return_failed_command_no_restart \
ssd_return_failed_command_no_restart
#define sd_return_command ssd_return_command
#define sd_sync_with_callback ssd_sync_with_callback
#define sdrunout ssdrunout
#define sd_mark_rqs_busy ssd_mark_rqs_busy
#define sd_mark_rqs_idle ssd_mark_rqs_idle
#define sd_reduce_throttle ssd_reduce_throttle
#define sd_restore_throttle ssd_restore_throttle
#define sd_print_incomplete_msg ssd_print_incomplete_msg
#define sd_init_cdb_limits ssd_init_cdb_limits
#define sd_pkt_status_good ssd_pkt_status_good
#define sd_pkt_status_check_condition ssd_pkt_status_check_condition
#define sd_pkt_status_busy ssd_pkt_status_busy
#define sd_pkt_status_reservation_conflict \
ssd_pkt_status_reservation_conflict
#define sd_pkt_status_qfull ssd_pkt_status_qfull
#define sd_handle_request_sense ssd_handle_request_sense
#define sd_handle_auto_request_sense ssd_handle_auto_request_sense
#define sd_print_sense_failed_msg ssd_print_sense_failed_msg
#define sd_validate_sense_data ssd_validate_sense_data
#define sd_decode_sense ssd_decode_sense
#define sd_print_sense_msg ssd_print_sense_msg
#define sd_sense_key_no_sense ssd_sense_key_no_sense
#define sd_sense_key_recoverable_error ssd_sense_key_recoverable_error
#define sd_sense_key_not_ready ssd_sense_key_not_ready
#define sd_sense_key_medium_or_hardware_error \
ssd_sense_key_medium_or_hardware_error
#define sd_sense_key_illegal_request ssd_sense_key_illegal_request
#define sd_sense_key_unit_attention ssd_sense_key_unit_attention
#define sd_sense_key_fail_command ssd_sense_key_fail_command
#define sd_sense_key_blank_check ssd_sense_key_blank_check
#define sd_sense_key_aborted_command ssd_sense_key_aborted_command
#define sd_sense_key_default ssd_sense_key_default
#define sd_print_retry_msg ssd_print_retry_msg
#define sd_print_cmd_incomplete_msg ssd_print_cmd_incomplete_msg
#define sd_pkt_reason_cmd_incomplete ssd_pkt_reason_cmd_incomplete
#define sd_pkt_reason_cmd_tran_err ssd_pkt_reason_cmd_tran_err
#define sd_pkt_reason_cmd_reset ssd_pkt_reason_cmd_reset
#define sd_pkt_reason_cmd_aborted ssd_pkt_reason_cmd_aborted
#define sd_pkt_reason_cmd_timeout ssd_pkt_reason_cmd_timeout
#define sd_pkt_reason_cmd_unx_bus_free ssd_pkt_reason_cmd_unx_bus_free
#define sd_pkt_reason_cmd_tag_reject ssd_pkt_reason_cmd_tag_reject
#define sd_pkt_reason_default ssd_pkt_reason_default
#define sd_reset_target ssd_reset_target
#define sd_start_stop_unit_callback ssd_start_stop_unit_callback
#define sd_start_stop_unit_task ssd_start_stop_unit_task
#define sd_taskq_create ssd_taskq_create
#define sd_taskq_delete ssd_taskq_delete
#define sd_target_change_task ssd_target_change_task
#define sd_log_dev_status_event ssd_log_dev_status_event
#define sd_log_lun_expansion_event ssd_log_lun_expansion_event
#define sd_log_eject_request_event ssd_log_eject_request_event
#define sd_media_change_task ssd_media_change_task
#define sd_handle_mchange ssd_handle_mchange
#define sd_send_scsi_DOORLOCK ssd_send_scsi_DOORLOCK
#define sd_send_scsi_READ_CAPACITY ssd_send_scsi_READ_CAPACITY
#define sd_send_scsi_READ_CAPACITY_16 ssd_send_scsi_READ_CAPACITY_16
#define sd_send_scsi_GET_CONFIGURATION ssd_send_scsi_GET_CONFIGURATION
#define sd_send_scsi_feature_GET_CONFIGURATION \
sd_send_scsi_feature_GET_CONFIGURATION
#define sd_send_scsi_START_STOP_UNIT ssd_send_scsi_START_STOP_UNIT
#define sd_send_scsi_INQUIRY ssd_send_scsi_INQUIRY
#define sd_send_scsi_TEST_UNIT_READY ssd_send_scsi_TEST_UNIT_READY
#define sd_send_scsi_PERSISTENT_RESERVE_IN \
ssd_send_scsi_PERSISTENT_RESERVE_IN
#define sd_send_scsi_PERSISTENT_RESERVE_OUT \
ssd_send_scsi_PERSISTENT_RESERVE_OUT
#define sd_send_scsi_SYNCHRONIZE_CACHE ssd_send_scsi_SYNCHRONIZE_CACHE
#define sd_send_scsi_SYNCHRONIZE_CACHE_biodone \
ssd_send_scsi_SYNCHRONIZE_CACHE_biodone
#define sd_send_scsi_MODE_SENSE ssd_send_scsi_MODE_SENSE
#define sd_send_scsi_MODE_SELECT ssd_send_scsi_MODE_SELECT
#define sd_send_scsi_RDWR ssd_send_scsi_RDWR
#define sd_send_scsi_LOG_SENSE ssd_send_scsi_LOG_SENSE
#define sd_send_scsi_GET_EVENT_STATUS_NOTIFICATION \
ssd_send_scsi_GET_EVENT_STATUS_NOTIFICATION
#define sd_gesn_media_data_valid ssd_gesn_media_data_valid
#define sd_alloc_rqs ssd_alloc_rqs
#define sd_free_rqs ssd_free_rqs
#define sd_dump_memory ssd_dump_memory
#define sd_get_media_info_com ssd_get_media_info_com
#define sd_get_media_info ssd_get_media_info
#define sd_get_media_info_ext ssd_get_media_info_ext
#define sd_dkio_ctrl_info ssd_dkio_ctrl_info
#define sd_nvpair_str_decode ssd_nvpair_str_decode
#define sd_strtok_r ssd_strtok_r
#define sd_set_properties ssd_set_properties
#define sd_get_tunables_from_conf ssd_get_tunables_from_conf
#define sd_setup_next_xfer ssd_setup_next_xfer
#define sd_dkio_get_temp ssd_dkio_get_temp
#define sd_check_mhd ssd_check_mhd
#define sd_mhd_watch_cb ssd_mhd_watch_cb
#define sd_mhd_watch_incomplete ssd_mhd_watch_incomplete
#define sd_sname ssd_sname
#define sd_mhd_resvd_recover ssd_mhd_resvd_recover
#define sd_resv_reclaim_thread ssd_resv_reclaim_thread
#define sd_take_ownership ssd_take_ownership
#define sd_reserve_release ssd_reserve_release
#define sd_rmv_resv_reclaim_req ssd_rmv_resv_reclaim_req
#define sd_mhd_reset_notify_cb ssd_mhd_reset_notify_cb
#define sd_persistent_reservation_in_read_keys \
ssd_persistent_reservation_in_read_keys
#define sd_persistent_reservation_in_read_resv \
ssd_persistent_reservation_in_read_resv
#define sd_mhdioc_takeown ssd_mhdioc_takeown
#define sd_mhdioc_failfast ssd_mhdioc_failfast
#define sd_mhdioc_release ssd_mhdioc_release
#define sd_mhdioc_register_devid ssd_mhdioc_register_devid
#define sd_mhdioc_inkeys ssd_mhdioc_inkeys
#define sd_mhdioc_inresv ssd_mhdioc_inresv
#define sr_change_blkmode ssr_change_blkmode
#define sr_change_speed ssr_change_speed
#define sr_atapi_change_speed ssr_atapi_change_speed
#define sr_pause_resume ssr_pause_resume
#define sr_play_msf ssr_play_msf
#define sr_play_trkind ssr_play_trkind
#define sr_read_all_subcodes ssr_read_all_subcodes
#define sr_read_subchannel ssr_read_subchannel
#define sr_read_tocentry ssr_read_tocentry
#define sr_read_tochdr ssr_read_tochdr
#define sr_read_cdda ssr_read_cdda
#define sr_read_cdxa ssr_read_cdxa
#define sr_read_mode1 ssr_read_mode1
#define sr_read_mode2 ssr_read_mode2
#define sr_read_cd_mode2 ssr_read_cd_mode2
#define sr_sector_mode ssr_sector_mode
#define sr_eject ssr_eject
#define sr_ejected ssr_ejected
#define sr_check_wp ssr_check_wp
#define sd_watch_request_submit ssd_watch_request_submit
#define sd_check_media ssd_check_media
#define sd_media_watch_cb ssd_media_watch_cb
#define sd_delayed_cv_broadcast ssd_delayed_cv_broadcast
#define sr_volume_ctrl ssr_volume_ctrl
#define sr_read_sony_session_offset ssr_read_sony_session_offset
#define sd_log_page_supported ssd_log_page_supported
#define sd_check_for_writable_cd ssd_check_for_writable_cd
#define sd_wm_cache_constructor ssd_wm_cache_constructor
#define sd_wm_cache_destructor ssd_wm_cache_destructor
#define sd_range_lock ssd_range_lock
#define sd_get_range ssd_get_range
#define sd_free_inlist_wmap ssd_free_inlist_wmap
#define sd_range_unlock ssd_range_unlock
#define sd_read_modify_write_task ssd_read_modify_write_task
#define sddump_do_read_of_rmw ssddump_do_read_of_rmw
#define sd_iostart_chain ssd_iostart_chain
#define sd_iodone_chain ssd_iodone_chain
#define sd_initpkt_map ssd_initpkt_map
#define sd_destroypkt_map ssd_destroypkt_map
#define sd_chain_type_map ssd_chain_type_map
#define sd_chain_index_map ssd_chain_index_map
#define sd_failfast_flushctl ssd_failfast_flushctl
#define sd_failfast_flushq ssd_failfast_flushq
#define sd_failfast_flushq_callback ssd_failfast_flushq_callback
#define sd_is_lsi ssd_is_lsi
#define sd_tg_rdwr ssd_tg_rdwr
#define sd_tg_getinfo ssd_tg_getinfo
#define sd_rmw_msg_print_handler ssd_rmw_msg_print_handler
#endif /* #if (defined(__fibre)) */
typedef struct unmap_param_hdr_s {
uint16_t uph_data_len;
uint16_t uph_descr_data_len;
uint32_t uph_reserved;
} unmap_param_hdr_t;
typedef struct unmap_blk_descr_s {
uint64_t ubd_lba;
uint32_t ubd_lba_cnt;
uint32_t ubd_reserved;
} unmap_blk_descr_t;
/* Max number of block descriptors in UNMAP command */
#define SD_UNMAP_MAX_DESCR \
((UINT16_MAX - sizeof (unmap_param_hdr_t)) / sizeof (unmap_blk_descr_t))
/* Max size of the UNMAP parameter list in bytes */
#define SD_UNMAP_PARAM_LIST_MAXSZ (sizeof (unmap_param_hdr_t) + \
SD_UNMAP_MAX_DESCR * sizeof (unmap_blk_descr_t))
int _init(void);
int _fini(void);
int _info(struct modinfo *modinfop);
/*PRINTFLIKE3*/
static void sd_log_trace(uint_t comp, struct sd_lun *un, const char *fmt, ...);
/*PRINTFLIKE3*/
static void sd_log_info(uint_t comp, struct sd_lun *un, const char *fmt, ...);
/*PRINTFLIKE3*/
static void sd_log_err(uint_t comp, struct sd_lun *un, const char *fmt, ...);
static int sdprobe(dev_info_t *devi);
static int sdinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
void **result);
static int sd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
int mod_flags, char *name, caddr_t valuep, int *lengthp);
/*
* Smart probe for parallel scsi
*/
static void sd_scsi_probe_cache_init(void);
static void sd_scsi_probe_cache_fini(void);
static void sd_scsi_clear_probe_cache(void);
static int sd_scsi_probe_with_cache(struct scsi_device *devp, int (*fn)());
/*
* Attached luns on target for parallel scsi
*/
static void sd_scsi_target_lun_init(void);
static void sd_scsi_target_lun_fini(void);
static int sd_scsi_get_target_lun_count(dev_info_t *dip, int target);
static void sd_scsi_update_lun_on_target(dev_info_t *dip, int target, int flag);
static int sd_spin_up_unit(sd_ssc_t *ssc);
/*
* Using sd_ssc_init to establish sd_ssc_t struct
* Using sd_ssc_send to send uscsi internal command
* Using sd_ssc_fini to free sd_ssc_t struct
*/
static sd_ssc_t *sd_ssc_init(struct sd_lun *un);
static int sd_ssc_send(sd_ssc_t *ssc, struct uscsi_cmd *incmd,
int flag, enum uio_seg dataspace, int path_flag);
static void sd_ssc_fini(sd_ssc_t *ssc);
/*
* Using sd_ssc_assessment to set correct type-of-assessment
* Using sd_ssc_post to post ereport & system log
* sd_ssc_post will call sd_ssc_print to print system log
* sd_ssc_post will call sd_ssd_ereport_post to post ereport
*/
static void sd_ssc_assessment(sd_ssc_t *ssc,
enum sd_type_assessment tp_assess);
static void sd_ssc_post(sd_ssc_t *ssc, enum sd_driver_assessment sd_assess);
static void sd_ssc_print(sd_ssc_t *ssc, int sd_severity);
static void sd_ssc_ereport_post(sd_ssc_t *ssc,
enum sd_driver_assessment drv_assess);
/*
* Using sd_ssc_set_info to mark an un-decodable-data error.
* Using sd_ssc_extract_info to transfer information from internal
* data structures to sd_ssc_t.
*/
static void sd_ssc_set_info(sd_ssc_t *ssc, int ssc_flags, uint_t comp,
const char *fmt, ...);
static void sd_ssc_extract_info(sd_ssc_t *ssc, struct sd_lun *un,
struct scsi_pkt *pktp, struct buf *bp, struct sd_xbuf *xp);
static int sd_send_scsi_cmd(dev_t dev, struct uscsi_cmd *incmd, int flag,
enum uio_seg dataspace, int path_flag);
#ifdef _LP64
static void sd_enable_descr_sense(sd_ssc_t *ssc);
static void sd_reenable_dsense_task(void *arg);
#endif /* _LP64 */
static void sd_set_mmc_caps(sd_ssc_t *ssc);
static void sd_read_unit_properties(struct sd_lun *un);
static int sd_process_sdconf_file(struct sd_lun *un);
static void sd_nvpair_str_decode(struct sd_lun *un, char *nvpair_str);
static char *sd_strtok_r(char *string, const char *sepset, char **lasts);
static void sd_set_properties(struct sd_lun *un, char *name, char *value);
static void sd_get_tunables_from_conf(struct sd_lun *un, int flags,
int *data_list, sd_tunables *values);
static void sd_process_sdconf_table(struct sd_lun *un);
static int sd_sdconf_id_match(struct sd_lun *un, char *id, int idlen);
static int sd_blank_cmp(struct sd_lun *un, char *id, int idlen);
static int sd_chk_vers1_data(struct sd_lun *un, int flags, int *prop_list,
int list_len, char *dataname_ptr);
static void sd_set_vers1_properties(struct sd_lun *un, int flags,
sd_tunables *prop_list);
static void sd_register_devid(sd_ssc_t *ssc, dev_info_t *devi,
int reservation_flag);
static int sd_get_devid(sd_ssc_t *ssc);
static ddi_devid_t sd_create_devid(sd_ssc_t *ssc);
static int sd_write_deviceid(sd_ssc_t *ssc);
static int sd_check_vpd_page_support(sd_ssc_t *ssc);
static void sd_setup_pm(sd_ssc_t *ssc, dev_info_t *devi);
static void sd_create_pm_components(dev_info_t *devi, struct sd_lun *un);
static int sd_ddi_suspend(dev_info_t *devi);
static int sd_ddi_resume(dev_info_t *devi);
static int sd_pm_state_change(struct sd_lun *un, int level, int flag);
static int sdpower(dev_info_t *devi, int component, int level);
static int sdattach(dev_info_t *devi, ddi_attach_cmd_t cmd);
static int sddetach(dev_info_t *devi, ddi_detach_cmd_t cmd);
static int sd_unit_attach(dev_info_t *devi);
static int sd_unit_detach(dev_info_t *devi);
static void sd_set_unit_attributes(struct sd_lun *un, dev_info_t *devi);
static void sd_create_errstats(struct sd_lun *un, int instance);
static void sd_set_errstats(struct sd_lun *un);
static void sd_set_pstats(struct sd_lun *un);
static int sddump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk);
static int sd_scsi_poll(struct sd_lun *un, struct scsi_pkt *pkt);
static int sd_send_polled_RQS(struct sd_lun *un);
static int sd_ddi_scsi_poll(struct scsi_pkt *pkt);
#if (defined(__fibre))
/*
* Event callbacks (photon)
*/
static void sd_init_event_callbacks(struct sd_lun *un);
static void sd_event_callback(dev_info_t *, ddi_eventcookie_t, void *, void *);
#endif
/*
* Defines for sd_cache_control
*/
#define SD_CACHE_ENABLE 1
#define SD_CACHE_DISABLE 0
#define SD_CACHE_NOCHANGE -1
static int sd_cache_control(sd_ssc_t *ssc, int rcd_flag, int wce_flag);
static int sd_get_write_cache_enabled(sd_ssc_t *ssc, int *is_enabled);
static void sd_get_write_cache_changeable(sd_ssc_t *ssc, int *is_changeable);
static void sd_get_nv_sup(sd_ssc_t *ssc);
static dev_t sd_make_device(dev_info_t *devi);
static void sd_check_bdc_vpd(sd_ssc_t *ssc);
static void sd_check_emulation_mode(sd_ssc_t *ssc);
static void sd_update_block_info(struct sd_lun *un, uint32_t lbasize,
uint64_t capacity);
/*
* Driver entry point functions.
*/
static int sdopen(dev_t *dev_p, int flag, int otyp, cred_t *cred_p);
static int sdclose(dev_t dev, int flag, int otyp, cred_t *cred_p);
static int sd_ready_and_valid(sd_ssc_t *ssc, int part);
static void sdmin(struct buf *bp);
static int sdread(dev_t dev, struct uio *uio, cred_t *cred_p);
static int sdwrite(dev_t dev, struct uio *uio, cred_t *cred_p);
static int sdaread(dev_t dev, struct aio_req *aio, cred_t *cred_p);
static int sdawrite(dev_t dev, struct aio_req *aio, cred_t *cred_p);
static int sdstrategy(struct buf *bp);
static int sdioctl(dev_t, int, intptr_t, int, cred_t *, int *);
/*
* Function prototypes for layering functions in the iostart chain.
*/
static void sd_mapblockaddr_iostart(int index, struct sd_lun *un,
struct buf *bp);
static void sd_mapblocksize_iostart(int index, struct sd_lun *un,
struct buf *bp);
static void sd_checksum_iostart(int index, struct sd_lun *un, struct buf *bp);
static void sd_checksum_uscsi_iostart(int index, struct sd_lun *un,
struct buf *bp);
static void sd_pm_iostart(int index, struct sd_lun *un, struct buf *bp);
static void sd_core_iostart(int index, struct sd_lun *un, struct buf *bp);
/*
* Function prototypes for layering functions in the iodone chain.
*/
static void sd_buf_iodone(int index, struct sd_lun *un, struct buf *bp);
static void sd_uscsi_iodone(int index, struct sd_lun *un, struct buf *bp);
static void sd_mapblockaddr_iodone(int index, struct sd_lun *un,
struct buf *bp);
static void sd_mapblocksize_iodone(int index, struct sd_lun *un,
struct buf *bp);
static void sd_checksum_iodone(int index, struct sd_lun *un, struct buf *bp);
static void sd_checksum_uscsi_iodone(int index, struct sd_lun *un,
struct buf *bp);
static void sd_pm_iodone(int index, struct sd_lun *un, struct buf *bp);
/*
* Prototypes for functions to support buf(9S) based IO.
*/
static void sd_xbuf_strategy(struct buf *bp, ddi_xbuf_t xp, void *arg);
static int sd_initpkt_for_buf(struct buf *, struct scsi_pkt **);
static void sd_destroypkt_for_buf(struct buf *);
static int sd_setup_rw_pkt(struct sd_lun *un, struct scsi_pkt **pktpp,
struct buf *bp, int flags,
int (*callback)(caddr_t), caddr_t callback_arg,
diskaddr_t lba, uint32_t blockcount);
static int sd_setup_next_rw_pkt(struct sd_lun *un, struct scsi_pkt *pktp,
struct buf *bp, diskaddr_t lba, uint32_t blockcount);
/*
* Prototypes for functions to support USCSI IO.
*/
static int sd_uscsi_strategy(struct buf *bp);
static int sd_initpkt_for_uscsi(struct buf *, struct scsi_pkt **);
static void sd_destroypkt_for_uscsi(struct buf *);
static void sd_xbuf_init(struct sd_lun *un, struct buf *bp, struct sd_xbuf *xp,
uchar_t chain_type, void *pktinfop);
static int sd_pm_entry(struct sd_lun *un);
static void sd_pm_exit(struct sd_lun *un);
static void sd_pm_idletimeout_handler(void *arg);
/*
* sd_core internal functions (used at the sd_core_io layer).
*/
static void sd_add_buf_to_waitq(struct sd_lun *un, struct buf *bp);
static void sdintr(struct scsi_pkt *pktp);
static void sd_start_cmds(struct sd_lun *un, struct buf *immed_bp);
static int sd_send_scsi_cmd(dev_t dev, struct uscsi_cmd *incmd, int flag,
enum uio_seg dataspace, int path_flag);
static struct buf *sd_bioclone_alloc(struct buf *bp, size_t datalen,
daddr_t blkno, int (*func)(struct buf *));
static struct buf *sd_shadow_buf_alloc(struct buf *bp, size_t datalen,
uint_t bflags, daddr_t blkno, int (*func)(struct buf *));
static void sd_bioclone_free(struct buf *bp);
static void sd_shadow_buf_free(struct buf *bp);
static void sd_print_transport_rejected_message(struct sd_lun *un,
struct sd_xbuf *xp, int code);
static void sd_print_incomplete_msg(struct sd_lun *un, struct buf *bp,
void *arg, int code);
static void sd_print_sense_failed_msg(struct sd_lun *un, struct buf *bp,
void *arg, int code);
static void sd_print_cmd_incomplete_msg(struct sd_lun *un, struct buf *bp,
void *arg, int code);
static void sd_retry_command(struct sd_lun *un, struct buf *bp,
int retry_check_flag,
void (*user_funcp)(struct sd_lun *un, struct buf *bp, void *argp,
int c),
void *user_arg, int failure_code, clock_t retry_delay,
void (*statp)(kstat_io_t *));
static void sd_set_retry_bp(struct sd_lun *un, struct buf *bp,
clock_t retry_delay, void (*statp)(kstat_io_t *));
static void sd_send_request_sense_command(struct sd_lun *un, struct buf *bp,
struct scsi_pkt *pktp);
static void sd_start_retry_command(void *arg);
static void sd_start_direct_priority_command(void *arg);
static void sd_return_failed_command(struct sd_lun *un, struct buf *bp,
int errcode);
static void sd_return_failed_command_no_restart(struct sd_lun *un,
struct buf *bp, int errcode);
static void sd_return_command(struct sd_lun *un, struct buf *bp);
static void sd_sync_with_callback(struct sd_lun *un);
static int sdrunout(caddr_t arg);
static void sd_mark_rqs_busy(struct sd_lun *un, struct buf *bp);
static struct buf *sd_mark_rqs_idle(struct sd_lun *un, struct sd_xbuf *xp);
static void sd_reduce_throttle(struct sd_lun *un, int throttle_type);
static void sd_restore_throttle(void *arg);
static void sd_init_cdb_limits(struct sd_lun *un);
static void sd_pkt_status_good(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
/*
* Error handling functions
*/
static void sd_pkt_status_check_condition(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_pkt_status_busy(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_pkt_status_reservation_conflict(struct sd_lun *un,
struct buf *bp, struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_pkt_status_qfull(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_handle_request_sense(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_handle_auto_request_sense(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static int sd_validate_sense_data(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, size_t actual_len);
static void sd_decode_sense(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_print_sense_msg(struct sd_lun *un, struct buf *bp,
void *arg, int code);
static void sd_sense_key_no_sense(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_sense_key_recoverable_error(struct sd_lun *un,
uint8_t *sense_datap,
struct buf *bp, struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_sense_key_not_ready(struct sd_lun *un,
uint8_t *sense_datap,
struct buf *bp, struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_sense_key_medium_or_hardware_error(struct sd_lun *un,
uint8_t *sense_datap,
struct buf *bp, struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_sense_key_illegal_request(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_sense_key_unit_attention(struct sd_lun *un,
uint8_t *sense_datap,
struct buf *bp, struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_sense_key_fail_command(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_sense_key_blank_check(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_sense_key_aborted_command(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_sense_key_default(struct sd_lun *un,
uint8_t *sense_datap,
struct buf *bp, struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_print_retry_msg(struct sd_lun *un, struct buf *bp,
void *arg, int flag);
static void sd_pkt_reason_cmd_incomplete(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_pkt_reason_cmd_tran_err(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_pkt_reason_cmd_reset(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_pkt_reason_cmd_aborted(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_pkt_reason_cmd_timeout(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_pkt_reason_cmd_unx_bus_free(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_pkt_reason_cmd_tag_reject(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_pkt_reason_default(struct sd_lun *un, struct buf *bp,
struct sd_xbuf *xp, struct scsi_pkt *pktp);
static void sd_reset_target(struct sd_lun *un, struct scsi_pkt *pktp);
static void sd_start_stop_unit_callback(void *arg);
static void sd_start_stop_unit_task(void *arg);
static void sd_taskq_create(void);
static void sd_taskq_delete(void);
static void sd_target_change_task(void *arg);
static void sd_log_dev_status_event(struct sd_lun *un, char *esc, int km_flag);
static void sd_log_lun_expansion_event(struct sd_lun *un, int km_flag);
static void sd_log_eject_request_event(struct sd_lun *un, int km_flag);
static void sd_media_change_task(void *arg);
static int sd_handle_mchange(struct sd_lun *un);
static int sd_send_scsi_DOORLOCK(sd_ssc_t *ssc, int flag, int path_flag);
static int sd_send_scsi_READ_CAPACITY(sd_ssc_t *ssc, uint64_t *capp,
uint32_t *lbap, int path_flag);
static int sd_send_scsi_READ_CAPACITY_16(sd_ssc_t *ssc, uint64_t *capp,
uint32_t *lbap, uint32_t *psp, int path_flag);
static int sd_send_scsi_START_STOP_UNIT(sd_ssc_t *ssc, int pc_flag,
int flag, int path_flag);
static int sd_send_scsi_INQUIRY(sd_ssc_t *ssc, uchar_t *bufaddr,
size_t buflen, uchar_t evpd, uchar_t page_code, size_t *residp);
static int sd_send_scsi_TEST_UNIT_READY(sd_ssc_t *ssc, int flag);
static int sd_send_scsi_PERSISTENT_RESERVE_IN(sd_ssc_t *ssc,
uchar_t usr_cmd, uint16_t data_len, uchar_t *data_bufp);
static int sd_send_scsi_PERSISTENT_RESERVE_OUT(sd_ssc_t *ssc,
uchar_t usr_cmd, uchar_t *usr_bufp);
static int sd_send_scsi_SYNCHRONIZE_CACHE(struct sd_lun *un,
struct dk_callback *dkc);
static int sd_send_scsi_SYNCHRONIZE_CACHE_biodone(struct buf *bp);
static int sd_send_scsi_UNMAP(dev_t dev, sd_ssc_t *ssc, dkioc_free_list_t *dfl,
int flag);
static int sd_send_scsi_GET_CONFIGURATION(sd_ssc_t *ssc,
struct uscsi_cmd *ucmdbuf, uchar_t *rqbuf, uint_t rqbuflen,
uchar_t *bufaddr, uint_t buflen, int path_flag);
static int sd_send_scsi_feature_GET_CONFIGURATION(sd_ssc_t *ssc,
struct uscsi_cmd *ucmdbuf, uchar_t *rqbuf, uint_t rqbuflen,
uchar_t *bufaddr, uint_t buflen, char feature, int path_flag);
static int sd_send_scsi_MODE_SENSE(sd_ssc_t *ssc, int cdbsize,
uchar_t *bufaddr, size_t buflen, uchar_t page_code, int path_flag);
static int sd_send_scsi_MODE_SELECT(sd_ssc_t *ssc, int cdbsize,
uchar_t *bufaddr, size_t buflen, uchar_t save_page, int path_flag);
static int sd_send_scsi_RDWR(sd_ssc_t *ssc, uchar_t cmd, void *bufaddr,
size_t buflen, daddr_t start_block, int path_flag);
#define sd_send_scsi_READ(ssc, bufaddr, buflen, start_block, path_flag) \
sd_send_scsi_RDWR(ssc, SCMD_READ, bufaddr, buflen, start_block, \
path_flag)
#define sd_send_scsi_WRITE(ssc, bufaddr, buflen, start_block, path_flag)\
sd_send_scsi_RDWR(ssc, SCMD_WRITE, bufaddr, buflen, start_block,\
path_flag)
static int sd_send_scsi_LOG_SENSE(sd_ssc_t *ssc, uchar_t *bufaddr,
uint16_t buflen, uchar_t page_code, uchar_t page_control,
uint16_t param_ptr, int path_flag);
static int sd_send_scsi_GET_EVENT_STATUS_NOTIFICATION(sd_ssc_t *ssc,
uchar_t *bufaddr, size_t buflen, uchar_t class_req);
static boolean_t sd_gesn_media_data_valid(uchar_t *data);
static int sd_alloc_rqs(struct scsi_device *devp, struct sd_lun *un);
static void sd_free_rqs(struct sd_lun *un);
static void sd_dump_memory(struct sd_lun *un, uint_t comp, char *title,
uchar_t *data, int len, int fmt);
static void sd_panic_for_res_conflict(struct sd_lun *un);
/*
* Disk Ioctl Function Prototypes
*/
static int sd_get_media_info(dev_t dev, caddr_t arg, int flag);
static int sd_get_media_info_ext(dev_t dev, caddr_t arg, int flag);
static int sd_dkio_ctrl_info(dev_t dev, caddr_t arg, int flag);
static int sd_dkio_get_temp(dev_t dev, caddr_t arg, int flag);
/*
* Multi-host Ioctl Prototypes
*/
static int sd_check_mhd(dev_t dev, int interval);
static int sd_mhd_watch_cb(caddr_t arg, struct scsi_watch_result *resultp);
static void sd_mhd_watch_incomplete(struct sd_lun *un, struct scsi_pkt *pkt);
static char *sd_sname(uchar_t status);
static void sd_mhd_resvd_recover(void *arg);
static void sd_resv_reclaim_thread();
static int sd_take_ownership(dev_t dev, struct mhioctkown *p);
static int sd_reserve_release(dev_t dev, int cmd);
static void sd_rmv_resv_reclaim_req(dev_t dev);
static void sd_mhd_reset_notify_cb(caddr_t arg);
static int sd_persistent_reservation_in_read_keys(struct sd_lun *un,
mhioc_inkeys_t *usrp, int flag);
static int sd_persistent_reservation_in_read_resv(struct sd_lun *un,
mhioc_inresvs_t *usrp, int flag);
static int sd_mhdioc_takeown(dev_t dev, caddr_t arg, int flag);
static int sd_mhdioc_failfast(dev_t dev, caddr_t arg, int flag);
static int sd_mhdioc_release(dev_t dev);
static int sd_mhdioc_register_devid(dev_t dev);
static int sd_mhdioc_inkeys(dev_t dev, caddr_t arg, int flag);
static int sd_mhdioc_inresv(dev_t dev, caddr_t arg, int flag);
/*
* SCSI removable prototypes
*/
static int sr_change_blkmode(dev_t dev, int cmd, intptr_t data, int flag);
static int sr_change_speed(dev_t dev, int cmd, intptr_t data, int flag);
static int sr_atapi_change_speed(dev_t dev, int cmd, intptr_t data, int flag);
static int sr_pause_resume(dev_t dev, int mode);
static int sr_play_msf(dev_t dev, caddr_t data, int flag);
static int sr_play_trkind(dev_t dev, caddr_t data, int flag);
static int sr_read_all_subcodes(dev_t dev, caddr_t data, int flag);
static int sr_read_subchannel(dev_t dev, caddr_t data, int flag);
static int sr_read_tocentry(dev_t dev, caddr_t data, int flag);
static int sr_read_tochdr(dev_t dev, caddr_t data, int flag);
static int sr_read_cdda(dev_t dev, caddr_t data, int flag);
static int sr_read_cdxa(dev_t dev, caddr_t data, int flag);
static int sr_read_mode1(dev_t dev, caddr_t data, int flag);
static int sr_read_mode2(dev_t dev, caddr_t data, int flag);
static int sr_read_cd_mode2(dev_t dev, caddr_t data, int flag);
static int sr_sector_mode(dev_t dev, uint32_t blksize);
static int sr_eject(dev_t dev);
static void sr_ejected(register struct sd_lun *un);
static int sr_check_wp(dev_t dev);
static opaque_t sd_watch_request_submit(struct sd_lun *un);
static int sd_check_media(dev_t dev, enum dkio_state state);
static int sd_media_watch_cb(caddr_t arg, struct scsi_watch_result *resultp);
static void sd_delayed_cv_broadcast(void *arg);
static int sr_volume_ctrl(dev_t dev, caddr_t data, int flag);
static int sr_read_sony_session_offset(dev_t dev, caddr_t data, int flag);
static int sd_log_page_supported(sd_ssc_t *ssc, int log_page);
/*
* Function Prototype for the non-512 support (DVDRAM, MO etc.) functions.
*/
static void sd_check_for_writable_cd(sd_ssc_t *ssc, int path_flag);
static int sd_wm_cache_constructor(void *wm, void *un, int flags);
static void sd_wm_cache_destructor(void *wm, void *un);
static struct sd_w_map *sd_range_lock(struct sd_lun *un, daddr_t startb,
daddr_t endb, ushort_t typ);
static struct sd_w_map *sd_get_range(struct sd_lun *un, daddr_t startb,
daddr_t endb);
static void sd_free_inlist_wmap(struct sd_lun *un, struct sd_w_map *wmp);
static void sd_range_unlock(struct sd_lun *un, struct sd_w_map *wm);
static void sd_read_modify_write_task(void * arg);
static int
sddump_do_read_of_rmw(struct sd_lun *un, uint64_t blkno, uint64_t nblk,
struct buf **bpp);
/*
* Function prototypes for failfast support.
*/
static void sd_failfast_flushq(struct sd_lun *un);
static int sd_failfast_flushq_callback(struct buf *bp);
/*
* Function prototypes to check for lsi devices
*/
static void sd_is_lsi(struct sd_lun *un);
/*
* Function prototypes for partial DMA support
*/
static int sd_setup_next_xfer(struct sd_lun *un, struct buf *bp,
struct scsi_pkt *pkt, struct sd_xbuf *xp);
/* Function prototypes for cmlb */
static int sd_tg_rdwr(dev_info_t *devi, uchar_t cmd, void *bufaddr,
diskaddr_t start_block, size_t reqlength, void *tg_cookie);
static int sd_tg_getinfo(dev_info_t *devi, int cmd, void *arg, void *tg_cookie);
/*
* For printing RMW warning message timely
*/
static void sd_rmw_msg_print_handler(void *arg);
/*
* Constants for failfast support:
*
* SD_FAILFAST_INACTIVE: Instance is currently in a normal state, with NO
* failfast processing being performed.
*
* SD_FAILFAST_ACTIVE: Instance is in the failfast state and is performing
* failfast processing on all bufs with B_FAILFAST set.
*/
#define SD_FAILFAST_INACTIVE 0
#define SD_FAILFAST_ACTIVE 1
/*
* Bitmask to control behavior of buf(9S) flushes when a transition to
* the failfast state occurs. Optional bits include:
*
* SD_FAILFAST_FLUSH_ALL_BUFS: When set, flush ALL bufs including those that
* do NOT have B_FAILFAST set. When clear, only bufs with B_FAILFAST will
* be flushed.
*
* SD_FAILFAST_FLUSH_ALL_QUEUES: When set, flush any/all other queues in the
* driver, in addition to the regular wait queue. This includes the xbuf
* queues. When clear, only the driver's wait queue will be flushed.
*/
#define SD_FAILFAST_FLUSH_ALL_BUFS 0x01
#define SD_FAILFAST_FLUSH_ALL_QUEUES 0x02
/*
* The default behavior is to only flush bufs that have B_FAILFAST set, but
* to flush all queues within the driver.
*/
static int sd_failfast_flushctl = SD_FAILFAST_FLUSH_ALL_QUEUES;
/*
* SD Testing Fault Injection
*/
#ifdef SD_FAULT_INJECTION
static void sd_faultinjection_ioctl(int cmd, intptr_t arg, struct sd_lun *un);
static void sd_faultinjection(struct scsi_pkt *pktp);
static void sd_injection_log(char *buf, struct sd_lun *un);
#endif
/*
* Device driver ops vector
*/
static struct cb_ops sd_cb_ops = {
sdopen, /* open */
sdclose, /* close */
sdstrategy, /* strategy */
nodev, /* print */
sddump, /* dump */
sdread, /* read */
sdwrite, /* write */
sdioctl, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
nodev, /* segmap */
nochpoll, /* poll */
sd_prop_op, /* cb_prop_op */
0, /* streamtab */
D_64BIT | D_MP | D_NEW | D_HOTPLUG, /* Driver compatibility flags */
CB_REV, /* cb_rev */
sdaread, /* async I/O read entry point */
sdawrite /* async I/O write entry point */
};
struct dev_ops sd_ops = {
DEVO_REV, /* devo_rev, */
0, /* refcnt */
sdinfo, /* info */
nulldev, /* identify */
sdprobe, /* probe */
sdattach, /* attach */
sddetach, /* detach */
nodev, /* reset */
&sd_cb_ops, /* driver operations */
NULL, /* bus operations */
sdpower, /* power */
ddi_quiesce_not_needed, /* quiesce */
};
/*
* This is the loadable module wrapper.
*/
#include <sys/modctl.h>
static struct modldrv modldrv = {
&mod_driverops, /* Type of module. This one is a driver */
SD_MODULE_NAME, /* Module name. */
&sd_ops /* driver ops */
};
static struct modlinkage modlinkage = {
MODREV_1, &modldrv, NULL
};
static cmlb_tg_ops_t sd_tgops = {
TG_DK_OPS_VERSION_1,
sd_tg_rdwr,
sd_tg_getinfo
};
static struct scsi_asq_key_strings sd_additional_codes[] = {
0x81, 0, "Logical Unit is Reserved",
0x85, 0, "Audio Address Not Valid",
0xb6, 0, "Media Load Mechanism Failed",
0xB9, 0, "Audio Play Operation Aborted",
0xbf, 0, "Buffer Overflow for Read All Subcodes Command",
0x53, 2, "Medium removal prevented",
0x6f, 0, "Authentication failed during key exchange",
0x6f, 1, "Key not present",
0x6f, 2, "Key not established",
0x6f, 3, "Read without proper authentication",
0x6f, 4, "Mismatched region to this logical unit",
0x6f, 5, "Region reset count error",
0xffff, 0x0, NULL
};
/*
* Struct for passing printing information for sense data messages
*/
struct sd_sense_info {
int ssi_severity;
int ssi_pfa_flag;
};
/*
* Table of function pointers for iostart-side routines. Separate "chains"
* of layered function calls are formed by placing the function pointers
* sequentially in the desired order. Functions are called according to an
* incrementing table index ordering. The last function in each chain must
* be sd_core_iostart(). The corresponding iodone-side routines are expected
* in the sd_iodone_chain[] array.
*
* Note: It may seem more natural to organize both the iostart and iodone
* functions together, into an array of structures (or some similar
* organization) with a common index, rather than two separate arrays which
* must be maintained in synchronization. The purpose of this division is
* to achieve improved performance: individual arrays allows for more
* effective cache line utilization on certain platforms.
*/
typedef void (*sd_chain_t)(int index, struct sd_lun *un, struct buf *bp);
static sd_chain_t sd_iostart_chain[] = {
/* Chain for buf IO for disk drive targets (PM enabled) */
sd_mapblockaddr_iostart, /* Index: 0 */
sd_pm_iostart, /* Index: 1 */
sd_core_iostart, /* Index: 2 */
/* Chain for buf IO for disk drive targets (PM disabled) */
sd_mapblockaddr_iostart, /* Index: 3 */
sd_core_iostart, /* Index: 4 */
/*
* Chain for buf IO for removable-media or large sector size
* disk drive targets with RMW needed (PM enabled)
*/
sd_mapblockaddr_iostart, /* Index: 5 */
sd_mapblocksize_iostart, /* Index: 6 */
sd_pm_iostart, /* Index: 7 */
sd_core_iostart, /* Index: 8 */
/*
* Chain for buf IO for removable-media or large sector size
* disk drive targets with RMW needed (PM disabled)
*/
sd_mapblockaddr_iostart, /* Index: 9 */
sd_mapblocksize_iostart, /* Index: 10 */
sd_core_iostart, /* Index: 11 */
/* Chain for buf IO for disk drives with checksumming (PM enabled) */
sd_mapblockaddr_iostart, /* Index: 12 */
sd_checksum_iostart, /* Index: 13 */
sd_pm_iostart, /* Index: 14 */
sd_core_iostart, /* Index: 15 */
/* Chain for buf IO for disk drives with checksumming (PM disabled) */
sd_mapblockaddr_iostart, /* Index: 16 */
sd_checksum_iostart, /* Index: 17 */
sd_core_iostart, /* Index: 18 */
/* Chain for USCSI commands (all targets) */
sd_pm_iostart, /* Index: 19 */
sd_core_iostart, /* Index: 20 */
/* Chain for checksumming USCSI commands (all targets) */
sd_checksum_uscsi_iostart, /* Index: 21 */
sd_pm_iostart, /* Index: 22 */
sd_core_iostart, /* Index: 23 */
/* Chain for "direct" USCSI commands (all targets) */
sd_core_iostart, /* Index: 24 */
/* Chain for "direct priority" USCSI commands (all targets) */
sd_core_iostart, /* Index: 25 */
/*
* Chain for buf IO for large sector size disk drive targets
* with RMW needed with checksumming (PM enabled)
*/
sd_mapblockaddr_iostart, /* Index: 26 */
sd_mapblocksize_iostart, /* Index: 27 */
sd_checksum_iostart, /* Index: 28 */
sd_pm_iostart, /* Index: 29 */
sd_core_iostart, /* Index: 30 */
/*
* Chain for buf IO for large sector size disk drive targets
* with RMW needed with checksumming (PM disabled)
*/
sd_mapblockaddr_iostart, /* Index: 31 */
sd_mapblocksize_iostart, /* Index: 32 */
sd_checksum_iostart, /* Index: 33 */
sd_core_iostart, /* Index: 34 */
};
/*
* Macros to locate the first function of each iostart chain in the
* sd_iostart_chain[] array. These are located by the index in the array.
*/
#define SD_CHAIN_DISK_IOSTART 0
#define SD_CHAIN_DISK_IOSTART_NO_PM 3
#define SD_CHAIN_MSS_DISK_IOSTART 5
#define SD_CHAIN_RMMEDIA_IOSTART 5
#define SD_CHAIN_MSS_DISK_IOSTART_NO_PM 9
#define SD_CHAIN_RMMEDIA_IOSTART_NO_PM 9
#define SD_CHAIN_CHKSUM_IOSTART 12
#define SD_CHAIN_CHKSUM_IOSTART_NO_PM 16
#define SD_CHAIN_USCSI_CMD_IOSTART 19
#define SD_CHAIN_USCSI_CHKSUM_IOSTART 21
#define SD_CHAIN_DIRECT_CMD_IOSTART 24
#define SD_CHAIN_PRIORITY_CMD_IOSTART 25
#define SD_CHAIN_MSS_CHKSUM_IOSTART 26
#define SD_CHAIN_MSS_CHKSUM_IOSTART_NO_PM 31
/*
* Table of function pointers for the iodone-side routines for the driver-
* internal layering mechanism. The calling sequence for iodone routines
* uses a decrementing table index, so the last routine called in a chain
* must be at the lowest array index location for that chain. The last
* routine for each chain must be either sd_buf_iodone() (for buf(9S) IOs)
* or sd_uscsi_iodone() (for uscsi IOs). Other than this, the ordering
* of the functions in an iodone side chain must correspond to the ordering
* of the iostart routines for that chain. Note that there is no iodone
* side routine that corresponds to sd_core_iostart(), so there is no
* entry in the table for this.
*/
static sd_chain_t sd_iodone_chain[] = {
/* Chain for buf IO for disk drive targets (PM enabled) */
sd_buf_iodone, /* Index: 0 */
sd_mapblockaddr_iodone, /* Index: 1 */
sd_pm_iodone, /* Index: 2 */
/* Chain for buf IO for disk drive targets (PM disabled) */
sd_buf_iodone, /* Index: 3 */
sd_mapblockaddr_iodone, /* Index: 4 */
/*
* Chain for buf IO for removable-media or large sector size
* disk drive targets with RMW needed (PM enabled)
*/
sd_buf_iodone, /* Index: 5 */
sd_mapblockaddr_iodone, /* Index: 6 */
sd_mapblocksize_iodone, /* Index: 7 */
sd_pm_iodone, /* Index: 8 */
/*
* Chain for buf IO for removable-media or large sector size
* disk drive targets with RMW needed (PM disabled)
*/
sd_buf_iodone, /* Index: 9 */
sd_mapblockaddr_iodone, /* Index: 10 */
sd_mapblocksize_iodone, /* Index: 11 */
/* Chain for buf IO for disk drives with checksumming (PM enabled) */
sd_buf_iodone, /* Index: 12 */
sd_mapblockaddr_iodone, /* Index: 13 */
sd_checksum_iodone, /* Index: 14 */
sd_pm_iodone, /* Index: 15 */
/* Chain for buf IO for disk drives with checksumming (PM disabled) */
sd_buf_iodone, /* Index: 16 */
sd_mapblockaddr_iodone, /* Index: 17 */
sd_checksum_iodone, /* Index: 18 */
/* Chain for USCSI commands (non-checksum targets) */
sd_uscsi_iodone, /* Index: 19 */
sd_pm_iodone, /* Index: 20 */
/* Chain for USCSI commands (checksum targets) */
sd_uscsi_iodone, /* Index: 21 */
sd_checksum_uscsi_iodone, /* Index: 22 */
sd_pm_iodone, /* Index: 22 */
/* Chain for "direct" USCSI commands (all targets) */
sd_uscsi_iodone, /* Index: 24 */
/* Chain for "direct priority" USCSI commands (all targets) */
sd_uscsi_iodone, /* Index: 25 */
/*
* Chain for buf IO for large sector size disk drive targets
* with checksumming (PM enabled)
*/
sd_buf_iodone, /* Index: 26 */
sd_mapblockaddr_iodone, /* Index: 27 */
sd_mapblocksize_iodone, /* Index: 28 */
sd_checksum_iodone, /* Index: 29 */
sd_pm_iodone, /* Index: 30 */
/*
* Chain for buf IO for large sector size disk drive targets
* with checksumming (PM disabled)
*/
sd_buf_iodone, /* Index: 31 */
sd_mapblockaddr_iodone, /* Index: 32 */
sd_mapblocksize_iodone, /* Index: 33 */
sd_checksum_iodone, /* Index: 34 */
};
/*
* Macros to locate the "first" function in the sd_iodone_chain[] array for
* each iodone-side chain. These are located by the array index, but as the
* iodone side functions are called in a decrementing-index order, the
* highest index number in each chain must be specified (as these correspond
* to the first function in the iodone chain that will be called by the core
* at IO completion time).
*/
#define SD_CHAIN_DISK_IODONE 2
#define SD_CHAIN_DISK_IODONE_NO_PM 4
#define SD_CHAIN_RMMEDIA_IODONE 8
#define SD_CHAIN_MSS_DISK_IODONE 8
#define SD_CHAIN_RMMEDIA_IODONE_NO_PM 11
#define SD_CHAIN_MSS_DISK_IODONE_NO_PM 11
#define SD_CHAIN_CHKSUM_IODONE 15
#define SD_CHAIN_CHKSUM_IODONE_NO_PM 18
#define SD_CHAIN_USCSI_CMD_IODONE 20
#define SD_CHAIN_USCSI_CHKSUM_IODONE 22
#define SD_CHAIN_DIRECT_CMD_IODONE 24
#define SD_CHAIN_PRIORITY_CMD_IODONE 25
#define SD_CHAIN_MSS_CHKSUM_IODONE 30
#define SD_CHAIN_MSS_CHKSUM_IODONE_NO_PM 34
/*
* Array to map a layering chain index to the appropriate initpkt routine.
* The redundant entries are present so that the index used for accessing
* the above sd_iostart_chain and sd_iodone_chain tables can be used directly
* with this table as well.
*/
typedef int (*sd_initpkt_t)(struct buf *, struct scsi_pkt **);
static sd_initpkt_t sd_initpkt_map[] = {
/* Chain for buf IO for disk drive targets (PM enabled) */
sd_initpkt_for_buf, /* Index: 0 */
sd_initpkt_for_buf, /* Index: 1 */
sd_initpkt_for_buf, /* Index: 2 */
/* Chain for buf IO for disk drive targets (PM disabled) */
sd_initpkt_for_buf, /* Index: 3 */
sd_initpkt_for_buf, /* Index: 4 */
/*
* Chain for buf IO for removable-media or large sector size
* disk drive targets (PM enabled)
*/
sd_initpkt_for_buf, /* Index: 5 */
sd_initpkt_for_buf, /* Index: 6 */
sd_initpkt_for_buf, /* Index: 7 */
sd_initpkt_for_buf, /* Index: 8 */
/*
* Chain for buf IO for removable-media or large sector size
* disk drive targets (PM disabled)
*/
sd_initpkt_for_buf, /* Index: 9 */
sd_initpkt_for_buf, /* Index: 10 */
sd_initpkt_for_buf, /* Index: 11 */
/* Chain for buf IO for disk drives with checksumming (PM enabled) */
sd_initpkt_for_buf, /* Index: 12 */
sd_initpkt_for_buf, /* Index: 13 */
sd_initpkt_for_buf, /* Index: 14 */
sd_initpkt_for_buf, /* Index: 15 */
/* Chain for buf IO for disk drives with checksumming (PM disabled) */
sd_initpkt_for_buf, /* Index: 16 */
sd_initpkt_for_buf, /* Index: 17 */
sd_initpkt_for_buf, /* Index: 18 */
/* Chain for USCSI commands (non-checksum targets) */
sd_initpkt_for_uscsi, /* Index: 19 */
sd_initpkt_for_uscsi, /* Index: 20 */
/* Chain for USCSI commands (checksum targets) */
sd_initpkt_for_uscsi, /* Index: 21 */
sd_initpkt_for_uscsi, /* Index: 22 */
sd_initpkt_for_uscsi, /* Index: 22 */
/* Chain for "direct" USCSI commands (all targets) */
sd_initpkt_for_uscsi, /* Index: 24 */
/* Chain for "direct priority" USCSI commands (all targets) */
sd_initpkt_for_uscsi, /* Index: 25 */
/*
* Chain for buf IO for large sector size disk drive targets
* with checksumming (PM enabled)
*/
sd_initpkt_for_buf, /* Index: 26 */
sd_initpkt_for_buf, /* Index: 27 */
sd_initpkt_for_buf, /* Index: 28 */
sd_initpkt_for_buf, /* Index: 29 */
sd_initpkt_for_buf, /* Index: 30 */
/*
* Chain for buf IO for large sector size disk drive targets
* with checksumming (PM disabled)
*/
sd_initpkt_for_buf, /* Index: 31 */
sd_initpkt_for_buf, /* Index: 32 */
sd_initpkt_for_buf, /* Index: 33 */
sd_initpkt_for_buf, /* Index: 34 */
};
/*
* Array to map a layering chain index to the appropriate destroypktpkt routine.
* The redundant entries are present so that the index used for accessing
* the above sd_iostart_chain and sd_iodone_chain tables can be used directly
* with this table as well.
*/
typedef void (*sd_destroypkt_t)(struct buf *);
static sd_destroypkt_t sd_destroypkt_map[] = {
/* Chain for buf IO for disk drive targets (PM enabled) */
sd_destroypkt_for_buf, /* Index: 0 */
sd_destroypkt_for_buf, /* Index: 1 */
sd_destroypkt_for_buf, /* Index: 2 */
/* Chain for buf IO for disk drive targets (PM disabled) */
sd_destroypkt_for_buf, /* Index: 3 */
sd_destroypkt_for_buf, /* Index: 4 */
/*
* Chain for buf IO for removable-media or large sector size
* disk drive targets (PM enabled)
*/
sd_destroypkt_for_buf, /* Index: 5 */
sd_destroypkt_for_buf, /* Index: 6 */
sd_destroypkt_for_buf, /* Index: 7 */
sd_destroypkt_for_buf, /* Index: 8 */
/*
* Chain for buf IO for removable-media or large sector size
* disk drive targets (PM disabled)
*/
sd_destroypkt_for_buf, /* Index: 9 */
sd_destroypkt_for_buf, /* Index: 10 */
sd_destroypkt_for_buf, /* Index: 11 */
/* Chain for buf IO for disk drives with checksumming (PM enabled) */
sd_destroypkt_for_buf, /* Index: 12 */
sd_destroypkt_for_buf, /* Index: 13 */
sd_destroypkt_for_buf, /* Index: 14 */
sd_destroypkt_for_buf, /* Index: 15 */
/* Chain for buf IO for disk drives with checksumming (PM disabled) */
sd_destroypkt_for_buf, /* Index: 16 */
sd_destroypkt_for_buf, /* Index: 17 */
sd_destroypkt_for_buf, /* Index: 18 */
/* Chain for USCSI commands (non-checksum targets) */
sd_destroypkt_for_uscsi, /* Index: 19 */
sd_destroypkt_for_uscsi, /* Index: 20 */
/* Chain for USCSI commands (checksum targets) */
sd_destroypkt_for_uscsi, /* Index: 21 */
sd_destroypkt_for_uscsi, /* Index: 22 */
sd_destroypkt_for_uscsi, /* Index: 22 */
/* Chain for "direct" USCSI commands (all targets) */
sd_destroypkt_for_uscsi, /* Index: 24 */
/* Chain for "direct priority" USCSI commands (all targets) */
sd_destroypkt_for_uscsi, /* Index: 25 */
/*
* Chain for buf IO for large sector size disk drive targets
* with checksumming (PM disabled)
*/
sd_destroypkt_for_buf, /* Index: 26 */
sd_destroypkt_for_buf, /* Index: 27 */
sd_destroypkt_for_buf, /* Index: 28 */
sd_destroypkt_for_buf, /* Index: 29 */
sd_destroypkt_for_buf, /* Index: 30 */
/*
* Chain for buf IO for large sector size disk drive targets
* with checksumming (PM enabled)
*/
sd_destroypkt_for_buf, /* Index: 31 */
sd_destroypkt_for_buf, /* Index: 32 */
sd_destroypkt_for_buf, /* Index: 33 */
sd_destroypkt_for_buf, /* Index: 34 */
};
/*
* Array to map a layering chain index to the appropriate chain "type".
* The chain type indicates a specific property/usage of the chain.
* The redundant entries are present so that the index used for accessing
* the above sd_iostart_chain and sd_iodone_chain tables can be used directly
* with this table as well.
*/
#define SD_CHAIN_NULL 0 /* for the special RQS cmd */
#define SD_CHAIN_BUFIO 1 /* regular buf IO */
#define SD_CHAIN_USCSI 2 /* regular USCSI commands */
#define SD_CHAIN_DIRECT 3 /* uscsi, w/ bypass power mgt */
#define SD_CHAIN_DIRECT_PRIORITY 4 /* uscsi, w/ bypass power mgt */
/* (for error recovery) */
static int sd_chain_type_map[] = {
/* Chain for buf IO for disk drive targets (PM enabled) */
SD_CHAIN_BUFIO, /* Index: 0 */
SD_CHAIN_BUFIO, /* Index: 1 */
SD_CHAIN_BUFIO, /* Index: 2 */
/* Chain for buf IO for disk drive targets (PM disabled) */
SD_CHAIN_BUFIO, /* Index: 3 */
SD_CHAIN_BUFIO, /* Index: 4 */
/*
* Chain for buf IO for removable-media or large sector size
* disk drive targets (PM enabled)
*/
SD_CHAIN_BUFIO, /* Index: 5 */
SD_CHAIN_BUFIO, /* Index: 6 */
SD_CHAIN_BUFIO, /* Index: 7 */
SD_CHAIN_BUFIO, /* Index: 8 */
/*
* Chain for buf IO for removable-media or large sector size
* disk drive targets (PM disabled)
*/
SD_CHAIN_BUFIO, /* Index: 9 */
SD_CHAIN_BUFIO, /* Index: 10 */
SD_CHAIN_BUFIO, /* Index: 11 */
/* Chain for buf IO for disk drives with checksumming (PM enabled) */
SD_CHAIN_BUFIO, /* Index: 12 */
SD_CHAIN_BUFIO, /* Index: 13 */
SD_CHAIN_BUFIO, /* Index: 14 */
SD_CHAIN_BUFIO, /* Index: 15 */
/* Chain for buf IO for disk drives with checksumming (PM disabled) */
SD_CHAIN_BUFIO, /* Index: 16 */
SD_CHAIN_BUFIO, /* Index: 17 */
SD_CHAIN_BUFIO, /* Index: 18 */
/* Chain for USCSI commands (non-checksum targets) */
SD_CHAIN_USCSI, /* Index: 19 */
SD_CHAIN_USCSI, /* Index: 20 */
/* Chain for USCSI commands (checksum targets) */
SD_CHAIN_USCSI, /* Index: 21 */
SD_CHAIN_USCSI, /* Index: 22 */
SD_CHAIN_USCSI, /* Index: 23 */
/* Chain for "direct" USCSI commands (all targets) */
SD_CHAIN_DIRECT, /* Index: 24 */
/* Chain for "direct priority" USCSI commands (all targets) */
SD_CHAIN_DIRECT_PRIORITY, /* Index: 25 */
/*
* Chain for buf IO for large sector size disk drive targets
* with checksumming (PM enabled)
*/
SD_CHAIN_BUFIO, /* Index: 26 */
SD_CHAIN_BUFIO, /* Index: 27 */
SD_CHAIN_BUFIO, /* Index: 28 */
SD_CHAIN_BUFIO, /* Index: 29 */
SD_CHAIN_BUFIO, /* Index: 30 */
/*
* Chain for buf IO for large sector size disk drive targets
* with checksumming (PM disabled)
*/
SD_CHAIN_BUFIO, /* Index: 31 */
SD_CHAIN_BUFIO, /* Index: 32 */
SD_CHAIN_BUFIO, /* Index: 33 */
SD_CHAIN_BUFIO, /* Index: 34 */
};
/* Macro to return TRUE if the IO has come from the sd_buf_iostart() chain. */
#define SD_IS_BUFIO(xp) \
(sd_chain_type_map[(xp)->xb_chain_iostart] == SD_CHAIN_BUFIO)
/* Macro to return TRUE if the IO has come from the "direct priority" chain. */
#define SD_IS_DIRECT_PRIORITY(xp) \
(sd_chain_type_map[(xp)->xb_chain_iostart] == SD_CHAIN_DIRECT_PRIORITY)
/*
* Struct, array, and macros to map a specific chain to the appropriate
* layering indexes in the sd_iostart_chain[] and sd_iodone_chain[] arrays.
*
* The sd_chain_index_map[] array is used at attach time to set the various
* un_xxx_chain type members of the sd_lun softstate to the specific layering
* chain to be used with the instance. This allows different instances to use
* different chain for buf IO, uscsi IO, etc.. Also, since the xb_chain_iostart
* and xb_chain_iodone index values in the sd_xbuf are initialized to these
* values at sd_xbuf init time, this allows (1) layering chains may be changed
* dynamically & without the use of locking; and (2) a layer may update the
* xb_chain_io[start|done] member in a given xbuf with its current index value,
* to allow for deferred processing of an IO within the same chain from a
* different execution context.
*/
struct sd_chain_index {
int sci_iostart_index;
int sci_iodone_index;
};
static struct sd_chain_index sd_chain_index_map[] = {
{ SD_CHAIN_DISK_IOSTART, SD_CHAIN_DISK_IODONE },
{ SD_CHAIN_DISK_IOSTART_NO_PM, SD_CHAIN_DISK_IODONE_NO_PM },
{ SD_CHAIN_RMMEDIA_IOSTART, SD_CHAIN_RMMEDIA_IODONE },
{ SD_CHAIN_RMMEDIA_IOSTART_NO_PM, SD_CHAIN_RMMEDIA_IODONE_NO_PM },
{ SD_CHAIN_CHKSUM_IOSTART, SD_CHAIN_CHKSUM_IODONE },
{ SD_CHAIN_CHKSUM_IOSTART_NO_PM, SD_CHAIN_CHKSUM_IODONE_NO_PM },
{ SD_CHAIN_USCSI_CMD_IOSTART, SD_CHAIN_USCSI_CMD_IODONE },
{ SD_CHAIN_USCSI_CHKSUM_IOSTART, SD_CHAIN_USCSI_CHKSUM_IODONE },
{ SD_CHAIN_DIRECT_CMD_IOSTART, SD_CHAIN_DIRECT_CMD_IODONE },
{ SD_CHAIN_PRIORITY_CMD_IOSTART, SD_CHAIN_PRIORITY_CMD_IODONE },
{ SD_CHAIN_MSS_CHKSUM_IOSTART, SD_CHAIN_MSS_CHKSUM_IODONE },
{ SD_CHAIN_MSS_CHKSUM_IOSTART_NO_PM, SD_CHAIN_MSS_CHKSUM_IODONE_NO_PM },
};
/*
* The following are indexes into the sd_chain_index_map[] array.
*/
/* un->un_buf_chain_type must be set to one of these */
#define SD_CHAIN_INFO_DISK 0
#define SD_CHAIN_INFO_DISK_NO_PM 1
#define SD_CHAIN_INFO_RMMEDIA 2
#define SD_CHAIN_INFO_MSS_DISK 2
#define SD_CHAIN_INFO_RMMEDIA_NO_PM 3
#define SD_CHAIN_INFO_MSS_DSK_NO_PM 3
#define SD_CHAIN_INFO_CHKSUM 4
#define SD_CHAIN_INFO_CHKSUM_NO_PM 5
#define SD_CHAIN_INFO_MSS_DISK_CHKSUM 10
#define SD_CHAIN_INFO_MSS_DISK_CHKSUM_NO_PM 11
/* un->un_uscsi_chain_type must be set to one of these */
#define SD_CHAIN_INFO_USCSI_CMD 6
/* USCSI with PM disabled is the same as DIRECT */
#define SD_CHAIN_INFO_USCSI_CMD_NO_PM 8
#define SD_CHAIN_INFO_USCSI_CHKSUM 7
/* un->un_direct_chain_type must be set to one of these */
#define SD_CHAIN_INFO_DIRECT_CMD 8
/* un->un_priority_chain_type must be set to one of these */
#define SD_CHAIN_INFO_PRIORITY_CMD 9
/* size for devid inquiries */
#define MAX_INQUIRY_SIZE 0xF0
/*
* Macros used by functions to pass a given buf(9S) struct along to the
* next function in the layering chain for further processing.
*
* In the following macros, passing more than three arguments to the called
* routines causes the optimizer for the SPARC compiler to stop doing tail
* call elimination which results in significant performance degradation.
*/
#define SD_BEGIN_IOSTART(index, un, bp) \
((*(sd_iostart_chain[index]))(index, un, bp))
#define SD_BEGIN_IODONE(index, un, bp) \
((*(sd_iodone_chain[index]))(index, un, bp))
#define SD_NEXT_IOSTART(index, un, bp) \
((*(sd_iostart_chain[(index) + 1]))((index) + 1, un, bp))
#define SD_NEXT_IODONE(index, un, bp) \
((*(sd_iodone_chain[(index) - 1]))((index) - 1, un, bp))
/*
* Function: _init
*
* Description: This is the driver _init(9E) entry point.
*
* Return Code: Returns the value from mod_install(9F) or
* ddi_soft_state_init(9F) as appropriate.
*
* Context: Called when driver module loaded.
*/
int
_init(void)
{
int err;
/* establish driver name from module name */
sd_label = (char *)mod_modname(&modlinkage);
err = ddi_soft_state_init(&sd_state, sizeof (struct sd_lun),
SD_MAXUNIT);
if (err != 0) {
return (err);
}
mutex_init(&sd_detach_mutex, NULL, MUTEX_DRIVER, NULL);
mutex_init(&sd_log_mutex, NULL, MUTEX_DRIVER, NULL);
mutex_init(&sd_label_mutex, NULL, MUTEX_DRIVER, NULL);
mutex_init(&sd_tr.srq_resv_reclaim_mutex, NULL, MUTEX_DRIVER, NULL);
cv_init(&sd_tr.srq_resv_reclaim_cv, NULL, CV_DRIVER, NULL);
cv_init(&sd_tr.srq_inprocess_cv, NULL, CV_DRIVER, NULL);
/*
* it's ok to init here even for fibre device
*/
sd_scsi_probe_cache_init();
sd_scsi_target_lun_init();
/*
* Creating taskq before mod_install ensures that all callers (threads)
* that enter the module after a successful mod_install encounter
* a valid taskq.
*/
sd_taskq_create();
err = mod_install(&modlinkage);
if (err != 0) {
/* delete taskq if install fails */
sd_taskq_delete();
mutex_destroy(&sd_detach_mutex);
mutex_destroy(&sd_log_mutex);
mutex_destroy(&sd_label_mutex);
mutex_destroy(&sd_tr.srq_resv_reclaim_mutex);
cv_destroy(&sd_tr.srq_resv_reclaim_cv);
cv_destroy(&sd_tr.srq_inprocess_cv);
sd_scsi_probe_cache_fini();
sd_scsi_target_lun_fini();
ddi_soft_state_fini(&sd_state);
return (err);
}
return (err);
}
/*
* Function: _fini
*
* Description: This is the driver _fini(9E) entry point.
*
* Return Code: Returns the value from mod_remove(9F)
*
* Context: Called when driver module is unloaded.
*/
int
_fini(void)
{
int err;
if ((err = mod_remove(&modlinkage)) != 0) {
return (err);
}
sd_taskq_delete();
mutex_destroy(&sd_detach_mutex);
mutex_destroy(&sd_log_mutex);
mutex_destroy(&sd_label_mutex);
mutex_destroy(&sd_tr.srq_resv_reclaim_mutex);
sd_scsi_probe_cache_fini();
sd_scsi_target_lun_fini();
cv_destroy(&sd_tr.srq_resv_reclaim_cv);
cv_destroy(&sd_tr.srq_inprocess_cv);
ddi_soft_state_fini(&sd_state);
return (err);
}
/*
* Function: _info
*
* Description: This is the driver _info(9E) entry point.
*
* Arguments: modinfop - pointer to the driver modinfo structure
*
* Return Code: Returns the value from mod_info(9F).
*
* Context: Kernel thread context
*/
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
/*
* The following routines implement the driver message logging facility.
* They provide component- and level- based debug output filtering.
* Output may also be restricted to messages for a single instance by
* specifying a soft state pointer in sd_debug_un. If sd_debug_un is set
* to NULL, then messages for all instances are printed.
*
* These routines have been cloned from each other due to the language
* constraints of macros and variable argument list processing.
*/
/*
* Function: sd_log_err
*
* Description: This routine is called by the SD_ERROR macro for debug
* logging of error conditions.
*
* Arguments: comp - driver component being logged
* dev - pointer to driver info structure
* fmt - error string and format to be logged
*/
static void
sd_log_err(uint_t comp, struct sd_lun *un, const char *fmt, ...)
{
va_list ap;
dev_info_t *dev;
ASSERT(un != NULL);
dev = SD_DEVINFO(un);
ASSERT(dev != NULL);
/*
* Filter messages based on the global component and level masks.
* Also print if un matches the value of sd_debug_un, or if
* sd_debug_un is set to NULL.
*/
if ((sd_component_mask & comp) && (sd_level_mask & SD_LOGMASK_ERROR) &&
((sd_debug_un == NULL) || (sd_debug_un == un))) {
mutex_enter(&sd_log_mutex);
va_start(ap, fmt);
(void) vsprintf(sd_log_buf, fmt, ap);
va_end(ap);
scsi_log(dev, sd_label, CE_CONT, "%s", sd_log_buf);
mutex_exit(&sd_log_mutex);
}
#ifdef SD_FAULT_INJECTION
_NOTE(DATA_READABLE_WITHOUT_LOCK(sd_lun::sd_injection_mask));
if (un->sd_injection_mask & comp) {
mutex_enter(&sd_log_mutex);
va_start(ap, fmt);
(void) vsprintf(sd_log_buf, fmt, ap);
va_end(ap);
sd_injection_log(sd_log_buf, un);
mutex_exit(&sd_log_mutex);
}
#endif
}
/*
* Function: sd_log_info
*
* Description: This routine is called by the SD_INFO macro for debug
* logging of general purpose informational conditions.
*
* Arguments: comp - driver component being logged
* dev - pointer to driver info structure
* fmt - info string and format to be logged
*/
static void
sd_log_info(uint_t component, struct sd_lun *un, const char *fmt, ...)
{
va_list ap;
dev_info_t *dev;
ASSERT(un != NULL);
dev = SD_DEVINFO(un);
ASSERT(dev != NULL);
/*
* Filter messages based on the global component and level masks.
* Also print if un matches the value of sd_debug_un, or if
* sd_debug_un is set to NULL.
*/
if ((sd_component_mask & component) &&
(sd_level_mask & SD_LOGMASK_INFO) &&
((sd_debug_un == NULL) || (sd_debug_un == un))) {
mutex_enter(&sd_log_mutex);
va_start(ap, fmt);
(void) vsprintf(sd_log_buf, fmt, ap);
va_end(ap);
scsi_log(dev, sd_label, CE_CONT, "%s", sd_log_buf);
mutex_exit(&sd_log_mutex);
}
#ifdef SD_FAULT_INJECTION
_NOTE(DATA_READABLE_WITHOUT_LOCK(sd_lun::sd_injection_mask));
if (un->sd_injection_mask & component) {
mutex_enter(&sd_log_mutex);
va_start(ap, fmt);
(void) vsprintf(sd_log_buf, fmt, ap);
va_end(ap);
sd_injection_log(sd_log_buf, un);
mutex_exit(&sd_log_mutex);
}
#endif
}
/*
* Function: sd_log_trace
*
* Description: This routine is called by the SD_TRACE macro for debug
* logging of trace conditions (i.e. function entry/exit).
*
* Arguments: comp - driver component being logged
* dev - pointer to driver info structure
* fmt - trace string and format to be logged
*/
static void
sd_log_trace(uint_t component, struct sd_lun *un, const char *fmt, ...)
{
va_list ap;
dev_info_t *dev;
ASSERT(un != NULL);
dev = SD_DEVINFO(un);
ASSERT(dev != NULL);
/*
* Filter messages based on the global component and level masks.
* Also print if un matches the value of sd_debug_un, or if
* sd_debug_un is set to NULL.
*/
if ((sd_component_mask & component) &&
(sd_level_mask & SD_LOGMASK_TRACE) &&
((sd_debug_un == NULL) || (sd_debug_un == un))) {
mutex_enter(&sd_log_mutex);
va_start(ap, fmt);
(void) vsprintf(sd_log_buf, fmt, ap);
va_end(ap);
scsi_log(dev, sd_label, CE_CONT, "%s", sd_log_buf);
mutex_exit(&sd_log_mutex);
}
#ifdef SD_FAULT_INJECTION
_NOTE(DATA_READABLE_WITHOUT_LOCK(sd_lun::sd_injection_mask));
if (un->sd_injection_mask & component) {
mutex_enter(&sd_log_mutex);
va_start(ap, fmt);
(void) vsprintf(sd_log_buf, fmt, ap);
va_end(ap);
sd_injection_log(sd_log_buf, un);
mutex_exit(&sd_log_mutex);
}
#endif
}
/*
* Function: sdprobe
*
* Description: This is the driver probe(9e) entry point function.
*
* Arguments: devi - opaque device info handle
*
* Return Code: DDI_PROBE_SUCCESS: If the probe was successful.
* DDI_PROBE_FAILURE: If the probe failed.
* DDI_PROBE_PARTIAL: If the instance is not present now,
* but may be present in the future.
*/
static int
sdprobe(dev_info_t *devi)
{
struct scsi_device *devp;
int rval;
int instance = ddi_get_instance(devi);
/*
* if it wasn't for pln, sdprobe could actually be nulldev
* in the "__fibre" case.
*/
if (ddi_dev_is_sid(devi) == DDI_SUCCESS) {
return (DDI_PROBE_DONTCARE);
}
devp = ddi_get_driver_private(devi);
if (devp == NULL) {
/* Ooops... nexus driver is mis-configured... */
return (DDI_PROBE_FAILURE);
}
if (ddi_get_soft_state(sd_state, instance) != NULL) {
return (DDI_PROBE_PARTIAL);
}
/*
* Call the SCSA utility probe routine to see if we actually
* have a target at this SCSI nexus.
*/
switch (sd_scsi_probe_with_cache(devp, NULL_FUNC)) {
case SCSIPROBE_EXISTS:
switch (devp->sd_inq->inq_dtype) {
case DTYPE_DIRECT:
rval = DDI_PROBE_SUCCESS;
break;
case DTYPE_RODIRECT:
/* CDs etc. Can be removable media */
rval = DDI_PROBE_SUCCESS;
break;
case DTYPE_OPTICAL:
/*
* Rewritable optical driver HP115AA
* Can also be removable media
*/
/*
* Do not attempt to bind to DTYPE_OPTICAL if
* pre solaris 9 sparc sd behavior is required
*
* If first time through and sd_dtype_optical_bind
* has not been set in /etc/system check properties
*/
if (sd_dtype_optical_bind < 0) {
sd_dtype_optical_bind = ddi_prop_get_int
(DDI_DEV_T_ANY, devi, 0,
"optical-device-bind", 1);
}
if (sd_dtype_optical_bind == 0) {
rval = DDI_PROBE_FAILURE;
} else {
rval = DDI_PROBE_SUCCESS;
}
break;
case DTYPE_NOTPRESENT:
default:
rval = DDI_PROBE_FAILURE;
break;
}
break;
default:
rval = DDI_PROBE_PARTIAL;
break;
}
/*
* This routine checks for resource allocation prior to freeing,
* so it will take care of the "smart probing" case where a
* scsi_probe() may or may not have been issued and will *not*
* free previously-freed resources.
*/
scsi_unprobe(devp);
return (rval);
}
/*
* Function: sdinfo
*
* Description: This is the driver getinfo(9e) entry point function.
* Given the device number, return the devinfo pointer from
* the scsi_device structure or the instance number
* associated with the dev_t.
*
* Arguments: dip - pointer to device info structure
* infocmd - command argument (DDI_INFO_DEVT2DEVINFO,
* DDI_INFO_DEVT2INSTANCE)
* arg - driver dev_t
* resultp - user buffer for request response
*
* Return Code: DDI_SUCCESS
* DDI_FAILURE
*/
/* ARGSUSED */
static int
sdinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
{
struct sd_lun *un;
dev_t dev;
int instance;
int error;
switch (infocmd) {
case DDI_INFO_DEVT2DEVINFO:
dev = (dev_t)arg;
instance = SDUNIT(dev);
if ((un = ddi_get_soft_state(sd_state, instance)) == NULL) {
return (DDI_FAILURE);
}
*result = (void *) SD_DEVINFO(un);
error = DDI_SUCCESS;
break;
case DDI_INFO_DEVT2INSTANCE:
dev = (dev_t)arg;
instance = SDUNIT(dev);
*result = (void *)(uintptr_t)instance;
error = DDI_SUCCESS;
break;
default:
error = DDI_FAILURE;
}
return (error);
}
/*
* Function: sd_prop_op
*
* Description: This is the driver prop_op(9e) entry point function.
* Return the number of blocks for the partition in question
* or forward the request to the property facilities.
*
* Arguments: dev - device number
* dip - pointer to device info structure
* prop_op - property operator
* mod_flags - DDI_PROP_DONTPASS, don't pass to parent
* name - pointer to property name
* valuep - pointer or address of the user buffer
* lengthp - property length
*
* Return Code: DDI_PROP_SUCCESS
* DDI_PROP_NOT_FOUND
* DDI_PROP_UNDEFINED
* DDI_PROP_NO_MEMORY
* DDI_PROP_BUF_TOO_SMALL
*/
static int
sd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
char *name, caddr_t valuep, int *lengthp)
{
struct sd_lun *un;
if ((un = ddi_get_soft_state(sd_state, ddi_get_instance(dip))) == NULL)
return (ddi_prop_op(dev, dip, prop_op, mod_flags,
name, valuep, lengthp));
return (cmlb_prop_op(un->un_cmlbhandle,
dev, dip, prop_op, mod_flags, name, valuep, lengthp,
SDPART(dev), (void *)SD_PATH_DIRECT));
}
/*
* The following functions are for smart probing:
* sd_scsi_probe_cache_init()
* sd_scsi_probe_cache_fini()
* sd_scsi_clear_probe_cache()
* sd_scsi_probe_with_cache()
*/
/*
* Function: sd_scsi_probe_cache_init
*
* Description: Initializes the probe response cache mutex and head pointer.
*
* Context: Kernel thread context
*/
static void
sd_scsi_probe_cache_init(void)
{
mutex_init(&sd_scsi_probe_cache_mutex, NULL, MUTEX_DRIVER, NULL);
sd_scsi_probe_cache_head = NULL;
}
/*
* Function: sd_scsi_probe_cache_fini
*
* Description: Frees all resources associated with the probe response cache.
*
* Context: Kernel thread context
*/
static void
sd_scsi_probe_cache_fini(void)
{
struct sd_scsi_probe_cache *cp;
struct sd_scsi_probe_cache *ncp;
/* Clean up our smart probing linked list */
for (cp = sd_scsi_probe_cache_head; cp != NULL; cp = ncp) {
ncp = cp->next;
kmem_free(cp, sizeof (struct sd_scsi_probe_cache));
}
sd_scsi_probe_cache_head = NULL;
mutex_destroy(&sd_scsi_probe_cache_mutex);
}
/*
* Function: sd_scsi_clear_probe_cache
*
* Description: This routine clears the probe response cache. This is
* done when open() returns ENXIO so that when deferred
* attach is attempted (possibly after a device has been
* turned on) we will retry the probe. Since we don't know
* which target we failed to open, we just clear the
* entire cache.
*
* Context: Kernel thread context
*/
static void
sd_scsi_clear_probe_cache(void)
{
struct sd_scsi_probe_cache *cp;
int i;
mutex_enter(&sd_scsi_probe_cache_mutex);
for (cp = sd_scsi_probe_cache_head; cp != NULL; cp = cp->next) {
/*
* Reset all entries to SCSIPROBE_EXISTS. This will
* force probing to be performed the next time
* sd_scsi_probe_with_cache is called.
*/
for (i = 0; i < NTARGETS_WIDE; i++) {
cp->cache[i] = SCSIPROBE_EXISTS;
}
}
mutex_exit(&sd_scsi_probe_cache_mutex);
}
/*
* Function: sd_scsi_probe_with_cache
*
* Description: This routine implements support for a scsi device probe
* with cache. The driver maintains a cache of the target
* responses to scsi probes. If we get no response from a
* target during a probe inquiry, we remember that, and we
* avoid additional calls to scsi_probe on non-zero LUNs
* on the same target until the cache is cleared. By doing
* so we avoid the 1/4 sec selection timeout for nonzero
* LUNs. lun0 of a target is always probed.
*
* Arguments: devp - Pointer to a scsi_device(9S) structure
* waitfunc - indicates what the allocator routines should
* do when resources are not available. This value
* is passed on to scsi_probe() when that routine
* is called.
*
* Return Code: SCSIPROBE_NORESP if a NORESP in probe response cache;
* otherwise the value returned by scsi_probe(9F).
*
* Context: Kernel thread context
*/
static int
sd_scsi_probe_with_cache(struct scsi_device *devp, int (*waitfn)())
{
struct sd_scsi_probe_cache *cp;
dev_info_t *pdip = ddi_get_parent(devp->sd_dev);
int lun, tgt;
lun = ddi_prop_get_int(DDI_DEV_T_ANY, devp->sd_dev, DDI_PROP_DONTPASS,
SCSI_ADDR_PROP_LUN, 0);
tgt = ddi_prop_get_int(DDI_DEV_T_ANY, devp->sd_dev, DDI_PROP_DONTPASS,
SCSI_ADDR_PROP_TARGET, -1);
/* Make sure caching enabled and target in range */
if ((tgt < 0) || (tgt >= NTARGETS_WIDE)) {
/* do it the old way (no cache) */
return (scsi_probe(devp, waitfn));
}
mutex_enter(&sd_scsi_probe_cache_mutex);
/* Find the cache for this scsi bus instance */
for (cp = sd_scsi_probe_cache_head; cp != NULL; cp = cp->next) {
if (cp->pdip == pdip) {
break;
}
}
/* If we can't find a cache for this pdip, create one */
if (cp == NULL) {
int i;
cp = kmem_zalloc(sizeof (struct sd_scsi_probe_cache),
KM_SLEEP);
cp->pdip = pdip;
cp->next = sd_scsi_probe_cache_head;
sd_scsi_probe_cache_head = cp;
for (i = 0; i < NTARGETS_WIDE; i++) {
cp->cache[i] = SCSIPROBE_EXISTS;
}
}
mutex_exit(&sd_scsi_probe_cache_mutex);
/* Recompute the cache for this target if LUN zero */
if (lun == 0) {
cp->cache[tgt] = SCSIPROBE_EXISTS;
}
/* Don't probe if cache remembers a NORESP from a previous LUN. */
if (cp->cache[tgt] != SCSIPROBE_EXISTS) {
return (SCSIPROBE_NORESP);
}
/* Do the actual probe; save & return the result */
return (cp->cache[tgt] = scsi_probe(devp, waitfn));
}
/*
* Function: sd_scsi_target_lun_init
*
* Description: Initializes the attached lun chain mutex and head pointer.
*
* Context: Kernel thread context
*/
static void
sd_scsi_target_lun_init(void)
{