1/* 2 * This file is part of the zfcp device driver for 3 * FCP adapters for IBM System z9 and zSeries. 4 * 5 * (C) Copyright IBM Corp. 2002, 2006 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 */ 21 22#include "zfcp_ext.h" 23 24#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG 25 26/** 27 * zfcp_sysfs_port_release - gets called when a struct device port is released 28 * @dev: pointer to belonging device 29 */ 30void 31zfcp_sysfs_port_release(struct device *dev) 32{ 33 kfree(dev); 34} 35 36/** 37 * ZFCP_DEFINE_PORT_ATTR 38 * @_name: name of show attribute 39 * @_format: format string 40 * @_value: value to print 41 * 42 * Generates attributes for a port. 43 */ 44#define ZFCP_DEFINE_PORT_ATTR(_name, _format, _value) \ 45static ssize_t zfcp_sysfs_port_##_name##_show(struct device *dev, struct device_attribute *attr, \ 46 char *buf) \ 47{ \ 48 struct zfcp_port *port; \ 49 \ 50 port = dev_get_drvdata(dev); \ 51 return sprintf(buf, _format, _value); \ 52} \ 53 \ 54static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_port_##_name##_show, NULL); 55 56ZFCP_DEFINE_PORT_ATTR(status, "0x%08x\n", atomic_read(&port->status)); 57ZFCP_DEFINE_PORT_ATTR(in_recovery, "%d\n", atomic_test_mask 58 (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status)); 59ZFCP_DEFINE_PORT_ATTR(access_denied, "%d\n", atomic_test_mask 60 (ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status)); 61 62/** 63 * zfcp_sysfs_unit_add_store - add a unit to sysfs tree 64 * @dev: pointer to belonging device 65 * @buf: pointer to input buffer 66 * @count: number of bytes in buffer 67 * 68 * Store function of the "unit_add" attribute of a port. 69 */ 70static ssize_t 71zfcp_sysfs_unit_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 72{ 73 fcp_lun_t fcp_lun; 74 char *endp; 75 struct zfcp_port *port; 76 struct zfcp_unit *unit; 77 int retval = -EINVAL; 78 79 down(&zfcp_data.config_sema); 80 81 port = dev_get_drvdata(dev); 82 if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) { 83 retval = -EBUSY; 84 goto out; 85 } 86 87 fcp_lun = simple_strtoull(buf, &endp, 0); 88 if ((endp + 1) < (buf + count)) 89 goto out; 90 91 unit = zfcp_unit_enqueue(port, fcp_lun); 92 if (!unit) 93 goto out; 94 95 retval = 0; 96 97 zfcp_erp_unit_reopen(unit, 0); 98 zfcp_erp_wait(unit->port->adapter); 99 zfcp_unit_put(unit); 100 out: 101 up(&zfcp_data.config_sema); 102 return retval ? retval : (ssize_t) count; 103} 104 105static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); 106 107/** 108 * zfcp_sysfs_unit_remove_store - remove a unit from sysfs tree 109 * @dev: pointer to belonging device 110 * @buf: pointer to input buffer 111 * @count: number of bytes in buffer 112 */ 113static ssize_t 114zfcp_sysfs_unit_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 115{ 116 struct zfcp_port *port; 117 struct zfcp_unit *unit; 118 fcp_lun_t fcp_lun; 119 char *endp; 120 int retval = 0; 121 122 down(&zfcp_data.config_sema); 123 124 port = dev_get_drvdata(dev); 125 if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) { 126 retval = -EBUSY; 127 goto out; 128 } 129 130 fcp_lun = simple_strtoull(buf, &endp, 0); 131 if ((endp + 1) < (buf + count)) { 132 retval = -EINVAL; 133 goto out; 134 } 135 136 write_lock_irq(&zfcp_data.config_lock); 137 unit = zfcp_get_unit_by_lun(port, fcp_lun); 138 if (unit && (atomic_read(&unit->refcount) == 0)) { 139 zfcp_unit_get(unit); 140 atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); 141 list_move(&unit->list, &port->unit_remove_lh); 142 } 143 else { 144 unit = NULL; 145 } 146 write_unlock_irq(&zfcp_data.config_lock); 147 148 if (!unit) { 149 retval = -ENXIO; 150 goto out; 151 } 152 153 zfcp_erp_unit_shutdown(unit, 0); 154 zfcp_erp_wait(unit->port->adapter); 155 zfcp_unit_put(unit); 156 zfcp_unit_dequeue(unit); 157 out: 158 up(&zfcp_data.config_sema); 159 return retval ? retval : (ssize_t) count; 160} 161 162static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); 163 164/** 165 * zfcp_sysfs_port_failed_store - failed state of port 166 * @dev: pointer to belonging device 167 * @buf: pointer to input buffer 168 * @count: number of bytes in buffer 169 * 170 * Store function of the "failed" attribute of a port. 171 * If a "0" gets written to "failed", error recovery will be 172 * started for the belonging port. 173 */ 174static ssize_t 175zfcp_sysfs_port_failed_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 176{ 177 struct zfcp_port *port; 178 unsigned int val; 179 char *endp; 180 int retval = 0; 181 182 down(&zfcp_data.config_sema); 183 184 port = dev_get_drvdata(dev); 185 if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) { 186 retval = -EBUSY; 187 goto out; 188 } 189 190 val = simple_strtoul(buf, &endp, 0); 191 if (((endp + 1) < (buf + count)) || (val != 0)) { 192 retval = -EINVAL; 193 goto out; 194 } 195 196 zfcp_erp_modify_port_status(port, ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); 197 zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED); 198 zfcp_erp_wait(port->adapter); 199 out: 200 up(&zfcp_data.config_sema); 201 return retval ? retval : (ssize_t) count; 202} 203 204/** 205 * zfcp_sysfs_port_failed_show - failed state of port 206 * @dev: pointer to belonging device 207 * @buf: pointer to input buffer 208 * 209 * Show function of "failed" attribute of port. Will be 210 * "0" if port is working, otherwise "1". 211 */ 212static ssize_t 213zfcp_sysfs_port_failed_show(struct device *dev, struct device_attribute *attr, char *buf) 214{ 215 struct zfcp_port *port; 216 217 port = dev_get_drvdata(dev); 218 if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) 219 return sprintf(buf, "1\n"); 220 else 221 return sprintf(buf, "0\n"); 222} 223 224static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_port_failed_show, 225 zfcp_sysfs_port_failed_store); 226 227/** 228 * zfcp_port_common_attrs 229 * sysfs attributes that are common for all kind of fc ports. 230 */ 231static struct attribute *zfcp_port_common_attrs[] = { 232 &dev_attr_failed.attr, 233 &dev_attr_in_recovery.attr, 234 &dev_attr_status.attr, 235 &dev_attr_access_denied.attr, 236 NULL 237}; 238 239static struct attribute_group zfcp_port_common_attr_group = { 240 .attrs = zfcp_port_common_attrs, 241}; 242 243/** 244 * zfcp_port_no_ns_attrs 245 * sysfs attributes not to be used for nameserver ports. 246 */ 247static struct attribute *zfcp_port_no_ns_attrs[] = { 248 &dev_attr_unit_add.attr, 249 &dev_attr_unit_remove.attr, 250 NULL 251}; 252 253static struct attribute_group zfcp_port_no_ns_attr_group = { 254 .attrs = zfcp_port_no_ns_attrs, 255}; 256 257/** 258 * zfcp_sysfs_port_create_files - create sysfs port files 259 * @dev: pointer to belonging device 260 * 261 * Create all attributes of the sysfs representation of a port. 262 */ 263int 264zfcp_sysfs_port_create_files(struct device *dev, u32 flags) 265{ 266 int retval; 267 268 retval = sysfs_create_group(&dev->kobj, &zfcp_port_common_attr_group); 269 270 if ((flags & ZFCP_STATUS_PORT_WKA) || retval) 271 return retval; 272 273 retval = sysfs_create_group(&dev->kobj, &zfcp_port_no_ns_attr_group); 274 if (retval) 275 sysfs_remove_group(&dev->kobj, &zfcp_port_common_attr_group); 276 277 return retval; 278} 279 280/** 281 * zfcp_sysfs_port_remove_files - remove sysfs port files 282 * @dev: pointer to belonging device 283 * 284 * Remove all attributes of the sysfs representation of a port. 285 */ 286void 287zfcp_sysfs_port_remove_files(struct device *dev, u32 flags) 288{ 289 sysfs_remove_group(&dev->kobj, &zfcp_port_common_attr_group); 290 if (!(flags & ZFCP_STATUS_PORT_WKA)) 291 sysfs_remove_group(&dev->kobj, &zfcp_port_no_ns_attr_group); 292} 293 294#undef ZFCP_LOG_AREA 295