18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * scsi_sysfs.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * SCSI sysfs interface routines. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Created to pull SCSI mid layer sysfs routines into one file. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 148c2ecf20Sopenharmony_ci#include <linux/device.h> 158c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 188c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 198c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 208c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h> 218c2ecf20Sopenharmony_ci#include <scsi/scsi_dh.h> 228c2ecf20Sopenharmony_ci#include <scsi/scsi_transport.h> 238c2ecf20Sopenharmony_ci#include <scsi/scsi_driver.h> 248c2ecf20Sopenharmony_ci#include <scsi/scsi_devinfo.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "scsi_priv.h" 278c2ecf20Sopenharmony_ci#include "scsi_logging.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic struct device_type scsi_dev_type; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic const struct { 328c2ecf20Sopenharmony_ci enum scsi_device_state value; 338c2ecf20Sopenharmony_ci char *name; 348c2ecf20Sopenharmony_ci} sdev_states[] = { 358c2ecf20Sopenharmony_ci { SDEV_CREATED, "created" }, 368c2ecf20Sopenharmony_ci { SDEV_RUNNING, "running" }, 378c2ecf20Sopenharmony_ci { SDEV_CANCEL, "cancel" }, 388c2ecf20Sopenharmony_ci { SDEV_DEL, "deleted" }, 398c2ecf20Sopenharmony_ci { SDEV_QUIESCE, "quiesce" }, 408c2ecf20Sopenharmony_ci { SDEV_OFFLINE, "offline" }, 418c2ecf20Sopenharmony_ci { SDEV_TRANSPORT_OFFLINE, "transport-offline" }, 428c2ecf20Sopenharmony_ci { SDEV_BLOCK, "blocked" }, 438c2ecf20Sopenharmony_ci { SDEV_CREATED_BLOCK, "created-blocked" }, 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ciconst char *scsi_device_state_name(enum scsi_device_state state) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci int i; 498c2ecf20Sopenharmony_ci char *name = NULL; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sdev_states); i++) { 528c2ecf20Sopenharmony_ci if (sdev_states[i].value == state) { 538c2ecf20Sopenharmony_ci name = sdev_states[i].name; 548c2ecf20Sopenharmony_ci break; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci return name; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic const struct { 618c2ecf20Sopenharmony_ci enum scsi_host_state value; 628c2ecf20Sopenharmony_ci char *name; 638c2ecf20Sopenharmony_ci} shost_states[] = { 648c2ecf20Sopenharmony_ci { SHOST_CREATED, "created" }, 658c2ecf20Sopenharmony_ci { SHOST_RUNNING, "running" }, 668c2ecf20Sopenharmony_ci { SHOST_CANCEL, "cancel" }, 678c2ecf20Sopenharmony_ci { SHOST_DEL, "deleted" }, 688c2ecf20Sopenharmony_ci { SHOST_RECOVERY, "recovery" }, 698c2ecf20Sopenharmony_ci { SHOST_CANCEL_RECOVERY, "cancel/recovery" }, 708c2ecf20Sopenharmony_ci { SHOST_DEL_RECOVERY, "deleted/recovery", }, 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ciconst char *scsi_host_state_name(enum scsi_host_state state) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci int i; 758c2ecf20Sopenharmony_ci char *name = NULL; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(shost_states); i++) { 788c2ecf20Sopenharmony_ci if (shost_states[i].value == state) { 798c2ecf20Sopenharmony_ci name = shost_states[i].name; 808c2ecf20Sopenharmony_ci break; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci return name; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#ifdef CONFIG_SCSI_DH 878c2ecf20Sopenharmony_cistatic const struct { 888c2ecf20Sopenharmony_ci unsigned char value; 898c2ecf20Sopenharmony_ci char *name; 908c2ecf20Sopenharmony_ci} sdev_access_states[] = { 918c2ecf20Sopenharmony_ci { SCSI_ACCESS_STATE_OPTIMAL, "active/optimized" }, 928c2ecf20Sopenharmony_ci { SCSI_ACCESS_STATE_ACTIVE, "active/non-optimized" }, 938c2ecf20Sopenharmony_ci { SCSI_ACCESS_STATE_STANDBY, "standby" }, 948c2ecf20Sopenharmony_ci { SCSI_ACCESS_STATE_UNAVAILABLE, "unavailable" }, 958c2ecf20Sopenharmony_ci { SCSI_ACCESS_STATE_LBA, "lba-dependent" }, 968c2ecf20Sopenharmony_ci { SCSI_ACCESS_STATE_OFFLINE, "offline" }, 978c2ecf20Sopenharmony_ci { SCSI_ACCESS_STATE_TRANSITIONING, "transitioning" }, 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic const char *scsi_access_state_name(unsigned char state) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci int i; 1038c2ecf20Sopenharmony_ci char *name = NULL; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sdev_access_states); i++) { 1068c2ecf20Sopenharmony_ci if (sdev_access_states[i].value == state) { 1078c2ecf20Sopenharmony_ci name = sdev_access_states[i].name; 1088c2ecf20Sopenharmony_ci break; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci return name; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci#endif 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int check_set(unsigned long long *val, char *src) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci char *last; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (strcmp(src, "-") == 0) { 1208c2ecf20Sopenharmony_ci *val = SCAN_WILD_CARD; 1218c2ecf20Sopenharmony_ci } else { 1228c2ecf20Sopenharmony_ci /* 1238c2ecf20Sopenharmony_ci * Doesn't check for int overflow 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ci *val = simple_strtoull(src, &last, 0); 1268c2ecf20Sopenharmony_ci if (*last != '\0') 1278c2ecf20Sopenharmony_ci return 1; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci return 0; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int scsi_scan(struct Scsi_Host *shost, const char *str) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci char s1[15], s2[15], s3[17], junk; 1358c2ecf20Sopenharmony_ci unsigned long long channel, id, lun; 1368c2ecf20Sopenharmony_ci int res; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci res = sscanf(str, "%10s %10s %16s %c", s1, s2, s3, &junk); 1398c2ecf20Sopenharmony_ci if (res != 3) 1408c2ecf20Sopenharmony_ci return -EINVAL; 1418c2ecf20Sopenharmony_ci if (check_set(&channel, s1)) 1428c2ecf20Sopenharmony_ci return -EINVAL; 1438c2ecf20Sopenharmony_ci if (check_set(&id, s2)) 1448c2ecf20Sopenharmony_ci return -EINVAL; 1458c2ecf20Sopenharmony_ci if (check_set(&lun, s3)) 1468c2ecf20Sopenharmony_ci return -EINVAL; 1478c2ecf20Sopenharmony_ci if (shost->transportt->user_scan) 1488c2ecf20Sopenharmony_ci res = shost->transportt->user_scan(shost, channel, id, lun); 1498c2ecf20Sopenharmony_ci else 1508c2ecf20Sopenharmony_ci res = scsi_scan_host_selected(shost, channel, id, lun, 1518c2ecf20Sopenharmony_ci SCSI_SCAN_MANUAL); 1528c2ecf20Sopenharmony_ci return res; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/* 1568c2ecf20Sopenharmony_ci * shost_show_function: macro to create an attr function that can be used to 1578c2ecf20Sopenharmony_ci * show a non-bit field. 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_ci#define shost_show_function(name, field, format_string) \ 1608c2ecf20Sopenharmony_cistatic ssize_t \ 1618c2ecf20Sopenharmony_cishow_##name (struct device *dev, struct device_attribute *attr, \ 1628c2ecf20Sopenharmony_ci char *buf) \ 1638c2ecf20Sopenharmony_ci{ \ 1648c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(dev); \ 1658c2ecf20Sopenharmony_ci return snprintf (buf, 20, format_string, shost->field); \ 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci/* 1698c2ecf20Sopenharmony_ci * shost_rd_attr: macro to create a function and attribute variable for a 1708c2ecf20Sopenharmony_ci * read only field. 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_ci#define shost_rd_attr2(name, field, format_string) \ 1738c2ecf20Sopenharmony_ci shost_show_function(name, field, format_string) \ 1748c2ecf20Sopenharmony_cistatic DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci#define shost_rd_attr(field, format_string) \ 1778c2ecf20Sopenharmony_cishost_rd_attr2(field, field, format_string) 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/* 1808c2ecf20Sopenharmony_ci * Create the actual show/store functions and data structures. 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic ssize_t 1848c2ecf20Sopenharmony_cistore_scan(struct device *dev, struct device_attribute *attr, 1858c2ecf20Sopenharmony_ci const char *buf, size_t count) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(dev); 1888c2ecf20Sopenharmony_ci int res; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci res = scsi_scan(shost, buf); 1918c2ecf20Sopenharmony_ci if (res == 0) 1928c2ecf20Sopenharmony_ci res = count; 1938c2ecf20Sopenharmony_ci return res; 1948c2ecf20Sopenharmony_ci}; 1958c2ecf20Sopenharmony_cistatic DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic ssize_t 1988c2ecf20Sopenharmony_cistore_shost_state(struct device *dev, struct device_attribute *attr, 1998c2ecf20Sopenharmony_ci const char *buf, size_t count) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci int i; 2028c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(dev); 2038c2ecf20Sopenharmony_ci enum scsi_host_state state = 0; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(shost_states); i++) { 2068c2ecf20Sopenharmony_ci const int len = strlen(shost_states[i].name); 2078c2ecf20Sopenharmony_ci if (strncmp(shost_states[i].name, buf, len) == 0 && 2088c2ecf20Sopenharmony_ci buf[len] == '\n') { 2098c2ecf20Sopenharmony_ci state = shost_states[i].value; 2108c2ecf20Sopenharmony_ci break; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci if (!state) 2148c2ecf20Sopenharmony_ci return -EINVAL; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (scsi_host_set_state(shost, state)) 2178c2ecf20Sopenharmony_ci return -EINVAL; 2188c2ecf20Sopenharmony_ci return count; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic ssize_t 2228c2ecf20Sopenharmony_cishow_shost_state(struct device *dev, struct device_attribute *attr, char *buf) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(dev); 2258c2ecf20Sopenharmony_ci const char *name = scsi_host_state_name(shost->shost_state); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (!name) 2288c2ecf20Sopenharmony_ci return -EINVAL; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci return snprintf(buf, 20, "%s\n", name); 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci/* DEVICE_ATTR(state) clashes with dev_attr_state for sdev */ 2348c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_hstate = 2358c2ecf20Sopenharmony_ci __ATTR(state, S_IRUGO | S_IWUSR, show_shost_state, store_shost_state); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic ssize_t 2388c2ecf20Sopenharmony_cishow_shost_mode(unsigned int mode, char *buf) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci ssize_t len = 0; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (mode & MODE_INITIATOR) 2438c2ecf20Sopenharmony_ci len = sprintf(buf, "%s", "Initiator"); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (mode & MODE_TARGET) 2468c2ecf20Sopenharmony_ci len += sprintf(buf + len, "%s%s", len ? ", " : "", "Target"); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci len += sprintf(buf + len, "\n"); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return len; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic ssize_t 2548c2ecf20Sopenharmony_cishow_shost_supported_mode(struct device *dev, struct device_attribute *attr, 2558c2ecf20Sopenharmony_ci char *buf) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(dev); 2588c2ecf20Sopenharmony_ci unsigned int supported_mode = shost->hostt->supported_mode; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (supported_mode == MODE_UNKNOWN) 2618c2ecf20Sopenharmony_ci /* by default this should be initiator */ 2628c2ecf20Sopenharmony_ci supported_mode = MODE_INITIATOR; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci return show_shost_mode(supported_mode, buf); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic DEVICE_ATTR(supported_mode, S_IRUGO | S_IWUSR, show_shost_supported_mode, NULL); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic ssize_t 2708c2ecf20Sopenharmony_cishow_shost_active_mode(struct device *dev, 2718c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(dev); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (shost->active_mode == MODE_UNKNOWN) 2768c2ecf20Sopenharmony_ci return snprintf(buf, 20, "unknown\n"); 2778c2ecf20Sopenharmony_ci else 2788c2ecf20Sopenharmony_ci return show_shost_mode(shost->active_mode, buf); 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic DEVICE_ATTR(active_mode, S_IRUGO | S_IWUSR, show_shost_active_mode, NULL); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic int check_reset_type(const char *str) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci if (sysfs_streq(str, "adapter")) 2868c2ecf20Sopenharmony_ci return SCSI_ADAPTER_RESET; 2878c2ecf20Sopenharmony_ci else if (sysfs_streq(str, "firmware")) 2888c2ecf20Sopenharmony_ci return SCSI_FIRMWARE_RESET; 2898c2ecf20Sopenharmony_ci else 2908c2ecf20Sopenharmony_ci return 0; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic ssize_t 2948c2ecf20Sopenharmony_cistore_host_reset(struct device *dev, struct device_attribute *attr, 2958c2ecf20Sopenharmony_ci const char *buf, size_t count) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(dev); 2988c2ecf20Sopenharmony_ci struct scsi_host_template *sht = shost->hostt; 2998c2ecf20Sopenharmony_ci int ret = -EINVAL; 3008c2ecf20Sopenharmony_ci int type; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci type = check_reset_type(buf); 3038c2ecf20Sopenharmony_ci if (!type) 3048c2ecf20Sopenharmony_ci goto exit_store_host_reset; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (sht->host_reset) 3078c2ecf20Sopenharmony_ci ret = sht->host_reset(shost, type); 3088c2ecf20Sopenharmony_ci else 3098c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ciexit_store_host_reset: 3128c2ecf20Sopenharmony_ci if (ret == 0) 3138c2ecf20Sopenharmony_ci ret = count; 3148c2ecf20Sopenharmony_ci return ret; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic DEVICE_ATTR(host_reset, S_IWUSR, NULL, store_host_reset); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic ssize_t 3208c2ecf20Sopenharmony_cishow_shost_eh_deadline(struct device *dev, 3218c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(dev); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (shost->eh_deadline == -1) 3268c2ecf20Sopenharmony_ci return snprintf(buf, strlen("off") + 2, "off\n"); 3278c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", shost->eh_deadline / HZ); 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic ssize_t 3318c2ecf20Sopenharmony_cistore_shost_eh_deadline(struct device *dev, struct device_attribute *attr, 3328c2ecf20Sopenharmony_ci const char *buf, size_t count) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(dev); 3358c2ecf20Sopenharmony_ci int ret = -EINVAL; 3368c2ecf20Sopenharmony_ci unsigned long deadline, flags; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (shost->transportt && 3398c2ecf20Sopenharmony_ci (shost->transportt->eh_strategy_handler || 3408c2ecf20Sopenharmony_ci !shost->hostt->eh_host_reset_handler)) 3418c2ecf20Sopenharmony_ci return ret; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (!strncmp(buf, "off", strlen("off"))) 3448c2ecf20Sopenharmony_ci deadline = -1; 3458c2ecf20Sopenharmony_ci else { 3468c2ecf20Sopenharmony_ci ret = kstrtoul(buf, 10, &deadline); 3478c2ecf20Sopenharmony_ci if (ret) 3488c2ecf20Sopenharmony_ci return ret; 3498c2ecf20Sopenharmony_ci if (deadline * HZ > UINT_MAX) 3508c2ecf20Sopenharmony_ci return -EINVAL; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci spin_lock_irqsave(shost->host_lock, flags); 3548c2ecf20Sopenharmony_ci if (scsi_host_in_recovery(shost)) 3558c2ecf20Sopenharmony_ci ret = -EBUSY; 3568c2ecf20Sopenharmony_ci else { 3578c2ecf20Sopenharmony_ci if (deadline == -1) 3588c2ecf20Sopenharmony_ci shost->eh_deadline = -1; 3598c2ecf20Sopenharmony_ci else 3608c2ecf20Sopenharmony_ci shost->eh_deadline = deadline * HZ; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci ret = count; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, flags); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci return ret; 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic DEVICE_ATTR(eh_deadline, S_IRUGO | S_IWUSR, show_shost_eh_deadline, store_shost_eh_deadline); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cishost_rd_attr(unique_id, "%u\n"); 3728c2ecf20Sopenharmony_cishost_rd_attr(cmd_per_lun, "%hd\n"); 3738c2ecf20Sopenharmony_cishost_rd_attr(can_queue, "%hd\n"); 3748c2ecf20Sopenharmony_cishost_rd_attr(sg_tablesize, "%hu\n"); 3758c2ecf20Sopenharmony_cishost_rd_attr(sg_prot_tablesize, "%hu\n"); 3768c2ecf20Sopenharmony_cishost_rd_attr(unchecked_isa_dma, "%d\n"); 3778c2ecf20Sopenharmony_cishost_rd_attr(prot_capabilities, "%u\n"); 3788c2ecf20Sopenharmony_cishost_rd_attr(prot_guard_type, "%hd\n"); 3798c2ecf20Sopenharmony_cishost_rd_attr2(proc_name, hostt->proc_name, "%s\n"); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic ssize_t 3828c2ecf20Sopenharmony_cishow_host_busy(struct device *dev, struct device_attribute *attr, char *buf) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(dev); 3858c2ecf20Sopenharmony_ci return snprintf(buf, 20, "%d\n", scsi_host_busy(shost)); 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_cistatic DEVICE_ATTR(host_busy, S_IRUGO, show_host_busy, NULL); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic ssize_t 3908c2ecf20Sopenharmony_cishow_use_blk_mq(struct device *dev, struct device_attribute *attr, char *buf) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci return sprintf(buf, "1\n"); 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_cistatic DEVICE_ATTR(use_blk_mq, S_IRUGO, show_use_blk_mq, NULL); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic ssize_t 3978c2ecf20Sopenharmony_cishow_nr_hw_queues(struct device *dev, struct device_attribute *attr, char *buf) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(dev); 4008c2ecf20Sopenharmony_ci struct blk_mq_tag_set *tag_set = &shost->tag_set; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci return snprintf(buf, 20, "%d\n", tag_set->nr_hw_queues); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_cistatic DEVICE_ATTR(nr_hw_queues, S_IRUGO, show_nr_hw_queues, NULL); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic struct attribute *scsi_sysfs_shost_attrs[] = { 4078c2ecf20Sopenharmony_ci &dev_attr_use_blk_mq.attr, 4088c2ecf20Sopenharmony_ci &dev_attr_unique_id.attr, 4098c2ecf20Sopenharmony_ci &dev_attr_host_busy.attr, 4108c2ecf20Sopenharmony_ci &dev_attr_cmd_per_lun.attr, 4118c2ecf20Sopenharmony_ci &dev_attr_can_queue.attr, 4128c2ecf20Sopenharmony_ci &dev_attr_sg_tablesize.attr, 4138c2ecf20Sopenharmony_ci &dev_attr_sg_prot_tablesize.attr, 4148c2ecf20Sopenharmony_ci &dev_attr_unchecked_isa_dma.attr, 4158c2ecf20Sopenharmony_ci &dev_attr_proc_name.attr, 4168c2ecf20Sopenharmony_ci &dev_attr_scan.attr, 4178c2ecf20Sopenharmony_ci &dev_attr_hstate.attr, 4188c2ecf20Sopenharmony_ci &dev_attr_supported_mode.attr, 4198c2ecf20Sopenharmony_ci &dev_attr_active_mode.attr, 4208c2ecf20Sopenharmony_ci &dev_attr_prot_capabilities.attr, 4218c2ecf20Sopenharmony_ci &dev_attr_prot_guard_type.attr, 4228c2ecf20Sopenharmony_ci &dev_attr_host_reset.attr, 4238c2ecf20Sopenharmony_ci &dev_attr_eh_deadline.attr, 4248c2ecf20Sopenharmony_ci &dev_attr_nr_hw_queues.attr, 4258c2ecf20Sopenharmony_ci NULL 4268c2ecf20Sopenharmony_ci}; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic struct attribute_group scsi_shost_attr_group = { 4298c2ecf20Sopenharmony_ci .attrs = scsi_sysfs_shost_attrs, 4308c2ecf20Sopenharmony_ci}; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ciconst struct attribute_group *scsi_sysfs_shost_attr_groups[] = { 4338c2ecf20Sopenharmony_ci &scsi_shost_attr_group, 4348c2ecf20Sopenharmony_ci NULL 4358c2ecf20Sopenharmony_ci}; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic void scsi_device_cls_release(struct device *class_dev) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct scsi_device *sdev; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci sdev = class_to_sdev(class_dev); 4428c2ecf20Sopenharmony_ci put_device(&sdev->sdev_gendev); 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic void scsi_device_dev_release_usercontext(struct work_struct *work) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci struct scsi_device *sdev; 4488c2ecf20Sopenharmony_ci struct device *parent; 4498c2ecf20Sopenharmony_ci struct list_head *this, *tmp; 4508c2ecf20Sopenharmony_ci struct scsi_vpd *vpd_pg80 = NULL, *vpd_pg83 = NULL; 4518c2ecf20Sopenharmony_ci struct scsi_vpd *vpd_pg0 = NULL, *vpd_pg89 = NULL; 4528c2ecf20Sopenharmony_ci unsigned long flags; 4538c2ecf20Sopenharmony_ci struct module *mod; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci sdev = container_of(work, struct scsi_device, ew.work); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci mod = sdev->host->hostt->module; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci scsi_dh_release_device(sdev); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci parent = sdev->sdev_gendev.parent; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci spin_lock_irqsave(sdev->host->host_lock, flags); 4648c2ecf20Sopenharmony_ci list_del(&sdev->siblings); 4658c2ecf20Sopenharmony_ci list_del(&sdev->same_target_siblings); 4668c2ecf20Sopenharmony_ci list_del(&sdev->starved_entry); 4678c2ecf20Sopenharmony_ci spin_unlock_irqrestore(sdev->host->host_lock, flags); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci cancel_work_sync(&sdev->event_work); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci list_for_each_safe(this, tmp, &sdev->event_list) { 4728c2ecf20Sopenharmony_ci struct scsi_event *evt; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci evt = list_entry(this, struct scsi_event, node); 4758c2ecf20Sopenharmony_ci list_del(&evt->node); 4768c2ecf20Sopenharmony_ci kfree(evt); 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci blk_put_queue(sdev->request_queue); 4808c2ecf20Sopenharmony_ci /* NULL queue means the device can't be used */ 4818c2ecf20Sopenharmony_ci sdev->request_queue = NULL; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci mutex_lock(&sdev->inquiry_mutex); 4848c2ecf20Sopenharmony_ci vpd_pg0 = rcu_replace_pointer(sdev->vpd_pg0, vpd_pg0, 4858c2ecf20Sopenharmony_ci lockdep_is_held(&sdev->inquiry_mutex)); 4868c2ecf20Sopenharmony_ci vpd_pg80 = rcu_replace_pointer(sdev->vpd_pg80, vpd_pg80, 4878c2ecf20Sopenharmony_ci lockdep_is_held(&sdev->inquiry_mutex)); 4888c2ecf20Sopenharmony_ci vpd_pg83 = rcu_replace_pointer(sdev->vpd_pg83, vpd_pg83, 4898c2ecf20Sopenharmony_ci lockdep_is_held(&sdev->inquiry_mutex)); 4908c2ecf20Sopenharmony_ci vpd_pg89 = rcu_replace_pointer(sdev->vpd_pg89, vpd_pg89, 4918c2ecf20Sopenharmony_ci lockdep_is_held(&sdev->inquiry_mutex)); 4928c2ecf20Sopenharmony_ci mutex_unlock(&sdev->inquiry_mutex); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (vpd_pg0) 4958c2ecf20Sopenharmony_ci kfree_rcu(vpd_pg0, rcu); 4968c2ecf20Sopenharmony_ci if (vpd_pg83) 4978c2ecf20Sopenharmony_ci kfree_rcu(vpd_pg83, rcu); 4988c2ecf20Sopenharmony_ci if (vpd_pg80) 4998c2ecf20Sopenharmony_ci kfree_rcu(vpd_pg80, rcu); 5008c2ecf20Sopenharmony_ci if (vpd_pg89) 5018c2ecf20Sopenharmony_ci kfree_rcu(vpd_pg89, rcu); 5028c2ecf20Sopenharmony_ci kfree(sdev->inquiry); 5038c2ecf20Sopenharmony_ci kfree(sdev); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if (parent) 5068c2ecf20Sopenharmony_ci put_device(parent); 5078c2ecf20Sopenharmony_ci module_put(mod); 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic void scsi_device_dev_release(struct device *dev) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci struct scsi_device *sdp = to_scsi_device(dev); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci /* Set module pointer as NULL in case of module unloading */ 5158c2ecf20Sopenharmony_ci if (!try_module_get(sdp->host->hostt->module)) 5168c2ecf20Sopenharmony_ci sdp->host->hostt->module = NULL; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci execute_in_process_context(scsi_device_dev_release_usercontext, 5198c2ecf20Sopenharmony_ci &sdp->ew); 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic struct class sdev_class = { 5238c2ecf20Sopenharmony_ci .name = "scsi_device", 5248c2ecf20Sopenharmony_ci .dev_release = scsi_device_cls_release, 5258c2ecf20Sopenharmony_ci}; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci/* all probing is done in the individual ->probe routines */ 5288c2ecf20Sopenharmony_cistatic int scsi_bus_match(struct device *dev, struct device_driver *gendrv) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci struct scsi_device *sdp; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (dev->type != &scsi_dev_type) 5338c2ecf20Sopenharmony_ci return 0; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci sdp = to_scsi_device(dev); 5368c2ecf20Sopenharmony_ci if (sdp->no_uld_attach) 5378c2ecf20Sopenharmony_ci return 0; 5388c2ecf20Sopenharmony_ci return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0; 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci struct scsi_device *sdev; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (dev->type != &scsi_dev_type) 5468c2ecf20Sopenharmony_ci return 0; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci sdev = to_scsi_device(dev); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci add_uevent_var(env, "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type); 5518c2ecf20Sopenharmony_ci return 0; 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cistruct bus_type scsi_bus_type = { 5558c2ecf20Sopenharmony_ci .name = "scsi", 5568c2ecf20Sopenharmony_ci .match = scsi_bus_match, 5578c2ecf20Sopenharmony_ci .uevent = scsi_bus_uevent, 5588c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 5598c2ecf20Sopenharmony_ci .pm = &scsi_bus_pm_ops, 5608c2ecf20Sopenharmony_ci#endif 5618c2ecf20Sopenharmony_ci}; 5628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scsi_bus_type); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ciint scsi_sysfs_register(void) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci int error; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci error = bus_register(&scsi_bus_type); 5698c2ecf20Sopenharmony_ci if (!error) { 5708c2ecf20Sopenharmony_ci error = class_register(&sdev_class); 5718c2ecf20Sopenharmony_ci if (error) 5728c2ecf20Sopenharmony_ci bus_unregister(&scsi_bus_type); 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci return error; 5768c2ecf20Sopenharmony_ci} 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_civoid scsi_sysfs_unregister(void) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci class_unregister(&sdev_class); 5818c2ecf20Sopenharmony_ci bus_unregister(&scsi_bus_type); 5828c2ecf20Sopenharmony_ci} 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci/* 5858c2ecf20Sopenharmony_ci * sdev_show_function: macro to create an attr function that can be used to 5868c2ecf20Sopenharmony_ci * show a non-bit field. 5878c2ecf20Sopenharmony_ci */ 5888c2ecf20Sopenharmony_ci#define sdev_show_function(field, format_string) \ 5898c2ecf20Sopenharmony_cistatic ssize_t \ 5908c2ecf20Sopenharmony_cisdev_show_##field (struct device *dev, struct device_attribute *attr, \ 5918c2ecf20Sopenharmony_ci char *buf) \ 5928c2ecf20Sopenharmony_ci{ \ 5938c2ecf20Sopenharmony_ci struct scsi_device *sdev; \ 5948c2ecf20Sopenharmony_ci sdev = to_scsi_device(dev); \ 5958c2ecf20Sopenharmony_ci return snprintf (buf, 20, format_string, sdev->field); \ 5968c2ecf20Sopenharmony_ci} \ 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci/* 5998c2ecf20Sopenharmony_ci * sdev_rd_attr: macro to create a function and attribute variable for a 6008c2ecf20Sopenharmony_ci * read only field. 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_ci#define sdev_rd_attr(field, format_string) \ 6038c2ecf20Sopenharmony_ci sdev_show_function(field, format_string) \ 6048c2ecf20Sopenharmony_cistatic DEVICE_ATTR(field, S_IRUGO, sdev_show_##field, NULL); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci/* 6088c2ecf20Sopenharmony_ci * sdev_rw_attr: create a function and attribute variable for a 6098c2ecf20Sopenharmony_ci * read/write field. 6108c2ecf20Sopenharmony_ci */ 6118c2ecf20Sopenharmony_ci#define sdev_rw_attr(field, format_string) \ 6128c2ecf20Sopenharmony_ci sdev_show_function(field, format_string) \ 6138c2ecf20Sopenharmony_ci \ 6148c2ecf20Sopenharmony_cistatic ssize_t \ 6158c2ecf20Sopenharmony_cisdev_store_##field (struct device *dev, struct device_attribute *attr, \ 6168c2ecf20Sopenharmony_ci const char *buf, size_t count) \ 6178c2ecf20Sopenharmony_ci{ \ 6188c2ecf20Sopenharmony_ci struct scsi_device *sdev; \ 6198c2ecf20Sopenharmony_ci sdev = to_scsi_device(dev); \ 6208c2ecf20Sopenharmony_ci sscanf (buf, format_string, &sdev->field); \ 6218c2ecf20Sopenharmony_ci return count; \ 6228c2ecf20Sopenharmony_ci} \ 6238c2ecf20Sopenharmony_cistatic DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci/* Currently we don't export bit fields, but we might in future, 6268c2ecf20Sopenharmony_ci * so leave this code in */ 6278c2ecf20Sopenharmony_ci#if 0 6288c2ecf20Sopenharmony_ci/* 6298c2ecf20Sopenharmony_ci * sdev_rd_attr: create a function and attribute variable for a 6308c2ecf20Sopenharmony_ci * read/write bit field. 6318c2ecf20Sopenharmony_ci */ 6328c2ecf20Sopenharmony_ci#define sdev_rw_attr_bit(field) \ 6338c2ecf20Sopenharmony_ci sdev_show_function(field, "%d\n") \ 6348c2ecf20Sopenharmony_ci \ 6358c2ecf20Sopenharmony_cistatic ssize_t \ 6368c2ecf20Sopenharmony_cisdev_store_##field (struct device *dev, struct device_attribute *attr, \ 6378c2ecf20Sopenharmony_ci const char *buf, size_t count) \ 6388c2ecf20Sopenharmony_ci{ \ 6398c2ecf20Sopenharmony_ci int ret; \ 6408c2ecf20Sopenharmony_ci struct scsi_device *sdev; \ 6418c2ecf20Sopenharmony_ci ret = scsi_sdev_check_buf_bit(buf); \ 6428c2ecf20Sopenharmony_ci if (ret >= 0) { \ 6438c2ecf20Sopenharmony_ci sdev = to_scsi_device(dev); \ 6448c2ecf20Sopenharmony_ci sdev->field = ret; \ 6458c2ecf20Sopenharmony_ci ret = count; \ 6468c2ecf20Sopenharmony_ci } \ 6478c2ecf20Sopenharmony_ci return ret; \ 6488c2ecf20Sopenharmony_ci} \ 6498c2ecf20Sopenharmony_cistatic DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci/* 6528c2ecf20Sopenharmony_ci * scsi_sdev_check_buf_bit: return 0 if buf is "0", return 1 if buf is "1", 6538c2ecf20Sopenharmony_ci * else return -EINVAL. 6548c2ecf20Sopenharmony_ci */ 6558c2ecf20Sopenharmony_cistatic int scsi_sdev_check_buf_bit(const char *buf) 6568c2ecf20Sopenharmony_ci{ 6578c2ecf20Sopenharmony_ci if ((buf[1] == '\0') || ((buf[1] == '\n') && (buf[2] == '\0'))) { 6588c2ecf20Sopenharmony_ci if (buf[0] == '1') 6598c2ecf20Sopenharmony_ci return 1; 6608c2ecf20Sopenharmony_ci else if (buf[0] == '0') 6618c2ecf20Sopenharmony_ci return 0; 6628c2ecf20Sopenharmony_ci else 6638c2ecf20Sopenharmony_ci return -EINVAL; 6648c2ecf20Sopenharmony_ci } else 6658c2ecf20Sopenharmony_ci return -EINVAL; 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci#endif 6688c2ecf20Sopenharmony_ci/* 6698c2ecf20Sopenharmony_ci * Create the actual show/store functions and data structures. 6708c2ecf20Sopenharmony_ci */ 6718c2ecf20Sopenharmony_cisdev_rd_attr (type, "%d\n"); 6728c2ecf20Sopenharmony_cisdev_rd_attr (scsi_level, "%d\n"); 6738c2ecf20Sopenharmony_cisdev_rd_attr (vendor, "%.8s\n"); 6748c2ecf20Sopenharmony_cisdev_rd_attr (model, "%.16s\n"); 6758c2ecf20Sopenharmony_cisdev_rd_attr (rev, "%.4s\n"); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistatic ssize_t 6788c2ecf20Sopenharmony_cisdev_show_device_busy(struct device *dev, struct device_attribute *attr, 6798c2ecf20Sopenharmony_ci char *buf) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 6828c2ecf20Sopenharmony_ci return snprintf(buf, 20, "%d\n", atomic_read(&sdev->device_busy)); 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_cistatic DEVICE_ATTR(device_busy, S_IRUGO, sdev_show_device_busy, NULL); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cistatic ssize_t 6878c2ecf20Sopenharmony_cisdev_show_device_blocked(struct device *dev, struct device_attribute *attr, 6888c2ecf20Sopenharmony_ci char *buf) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 6918c2ecf20Sopenharmony_ci return snprintf(buf, 20, "%d\n", atomic_read(&sdev->device_blocked)); 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_cistatic DEVICE_ATTR(device_blocked, S_IRUGO, sdev_show_device_blocked, NULL); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci/* 6968c2ecf20Sopenharmony_ci * TODO: can we make these symlinks to the block layer ones? 6978c2ecf20Sopenharmony_ci */ 6988c2ecf20Sopenharmony_cistatic ssize_t 6998c2ecf20Sopenharmony_cisdev_show_timeout (struct device *dev, struct device_attribute *attr, char *buf) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci struct scsi_device *sdev; 7028c2ecf20Sopenharmony_ci sdev = to_scsi_device(dev); 7038c2ecf20Sopenharmony_ci return snprintf(buf, 20, "%d\n", sdev->request_queue->rq_timeout / HZ); 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic ssize_t 7078c2ecf20Sopenharmony_cisdev_store_timeout (struct device *dev, struct device_attribute *attr, 7088c2ecf20Sopenharmony_ci const char *buf, size_t count) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci struct scsi_device *sdev; 7118c2ecf20Sopenharmony_ci int timeout; 7128c2ecf20Sopenharmony_ci sdev = to_scsi_device(dev); 7138c2ecf20Sopenharmony_ci sscanf (buf, "%d\n", &timeout); 7148c2ecf20Sopenharmony_ci blk_queue_rq_timeout(sdev->request_queue, timeout * HZ); 7158c2ecf20Sopenharmony_ci return count; 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_cistatic DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_cistatic ssize_t 7208c2ecf20Sopenharmony_cisdev_show_eh_timeout(struct device *dev, struct device_attribute *attr, char *buf) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci struct scsi_device *sdev; 7238c2ecf20Sopenharmony_ci sdev = to_scsi_device(dev); 7248c2ecf20Sopenharmony_ci return snprintf(buf, 20, "%u\n", sdev->eh_timeout / HZ); 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cistatic ssize_t 7288c2ecf20Sopenharmony_cisdev_store_eh_timeout(struct device *dev, struct device_attribute *attr, 7298c2ecf20Sopenharmony_ci const char *buf, size_t count) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci struct scsi_device *sdev; 7328c2ecf20Sopenharmony_ci unsigned int eh_timeout; 7338c2ecf20Sopenharmony_ci int err; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 7368c2ecf20Sopenharmony_ci return -EACCES; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci sdev = to_scsi_device(dev); 7398c2ecf20Sopenharmony_ci err = kstrtouint(buf, 10, &eh_timeout); 7408c2ecf20Sopenharmony_ci if (err) 7418c2ecf20Sopenharmony_ci return err; 7428c2ecf20Sopenharmony_ci sdev->eh_timeout = eh_timeout * HZ; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci return count; 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_cistatic DEVICE_ATTR(eh_timeout, S_IRUGO | S_IWUSR, sdev_show_eh_timeout, sdev_store_eh_timeout); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cistatic ssize_t 7498c2ecf20Sopenharmony_cistore_rescan_field (struct device *dev, struct device_attribute *attr, 7508c2ecf20Sopenharmony_ci const char *buf, size_t count) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci scsi_rescan_device(dev); 7538c2ecf20Sopenharmony_ci return count; 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_cistatic DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic ssize_t 7588c2ecf20Sopenharmony_cisdev_store_delete(struct device *dev, struct device_attribute *attr, 7598c2ecf20Sopenharmony_ci const char *buf, size_t count) 7608c2ecf20Sopenharmony_ci{ 7618c2ecf20Sopenharmony_ci struct kernfs_node *kn; 7628c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci /* 7658c2ecf20Sopenharmony_ci * We need to try to get module, avoiding the module been removed 7668c2ecf20Sopenharmony_ci * during delete. 7678c2ecf20Sopenharmony_ci */ 7688c2ecf20Sopenharmony_ci if (scsi_device_get(sdev)) 7698c2ecf20Sopenharmony_ci return -ENODEV; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci kn = sysfs_break_active_protection(&dev->kobj, &attr->attr); 7728c2ecf20Sopenharmony_ci WARN_ON_ONCE(!kn); 7738c2ecf20Sopenharmony_ci /* 7748c2ecf20Sopenharmony_ci * Concurrent writes into the "delete" sysfs attribute may trigger 7758c2ecf20Sopenharmony_ci * concurrent calls to device_remove_file() and scsi_remove_device(). 7768c2ecf20Sopenharmony_ci * device_remove_file() handles concurrent removal calls by 7778c2ecf20Sopenharmony_ci * serializing these and by ignoring the second and later removal 7788c2ecf20Sopenharmony_ci * attempts. Concurrent calls of scsi_remove_device() are 7798c2ecf20Sopenharmony_ci * serialized. The second and later calls of scsi_remove_device() are 7808c2ecf20Sopenharmony_ci * ignored because the first call of that function changes the device 7818c2ecf20Sopenharmony_ci * state into SDEV_DEL. 7828c2ecf20Sopenharmony_ci */ 7838c2ecf20Sopenharmony_ci device_remove_file(dev, attr); 7848c2ecf20Sopenharmony_ci scsi_remove_device(sdev); 7858c2ecf20Sopenharmony_ci if (kn) 7868c2ecf20Sopenharmony_ci sysfs_unbreak_active_protection(kn); 7878c2ecf20Sopenharmony_ci scsi_device_put(sdev); 7888c2ecf20Sopenharmony_ci return count; 7898c2ecf20Sopenharmony_ci}; 7908c2ecf20Sopenharmony_cistatic DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_cistatic ssize_t 7938c2ecf20Sopenharmony_cistore_state_field(struct device *dev, struct device_attribute *attr, 7948c2ecf20Sopenharmony_ci const char *buf, size_t count) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci int i, ret; 7978c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 7988c2ecf20Sopenharmony_ci enum scsi_device_state state = 0; 7998c2ecf20Sopenharmony_ci bool rescan_dev = false; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sdev_states); i++) { 8028c2ecf20Sopenharmony_ci const int len = strlen(sdev_states[i].name); 8038c2ecf20Sopenharmony_ci if (strncmp(sdev_states[i].name, buf, len) == 0 && 8048c2ecf20Sopenharmony_ci buf[len] == '\n') { 8058c2ecf20Sopenharmony_ci state = sdev_states[i].value; 8068c2ecf20Sopenharmony_ci break; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci switch (state) { 8108c2ecf20Sopenharmony_ci case SDEV_RUNNING: 8118c2ecf20Sopenharmony_ci case SDEV_OFFLINE: 8128c2ecf20Sopenharmony_ci break; 8138c2ecf20Sopenharmony_ci default: 8148c2ecf20Sopenharmony_ci return -EINVAL; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci mutex_lock(&sdev->state_mutex); 8188c2ecf20Sopenharmony_ci switch (sdev->sdev_state) { 8198c2ecf20Sopenharmony_ci case SDEV_RUNNING: 8208c2ecf20Sopenharmony_ci case SDEV_OFFLINE: 8218c2ecf20Sopenharmony_ci break; 8228c2ecf20Sopenharmony_ci default: 8238c2ecf20Sopenharmony_ci mutex_unlock(&sdev->state_mutex); 8248c2ecf20Sopenharmony_ci return -EINVAL; 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci if (sdev->sdev_state == SDEV_RUNNING && state == SDEV_RUNNING) { 8278c2ecf20Sopenharmony_ci ret = 0; 8288c2ecf20Sopenharmony_ci } else { 8298c2ecf20Sopenharmony_ci ret = scsi_device_set_state(sdev, state); 8308c2ecf20Sopenharmony_ci if (ret == 0 && state == SDEV_RUNNING) 8318c2ecf20Sopenharmony_ci rescan_dev = true; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci mutex_unlock(&sdev->state_mutex); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci if (rescan_dev) { 8368c2ecf20Sopenharmony_ci /* 8378c2ecf20Sopenharmony_ci * If the device state changes to SDEV_RUNNING, we need to 8388c2ecf20Sopenharmony_ci * run the queue to avoid I/O hang, and rescan the device 8398c2ecf20Sopenharmony_ci * to revalidate it. Running the queue first is necessary 8408c2ecf20Sopenharmony_ci * because another thread may be waiting inside 8418c2ecf20Sopenharmony_ci * blk_mq_freeze_queue_wait() and because that call may be 8428c2ecf20Sopenharmony_ci * waiting for pending I/O to finish. 8438c2ecf20Sopenharmony_ci */ 8448c2ecf20Sopenharmony_ci blk_mq_run_hw_queues(sdev->request_queue, true); 8458c2ecf20Sopenharmony_ci scsi_rescan_device(dev); 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci return ret == 0 ? count : -EINVAL; 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_cistatic ssize_t 8528c2ecf20Sopenharmony_cishow_state_field(struct device *dev, struct device_attribute *attr, char *buf) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 8558c2ecf20Sopenharmony_ci const char *name = scsi_device_state_name(sdev->sdev_state); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci if (!name) 8588c2ecf20Sopenharmony_ci return -EINVAL; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci return snprintf(buf, 20, "%s\n", name); 8618c2ecf20Sopenharmony_ci} 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_cistatic DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_state_field, store_state_field); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic ssize_t 8668c2ecf20Sopenharmony_cishow_queue_type_field(struct device *dev, struct device_attribute *attr, 8678c2ecf20Sopenharmony_ci char *buf) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 8708c2ecf20Sopenharmony_ci const char *name = "none"; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci if (sdev->simple_tags) 8738c2ecf20Sopenharmony_ci name = "simple"; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci return snprintf(buf, 20, "%s\n", name); 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cistatic ssize_t 8798c2ecf20Sopenharmony_cistore_queue_type_field(struct device *dev, struct device_attribute *attr, 8808c2ecf20Sopenharmony_ci const char *buf, size_t count) 8818c2ecf20Sopenharmony_ci{ 8828c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (!sdev->tagged_supported) 8858c2ecf20Sopenharmony_ci return -EINVAL; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, sdev, 8888c2ecf20Sopenharmony_ci "ignoring write to deprecated queue_type attribute"); 8898c2ecf20Sopenharmony_ci return count; 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic DEVICE_ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field, 8938c2ecf20Sopenharmony_ci store_queue_type_field); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci#define sdev_vpd_pg_attr(_page) \ 8968c2ecf20Sopenharmony_cistatic ssize_t \ 8978c2ecf20Sopenharmony_cishow_vpd_##_page(struct file *filp, struct kobject *kobj, \ 8988c2ecf20Sopenharmony_ci struct bin_attribute *bin_attr, \ 8998c2ecf20Sopenharmony_ci char *buf, loff_t off, size_t count) \ 9008c2ecf20Sopenharmony_ci{ \ 9018c2ecf20Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); \ 9028c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); \ 9038c2ecf20Sopenharmony_ci struct scsi_vpd *vpd_page; \ 9048c2ecf20Sopenharmony_ci int ret = -EINVAL; \ 9058c2ecf20Sopenharmony_ci \ 9068c2ecf20Sopenharmony_ci rcu_read_lock(); \ 9078c2ecf20Sopenharmony_ci vpd_page = rcu_dereference(sdev->vpd_##_page); \ 9088c2ecf20Sopenharmony_ci if (vpd_page) \ 9098c2ecf20Sopenharmony_ci ret = memory_read_from_buffer(buf, count, &off, \ 9108c2ecf20Sopenharmony_ci vpd_page->data, vpd_page->len); \ 9118c2ecf20Sopenharmony_ci rcu_read_unlock(); \ 9128c2ecf20Sopenharmony_ci return ret; \ 9138c2ecf20Sopenharmony_ci} \ 9148c2ecf20Sopenharmony_cistatic struct bin_attribute dev_attr_vpd_##_page = { \ 9158c2ecf20Sopenharmony_ci .attr = {.name = __stringify(vpd_##_page), .mode = S_IRUGO }, \ 9168c2ecf20Sopenharmony_ci .size = 0, \ 9178c2ecf20Sopenharmony_ci .read = show_vpd_##_page, \ 9188c2ecf20Sopenharmony_ci}; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_cisdev_vpd_pg_attr(pg83); 9218c2ecf20Sopenharmony_cisdev_vpd_pg_attr(pg80); 9228c2ecf20Sopenharmony_cisdev_vpd_pg_attr(pg89); 9238c2ecf20Sopenharmony_cisdev_vpd_pg_attr(pg0); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_cistatic ssize_t show_inquiry(struct file *filep, struct kobject *kobj, 9268c2ecf20Sopenharmony_ci struct bin_attribute *bin_attr, 9278c2ecf20Sopenharmony_ci char *buf, loff_t off, size_t count) 9288c2ecf20Sopenharmony_ci{ 9298c2ecf20Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 9308c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci if (!sdev->inquiry) 9338c2ecf20Sopenharmony_ci return -EINVAL; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci return memory_read_from_buffer(buf, count, &off, sdev->inquiry, 9368c2ecf20Sopenharmony_ci sdev->inquiry_len); 9378c2ecf20Sopenharmony_ci} 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_cistatic struct bin_attribute dev_attr_inquiry = { 9408c2ecf20Sopenharmony_ci .attr = { 9418c2ecf20Sopenharmony_ci .name = "inquiry", 9428c2ecf20Sopenharmony_ci .mode = S_IRUGO, 9438c2ecf20Sopenharmony_ci }, 9448c2ecf20Sopenharmony_ci .size = 0, 9458c2ecf20Sopenharmony_ci .read = show_inquiry, 9468c2ecf20Sopenharmony_ci}; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic ssize_t 9498c2ecf20Sopenharmony_cishow_iostat_counterbits(struct device *dev, struct device_attribute *attr, 9508c2ecf20Sopenharmony_ci char *buf) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci return snprintf(buf, 20, "%d\n", (int)sizeof(atomic_t) * 8); 9538c2ecf20Sopenharmony_ci} 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_cistatic DEVICE_ATTR(iocounterbits, S_IRUGO, show_iostat_counterbits, NULL); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci#define show_sdev_iostat(field) \ 9588c2ecf20Sopenharmony_cistatic ssize_t \ 9598c2ecf20Sopenharmony_cishow_iostat_##field(struct device *dev, struct device_attribute *attr, \ 9608c2ecf20Sopenharmony_ci char *buf) \ 9618c2ecf20Sopenharmony_ci{ \ 9628c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); \ 9638c2ecf20Sopenharmony_ci unsigned long long count = atomic_read(&sdev->field); \ 9648c2ecf20Sopenharmony_ci return snprintf(buf, 20, "0x%llx\n", count); \ 9658c2ecf20Sopenharmony_ci} \ 9668c2ecf20Sopenharmony_cistatic DEVICE_ATTR(field, S_IRUGO, show_iostat_##field, NULL) 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_cishow_sdev_iostat(iorequest_cnt); 9698c2ecf20Sopenharmony_cishow_sdev_iostat(iodone_cnt); 9708c2ecf20Sopenharmony_cishow_sdev_iostat(ioerr_cnt); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_cistatic ssize_t 9738c2ecf20Sopenharmony_cisdev_show_modalias(struct device *dev, struct device_attribute *attr, char *buf) 9748c2ecf20Sopenharmony_ci{ 9758c2ecf20Sopenharmony_ci struct scsi_device *sdev; 9768c2ecf20Sopenharmony_ci sdev = to_scsi_device(dev); 9778c2ecf20Sopenharmony_ci return snprintf (buf, 20, SCSI_DEVICE_MODALIAS_FMT "\n", sdev->type); 9788c2ecf20Sopenharmony_ci} 9798c2ecf20Sopenharmony_cistatic DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci#define DECLARE_EVT_SHOW(name, Cap_name) \ 9828c2ecf20Sopenharmony_cistatic ssize_t \ 9838c2ecf20Sopenharmony_cisdev_show_evt_##name(struct device *dev, struct device_attribute *attr, \ 9848c2ecf20Sopenharmony_ci char *buf) \ 9858c2ecf20Sopenharmony_ci{ \ 9868c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); \ 9878c2ecf20Sopenharmony_ci int val = test_bit(SDEV_EVT_##Cap_name, sdev->supported_events);\ 9888c2ecf20Sopenharmony_ci return snprintf(buf, 20, "%d\n", val); \ 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci#define DECLARE_EVT_STORE(name, Cap_name) \ 9928c2ecf20Sopenharmony_cistatic ssize_t \ 9938c2ecf20Sopenharmony_cisdev_store_evt_##name(struct device *dev, struct device_attribute *attr,\ 9948c2ecf20Sopenharmony_ci const char *buf, size_t count) \ 9958c2ecf20Sopenharmony_ci{ \ 9968c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); \ 9978c2ecf20Sopenharmony_ci int val = simple_strtoul(buf, NULL, 0); \ 9988c2ecf20Sopenharmony_ci if (val == 0) \ 9998c2ecf20Sopenharmony_ci clear_bit(SDEV_EVT_##Cap_name, sdev->supported_events); \ 10008c2ecf20Sopenharmony_ci else if (val == 1) \ 10018c2ecf20Sopenharmony_ci set_bit(SDEV_EVT_##Cap_name, sdev->supported_events); \ 10028c2ecf20Sopenharmony_ci else \ 10038c2ecf20Sopenharmony_ci return -EINVAL; \ 10048c2ecf20Sopenharmony_ci return count; \ 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci#define DECLARE_EVT(name, Cap_name) \ 10088c2ecf20Sopenharmony_ci DECLARE_EVT_SHOW(name, Cap_name) \ 10098c2ecf20Sopenharmony_ci DECLARE_EVT_STORE(name, Cap_name) \ 10108c2ecf20Sopenharmony_ci static DEVICE_ATTR(evt_##name, S_IRUGO, sdev_show_evt_##name, \ 10118c2ecf20Sopenharmony_ci sdev_store_evt_##name); 10128c2ecf20Sopenharmony_ci#define REF_EVT(name) &dev_attr_evt_##name.attr 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ciDECLARE_EVT(media_change, MEDIA_CHANGE) 10158c2ecf20Sopenharmony_ciDECLARE_EVT(inquiry_change_reported, INQUIRY_CHANGE_REPORTED) 10168c2ecf20Sopenharmony_ciDECLARE_EVT(capacity_change_reported, CAPACITY_CHANGE_REPORTED) 10178c2ecf20Sopenharmony_ciDECLARE_EVT(soft_threshold_reached, SOFT_THRESHOLD_REACHED_REPORTED) 10188c2ecf20Sopenharmony_ciDECLARE_EVT(mode_parameter_change_reported, MODE_PARAMETER_CHANGE_REPORTED) 10198c2ecf20Sopenharmony_ciDECLARE_EVT(lun_change_reported, LUN_CHANGE_REPORTED) 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_cistatic ssize_t 10228c2ecf20Sopenharmony_cisdev_store_queue_depth(struct device *dev, struct device_attribute *attr, 10238c2ecf20Sopenharmony_ci const char *buf, size_t count) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci int depth, retval; 10268c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 10278c2ecf20Sopenharmony_ci struct scsi_host_template *sht = sdev->host->hostt; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci if (!sht->change_queue_depth) 10308c2ecf20Sopenharmony_ci return -EINVAL; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci depth = simple_strtoul(buf, NULL, 0); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci if (depth < 1 || depth > sdev->host->can_queue) 10358c2ecf20Sopenharmony_ci return -EINVAL; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci retval = sht->change_queue_depth(sdev, depth); 10388c2ecf20Sopenharmony_ci if (retval < 0) 10398c2ecf20Sopenharmony_ci return retval; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci sdev->max_queue_depth = sdev->queue_depth; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci return count; 10448c2ecf20Sopenharmony_ci} 10458c2ecf20Sopenharmony_cisdev_show_function(queue_depth, "%d\n"); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_cistatic DEVICE_ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth, 10488c2ecf20Sopenharmony_ci sdev_store_queue_depth); 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_cistatic ssize_t 10518c2ecf20Sopenharmony_cisdev_show_wwid(struct device *dev, struct device_attribute *attr, 10528c2ecf20Sopenharmony_ci char *buf) 10538c2ecf20Sopenharmony_ci{ 10548c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 10558c2ecf20Sopenharmony_ci ssize_t count; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci count = scsi_vpd_lun_id(sdev, buf, PAGE_SIZE); 10588c2ecf20Sopenharmony_ci if (count > 0) { 10598c2ecf20Sopenharmony_ci buf[count] = '\n'; 10608c2ecf20Sopenharmony_ci count++; 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci return count; 10638c2ecf20Sopenharmony_ci} 10648c2ecf20Sopenharmony_cistatic DEVICE_ATTR(wwid, S_IRUGO, sdev_show_wwid, NULL); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci#define BLIST_FLAG_NAME(name) \ 10678c2ecf20Sopenharmony_ci [const_ilog2((__force __u64)BLIST_##name)] = #name 10688c2ecf20Sopenharmony_cistatic const char *const sdev_bflags_name[] = { 10698c2ecf20Sopenharmony_ci#include "scsi_devinfo_tbl.c" 10708c2ecf20Sopenharmony_ci}; 10718c2ecf20Sopenharmony_ci#undef BLIST_FLAG_NAME 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_cistatic ssize_t 10748c2ecf20Sopenharmony_cisdev_show_blacklist(struct device *dev, struct device_attribute *attr, 10758c2ecf20Sopenharmony_ci char *buf) 10768c2ecf20Sopenharmony_ci{ 10778c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 10788c2ecf20Sopenharmony_ci int i; 10798c2ecf20Sopenharmony_ci ssize_t len = 0; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(sdev->sdev_bflags) * BITS_PER_BYTE; i++) { 10828c2ecf20Sopenharmony_ci const char *name = NULL; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci if (!(sdev->sdev_bflags & (__force blist_flags_t)BIT(i))) 10858c2ecf20Sopenharmony_ci continue; 10868c2ecf20Sopenharmony_ci if (i < ARRAY_SIZE(sdev_bflags_name) && sdev_bflags_name[i]) 10878c2ecf20Sopenharmony_ci name = sdev_bflags_name[i]; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci if (name) 10908c2ecf20Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE - len, 10918c2ecf20Sopenharmony_ci "%s%s", len ? " " : "", name); 10928c2ecf20Sopenharmony_ci else 10938c2ecf20Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE - len, 10948c2ecf20Sopenharmony_ci "%sINVALID_BIT(%d)", len ? " " : "", i); 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci if (len) 10978c2ecf20Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); 10988c2ecf20Sopenharmony_ci return len; 10998c2ecf20Sopenharmony_ci} 11008c2ecf20Sopenharmony_cistatic DEVICE_ATTR(blacklist, S_IRUGO, sdev_show_blacklist, NULL); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci#ifdef CONFIG_SCSI_DH 11038c2ecf20Sopenharmony_cistatic ssize_t 11048c2ecf20Sopenharmony_cisdev_show_dh_state(struct device *dev, struct device_attribute *attr, 11058c2ecf20Sopenharmony_ci char *buf) 11068c2ecf20Sopenharmony_ci{ 11078c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci if (!sdev->handler) 11108c2ecf20Sopenharmony_ci return snprintf(buf, 20, "detached\n"); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci return snprintf(buf, 20, "%s\n", sdev->handler->name); 11138c2ecf20Sopenharmony_ci} 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_cistatic ssize_t 11168c2ecf20Sopenharmony_cisdev_store_dh_state(struct device *dev, struct device_attribute *attr, 11178c2ecf20Sopenharmony_ci const char *buf, size_t count) 11188c2ecf20Sopenharmony_ci{ 11198c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 11208c2ecf20Sopenharmony_ci int err = -EINVAL; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci if (sdev->sdev_state == SDEV_CANCEL || 11238c2ecf20Sopenharmony_ci sdev->sdev_state == SDEV_DEL) 11248c2ecf20Sopenharmony_ci return -ENODEV; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci if (!sdev->handler) { 11278c2ecf20Sopenharmony_ci /* 11288c2ecf20Sopenharmony_ci * Attach to a device handler 11298c2ecf20Sopenharmony_ci */ 11308c2ecf20Sopenharmony_ci err = scsi_dh_attach(sdev->request_queue, buf); 11318c2ecf20Sopenharmony_ci } else if (!strncmp(buf, "activate", 8)) { 11328c2ecf20Sopenharmony_ci /* 11338c2ecf20Sopenharmony_ci * Activate a device handler 11348c2ecf20Sopenharmony_ci */ 11358c2ecf20Sopenharmony_ci if (sdev->handler->activate) 11368c2ecf20Sopenharmony_ci err = sdev->handler->activate(sdev, NULL, NULL); 11378c2ecf20Sopenharmony_ci else 11388c2ecf20Sopenharmony_ci err = 0; 11398c2ecf20Sopenharmony_ci } else if (!strncmp(buf, "detach", 6)) { 11408c2ecf20Sopenharmony_ci /* 11418c2ecf20Sopenharmony_ci * Detach from a device handler 11428c2ecf20Sopenharmony_ci */ 11438c2ecf20Sopenharmony_ci sdev_printk(KERN_WARNING, sdev, 11448c2ecf20Sopenharmony_ci "can't detach handler %s.\n", 11458c2ecf20Sopenharmony_ci sdev->handler->name); 11468c2ecf20Sopenharmony_ci err = -EINVAL; 11478c2ecf20Sopenharmony_ci } 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci return err < 0 ? err : count; 11508c2ecf20Sopenharmony_ci} 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_cistatic DEVICE_ATTR(dh_state, S_IRUGO | S_IWUSR, sdev_show_dh_state, 11538c2ecf20Sopenharmony_ci sdev_store_dh_state); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_cistatic ssize_t 11568c2ecf20Sopenharmony_cisdev_show_access_state(struct device *dev, 11578c2ecf20Sopenharmony_ci struct device_attribute *attr, 11588c2ecf20Sopenharmony_ci char *buf) 11598c2ecf20Sopenharmony_ci{ 11608c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 11618c2ecf20Sopenharmony_ci unsigned char access_state; 11628c2ecf20Sopenharmony_ci const char *access_state_name; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci if (!sdev->handler) 11658c2ecf20Sopenharmony_ci return -EINVAL; 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci access_state = (sdev->access_state & SCSI_ACCESS_STATE_MASK); 11688c2ecf20Sopenharmony_ci access_state_name = scsi_access_state_name(access_state); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", 11718c2ecf20Sopenharmony_ci access_state_name ? access_state_name : "unknown"); 11728c2ecf20Sopenharmony_ci} 11738c2ecf20Sopenharmony_cistatic DEVICE_ATTR(access_state, S_IRUGO, sdev_show_access_state, NULL); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_cistatic ssize_t 11768c2ecf20Sopenharmony_cisdev_show_preferred_path(struct device *dev, 11778c2ecf20Sopenharmony_ci struct device_attribute *attr, 11788c2ecf20Sopenharmony_ci char *buf) 11798c2ecf20Sopenharmony_ci{ 11808c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci if (!sdev->handler) 11838c2ecf20Sopenharmony_ci return -EINVAL; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci if (sdev->access_state & SCSI_ACCESS_STATE_PREFERRED) 11868c2ecf20Sopenharmony_ci return sprintf(buf, "1\n"); 11878c2ecf20Sopenharmony_ci else 11888c2ecf20Sopenharmony_ci return sprintf(buf, "0\n"); 11898c2ecf20Sopenharmony_ci} 11908c2ecf20Sopenharmony_cistatic DEVICE_ATTR(preferred_path, S_IRUGO, sdev_show_preferred_path, NULL); 11918c2ecf20Sopenharmony_ci#endif 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_cistatic ssize_t 11948c2ecf20Sopenharmony_cisdev_show_queue_ramp_up_period(struct device *dev, 11958c2ecf20Sopenharmony_ci struct device_attribute *attr, 11968c2ecf20Sopenharmony_ci char *buf) 11978c2ecf20Sopenharmony_ci{ 11988c2ecf20Sopenharmony_ci struct scsi_device *sdev; 11998c2ecf20Sopenharmony_ci sdev = to_scsi_device(dev); 12008c2ecf20Sopenharmony_ci return snprintf(buf, 20, "%u\n", 12018c2ecf20Sopenharmony_ci jiffies_to_msecs(sdev->queue_ramp_up_period)); 12028c2ecf20Sopenharmony_ci} 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_cistatic ssize_t 12058c2ecf20Sopenharmony_cisdev_store_queue_ramp_up_period(struct device *dev, 12068c2ecf20Sopenharmony_ci struct device_attribute *attr, 12078c2ecf20Sopenharmony_ci const char *buf, size_t count) 12088c2ecf20Sopenharmony_ci{ 12098c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 12108c2ecf20Sopenharmony_ci unsigned int period; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci if (kstrtouint(buf, 10, &period)) 12138c2ecf20Sopenharmony_ci return -EINVAL; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci sdev->queue_ramp_up_period = msecs_to_jiffies(period); 12168c2ecf20Sopenharmony_ci return count; 12178c2ecf20Sopenharmony_ci} 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_cistatic DEVICE_ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR, 12208c2ecf20Sopenharmony_ci sdev_show_queue_ramp_up_period, 12218c2ecf20Sopenharmony_ci sdev_store_queue_ramp_up_period); 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_cistatic umode_t scsi_sdev_attr_is_visible(struct kobject *kobj, 12248c2ecf20Sopenharmony_ci struct attribute *attr, int i) 12258c2ecf20Sopenharmony_ci{ 12268c2ecf20Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 12278c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci if (attr == &dev_attr_queue_depth.attr && 12318c2ecf20Sopenharmony_ci !sdev->host->hostt->change_queue_depth) 12328c2ecf20Sopenharmony_ci return S_IRUGO; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci if (attr == &dev_attr_queue_ramp_up_period.attr && 12358c2ecf20Sopenharmony_ci !sdev->host->hostt->change_queue_depth) 12368c2ecf20Sopenharmony_ci return 0; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci#ifdef CONFIG_SCSI_DH 12398c2ecf20Sopenharmony_ci if (attr == &dev_attr_access_state.attr && 12408c2ecf20Sopenharmony_ci !sdev->handler) 12418c2ecf20Sopenharmony_ci return 0; 12428c2ecf20Sopenharmony_ci if (attr == &dev_attr_preferred_path.attr && 12438c2ecf20Sopenharmony_ci !sdev->handler) 12448c2ecf20Sopenharmony_ci return 0; 12458c2ecf20Sopenharmony_ci#endif 12468c2ecf20Sopenharmony_ci return attr->mode; 12478c2ecf20Sopenharmony_ci} 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_cistatic umode_t scsi_sdev_bin_attr_is_visible(struct kobject *kobj, 12508c2ecf20Sopenharmony_ci struct bin_attribute *attr, int i) 12518c2ecf20Sopenharmony_ci{ 12528c2ecf20Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 12538c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci if (attr == &dev_attr_vpd_pg0 && !sdev->vpd_pg0) 12578c2ecf20Sopenharmony_ci return 0; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci if (attr == &dev_attr_vpd_pg80 && !sdev->vpd_pg80) 12608c2ecf20Sopenharmony_ci return 0; 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci if (attr == &dev_attr_vpd_pg83 && !sdev->vpd_pg83) 12638c2ecf20Sopenharmony_ci return 0; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci if (attr == &dev_attr_vpd_pg89 && !sdev->vpd_pg89) 12668c2ecf20Sopenharmony_ci return 0; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci return S_IRUGO; 12698c2ecf20Sopenharmony_ci} 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci/* Default template for device attributes. May NOT be modified */ 12728c2ecf20Sopenharmony_cistatic struct attribute *scsi_sdev_attrs[] = { 12738c2ecf20Sopenharmony_ci &dev_attr_device_blocked.attr, 12748c2ecf20Sopenharmony_ci &dev_attr_type.attr, 12758c2ecf20Sopenharmony_ci &dev_attr_scsi_level.attr, 12768c2ecf20Sopenharmony_ci &dev_attr_device_busy.attr, 12778c2ecf20Sopenharmony_ci &dev_attr_vendor.attr, 12788c2ecf20Sopenharmony_ci &dev_attr_model.attr, 12798c2ecf20Sopenharmony_ci &dev_attr_rev.attr, 12808c2ecf20Sopenharmony_ci &dev_attr_rescan.attr, 12818c2ecf20Sopenharmony_ci &dev_attr_delete.attr, 12828c2ecf20Sopenharmony_ci &dev_attr_state.attr, 12838c2ecf20Sopenharmony_ci &dev_attr_timeout.attr, 12848c2ecf20Sopenharmony_ci &dev_attr_eh_timeout.attr, 12858c2ecf20Sopenharmony_ci &dev_attr_iocounterbits.attr, 12868c2ecf20Sopenharmony_ci &dev_attr_iorequest_cnt.attr, 12878c2ecf20Sopenharmony_ci &dev_attr_iodone_cnt.attr, 12888c2ecf20Sopenharmony_ci &dev_attr_ioerr_cnt.attr, 12898c2ecf20Sopenharmony_ci &dev_attr_modalias.attr, 12908c2ecf20Sopenharmony_ci &dev_attr_queue_depth.attr, 12918c2ecf20Sopenharmony_ci &dev_attr_queue_type.attr, 12928c2ecf20Sopenharmony_ci &dev_attr_wwid.attr, 12938c2ecf20Sopenharmony_ci &dev_attr_blacklist.attr, 12948c2ecf20Sopenharmony_ci#ifdef CONFIG_SCSI_DH 12958c2ecf20Sopenharmony_ci &dev_attr_dh_state.attr, 12968c2ecf20Sopenharmony_ci &dev_attr_access_state.attr, 12978c2ecf20Sopenharmony_ci &dev_attr_preferred_path.attr, 12988c2ecf20Sopenharmony_ci#endif 12998c2ecf20Sopenharmony_ci &dev_attr_queue_ramp_up_period.attr, 13008c2ecf20Sopenharmony_ci REF_EVT(media_change), 13018c2ecf20Sopenharmony_ci REF_EVT(inquiry_change_reported), 13028c2ecf20Sopenharmony_ci REF_EVT(capacity_change_reported), 13038c2ecf20Sopenharmony_ci REF_EVT(soft_threshold_reached), 13048c2ecf20Sopenharmony_ci REF_EVT(mode_parameter_change_reported), 13058c2ecf20Sopenharmony_ci REF_EVT(lun_change_reported), 13068c2ecf20Sopenharmony_ci NULL 13078c2ecf20Sopenharmony_ci}; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_cistatic struct bin_attribute *scsi_sdev_bin_attrs[] = { 13108c2ecf20Sopenharmony_ci &dev_attr_vpd_pg0, 13118c2ecf20Sopenharmony_ci &dev_attr_vpd_pg83, 13128c2ecf20Sopenharmony_ci &dev_attr_vpd_pg80, 13138c2ecf20Sopenharmony_ci &dev_attr_vpd_pg89, 13148c2ecf20Sopenharmony_ci &dev_attr_inquiry, 13158c2ecf20Sopenharmony_ci NULL 13168c2ecf20Sopenharmony_ci}; 13178c2ecf20Sopenharmony_cistatic struct attribute_group scsi_sdev_attr_group = { 13188c2ecf20Sopenharmony_ci .attrs = scsi_sdev_attrs, 13198c2ecf20Sopenharmony_ci .bin_attrs = scsi_sdev_bin_attrs, 13208c2ecf20Sopenharmony_ci .is_visible = scsi_sdev_attr_is_visible, 13218c2ecf20Sopenharmony_ci .is_bin_visible = scsi_sdev_bin_attr_is_visible, 13228c2ecf20Sopenharmony_ci}; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_cistatic const struct attribute_group *scsi_sdev_attr_groups[] = { 13258c2ecf20Sopenharmony_ci &scsi_sdev_attr_group, 13268c2ecf20Sopenharmony_ci NULL 13278c2ecf20Sopenharmony_ci}; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_cistatic int scsi_target_add(struct scsi_target *starget) 13308c2ecf20Sopenharmony_ci{ 13318c2ecf20Sopenharmony_ci int error; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci if (starget->state != STARGET_CREATED) 13348c2ecf20Sopenharmony_ci return 0; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci error = device_add(&starget->dev); 13378c2ecf20Sopenharmony_ci if (error) { 13388c2ecf20Sopenharmony_ci dev_err(&starget->dev, "target device_add failed, error %d\n", error); 13398c2ecf20Sopenharmony_ci return error; 13408c2ecf20Sopenharmony_ci } 13418c2ecf20Sopenharmony_ci transport_add_device(&starget->dev); 13428c2ecf20Sopenharmony_ci starget->state = STARGET_RUNNING; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci pm_runtime_set_active(&starget->dev); 13458c2ecf20Sopenharmony_ci pm_runtime_enable(&starget->dev); 13468c2ecf20Sopenharmony_ci device_enable_async_suspend(&starget->dev); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci return 0; 13498c2ecf20Sopenharmony_ci} 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci/** 13528c2ecf20Sopenharmony_ci * scsi_sysfs_add_sdev - add scsi device to sysfs 13538c2ecf20Sopenharmony_ci * @sdev: scsi_device to add 13548c2ecf20Sopenharmony_ci * 13558c2ecf20Sopenharmony_ci * Return value: 13568c2ecf20Sopenharmony_ci * 0 on Success / non-zero on Failure 13578c2ecf20Sopenharmony_ci **/ 13588c2ecf20Sopenharmony_ciint scsi_sysfs_add_sdev(struct scsi_device *sdev) 13598c2ecf20Sopenharmony_ci{ 13608c2ecf20Sopenharmony_ci int error, i; 13618c2ecf20Sopenharmony_ci struct request_queue *rq = sdev->request_queue; 13628c2ecf20Sopenharmony_ci struct scsi_target *starget = sdev->sdev_target; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci error = scsi_target_add(starget); 13658c2ecf20Sopenharmony_ci if (error) 13668c2ecf20Sopenharmony_ci return error; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci transport_configure_device(&starget->dev); 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci device_enable_async_suspend(&sdev->sdev_gendev); 13718c2ecf20Sopenharmony_ci scsi_autopm_get_target(starget); 13728c2ecf20Sopenharmony_ci pm_runtime_set_active(&sdev->sdev_gendev); 13738c2ecf20Sopenharmony_ci if (!sdev->rpm_autosuspend) 13748c2ecf20Sopenharmony_ci pm_runtime_forbid(&sdev->sdev_gendev); 13758c2ecf20Sopenharmony_ci pm_runtime_enable(&sdev->sdev_gendev); 13768c2ecf20Sopenharmony_ci scsi_autopm_put_target(starget); 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci scsi_autopm_get_device(sdev); 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci scsi_dh_add_device(sdev); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci error = device_add(&sdev->sdev_gendev); 13838c2ecf20Sopenharmony_ci if (error) { 13848c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, sdev, 13858c2ecf20Sopenharmony_ci "failed to add device: %d\n", error); 13868c2ecf20Sopenharmony_ci return error; 13878c2ecf20Sopenharmony_ci } 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci device_enable_async_suspend(&sdev->sdev_dev); 13908c2ecf20Sopenharmony_ci error = device_add(&sdev->sdev_dev); 13918c2ecf20Sopenharmony_ci if (error) { 13928c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, sdev, 13938c2ecf20Sopenharmony_ci "failed to add class device: %d\n", error); 13948c2ecf20Sopenharmony_ci device_del(&sdev->sdev_gendev); 13958c2ecf20Sopenharmony_ci return error; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci transport_add_device(&sdev->sdev_gendev); 13988c2ecf20Sopenharmony_ci sdev->is_visible = 1; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci error = bsg_scsi_register_queue(rq, &sdev->sdev_gendev); 14018c2ecf20Sopenharmony_ci if (error) 14028c2ecf20Sopenharmony_ci /* we're treating error on bsg register as non-fatal, 14038c2ecf20Sopenharmony_ci * so pretend nothing went wrong */ 14048c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, sdev, 14058c2ecf20Sopenharmony_ci "Failed to register bsg queue, errno=%d\n", error); 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci /* add additional host specific attributes */ 14088c2ecf20Sopenharmony_ci if (sdev->host->hostt->sdev_attrs) { 14098c2ecf20Sopenharmony_ci for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) { 14108c2ecf20Sopenharmony_ci error = device_create_file(&sdev->sdev_gendev, 14118c2ecf20Sopenharmony_ci sdev->host->hostt->sdev_attrs[i]); 14128c2ecf20Sopenharmony_ci if (error) 14138c2ecf20Sopenharmony_ci return error; 14148c2ecf20Sopenharmony_ci } 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci if (sdev->host->hostt->sdev_groups) { 14188c2ecf20Sopenharmony_ci error = sysfs_create_groups(&sdev->sdev_gendev.kobj, 14198c2ecf20Sopenharmony_ci sdev->host->hostt->sdev_groups); 14208c2ecf20Sopenharmony_ci if (error) 14218c2ecf20Sopenharmony_ci return error; 14228c2ecf20Sopenharmony_ci } 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci scsi_autopm_put_device(sdev); 14258c2ecf20Sopenharmony_ci return error; 14268c2ecf20Sopenharmony_ci} 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_civoid __scsi_remove_device(struct scsi_device *sdev) 14298c2ecf20Sopenharmony_ci{ 14308c2ecf20Sopenharmony_ci struct device *dev = &sdev->sdev_gendev; 14318c2ecf20Sopenharmony_ci int res; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci /* 14348c2ecf20Sopenharmony_ci * This cleanup path is not reentrant and while it is impossible 14358c2ecf20Sopenharmony_ci * to get a new reference with scsi_device_get() someone can still 14368c2ecf20Sopenharmony_ci * hold a previously acquired one. 14378c2ecf20Sopenharmony_ci */ 14388c2ecf20Sopenharmony_ci if (sdev->sdev_state == SDEV_DEL) 14398c2ecf20Sopenharmony_ci return; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci if (sdev->is_visible) { 14428c2ecf20Sopenharmony_ci /* 14438c2ecf20Sopenharmony_ci * If scsi_internal_target_block() is running concurrently, 14448c2ecf20Sopenharmony_ci * wait until it has finished before changing the device state. 14458c2ecf20Sopenharmony_ci */ 14468c2ecf20Sopenharmony_ci mutex_lock(&sdev->state_mutex); 14478c2ecf20Sopenharmony_ci /* 14488c2ecf20Sopenharmony_ci * If blocked, we go straight to DEL and restart the queue so 14498c2ecf20Sopenharmony_ci * any commands issued during driver shutdown (like sync 14508c2ecf20Sopenharmony_ci * cache) are errored immediately. 14518c2ecf20Sopenharmony_ci */ 14528c2ecf20Sopenharmony_ci res = scsi_device_set_state(sdev, SDEV_CANCEL); 14538c2ecf20Sopenharmony_ci if (res != 0) { 14548c2ecf20Sopenharmony_ci res = scsi_device_set_state(sdev, SDEV_DEL); 14558c2ecf20Sopenharmony_ci if (res == 0) 14568c2ecf20Sopenharmony_ci scsi_start_queue(sdev); 14578c2ecf20Sopenharmony_ci } 14588c2ecf20Sopenharmony_ci mutex_unlock(&sdev->state_mutex); 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci if (res != 0) 14618c2ecf20Sopenharmony_ci return; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci if (sdev->host->hostt->sdev_groups) 14648c2ecf20Sopenharmony_ci sysfs_remove_groups(&sdev->sdev_gendev.kobj, 14658c2ecf20Sopenharmony_ci sdev->host->hostt->sdev_groups); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci bsg_unregister_queue(sdev->request_queue); 14688c2ecf20Sopenharmony_ci device_unregister(&sdev->sdev_dev); 14698c2ecf20Sopenharmony_ci transport_remove_device(dev); 14708c2ecf20Sopenharmony_ci device_del(dev); 14718c2ecf20Sopenharmony_ci } else 14728c2ecf20Sopenharmony_ci put_device(&sdev->sdev_dev); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci /* 14758c2ecf20Sopenharmony_ci * Stop accepting new requests and wait until all queuecommand() and 14768c2ecf20Sopenharmony_ci * scsi_run_queue() invocations have finished before tearing down the 14778c2ecf20Sopenharmony_ci * device. 14788c2ecf20Sopenharmony_ci */ 14798c2ecf20Sopenharmony_ci mutex_lock(&sdev->state_mutex); 14808c2ecf20Sopenharmony_ci scsi_device_set_state(sdev, SDEV_DEL); 14818c2ecf20Sopenharmony_ci mutex_unlock(&sdev->state_mutex); 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci blk_cleanup_queue(sdev->request_queue); 14848c2ecf20Sopenharmony_ci cancel_work_sync(&sdev->requeue_work); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci if (sdev->host->hostt->slave_destroy) 14878c2ecf20Sopenharmony_ci sdev->host->hostt->slave_destroy(sdev); 14888c2ecf20Sopenharmony_ci transport_destroy_device(dev); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci /* 14918c2ecf20Sopenharmony_ci * Paired with the kref_get() in scsi_sysfs_initialize(). We have 14928c2ecf20Sopenharmony_ci * remoed sysfs visibility from the device, so make the target 14938c2ecf20Sopenharmony_ci * invisible if this was the last device underneath it. 14948c2ecf20Sopenharmony_ci */ 14958c2ecf20Sopenharmony_ci scsi_target_reap(scsi_target(sdev)); 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci put_device(dev); 14988c2ecf20Sopenharmony_ci} 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci/** 15018c2ecf20Sopenharmony_ci * scsi_remove_device - unregister a device from the scsi bus 15028c2ecf20Sopenharmony_ci * @sdev: scsi_device to unregister 15038c2ecf20Sopenharmony_ci **/ 15048c2ecf20Sopenharmony_civoid scsi_remove_device(struct scsi_device *sdev) 15058c2ecf20Sopenharmony_ci{ 15068c2ecf20Sopenharmony_ci struct Scsi_Host *shost = sdev->host; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci mutex_lock(&shost->scan_mutex); 15098c2ecf20Sopenharmony_ci __scsi_remove_device(sdev); 15108c2ecf20Sopenharmony_ci mutex_unlock(&shost->scan_mutex); 15118c2ecf20Sopenharmony_ci} 15128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_remove_device); 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_cistatic void __scsi_remove_target(struct scsi_target *starget) 15158c2ecf20Sopenharmony_ci{ 15168c2ecf20Sopenharmony_ci struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 15178c2ecf20Sopenharmony_ci unsigned long flags; 15188c2ecf20Sopenharmony_ci struct scsi_device *sdev; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci spin_lock_irqsave(shost->host_lock, flags); 15218c2ecf20Sopenharmony_ci restart: 15228c2ecf20Sopenharmony_ci list_for_each_entry(sdev, &shost->__devices, siblings) { 15238c2ecf20Sopenharmony_ci /* 15248c2ecf20Sopenharmony_ci * We cannot call scsi_device_get() here, as 15258c2ecf20Sopenharmony_ci * we might've been called from rmmod() causing 15268c2ecf20Sopenharmony_ci * scsi_device_get() to fail the module_is_live() 15278c2ecf20Sopenharmony_ci * check. 15288c2ecf20Sopenharmony_ci */ 15298c2ecf20Sopenharmony_ci if (sdev->channel != starget->channel || 15308c2ecf20Sopenharmony_ci sdev->id != starget->id) 15318c2ecf20Sopenharmony_ci continue; 15328c2ecf20Sopenharmony_ci if (sdev->sdev_state == SDEV_DEL || 15338c2ecf20Sopenharmony_ci sdev->sdev_state == SDEV_CANCEL || 15348c2ecf20Sopenharmony_ci !get_device(&sdev->sdev_gendev)) 15358c2ecf20Sopenharmony_ci continue; 15368c2ecf20Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, flags); 15378c2ecf20Sopenharmony_ci scsi_remove_device(sdev); 15388c2ecf20Sopenharmony_ci put_device(&sdev->sdev_gendev); 15398c2ecf20Sopenharmony_ci spin_lock_irqsave(shost->host_lock, flags); 15408c2ecf20Sopenharmony_ci goto restart; 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, flags); 15438c2ecf20Sopenharmony_ci} 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci/** 15468c2ecf20Sopenharmony_ci * scsi_remove_target - try to remove a target and all its devices 15478c2ecf20Sopenharmony_ci * @dev: generic starget or parent of generic stargets to be removed 15488c2ecf20Sopenharmony_ci * 15498c2ecf20Sopenharmony_ci * Note: This is slightly racy. It is possible that if the user 15508c2ecf20Sopenharmony_ci * requests the addition of another device then the target won't be 15518c2ecf20Sopenharmony_ci * removed. 15528c2ecf20Sopenharmony_ci */ 15538c2ecf20Sopenharmony_civoid scsi_remove_target(struct device *dev) 15548c2ecf20Sopenharmony_ci{ 15558c2ecf20Sopenharmony_ci struct Scsi_Host *shost = dev_to_shost(dev->parent); 15568c2ecf20Sopenharmony_ci struct scsi_target *starget; 15578c2ecf20Sopenharmony_ci unsigned long flags; 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_cirestart: 15608c2ecf20Sopenharmony_ci spin_lock_irqsave(shost->host_lock, flags); 15618c2ecf20Sopenharmony_ci list_for_each_entry(starget, &shost->__targets, siblings) { 15628c2ecf20Sopenharmony_ci if (starget->state == STARGET_DEL || 15638c2ecf20Sopenharmony_ci starget->state == STARGET_REMOVE || 15648c2ecf20Sopenharmony_ci starget->state == STARGET_CREATED_REMOVE) 15658c2ecf20Sopenharmony_ci continue; 15668c2ecf20Sopenharmony_ci if (starget->dev.parent == dev || &starget->dev == dev) { 15678c2ecf20Sopenharmony_ci kref_get(&starget->reap_ref); 15688c2ecf20Sopenharmony_ci if (starget->state == STARGET_CREATED) 15698c2ecf20Sopenharmony_ci starget->state = STARGET_CREATED_REMOVE; 15708c2ecf20Sopenharmony_ci else 15718c2ecf20Sopenharmony_ci starget->state = STARGET_REMOVE; 15728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, flags); 15738c2ecf20Sopenharmony_ci __scsi_remove_target(starget); 15748c2ecf20Sopenharmony_ci scsi_target_reap(starget); 15758c2ecf20Sopenharmony_ci goto restart; 15768c2ecf20Sopenharmony_ci } 15778c2ecf20Sopenharmony_ci } 15788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, flags); 15798c2ecf20Sopenharmony_ci} 15808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_remove_target); 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ciint scsi_register_driver(struct device_driver *drv) 15838c2ecf20Sopenharmony_ci{ 15848c2ecf20Sopenharmony_ci drv->bus = &scsi_bus_type; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci return driver_register(drv); 15878c2ecf20Sopenharmony_ci} 15888c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_register_driver); 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ciint scsi_register_interface(struct class_interface *intf) 15918c2ecf20Sopenharmony_ci{ 15928c2ecf20Sopenharmony_ci intf->class = &sdev_class; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci return class_interface_register(intf); 15958c2ecf20Sopenharmony_ci} 15968c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_register_interface); 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci/** 15998c2ecf20Sopenharmony_ci * scsi_sysfs_add_host - add scsi host to subsystem 16008c2ecf20Sopenharmony_ci * @shost: scsi host struct to add to subsystem 16018c2ecf20Sopenharmony_ci **/ 16028c2ecf20Sopenharmony_ciint scsi_sysfs_add_host(struct Scsi_Host *shost) 16038c2ecf20Sopenharmony_ci{ 16048c2ecf20Sopenharmony_ci int error, i; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci /* add host specific attributes */ 16078c2ecf20Sopenharmony_ci if (shost->hostt->shost_attrs) { 16088c2ecf20Sopenharmony_ci for (i = 0; shost->hostt->shost_attrs[i]; i++) { 16098c2ecf20Sopenharmony_ci error = device_create_file(&shost->shost_dev, 16108c2ecf20Sopenharmony_ci shost->hostt->shost_attrs[i]); 16118c2ecf20Sopenharmony_ci if (error) 16128c2ecf20Sopenharmony_ci return error; 16138c2ecf20Sopenharmony_ci } 16148c2ecf20Sopenharmony_ci } 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci transport_register_device(&shost->shost_gendev); 16178c2ecf20Sopenharmony_ci transport_configure_device(&shost->shost_gendev); 16188c2ecf20Sopenharmony_ci return 0; 16198c2ecf20Sopenharmony_ci} 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_cistatic struct device_type scsi_dev_type = { 16228c2ecf20Sopenharmony_ci .name = "scsi_device", 16238c2ecf20Sopenharmony_ci .release = scsi_device_dev_release, 16248c2ecf20Sopenharmony_ci .groups = scsi_sdev_attr_groups, 16258c2ecf20Sopenharmony_ci}; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_civoid scsi_sysfs_device_initialize(struct scsi_device *sdev) 16288c2ecf20Sopenharmony_ci{ 16298c2ecf20Sopenharmony_ci unsigned long flags; 16308c2ecf20Sopenharmony_ci struct Scsi_Host *shost = sdev->host; 16318c2ecf20Sopenharmony_ci struct scsi_target *starget = sdev->sdev_target; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci device_initialize(&sdev->sdev_gendev); 16348c2ecf20Sopenharmony_ci sdev->sdev_gendev.bus = &scsi_bus_type; 16358c2ecf20Sopenharmony_ci sdev->sdev_gendev.type = &scsi_dev_type; 16368c2ecf20Sopenharmony_ci dev_set_name(&sdev->sdev_gendev, "%d:%d:%d:%llu", 16378c2ecf20Sopenharmony_ci sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci device_initialize(&sdev->sdev_dev); 16408c2ecf20Sopenharmony_ci sdev->sdev_dev.parent = get_device(&sdev->sdev_gendev); 16418c2ecf20Sopenharmony_ci sdev->sdev_dev.class = &sdev_class; 16428c2ecf20Sopenharmony_ci dev_set_name(&sdev->sdev_dev, "%d:%d:%d:%llu", 16438c2ecf20Sopenharmony_ci sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); 16448c2ecf20Sopenharmony_ci /* 16458c2ecf20Sopenharmony_ci * Get a default scsi_level from the target (derived from sibling 16468c2ecf20Sopenharmony_ci * devices). This is the best we can do for guessing how to set 16478c2ecf20Sopenharmony_ci * sdev->lun_in_cdb for the initial INQUIRY command. For LUN 0 the 16488c2ecf20Sopenharmony_ci * setting doesn't matter, because all the bits are zero anyway. 16498c2ecf20Sopenharmony_ci * But it does matter for higher LUNs. 16508c2ecf20Sopenharmony_ci */ 16518c2ecf20Sopenharmony_ci sdev->scsi_level = starget->scsi_level; 16528c2ecf20Sopenharmony_ci if (sdev->scsi_level <= SCSI_2 && 16538c2ecf20Sopenharmony_ci sdev->scsi_level != SCSI_UNKNOWN && 16548c2ecf20Sopenharmony_ci !shost->no_scsi2_lun_in_cdb) 16558c2ecf20Sopenharmony_ci sdev->lun_in_cdb = 1; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci transport_setup_device(&sdev->sdev_gendev); 16588c2ecf20Sopenharmony_ci spin_lock_irqsave(shost->host_lock, flags); 16598c2ecf20Sopenharmony_ci list_add_tail(&sdev->same_target_siblings, &starget->devices); 16608c2ecf20Sopenharmony_ci list_add_tail(&sdev->siblings, &shost->__devices); 16618c2ecf20Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, flags); 16628c2ecf20Sopenharmony_ci /* 16638c2ecf20Sopenharmony_ci * device can now only be removed via __scsi_remove_device() so hold 16648c2ecf20Sopenharmony_ci * the target. Target will be held in CREATED state until something 16658c2ecf20Sopenharmony_ci * beneath it becomes visible (in which case it moves to RUNNING) 16668c2ecf20Sopenharmony_ci */ 16678c2ecf20Sopenharmony_ci kref_get(&starget->reap_ref); 16688c2ecf20Sopenharmony_ci} 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ciint scsi_is_sdev_device(const struct device *dev) 16718c2ecf20Sopenharmony_ci{ 16728c2ecf20Sopenharmony_ci return dev->type == &scsi_dev_type; 16738c2ecf20Sopenharmony_ci} 16748c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_is_sdev_device); 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci/* A blank transport template that is used in drivers that don't 16778c2ecf20Sopenharmony_ci * yet implement Transport Attributes */ 16788c2ecf20Sopenharmony_cistruct scsi_transport_template blank_transport_template = { { { {NULL, }, }, }, }; 1679