diff options
Diffstat (limited to 'drivers/scsi/fcoe/fcoe_sysfs.c')
| -rw-r--r-- | drivers/scsi/fcoe/fcoe_sysfs.c | 186 |
1 files changed, 152 insertions, 34 deletions
diff --git a/drivers/scsi/fcoe/fcoe_sysfs.c b/drivers/scsi/fcoe/fcoe_sysfs.c index 5e751689a089..8c05ae017f5b 100644 --- a/drivers/scsi/fcoe/fcoe_sysfs.c +++ b/drivers/scsi/fcoe/fcoe_sysfs.c | |||
| @@ -21,8 +21,17 @@ | |||
| 21 | #include <linux/types.h> | 21 | #include <linux/types.h> |
| 22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
| 23 | #include <linux/etherdevice.h> | 23 | #include <linux/etherdevice.h> |
| 24 | #include <linux/ctype.h> | ||
| 24 | 25 | ||
| 25 | #include <scsi/fcoe_sysfs.h> | 26 | #include <scsi/fcoe_sysfs.h> |
| 27 | #include <scsi/libfcoe.h> | ||
| 28 | |||
| 29 | /* | ||
| 30 | * OK to include local libfcoe.h for debug_logging, but cannot include | ||
| 31 | * <scsi/libfcoe.h> otherwise non-netdev based fcoe solutions would have | ||
| 32 | * have to include more than fcoe_sysfs.h. | ||
| 33 | */ | ||
| 34 | #include "libfcoe.h" | ||
| 26 | 35 | ||
| 27 | static atomic_t ctlr_num; | 36 | static atomic_t ctlr_num; |
| 28 | static atomic_t fcf_num; | 37 | static atomic_t fcf_num; |
| @@ -71,6 +80,8 @@ MODULE_PARM_DESC(fcf_dev_loss_tmo, | |||
| 71 | ((x)->lesb.lesb_err_block) | 80 | ((x)->lesb.lesb_err_block) |
| 72 | #define fcoe_ctlr_fcs_error(x) \ | 81 | #define fcoe_ctlr_fcs_error(x) \ |
| 73 | ((x)->lesb.lesb_fcs_error) | 82 | ((x)->lesb.lesb_fcs_error) |
| 83 | #define fcoe_ctlr_enabled(x) \ | ||
| 84 | ((x)->enabled) | ||
| 74 | #define fcoe_fcf_state(x) \ | 85 | #define fcoe_fcf_state(x) \ |
| 75 | ((x)->state) | 86 | ((x)->state) |
| 76 | #define fcoe_fcf_fabric_name(x) \ | 87 | #define fcoe_fcf_fabric_name(x) \ |
| @@ -210,25 +221,34 @@ static ssize_t show_fcoe_fcf_device_##field(struct device *dev, \ | |||
| 210 | #define fcoe_enum_name_search(title, table_type, table) \ | 221 | #define fcoe_enum_name_search(title, table_type, table) \ |
| 211 | static const char *get_fcoe_##title##_name(enum table_type table_key) \ | 222 | static const char *get_fcoe_##title##_name(enum table_type table_key) \ |
| 212 | { \ | 223 | { \ |
| 213 | int i; \ | 224 | if (table_key < 0 || table_key >= ARRAY_SIZE(table)) \ |
| 214 | char *name = NULL; \ | 225 | return NULL; \ |
| 215 | \ | 226 | return table[table_key]; \ |
| 216 | for (i = 0; i < ARRAY_SIZE(table); i++) { \ | 227 | } |
| 217 | if (table[i].value == table_key) { \ | 228 | |
| 218 | name = table[i].name; \ | 229 | static char *fip_conn_type_names[] = { |
| 219 | break; \ | 230 | [ FIP_CONN_TYPE_UNKNOWN ] = "Unknown", |
| 220 | } \ | 231 | [ FIP_CONN_TYPE_FABRIC ] = "Fabric", |
| 221 | } \ | 232 | [ FIP_CONN_TYPE_VN2VN ] = "VN2VN", |
| 222 | return name; \ | 233 | }; |
| 234 | fcoe_enum_name_search(ctlr_mode, fip_conn_type, fip_conn_type_names) | ||
| 235 | |||
| 236 | static enum fip_conn_type fcoe_parse_mode(const char *buf) | ||
| 237 | { | ||
| 238 | int i; | ||
| 239 | |||
| 240 | for (i = 0; i < ARRAY_SIZE(fip_conn_type_names); i++) { | ||
| 241 | if (strcasecmp(buf, fip_conn_type_names[i]) == 0) | ||
| 242 | return i; | ||
| 243 | } | ||
| 244 | |||
| 245 | return FIP_CONN_TYPE_UNKNOWN; | ||
| 223 | } | 246 | } |
| 224 | 247 | ||
| 225 | static struct { | 248 | static char *fcf_state_names[] = { |
| 226 | enum fcf_state value; | 249 | [ FCOE_FCF_STATE_UNKNOWN ] = "Unknown", |
| 227 | char *name; | 250 | [ FCOE_FCF_STATE_DISCONNECTED ] = "Disconnected", |
| 228 | } fcf_state_names[] = { | 251 | [ FCOE_FCF_STATE_CONNECTED ] = "Connected", |
| 229 | { FCOE_FCF_STATE_UNKNOWN, "Unknown" }, | ||
| 230 | { FCOE_FCF_STATE_DISCONNECTED, "Disconnected" }, | ||
| 231 | { FCOE_FCF_STATE_CONNECTED, "Connected" }, | ||
| 232 | }; | 252 | }; |
| 233 | fcoe_enum_name_search(fcf_state, fcf_state, fcf_state_names) | 253 | fcoe_enum_name_search(fcf_state, fcf_state, fcf_state_names) |
| 234 | #define FCOE_FCF_STATE_MAX_NAMELEN 50 | 254 | #define FCOE_FCF_STATE_MAX_NAMELEN 50 |
| @@ -246,17 +266,7 @@ static ssize_t show_fcf_state(struct device *dev, | |||
| 246 | } | 266 | } |
| 247 | static FCOE_DEVICE_ATTR(fcf, state, S_IRUGO, show_fcf_state, NULL); | 267 | static FCOE_DEVICE_ATTR(fcf, state, S_IRUGO, show_fcf_state, NULL); |
| 248 | 268 | ||
| 249 | static struct { | 269 | #define FCOE_MAX_MODENAME_LEN 20 |
| 250 | enum fip_conn_type value; | ||
| 251 | char *name; | ||
| 252 | } fip_conn_type_names[] = { | ||
| 253 | { FIP_CONN_TYPE_UNKNOWN, "Unknown" }, | ||
| 254 | { FIP_CONN_TYPE_FABRIC, "Fabric" }, | ||
| 255 | { FIP_CONN_TYPE_VN2VN, "VN2VN" }, | ||
| 256 | }; | ||
| 257 | fcoe_enum_name_search(ctlr_mode, fip_conn_type, fip_conn_type_names) | ||
| 258 | #define FCOE_CTLR_MODE_MAX_NAMELEN 50 | ||
| 259 | |||
| 260 | static ssize_t show_ctlr_mode(struct device *dev, | 270 | static ssize_t show_ctlr_mode(struct device *dev, |
| 261 | struct device_attribute *attr, | 271 | struct device_attribute *attr, |
| 262 | char *buf) | 272 | char *buf) |
| @@ -264,17 +274,116 @@ static ssize_t show_ctlr_mode(struct device *dev, | |||
| 264 | struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); | 274 | struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); |
| 265 | const char *name; | 275 | const char *name; |
| 266 | 276 | ||
| 267 | if (ctlr->f->get_fcoe_ctlr_mode) | ||
| 268 | ctlr->f->get_fcoe_ctlr_mode(ctlr); | ||
| 269 | |||
| 270 | name = get_fcoe_ctlr_mode_name(ctlr->mode); | 277 | name = get_fcoe_ctlr_mode_name(ctlr->mode); |
| 271 | if (!name) | 278 | if (!name) |
| 272 | return -EINVAL; | 279 | return -EINVAL; |
| 273 | return snprintf(buf, FCOE_CTLR_MODE_MAX_NAMELEN, | 280 | return snprintf(buf, FCOE_MAX_MODENAME_LEN, |
| 281 | "%s\n", name); | ||
| 282 | } | ||
| 283 | |||
| 284 | static ssize_t store_ctlr_mode(struct device *dev, | ||
| 285 | struct device_attribute *attr, | ||
| 286 | const char *buf, size_t count) | ||
| 287 | { | ||
| 288 | struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); | ||
| 289 | char mode[FCOE_MAX_MODENAME_LEN + 1]; | ||
| 290 | |||
| 291 | if (count > FCOE_MAX_MODENAME_LEN) | ||
| 292 | return -EINVAL; | ||
| 293 | |||
| 294 | strncpy(mode, buf, count); | ||
| 295 | |||
| 296 | if (mode[count - 1] == '\n') | ||
| 297 | mode[count - 1] = '\0'; | ||
| 298 | else | ||
| 299 | mode[count] = '\0'; | ||
| 300 | |||
| 301 | switch (ctlr->enabled) { | ||
| 302 | case FCOE_CTLR_ENABLED: | ||
| 303 | LIBFCOE_SYSFS_DBG(ctlr, "Cannot change mode when enabled."); | ||
| 304 | return -EBUSY; | ||
| 305 | case FCOE_CTLR_DISABLED: | ||
| 306 | if (!ctlr->f->set_fcoe_ctlr_mode) { | ||
| 307 | LIBFCOE_SYSFS_DBG(ctlr, | ||
| 308 | "Mode change not supported by LLD."); | ||
| 309 | return -ENOTSUPP; | ||
| 310 | } | ||
| 311 | |||
| 312 | ctlr->mode = fcoe_parse_mode(mode); | ||
| 313 | if (ctlr->mode == FIP_CONN_TYPE_UNKNOWN) { | ||
| 314 | LIBFCOE_SYSFS_DBG(ctlr, | ||
| 315 | "Unknown mode %s provided.", buf); | ||
| 316 | return -EINVAL; | ||
| 317 | } | ||
| 318 | |||
| 319 | ctlr->f->set_fcoe_ctlr_mode(ctlr); | ||
| 320 | LIBFCOE_SYSFS_DBG(ctlr, "Mode changed to %s.", buf); | ||
| 321 | |||
| 322 | return count; | ||
| 323 | case FCOE_CTLR_UNUSED: | ||
| 324 | default: | ||
| 325 | LIBFCOE_SYSFS_DBG(ctlr, "Mode change not supported."); | ||
| 326 | return -ENOTSUPP; | ||
| 327 | }; | ||
| 328 | } | ||
| 329 | |||
| 330 | static FCOE_DEVICE_ATTR(ctlr, mode, S_IRUGO | S_IWUSR, | ||
| 331 | show_ctlr_mode, store_ctlr_mode); | ||
| 332 | |||
| 333 | static ssize_t store_ctlr_enabled(struct device *dev, | ||
| 334 | struct device_attribute *attr, | ||
| 335 | const char *buf, size_t count) | ||
| 336 | { | ||
| 337 | struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); | ||
| 338 | int rc; | ||
| 339 | |||
| 340 | switch (ctlr->enabled) { | ||
| 341 | case FCOE_CTLR_ENABLED: | ||
| 342 | if (*buf == '1') | ||
| 343 | return count; | ||
| 344 | ctlr->enabled = FCOE_CTLR_DISABLED; | ||
| 345 | break; | ||
| 346 | case FCOE_CTLR_DISABLED: | ||
| 347 | if (*buf == '0') | ||
| 348 | return count; | ||
| 349 | ctlr->enabled = FCOE_CTLR_ENABLED; | ||
| 350 | break; | ||
| 351 | case FCOE_CTLR_UNUSED: | ||
| 352 | return -ENOTSUPP; | ||
| 353 | }; | ||
| 354 | |||
| 355 | rc = ctlr->f->set_fcoe_ctlr_enabled(ctlr); | ||
| 356 | if (rc) | ||
| 357 | return rc; | ||
| 358 | |||
| 359 | return count; | ||
| 360 | } | ||
| 361 | |||
| 362 | static char *ctlr_enabled_state_names[] = { | ||
| 363 | [ FCOE_CTLR_ENABLED ] = "1", | ||
| 364 | [ FCOE_CTLR_DISABLED ] = "0", | ||
| 365 | }; | ||
| 366 | fcoe_enum_name_search(ctlr_enabled_state, ctlr_enabled_state, | ||
| 367 | ctlr_enabled_state_names) | ||
| 368 | #define FCOE_CTLR_ENABLED_MAX_NAMELEN 50 | ||
| 369 | |||
| 370 | static ssize_t show_ctlr_enabled_state(struct device *dev, | ||
| 371 | struct device_attribute *attr, | ||
| 372 | char *buf) | ||
| 373 | { | ||
| 374 | struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); | ||
| 375 | const char *name; | ||
| 376 | |||
| 377 | name = get_fcoe_ctlr_enabled_state_name(ctlr->enabled); | ||
| 378 | if (!name) | ||
| 379 | return -EINVAL; | ||
| 380 | return snprintf(buf, FCOE_CTLR_ENABLED_MAX_NAMELEN, | ||
| 274 | "%s\n", name); | 381 | "%s\n", name); |
| 275 | } | 382 | } |
| 276 | static FCOE_DEVICE_ATTR(ctlr, mode, S_IRUGO, | 383 | |
| 277 | show_ctlr_mode, NULL); | 384 | static FCOE_DEVICE_ATTR(ctlr, enabled, S_IRUGO | S_IWUSR, |
| 385 | show_ctlr_enabled_state, | ||
| 386 | store_ctlr_enabled); | ||
| 278 | 387 | ||
| 279 | static ssize_t | 388 | static ssize_t |
| 280 | store_private_fcoe_ctlr_fcf_dev_loss_tmo(struct device *dev, | 389 | store_private_fcoe_ctlr_fcf_dev_loss_tmo(struct device *dev, |
| @@ -359,6 +468,7 @@ static struct attribute_group fcoe_ctlr_lesb_attr_group = { | |||
| 359 | 468 | ||
| 360 | static struct attribute *fcoe_ctlr_attrs[] = { | 469 | static struct attribute *fcoe_ctlr_attrs[] = { |
| 361 | &device_attr_fcoe_ctlr_fcf_dev_loss_tmo.attr, | 470 | &device_attr_fcoe_ctlr_fcf_dev_loss_tmo.attr, |
| 471 | &device_attr_fcoe_ctlr_enabled.attr, | ||
| 362 | &device_attr_fcoe_ctlr_mode.attr, | 472 | &device_attr_fcoe_ctlr_mode.attr, |
| 363 | NULL, | 473 | NULL, |
| 364 | }; | 474 | }; |
| @@ -443,9 +553,16 @@ struct device_type fcoe_fcf_device_type = { | |||
| 443 | .release = fcoe_fcf_device_release, | 553 | .release = fcoe_fcf_device_release, |
| 444 | }; | 554 | }; |
| 445 | 555 | ||
| 556 | struct bus_attribute fcoe_bus_attr_group[] = { | ||
| 557 | __ATTR(ctlr_create, S_IWUSR, NULL, fcoe_ctlr_create_store), | ||
| 558 | __ATTR(ctlr_destroy, S_IWUSR, NULL, fcoe_ctlr_destroy_store), | ||
| 559 | __ATTR_NULL | ||
| 560 | }; | ||
| 561 | |||
| 446 | struct bus_type fcoe_bus_type = { | 562 | struct bus_type fcoe_bus_type = { |
| 447 | .name = "fcoe", | 563 | .name = "fcoe", |
| 448 | .match = &fcoe_bus_match, | 564 | .match = &fcoe_bus_match, |
| 565 | .bus_attrs = fcoe_bus_attr_group, | ||
| 449 | }; | 566 | }; |
| 450 | 567 | ||
| 451 | /** | 568 | /** |
| @@ -566,6 +683,7 @@ struct fcoe_ctlr_device *fcoe_ctlr_device_add(struct device *parent, | |||
| 566 | 683 | ||
| 567 | ctlr->id = atomic_inc_return(&ctlr_num) - 1; | 684 | ctlr->id = atomic_inc_return(&ctlr_num) - 1; |
| 568 | ctlr->f = f; | 685 | ctlr->f = f; |
| 686 | ctlr->mode = FIP_CONN_TYPE_FABRIC; | ||
| 569 | INIT_LIST_HEAD(&ctlr->fcfs); | 687 | INIT_LIST_HEAD(&ctlr->fcfs); |
| 570 | mutex_init(&ctlr->lock); | 688 | mutex_init(&ctlr->lock); |
| 571 | ctlr->dev.parent = parent; | 689 | ctlr->dev.parent = parent; |
