| /* |
| * 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 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 |
|