diff options
-rw-r--r-- | drivers/s390/scsi/Makefile | 2 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 425 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_cfdc.c | 259 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 43 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 8 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 246 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.h | 12 |
7 files changed, 331 insertions, 664 deletions
diff --git a/drivers/s390/scsi/Makefile b/drivers/s390/scsi/Makefile index f775f9e6030c..c0fa8ffe5448 100644 --- a/drivers/s390/scsi/Makefile +++ b/drivers/s390/scsi/Makefile | |||
@@ -4,6 +4,6 @@ | |||
4 | 4 | ||
5 | zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \ | 5 | zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \ |
6 | zfcp_fsf.o zfcp_dbf.o zfcp_sysfs_adapter.o zfcp_sysfs_port.o \ | 6 | zfcp_fsf.o zfcp_dbf.o zfcp_sysfs_adapter.o zfcp_sysfs_port.o \ |
7 | zfcp_sysfs_unit.o zfcp_sysfs_driver.o zfcp_fc.o | 7 | zfcp_sysfs_unit.o zfcp_sysfs_driver.o zfcp_fc.o zfcp_cfdc.o |
8 | 8 | ||
9 | obj-$(CONFIG_ZFCP) += zfcp.o | 9 | obj-$(CONFIG_ZFCP) += zfcp.o |
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 9eb8827e19e2..735f7af43d6a 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -33,6 +33,7 @@ | |||
33 | * Ralph Wuerthner | 33 | * Ralph Wuerthner |
34 | */ | 34 | */ |
35 | 35 | ||
36 | #include <linux/miscdevice.h> | ||
36 | #include "zfcp_ext.h" | 37 | #include "zfcp_ext.h" |
37 | 38 | ||
38 | /* accumulated log level (module parameter) */ | 39 | /* accumulated log level (module parameter) */ |
@@ -43,33 +44,6 @@ static char *device; | |||
43 | /* written against the module interface */ | 44 | /* written against the module interface */ |
44 | static int __init zfcp_module_init(void); | 45 | static int __init zfcp_module_init(void); |
45 | 46 | ||
46 | /* miscellaneous */ | ||
47 | static int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t); | ||
48 | static void zfcp_sg_list_free(struct zfcp_sg_list *); | ||
49 | static int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *, | ||
50 | void __user *, size_t); | ||
51 | static int zfcp_sg_list_copy_to_user(void __user *, | ||
52 | struct zfcp_sg_list *, size_t); | ||
53 | static long zfcp_cfdc_dev_ioctl(struct file *, unsigned int, unsigned long); | ||
54 | |||
55 | #define ZFCP_CFDC_IOC_MAGIC 0xDD | ||
56 | #define ZFCP_CFDC_IOC \ | ||
57 | _IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_sense_data) | ||
58 | |||
59 | |||
60 | static const struct file_operations zfcp_cfdc_fops = { | ||
61 | .unlocked_ioctl = zfcp_cfdc_dev_ioctl, | ||
62 | #ifdef CONFIG_COMPAT | ||
63 | .compat_ioctl = zfcp_cfdc_dev_ioctl | ||
64 | #endif | ||
65 | }; | ||
66 | |||
67 | static struct miscdevice zfcp_cfdc_misc = { | ||
68 | .minor = ZFCP_CFDC_DEV_MINOR, | ||
69 | .name = ZFCP_CFDC_DEV_NAME, | ||
70 | .fops = &zfcp_cfdc_fops | ||
71 | }; | ||
72 | |||
73 | /*********************** KERNEL/MODULE PARAMETERS ***************************/ | 47 | /*********************** KERNEL/MODULE PARAMETERS ***************************/ |
74 | 48 | ||
75 | /* declare driver module init/cleanup functions */ | 49 | /* declare driver module init/cleanup functions */ |
@@ -294,9 +268,6 @@ zfcp_module_init(void) | |||
294 | goto out_misc; | 268 | goto out_misc; |
295 | } | 269 | } |
296 | 270 | ||
297 | ZFCP_LOG_TRACE("major/minor for zfcp_cfdc: %d/%d\n", | ||
298 | ZFCP_CFDC_DEV_MAJOR, zfcp_cfdc_misc.minor); | ||
299 | |||
300 | /* Initialise proc semaphores */ | 271 | /* Initialise proc semaphores */ |
301 | sema_init(&zfcp_data.config_sema, 1); | 272 | sema_init(&zfcp_data.config_sema, 1); |
302 | 273 | ||
@@ -329,372 +300,6 @@ zfcp_module_init(void) | |||
329 | return retval; | 300 | return retval; |
330 | } | 301 | } |
331 | 302 | ||
332 | /* | ||
333 | * function: zfcp_cfdc_dev_ioctl | ||
334 | * | ||
335 | * purpose: Handle control file upload/download transaction via IOCTL | ||
336 | * interface | ||
337 | * | ||
338 | * returns: 0 - Operation completed successfuly | ||
339 | * -ENOTTY - Unknown IOCTL command | ||
340 | * -EINVAL - Invalid sense data record | ||
341 | * -ENXIO - The FCP adapter is not available | ||
342 | * -EOPNOTSUPP - The FCP adapter does not have CFDC support | ||
343 | * -ENOMEM - Insufficient memory | ||
344 | * -EFAULT - User space memory I/O operation fault | ||
345 | * -EPERM - Cannot create or queue FSF request or create SBALs | ||
346 | * -ERESTARTSYS- Received signal (is mapped to EAGAIN by VFS) | ||
347 | */ | ||
348 | static long | ||
349 | zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, | ||
350 | unsigned long buffer) | ||
351 | { | ||
352 | struct zfcp_cfdc_sense_data *sense_data, __user *sense_data_user; | ||
353 | struct zfcp_adapter *adapter = NULL; | ||
354 | struct zfcp_fsf_req *fsf_req = NULL; | ||
355 | struct zfcp_sg_list *sg_list = NULL; | ||
356 | u32 fsf_command, option; | ||
357 | char *bus_id = NULL; | ||
358 | int retval = 0; | ||
359 | |||
360 | sense_data = kmalloc(sizeof(struct zfcp_cfdc_sense_data), GFP_KERNEL); | ||
361 | if (sense_data == NULL) { | ||
362 | retval = -ENOMEM; | ||
363 | goto out; | ||
364 | } | ||
365 | |||
366 | sg_list = kzalloc(sizeof(struct zfcp_sg_list), GFP_KERNEL); | ||
367 | if (sg_list == NULL) { | ||
368 | retval = -ENOMEM; | ||
369 | goto out; | ||
370 | } | ||
371 | |||
372 | if (command != ZFCP_CFDC_IOC) { | ||
373 | ZFCP_LOG_INFO("IOC request code 0x%x invalid\n", command); | ||
374 | retval = -ENOTTY; | ||
375 | goto out; | ||
376 | } | ||
377 | |||
378 | if ((sense_data_user = (void __user *) buffer) == NULL) { | ||
379 | ZFCP_LOG_INFO("sense data record is required\n"); | ||
380 | retval = -EINVAL; | ||
381 | goto out; | ||
382 | } | ||
383 | |||
384 | retval = copy_from_user(sense_data, sense_data_user, | ||
385 | sizeof(struct zfcp_cfdc_sense_data)); | ||
386 | if (retval) { | ||
387 | retval = -EFAULT; | ||
388 | goto out; | ||
389 | } | ||
390 | |||
391 | if (sense_data->signature != ZFCP_CFDC_SIGNATURE) { | ||
392 | ZFCP_LOG_INFO("invalid sense data request signature 0x%08x\n", | ||
393 | ZFCP_CFDC_SIGNATURE); | ||
394 | retval = -EINVAL; | ||
395 | goto out; | ||
396 | } | ||
397 | |||
398 | switch (sense_data->command) { | ||
399 | |||
400 | case ZFCP_CFDC_CMND_DOWNLOAD_NORMAL: | ||
401 | fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
402 | option = FSF_CFDC_OPTION_NORMAL_MODE; | ||
403 | break; | ||
404 | |||
405 | case ZFCP_CFDC_CMND_DOWNLOAD_FORCE: | ||
406 | fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
407 | option = FSF_CFDC_OPTION_FORCE; | ||
408 | break; | ||
409 | |||
410 | case ZFCP_CFDC_CMND_FULL_ACCESS: | ||
411 | fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
412 | option = FSF_CFDC_OPTION_FULL_ACCESS; | ||
413 | break; | ||
414 | |||
415 | case ZFCP_CFDC_CMND_RESTRICTED_ACCESS: | ||
416 | fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
417 | option = FSF_CFDC_OPTION_RESTRICTED_ACCESS; | ||
418 | break; | ||
419 | |||
420 | case ZFCP_CFDC_CMND_UPLOAD: | ||
421 | fsf_command = FSF_QTCB_UPLOAD_CONTROL_FILE; | ||
422 | option = 0; | ||
423 | break; | ||
424 | |||
425 | default: | ||
426 | ZFCP_LOG_INFO("invalid command code 0x%08x\n", | ||
427 | sense_data->command); | ||
428 | retval = -EINVAL; | ||
429 | goto out; | ||
430 | } | ||
431 | |||
432 | bus_id = kmalloc(BUS_ID_SIZE, GFP_KERNEL); | ||
433 | if (bus_id == NULL) { | ||
434 | retval = -ENOMEM; | ||
435 | goto out; | ||
436 | } | ||
437 | snprintf(bus_id, BUS_ID_SIZE, "%d.%d.%04x", | ||
438 | (sense_data->devno >> 24), | ||
439 | (sense_data->devno >> 16) & 0xFF, | ||
440 | (sense_data->devno & 0xFFFF)); | ||
441 | |||
442 | read_lock_irq(&zfcp_data.config_lock); | ||
443 | adapter = zfcp_get_adapter_by_busid(bus_id); | ||
444 | if (adapter) | ||
445 | zfcp_adapter_get(adapter); | ||
446 | read_unlock_irq(&zfcp_data.config_lock); | ||
447 | |||
448 | kfree(bus_id); | ||
449 | |||
450 | if (adapter == NULL) { | ||
451 | ZFCP_LOG_INFO("invalid adapter\n"); | ||
452 | retval = -ENXIO; | ||
453 | goto out; | ||
454 | } | ||
455 | |||
456 | if (sense_data->command & ZFCP_CFDC_WITH_CONTROL_FILE) { | ||
457 | retval = zfcp_sg_list_alloc(sg_list, | ||
458 | ZFCP_CFDC_MAX_CONTROL_FILE_SIZE); | ||
459 | if (retval) { | ||
460 | retval = -ENOMEM; | ||
461 | goto out; | ||
462 | } | ||
463 | } | ||
464 | |||
465 | if ((sense_data->command & ZFCP_CFDC_DOWNLOAD) && | ||
466 | (sense_data->command & ZFCP_CFDC_WITH_CONTROL_FILE)) { | ||
467 | retval = zfcp_sg_list_copy_from_user( | ||
468 | sg_list, &sense_data_user->control_file, | ||
469 | ZFCP_CFDC_MAX_CONTROL_FILE_SIZE); | ||
470 | if (retval) { | ||
471 | retval = -EFAULT; | ||
472 | goto out; | ||
473 | } | ||
474 | } | ||
475 | |||
476 | retval = zfcp_fsf_control_file(adapter, &fsf_req, fsf_command, | ||
477 | option, sg_list); | ||
478 | if (retval) | ||
479 | goto out; | ||
480 | |||
481 | if ((fsf_req->qtcb->prefix.prot_status != FSF_PROT_GOOD) && | ||
482 | (fsf_req->qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) { | ||
483 | retval = -ENXIO; | ||
484 | goto out; | ||
485 | } | ||
486 | |||
487 | sense_data->fsf_status = fsf_req->qtcb->header.fsf_status; | ||
488 | memcpy(&sense_data->fsf_status_qual, | ||
489 | &fsf_req->qtcb->header.fsf_status_qual, | ||
490 | sizeof(union fsf_status_qual)); | ||
491 | memcpy(&sense_data->payloads, &fsf_req->qtcb->bottom.support.els, 256); | ||
492 | |||
493 | retval = copy_to_user(sense_data_user, sense_data, | ||
494 | sizeof(struct zfcp_cfdc_sense_data)); | ||
495 | if (retval) { | ||
496 | retval = -EFAULT; | ||
497 | goto out; | ||
498 | } | ||
499 | |||
500 | if (sense_data->command & ZFCP_CFDC_UPLOAD) { | ||
501 | retval = zfcp_sg_list_copy_to_user( | ||
502 | &sense_data_user->control_file, sg_list, | ||
503 | ZFCP_CFDC_MAX_CONTROL_FILE_SIZE); | ||
504 | if (retval) { | ||
505 | retval = -EFAULT; | ||
506 | goto out; | ||
507 | } | ||
508 | } | ||
509 | |||
510 | out: | ||
511 | if (fsf_req != NULL) | ||
512 | zfcp_fsf_req_free(fsf_req); | ||
513 | |||
514 | if ((adapter != NULL) && (retval != -ENXIO)) | ||
515 | zfcp_adapter_put(adapter); | ||
516 | |||
517 | if (sg_list != NULL) { | ||
518 | zfcp_sg_list_free(sg_list); | ||
519 | kfree(sg_list); | ||
520 | } | ||
521 | |||
522 | kfree(sense_data); | ||
523 | |||
524 | return retval; | ||
525 | } | ||
526 | |||
527 | |||
528 | /** | ||
529 | * zfcp_sg_list_alloc - create a scatter-gather list of the specified size | ||
530 | * @sg_list: structure describing a scatter gather list | ||
531 | * @size: size of scatter-gather list | ||
532 | * Return: 0 on success, else -ENOMEM | ||
533 | * | ||
534 | * In sg_list->sg a pointer to the created scatter-gather list is returned, | ||
535 | * or NULL if we run out of memory. sg_list->count specifies the number of | ||
536 | * elements of the scatter-gather list. The maximum size of a single element | ||
537 | * in the scatter-gather list is PAGE_SIZE. | ||
538 | */ | ||
539 | static int | ||
540 | zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size) | ||
541 | { | ||
542 | struct scatterlist *sg; | ||
543 | unsigned int i; | ||
544 | int retval = 0; | ||
545 | void *address; | ||
546 | |||
547 | BUG_ON(sg_list == NULL); | ||
548 | |||
549 | sg_list->count = size >> PAGE_SHIFT; | ||
550 | if (size & ~PAGE_MASK) | ||
551 | sg_list->count++; | ||
552 | sg_list->sg = kcalloc(sg_list->count, sizeof(struct scatterlist), | ||
553 | GFP_KERNEL); | ||
554 | if (sg_list->sg == NULL) { | ||
555 | sg_list->count = 0; | ||
556 | retval = -ENOMEM; | ||
557 | goto out; | ||
558 | } | ||
559 | sg_init_table(sg_list->sg, sg_list->count); | ||
560 | |||
561 | for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) { | ||
562 | address = (void *) get_zeroed_page(GFP_KERNEL); | ||
563 | if (address == NULL) { | ||
564 | sg_list->count = i; | ||
565 | zfcp_sg_list_free(sg_list); | ||
566 | retval = -ENOMEM; | ||
567 | goto out; | ||
568 | } | ||
569 | zfcp_address_to_sg(address, sg, min(size, PAGE_SIZE)); | ||
570 | size -= sg->length; | ||
571 | } | ||
572 | |||
573 | out: | ||
574 | return retval; | ||
575 | } | ||
576 | |||
577 | |||
578 | /** | ||
579 | * zfcp_sg_list_free - free memory of a scatter-gather list | ||
580 | * @sg_list: structure describing a scatter-gather list | ||
581 | * | ||
582 | * Memory for each element in the scatter-gather list is freed. | ||
583 | * Finally sg_list->sg is freed itself and sg_list->count is reset. | ||
584 | */ | ||
585 | static void | ||
586 | zfcp_sg_list_free(struct zfcp_sg_list *sg_list) | ||
587 | { | ||
588 | struct scatterlist *sg; | ||
589 | unsigned int i; | ||
590 | |||
591 | BUG_ON(sg_list == NULL); | ||
592 | |||
593 | for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) | ||
594 | free_page((unsigned long) zfcp_sg_to_address(sg)); | ||
595 | |||
596 | sg_list->count = 0; | ||
597 | kfree(sg_list->sg); | ||
598 | } | ||
599 | |||
600 | /** | ||
601 | * zfcp_sg_size - determine size of a scatter-gather list | ||
602 | * @sg: array of (struct scatterlist) | ||
603 | * @sg_count: elements in array | ||
604 | * Return: size of entire scatter-gather list | ||
605 | */ | ||
606 | static size_t zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count) | ||
607 | { | ||
608 | unsigned int i; | ||
609 | struct scatterlist *p; | ||
610 | size_t size; | ||
611 | |||
612 | size = 0; | ||
613 | for (i = 0, p = sg; i < sg_count; i++, p++) { | ||
614 | BUG_ON(p == NULL); | ||
615 | size += p->length; | ||
616 | } | ||
617 | |||
618 | return size; | ||
619 | } | ||
620 | |||
621 | |||
622 | /** | ||
623 | * zfcp_sg_list_copy_from_user -copy data from user space to scatter-gather list | ||
624 | * @sg_list: structure describing a scatter-gather list | ||
625 | * @user_buffer: pointer to buffer in user space | ||
626 | * @size: number of bytes to be copied | ||
627 | * Return: 0 on success, -EFAULT if copy_from_user fails. | ||
628 | */ | ||
629 | static int | ||
630 | zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, | ||
631 | void __user *user_buffer, | ||
632 | size_t size) | ||
633 | { | ||
634 | struct scatterlist *sg; | ||
635 | unsigned int length; | ||
636 | void *zfcp_buffer; | ||
637 | int retval = 0; | ||
638 | |||
639 | BUG_ON(sg_list == NULL); | ||
640 | |||
641 | if (zfcp_sg_size(sg_list->sg, sg_list->count) < size) | ||
642 | return -EFAULT; | ||
643 | |||
644 | for (sg = sg_list->sg; size > 0; sg++) { | ||
645 | length = min((unsigned int)size, sg->length); | ||
646 | zfcp_buffer = zfcp_sg_to_address(sg); | ||
647 | if (copy_from_user(zfcp_buffer, user_buffer, length)) { | ||
648 | retval = -EFAULT; | ||
649 | goto out; | ||
650 | } | ||
651 | user_buffer += length; | ||
652 | size -= length; | ||
653 | } | ||
654 | |||
655 | out: | ||
656 | return retval; | ||
657 | } | ||
658 | |||
659 | |||
660 | /** | ||
661 | * zfcp_sg_list_copy_to_user - copy data from scatter-gather list to user space | ||
662 | * @user_buffer: pointer to buffer in user space | ||
663 | * @sg_list: structure describing a scatter-gather list | ||
664 | * @size: number of bytes to be copied | ||
665 | * Return: 0 on success, -EFAULT if copy_to_user fails | ||
666 | */ | ||
667 | static int | ||
668 | zfcp_sg_list_copy_to_user(void __user *user_buffer, | ||
669 | struct zfcp_sg_list *sg_list, | ||
670 | size_t size) | ||
671 | { | ||
672 | struct scatterlist *sg; | ||
673 | unsigned int length; | ||
674 | void *zfcp_buffer; | ||
675 | int retval = 0; | ||
676 | |||
677 | BUG_ON(sg_list == NULL); | ||
678 | |||
679 | if (zfcp_sg_size(sg_list->sg, sg_list->count) < size) | ||
680 | return -EFAULT; | ||
681 | |||
682 | for (sg = sg_list->sg; size > 0; sg++) { | ||
683 | length = min((unsigned int) size, sg->length); | ||
684 | zfcp_buffer = zfcp_sg_to_address(sg); | ||
685 | if (copy_to_user(user_buffer, zfcp_buffer, length)) { | ||
686 | retval = -EFAULT; | ||
687 | goto out; | ||
688 | } | ||
689 | user_buffer += length; | ||
690 | size -= length; | ||
691 | } | ||
692 | |||
693 | out: | ||
694 | return retval; | ||
695 | } | ||
696 | |||
697 | |||
698 | #undef ZFCP_LOG_AREA | 303 | #undef ZFCP_LOG_AREA |
699 | 304 | ||
700 | /****************************************************************/ | 305 | /****************************************************************/ |
@@ -1345,4 +950,32 @@ zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) | |||
1345 | return 0; | 950 | return 0; |
1346 | } | 951 | } |
1347 | 952 | ||
953 | void zfcp_sg_free_table(struct scatterlist *sg, int count) | ||
954 | { | ||
955 | int i; | ||
956 | |||
957 | for (i = 0; i < count; i++, sg++) | ||
958 | if (sg) | ||
959 | free_page((unsigned long) sg_virt(sg)); | ||
960 | else | ||
961 | break; | ||
962 | } | ||
963 | |||
964 | int zfcp_sg_setup_table(struct scatterlist *sg, int count) | ||
965 | { | ||
966 | void *addr; | ||
967 | int i; | ||
968 | |||
969 | sg_init_table(sg, count); | ||
970 | for (i = 0; i < count; i++, sg++) { | ||
971 | addr = (void *) get_zeroed_page(GFP_KERNEL); | ||
972 | if (!addr) { | ||
973 | zfcp_sg_free_table(sg, i); | ||
974 | return -ENOMEM; | ||
975 | } | ||
976 | sg_set_buf(sg, addr, PAGE_SIZE); | ||
977 | } | ||
978 | return 0; | ||
979 | } | ||
980 | |||
1348 | #undef ZFCP_LOG_AREA | 981 | #undef ZFCP_LOG_AREA |
diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c new file mode 100644 index 000000000000..ec2abceca6dc --- /dev/null +++ b/drivers/s390/scsi/zfcp_cfdc.c | |||
@@ -0,0 +1,259 @@ | |||
1 | /* | ||
2 | * zfcp device driver | ||
3 | * | ||
4 | * Userspace interface for accessing the | ||
5 | * Access Control Lists / Control File Data Channel | ||
6 | * | ||
7 | * Copyright IBM Corporation 2008 | ||
8 | */ | ||
9 | |||
10 | #include <linux/types.h> | ||
11 | #include <linux/miscdevice.h> | ||
12 | #include <asm/ccwdev.h> | ||
13 | #include "zfcp_def.h" | ||
14 | #include "zfcp_ext.h" | ||
15 | #include "zfcp_fsf.h" | ||
16 | |||
17 | #define ZFCP_CFDC_CMND_DOWNLOAD_NORMAL 0x00010001 | ||
18 | #define ZFCP_CFDC_CMND_DOWNLOAD_FORCE 0x00010101 | ||
19 | #define ZFCP_CFDC_CMND_FULL_ACCESS 0x00000201 | ||
20 | #define ZFCP_CFDC_CMND_RESTRICTED_ACCESS 0x00000401 | ||
21 | #define ZFCP_CFDC_CMND_UPLOAD 0x00010002 | ||
22 | |||
23 | #define ZFCP_CFDC_DOWNLOAD 0x00000001 | ||
24 | #define ZFCP_CFDC_UPLOAD 0x00000002 | ||
25 | #define ZFCP_CFDC_WITH_CONTROL_FILE 0x00010000 | ||
26 | |||
27 | #define ZFCP_CFDC_IOC_MAGIC 0xDD | ||
28 | #define ZFCP_CFDC_IOC \ | ||
29 | _IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_data) | ||
30 | |||
31 | /** | ||
32 | * struct zfcp_cfdc_data - data for ioctl cfdc interface | ||
33 | * @signature: request signature | ||
34 | * @devno: FCP adapter device number | ||
35 | * @command: command code | ||
36 | * @fsf_status: returns status of FSF command to userspace | ||
37 | * @fsf_status_qual: returned to userspace | ||
38 | * @payloads: access conflicts list | ||
39 | * @control_file: access control table | ||
40 | */ | ||
41 | struct zfcp_cfdc_data { | ||
42 | u32 signature; | ||
43 | u32 devno; | ||
44 | u32 command; | ||
45 | u32 fsf_status; | ||
46 | u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; | ||
47 | u8 payloads[256]; | ||
48 | u8 control_file[0]; | ||
49 | }; | ||
50 | |||
51 | static int zfcp_cfdc_copy_from_user(struct scatterlist *sg, | ||
52 | void __user *user_buffer) | ||
53 | { | ||
54 | unsigned int length; | ||
55 | unsigned int size = ZFCP_CFDC_MAX_SIZE; | ||
56 | |||
57 | while (size) { | ||
58 | length = min((unsigned int)size, sg->length); | ||
59 | if (copy_from_user(sg_virt(sg++), user_buffer, length)) | ||
60 | return -EFAULT; | ||
61 | user_buffer += length; | ||
62 | size -= length; | ||
63 | } | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static int zfcp_cfdc_copy_to_user(void __user *user_buffer, | ||
68 | struct scatterlist *sg) | ||
69 | { | ||
70 | unsigned int length; | ||
71 | unsigned int size = ZFCP_CFDC_MAX_SIZE; | ||
72 | |||
73 | while (size) { | ||
74 | length = min((unsigned int) size, sg->length); | ||
75 | if (copy_to_user(user_buffer, sg_virt(sg++), length)) | ||
76 | return -EFAULT; | ||
77 | user_buffer += length; | ||
78 | size -= length; | ||
79 | } | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static struct zfcp_adapter *zfcp_cfdc_get_adapter(u32 devno) | ||
84 | { | ||
85 | struct zfcp_adapter *adapter = NULL, *cur_adapter; | ||
86 | struct ccw_dev_id dev_id; | ||
87 | |||
88 | read_lock_irq(&zfcp_data.config_lock); | ||
89 | list_for_each_entry(cur_adapter, &zfcp_data.adapter_list_head, list) { | ||
90 | ccw_device_get_id(cur_adapter->ccw_device, &dev_id); | ||
91 | if (dev_id.devno == devno) { | ||
92 | adapter = cur_adapter; | ||
93 | zfcp_adapter_get(adapter); | ||
94 | break; | ||
95 | } | ||
96 | } | ||
97 | read_unlock_irq(&zfcp_data.config_lock); | ||
98 | return adapter; | ||
99 | } | ||
100 | |||
101 | static int zfcp_cfdc_set_fsf(struct zfcp_fsf_cfdc *fsf_cfdc, int command) | ||
102 | { | ||
103 | switch (command) { | ||
104 | case ZFCP_CFDC_CMND_DOWNLOAD_NORMAL: | ||
105 | fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
106 | fsf_cfdc->option = FSF_CFDC_OPTION_NORMAL_MODE; | ||
107 | break; | ||
108 | case ZFCP_CFDC_CMND_DOWNLOAD_FORCE: | ||
109 | fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
110 | fsf_cfdc->option = FSF_CFDC_OPTION_FORCE; | ||
111 | break; | ||
112 | case ZFCP_CFDC_CMND_FULL_ACCESS: | ||
113 | fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
114 | fsf_cfdc->option = FSF_CFDC_OPTION_FULL_ACCESS; | ||
115 | break; | ||
116 | case ZFCP_CFDC_CMND_RESTRICTED_ACCESS: | ||
117 | fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
118 | fsf_cfdc->option = FSF_CFDC_OPTION_RESTRICTED_ACCESS; | ||
119 | break; | ||
120 | case ZFCP_CFDC_CMND_UPLOAD: | ||
121 | fsf_cfdc->command = FSF_QTCB_UPLOAD_CONTROL_FILE; | ||
122 | fsf_cfdc->option = 0; | ||
123 | break; | ||
124 | default: | ||
125 | return -EINVAL; | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int zfcp_cfdc_sg_setup(int command, struct scatterlist *sg, | ||
132 | u8 __user *control_file) | ||
133 | { | ||
134 | int retval; | ||
135 | retval = zfcp_sg_setup_table(sg, ZFCP_CFDC_PAGES); | ||
136 | if (retval) | ||
137 | return retval; | ||
138 | |||
139 | sg[ZFCP_CFDC_PAGES - 1].length = ZFCP_CFDC_MAX_SIZE % PAGE_SIZE; | ||
140 | |||
141 | if (command & ZFCP_CFDC_WITH_CONTROL_FILE && | ||
142 | command & ZFCP_CFDC_DOWNLOAD) { | ||
143 | retval = zfcp_cfdc_copy_from_user(sg, control_file); | ||
144 | if (retval) { | ||
145 | zfcp_sg_free_table(sg, ZFCP_CFDC_PAGES); | ||
146 | return -EFAULT; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static void zfcp_cfdc_req_to_sense(struct zfcp_cfdc_data *data, | ||
154 | struct zfcp_fsf_req *req) | ||
155 | { | ||
156 | data->fsf_status = req->qtcb->header.fsf_status; | ||
157 | memcpy(&data->fsf_status_qual, &req->qtcb->header.fsf_status_qual, | ||
158 | sizeof(union fsf_status_qual)); | ||
159 | memcpy(&data->payloads, &req->qtcb->bottom.support.els, | ||
160 | sizeof(req->qtcb->bottom.support.els)); | ||
161 | } | ||
162 | |||
163 | static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, | ||
164 | unsigned long buffer) | ||
165 | { | ||
166 | struct zfcp_cfdc_data *data; | ||
167 | struct zfcp_cfdc_data __user *data_user; | ||
168 | struct zfcp_adapter *adapter; | ||
169 | struct zfcp_fsf_req *req; | ||
170 | struct zfcp_fsf_cfdc *fsf_cfdc; | ||
171 | int retval; | ||
172 | |||
173 | if (command != ZFCP_CFDC_IOC) | ||
174 | return -ENOTTY; | ||
175 | |||
176 | data_user = (void __user *) buffer; | ||
177 | if (!data_user) | ||
178 | return -EINVAL; | ||
179 | |||
180 | fsf_cfdc = kmalloc(sizeof(struct zfcp_fsf_cfdc), GFP_KERNEL); | ||
181 | if (!fsf_cfdc) | ||
182 | return -ENOMEM; | ||
183 | |||
184 | data = kmalloc(sizeof(struct zfcp_cfdc_data), GFP_KERNEL); | ||
185 | if (!data) { | ||
186 | retval = -ENOMEM; | ||
187 | goto no_mem_sense; | ||
188 | } | ||
189 | |||
190 | retval = copy_from_user(data, data_user, sizeof(*data)); | ||
191 | if (retval) { | ||
192 | retval = -EFAULT; | ||
193 | goto free_buffer; | ||
194 | } | ||
195 | |||
196 | if (data->signature != 0xCFDCACDF) { | ||
197 | retval = -EINVAL; | ||
198 | goto free_buffer; | ||
199 | } | ||
200 | |||
201 | retval = zfcp_cfdc_set_fsf(fsf_cfdc, data->command); | ||
202 | |||
203 | adapter = zfcp_cfdc_get_adapter(data->devno); | ||
204 | if (!adapter) { | ||
205 | retval = -ENXIO; | ||
206 | goto free_buffer; | ||
207 | } | ||
208 | |||
209 | retval = zfcp_cfdc_sg_setup(data->command, fsf_cfdc->sg, | ||
210 | data_user->control_file); | ||
211 | if (retval) | ||
212 | goto adapter_put; | ||
213 | req = zfcp_fsf_control_file(adapter, fsf_cfdc); | ||
214 | if (IS_ERR(req)) { | ||
215 | retval = PTR_ERR(req); | ||
216 | goto free_sg; | ||
217 | } | ||
218 | |||
219 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) { | ||
220 | retval = -ENXIO; | ||
221 | goto free_fsf; | ||
222 | } | ||
223 | |||
224 | zfcp_cfdc_req_to_sense(data, req); | ||
225 | retval = copy_to_user(data_user, data, sizeof(*data_user)); | ||
226 | if (retval) { | ||
227 | retval = -EFAULT; | ||
228 | goto free_fsf; | ||
229 | } | ||
230 | |||
231 | if (data->command & ZFCP_CFDC_UPLOAD) | ||
232 | retval = zfcp_cfdc_copy_to_user(&data_user->control_file, | ||
233 | fsf_cfdc->sg); | ||
234 | |||
235 | free_fsf: | ||
236 | zfcp_fsf_req_free(req); | ||
237 | free_sg: | ||
238 | zfcp_sg_free_table(fsf_cfdc->sg, ZFCP_CFDC_PAGES); | ||
239 | adapter_put: | ||
240 | zfcp_adapter_put(adapter); | ||
241 | free_buffer: | ||
242 | kfree(data); | ||
243 | no_mem_sense: | ||
244 | kfree(fsf_cfdc); | ||
245 | return retval; | ||
246 | } | ||
247 | |||
248 | static const struct file_operations zfcp_cfdc_fops = { | ||
249 | .unlocked_ioctl = zfcp_cfdc_dev_ioctl, | ||
250 | #ifdef CONFIG_COMPAT | ||
251 | .compat_ioctl = zfcp_cfdc_dev_ioctl | ||
252 | #endif | ||
253 | }; | ||
254 | |||
255 | struct miscdevice zfcp_cfdc_misc = { | ||
256 | .minor = MISC_DYNAMIC_MINOR, | ||
257 | .name = "zfcp_cfdc", | ||
258 | .fops = &zfcp_cfdc_fops, | ||
259 | }; | ||
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index d23c3b9b283e..72f225817ebd 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
@@ -26,7 +26,6 @@ | |||
26 | 26 | ||
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/moduleparam.h> | 28 | #include <linux/moduleparam.h> |
29 | #include <linux/miscdevice.h> | ||
30 | #include <linux/major.h> | 29 | #include <linux/major.h> |
31 | #include <linux/blkdev.h> | 30 | #include <linux/blkdev.h> |
32 | #include <linux/delay.h> | 31 | #include <linux/delay.h> |
@@ -534,38 +533,6 @@ do { \ | |||
534 | #define ZFCP_ERP_DISMISSED 0x4 | 533 | #define ZFCP_ERP_DISMISSED 0x4 |
535 | #define ZFCP_ERP_NOMEM 0x5 | 534 | #define ZFCP_ERP_NOMEM 0x5 |
536 | 535 | ||
537 | |||
538 | /******************** CFDC SPECIFIC STUFF *****************************/ | ||
539 | |||
540 | /* Firewall data channel sense data record */ | ||
541 | struct zfcp_cfdc_sense_data { | ||
542 | u32 signature; /* Request signature */ | ||
543 | u32 devno; /* FCP adapter device number */ | ||
544 | u32 command; /* Command code */ | ||
545 | u32 fsf_status; /* FSF request status and status qualifier */ | ||
546 | u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; | ||
547 | u8 payloads[256]; /* Access conflicts list */ | ||
548 | u8 control_file[0]; /* Access control table */ | ||
549 | }; | ||
550 | |||
551 | #define ZFCP_CFDC_SIGNATURE 0xCFDCACDF | ||
552 | |||
553 | #define ZFCP_CFDC_CMND_DOWNLOAD_NORMAL 0x00010001 | ||
554 | #define ZFCP_CFDC_CMND_DOWNLOAD_FORCE 0x00010101 | ||
555 | #define ZFCP_CFDC_CMND_FULL_ACCESS 0x00000201 | ||
556 | #define ZFCP_CFDC_CMND_RESTRICTED_ACCESS 0x00000401 | ||
557 | #define ZFCP_CFDC_CMND_UPLOAD 0x00010002 | ||
558 | |||
559 | #define ZFCP_CFDC_DOWNLOAD 0x00000001 | ||
560 | #define ZFCP_CFDC_UPLOAD 0x00000002 | ||
561 | #define ZFCP_CFDC_WITH_CONTROL_FILE 0x00010000 | ||
562 | |||
563 | #define ZFCP_CFDC_DEV_NAME "zfcp_cfdc" | ||
564 | #define ZFCP_CFDC_DEV_MAJOR MISC_MAJOR | ||
565 | #define ZFCP_CFDC_DEV_MINOR MISC_DYNAMIC_MINOR | ||
566 | |||
567 | #define ZFCP_CFDC_MAX_CONTROL_FILE_SIZE 127 * 1024 | ||
568 | |||
569 | /************************* STRUCTURE DEFINITIONS *****************************/ | 536 | /************************* STRUCTURE DEFINITIONS *****************************/ |
570 | 537 | ||
571 | struct zfcp_fsf_req; | 538 | struct zfcp_fsf_req; |
@@ -897,16 +864,6 @@ struct zfcp_data { | |||
897 | struct kmem_cache *gid_pn_cache; | 864 | struct kmem_cache *gid_pn_cache; |
898 | }; | 865 | }; |
899 | 866 | ||
900 | /** | ||
901 | * struct zfcp_sg_list - struct describing a scatter-gather list | ||
902 | * @sg: pointer to array of (struct scatterlist) | ||
903 | * @count: number of elements in scatter-gather list | ||
904 | */ | ||
905 | struct zfcp_sg_list { | ||
906 | struct scatterlist *sg; | ||
907 | unsigned int count; | ||
908 | }; | ||
909 | |||
910 | /* number of elements for various memory pools */ | 867 | /* number of elements for various memory pools */ |
911 | #define ZFCP_POOL_FSF_REQ_ERP_NR 1 | 868 | #define ZFCP_POOL_FSF_REQ_ERP_NR 1 |
912 | #define ZFCP_POOL_FSF_REQ_SCSI_NR 1 | 869 | #define ZFCP_POOL_FSF_REQ_SCSI_NR 1 |
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 91d58843205c..867972898cb1 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -86,8 +86,8 @@ extern int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *, | |||
86 | extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *); | 86 | extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *); |
87 | extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *, | 87 | extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *, |
88 | struct fsf_qtcb_bottom_port *); | 88 | struct fsf_qtcb_bottom_port *); |
89 | extern int zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **, | 89 | extern struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, |
90 | u32, u32, struct zfcp_sg_list *); | 90 | struct zfcp_fsf_cfdc *fsf_cfdc); |
91 | extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long); | 91 | extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long); |
92 | extern void zfcp_erp_start_timer(struct zfcp_fsf_req *); | 92 | extern void zfcp_erp_start_timer(struct zfcp_fsf_req *); |
93 | extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); | 93 | extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); |
@@ -167,6 +167,8 @@ extern void zfcp_erp_port_access_changed(struct zfcp_port *, u8, void *); | |||
167 | extern void zfcp_erp_unit_access_changed(struct zfcp_unit *, u8, void *); | 167 | extern void zfcp_erp_unit_access_changed(struct zfcp_unit *, u8, void *); |
168 | 168 | ||
169 | /******************************** AUX ****************************************/ | 169 | /******************************** AUX ****************************************/ |
170 | extern void zfcp_sg_free_table(struct scatterlist *sg, int count); | ||
171 | extern int zfcp_sg_setup_table(struct scatterlist *sg, int count); | ||
170 | extern void zfcp_rec_dbf_event_thread(u8 id, struct zfcp_adapter *adapter); | 172 | extern void zfcp_rec_dbf_event_thread(u8 id, struct zfcp_adapter *adapter); |
171 | extern void zfcp_rec_dbf_event_thread_lock(u8 id, struct zfcp_adapter *adapter); | 173 | extern void zfcp_rec_dbf_event_thread_lock(u8 id, struct zfcp_adapter *adapter); |
172 | extern void zfcp_rec_dbf_event_adapter(u8 id, void *ref, struct zfcp_adapter *); | 174 | extern void zfcp_rec_dbf_event_adapter(u8 id, void *ref, struct zfcp_adapter *); |
@@ -200,4 +202,6 @@ extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *, | |||
200 | struct scsi_cmnd *); | 202 | struct scsi_cmnd *); |
201 | extern int zfcp_reqlist_isempty(struct zfcp_adapter *); | 203 | extern int zfcp_reqlist_isempty(struct zfcp_adapter *); |
202 | 204 | ||
205 | extern struct miscdevice zfcp_cfdc_misc; | ||
206 | |||
203 | #endif /* ZFCP_EXT_H */ | 207 | #endif /* ZFCP_EXT_H */ |
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 8568b6f3f27c..de42a01fc4b1 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -36,7 +36,7 @@ static int zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *); | |||
36 | static int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *); | 36 | static int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *); |
37 | static int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *); | 37 | static int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *); |
38 | static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *); | 38 | static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *); |
39 | static int zfcp_fsf_control_file_handler(struct zfcp_fsf_req *); | 39 | static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *); |
40 | static inline int zfcp_fsf_req_sbal_check( | 40 | static inline int zfcp_fsf_req_sbal_check( |
41 | unsigned long *, struct zfcp_qdio_queue *, int); | 41 | unsigned long *, struct zfcp_qdio_queue *, int); |
42 | static inline int zfcp_use_one_sbal( | 42 | static inline int zfcp_use_one_sbal( |
@@ -4183,53 +4183,35 @@ zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req) | |||
4183 | * -ENOMEM - Insufficient memory | 4183 | * -ENOMEM - Insufficient memory |
4184 | * -EPERM - Cannot create FSF request or place it in QDIO queue | 4184 | * -EPERM - Cannot create FSF request or place it in QDIO queue |
4185 | */ | 4185 | */ |
4186 | int | 4186 | struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, |
4187 | zfcp_fsf_control_file(struct zfcp_adapter *adapter, | 4187 | struct zfcp_fsf_cfdc *fsf_cfdc) |
4188 | struct zfcp_fsf_req **fsf_req_ptr, | ||
4189 | u32 fsf_command, | ||
4190 | u32 option, | ||
4191 | struct zfcp_sg_list *sg_list) | ||
4192 | { | 4188 | { |
4193 | struct zfcp_fsf_req *fsf_req; | 4189 | struct zfcp_fsf_req *fsf_req; |
4194 | struct fsf_qtcb_bottom_support *bottom; | 4190 | struct fsf_qtcb_bottom_support *bottom; |
4195 | volatile struct qdio_buffer_element *sbale; | 4191 | volatile struct qdio_buffer_element *sbale; |
4196 | unsigned long lock_flags; | 4192 | unsigned long lock_flags; |
4197 | int req_flags = 0; | ||
4198 | int direction; | 4193 | int direction; |
4199 | int retval = 0; | 4194 | int retval; |
4200 | 4195 | int bytes; | |
4201 | if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) { | ||
4202 | ZFCP_LOG_INFO("cfdc not supported (adapter %s)\n", | ||
4203 | zfcp_get_busid_by_adapter(adapter)); | ||
4204 | retval = -EOPNOTSUPP; | ||
4205 | goto out; | ||
4206 | } | ||
4207 | 4196 | ||
4208 | switch (fsf_command) { | 4197 | if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) |
4198 | return ERR_PTR(-EOPNOTSUPP); | ||
4209 | 4199 | ||
4200 | switch (fsf_cfdc->command) { | ||
4210 | case FSF_QTCB_DOWNLOAD_CONTROL_FILE: | 4201 | case FSF_QTCB_DOWNLOAD_CONTROL_FILE: |
4211 | direction = SBAL_FLAGS0_TYPE_WRITE; | 4202 | direction = SBAL_FLAGS0_TYPE_WRITE; |
4212 | if ((option != FSF_CFDC_OPTION_FULL_ACCESS) && | ||
4213 | (option != FSF_CFDC_OPTION_RESTRICTED_ACCESS)) | ||
4214 | req_flags = ZFCP_WAIT_FOR_SBAL; | ||
4215 | break; | 4203 | break; |
4216 | |||
4217 | case FSF_QTCB_UPLOAD_CONTROL_FILE: | 4204 | case FSF_QTCB_UPLOAD_CONTROL_FILE: |
4218 | direction = SBAL_FLAGS0_TYPE_READ; | 4205 | direction = SBAL_FLAGS0_TYPE_READ; |
4219 | break; | 4206 | break; |
4220 | |||
4221 | default: | 4207 | default: |
4222 | ZFCP_LOG_INFO("Invalid FSF command code 0x%08x\n", fsf_command); | 4208 | return ERR_PTR(-EINVAL); |
4223 | retval = -EINVAL; | ||
4224 | goto out; | ||
4225 | } | 4209 | } |
4226 | 4210 | ||
4227 | retval = zfcp_fsf_req_create(adapter, fsf_command, req_flags, | 4211 | retval = zfcp_fsf_req_create(adapter, fsf_cfdc->command, |
4212 | ZFCP_WAIT_FOR_SBAL, | ||
4228 | NULL, &lock_flags, &fsf_req); | 4213 | NULL, &lock_flags, &fsf_req); |
4229 | if (retval < 0) { | 4214 | if (retval < 0) { |
4230 | ZFCP_LOG_INFO("error: Could not create FSF request for the " | ||
4231 | "adapter %s\n", | ||
4232 | zfcp_get_busid_by_adapter(adapter)); | ||
4233 | retval = -EPERM; | 4215 | retval = -EPERM; |
4234 | goto unlock_queue_lock; | 4216 | goto unlock_queue_lock; |
4235 | } | 4217 | } |
@@ -4239,220 +4221,40 @@ zfcp_fsf_control_file(struct zfcp_adapter *adapter, | |||
4239 | 4221 | ||
4240 | bottom = &fsf_req->qtcb->bottom.support; | 4222 | bottom = &fsf_req->qtcb->bottom.support; |
4241 | bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE; | 4223 | bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE; |
4242 | bottom->option = option; | 4224 | bottom->option = fsf_cfdc->option; |
4243 | 4225 | ||
4244 | if (sg_list->count > 0) { | 4226 | bytes = zfcp_qdio_sbals_from_sg(fsf_req, direction, |
4245 | int bytes; | 4227 | fsf_cfdc->sg, ZFCP_CFDC_PAGES, |
4246 | 4228 | ZFCP_MAX_SBALS_PER_REQ); | |
4247 | bytes = zfcp_qdio_sbals_from_sg(fsf_req, direction, | 4229 | if (bytes != ZFCP_CFDC_MAX_SIZE) { |
4248 | sg_list->sg, sg_list->count, | 4230 | retval = -ENOMEM; |
4249 | ZFCP_MAX_SBALS_PER_REQ); | 4231 | goto free_fsf_req; |
4250 | if (bytes != ZFCP_CFDC_MAX_CONTROL_FILE_SIZE) { | 4232 | } |
4251 | ZFCP_LOG_INFO( | ||
4252 | "error: Could not create sufficient number of " | ||
4253 | "SBALS for an FSF request to the adapter %s\n", | ||
4254 | zfcp_get_busid_by_adapter(adapter)); | ||
4255 | retval = -ENOMEM; | ||
4256 | goto free_fsf_req; | ||
4257 | } | ||
4258 | } else | ||
4259 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | ||
4260 | 4233 | ||
4261 | zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | 4234 | zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); |
4262 | retval = zfcp_fsf_req_send(fsf_req); | 4235 | retval = zfcp_fsf_req_send(fsf_req); |
4263 | if (retval < 0) { | 4236 | if (retval < 0) { |
4264 | ZFCP_LOG_INFO("initiation of cfdc up/download failed" | ||
4265 | "(adapter %s)\n", | ||
4266 | zfcp_get_busid_by_adapter(adapter)); | ||
4267 | retval = -EPERM; | 4237 | retval = -EPERM; |
4268 | goto free_fsf_req; | 4238 | goto free_fsf_req; |
4269 | } | 4239 | } |
4270 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | 4240 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); |
4271 | 4241 | ||
4272 | ZFCP_LOG_NORMAL("Control file %s FSF request has been sent to the " | ||
4273 | "adapter %s\n", | ||
4274 | fsf_command == FSF_QTCB_DOWNLOAD_CONTROL_FILE ? | ||
4275 | "download" : "upload", | ||
4276 | zfcp_get_busid_by_adapter(adapter)); | ||
4277 | |||
4278 | wait_event(fsf_req->completion_wq, | 4242 | wait_event(fsf_req->completion_wq, |
4279 | fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); | 4243 | fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); |
4280 | 4244 | ||
4281 | *fsf_req_ptr = fsf_req; | 4245 | return fsf_req; |
4282 | goto out; | ||
4283 | 4246 | ||
4284 | free_fsf_req: | 4247 | free_fsf_req: |
4285 | zfcp_fsf_req_free(fsf_req); | 4248 | zfcp_fsf_req_free(fsf_req); |
4286 | unlock_queue_lock: | 4249 | unlock_queue_lock: |
4287 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | 4250 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); |
4288 | out: | 4251 | return ERR_PTR(retval); |
4289 | return retval; | ||
4290 | } | 4252 | } |
4291 | 4253 | ||
4292 | 4254 | static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *fsf_req) | |
4293 | /* | ||
4294 | * function: zfcp_fsf_control_file_handler | ||
4295 | * | ||
4296 | * purpose: Handler of the control file upload/download FSF requests | ||
4297 | * | ||
4298 | * returns: 0 - FSF request successfuly processed | ||
4299 | * -EAGAIN - Operation has to be repeated because of a temporary problem | ||
4300 | * -EACCES - There is no permission to execute an operation | ||
4301 | * -EPERM - The control file is not in a right format | ||
4302 | * -EIO - There is a problem with the FCP adapter | ||
4303 | * -EINVAL - Invalid operation | ||
4304 | * -EFAULT - User space memory I/O operation fault | ||
4305 | */ | ||
4306 | static int | ||
4307 | zfcp_fsf_control_file_handler(struct zfcp_fsf_req *fsf_req) | ||
4308 | { | 4255 | { |
4309 | struct zfcp_adapter *adapter = fsf_req->adapter; | 4256 | if (fsf_req->qtcb->header.fsf_status != FSF_GOOD) |
4310 | struct fsf_qtcb_header *header = &fsf_req->qtcb->header; | ||
4311 | struct fsf_qtcb_bottom_support *bottom = &fsf_req->qtcb->bottom.support; | ||
4312 | int retval = 0; | ||
4313 | |||
4314 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | ||
4315 | retval = -EINVAL; | ||
4316 | goto skip_fsfstatus; | ||
4317 | } | ||
4318 | |||
4319 | switch (header->fsf_status) { | ||
4320 | |||
4321 | case FSF_GOOD: | ||
4322 | ZFCP_LOG_NORMAL( | ||
4323 | "The FSF request has been successfully completed " | ||
4324 | "on the adapter %s\n", | ||
4325 | zfcp_get_busid_by_adapter(adapter)); | ||
4326 | break; | ||
4327 | |||
4328 | case FSF_OPERATION_PARTIALLY_SUCCESSFUL: | ||
4329 | if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) { | ||
4330 | switch (header->fsf_status_qual.word[0]) { | ||
4331 | |||
4332 | case FSF_SQ_CFDC_HARDENED_ON_SE: | ||
4333 | ZFCP_LOG_NORMAL( | ||
4334 | "CFDC on the adapter %s has being " | ||
4335 | "hardened on primary and secondary SE\n", | ||
4336 | zfcp_get_busid_by_adapter(adapter)); | ||
4337 | break; | ||
4338 | |||
4339 | case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE: | ||
4340 | ZFCP_LOG_NORMAL( | ||
4341 | "CFDC of the adapter %s could not " | ||
4342 | "be saved on the SE\n", | ||
4343 | zfcp_get_busid_by_adapter(adapter)); | ||
4344 | break; | ||
4345 | |||
4346 | case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE2: | ||
4347 | ZFCP_LOG_NORMAL( | ||
4348 | "CFDC of the adapter %s could not " | ||
4349 | "be copied to the secondary SE\n", | ||
4350 | zfcp_get_busid_by_adapter(adapter)); | ||
4351 | break; | ||
4352 | |||
4353 | default: | ||
4354 | ZFCP_LOG_NORMAL( | ||
4355 | "CFDC could not be hardened " | ||
4356 | "on the adapter %s\n", | ||
4357 | zfcp_get_busid_by_adapter(adapter)); | ||
4358 | } | ||
4359 | } | ||
4360 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4361 | retval = -EAGAIN; | ||
4362 | break; | ||
4363 | |||
4364 | case FSF_AUTHORIZATION_FAILURE: | ||
4365 | ZFCP_LOG_NORMAL( | ||
4366 | "Adapter %s does not accept privileged commands\n", | ||
4367 | zfcp_get_busid_by_adapter(adapter)); | ||
4368 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4369 | retval = -EACCES; | ||
4370 | break; | ||
4371 | |||
4372 | case FSF_CFDC_ERROR_DETECTED: | ||
4373 | ZFCP_LOG_NORMAL( | ||
4374 | "Error at position %d in the CFDC, " | ||
4375 | "CFDC is discarded by the adapter %s\n", | ||
4376 | header->fsf_status_qual.word[0], | ||
4377 | zfcp_get_busid_by_adapter(adapter)); | ||
4378 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4379 | retval = -EPERM; | ||
4380 | break; | ||
4381 | |||
4382 | case FSF_CONTROL_FILE_UPDATE_ERROR: | ||
4383 | ZFCP_LOG_NORMAL( | ||
4384 | "Adapter %s cannot harden the control file, " | ||
4385 | "file is discarded\n", | ||
4386 | zfcp_get_busid_by_adapter(adapter)); | ||
4387 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4388 | retval = -EIO; | ||
4389 | break; | ||
4390 | |||
4391 | case FSF_CONTROL_FILE_TOO_LARGE: | ||
4392 | ZFCP_LOG_NORMAL( | ||
4393 | "Control file is too large, file is discarded " | ||
4394 | "by the adapter %s\n", | ||
4395 | zfcp_get_busid_by_adapter(adapter)); | ||
4396 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4397 | retval = -EIO; | ||
4398 | break; | ||
4399 | |||
4400 | case FSF_ACCESS_CONFLICT_DETECTED: | ||
4401 | if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) | ||
4402 | ZFCP_LOG_NORMAL( | ||
4403 | "CFDC has been discarded by the adapter %s, " | ||
4404 | "because activation would impact " | ||
4405 | "%d active connection(s)\n", | ||
4406 | zfcp_get_busid_by_adapter(adapter), | ||
4407 | header->fsf_status_qual.word[0]); | ||
4408 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4409 | retval = -EIO; | ||
4410 | break; | ||
4411 | |||
4412 | case FSF_CONFLICTS_OVERRULED: | ||
4413 | if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) | ||
4414 | ZFCP_LOG_NORMAL( | ||
4415 | "CFDC has been activated on the adapter %s, " | ||
4416 | "but activation has impacted " | ||
4417 | "%d active connection(s)\n", | ||
4418 | zfcp_get_busid_by_adapter(adapter), | ||
4419 | header->fsf_status_qual.word[0]); | ||
4420 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4421 | retval = -EIO; | ||
4422 | break; | ||
4423 | |||
4424 | case FSF_UNKNOWN_OP_SUBTYPE: | ||
4425 | ZFCP_LOG_NORMAL("unknown operation subtype (adapter: %s, " | ||
4426 | "op_subtype=0x%x)\n", | ||
4427 | zfcp_get_busid_by_adapter(adapter), | ||
4428 | bottom->operation_subtype); | ||
4429 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4430 | retval = -EINVAL; | ||
4431 | break; | ||
4432 | |||
4433 | case FSF_INVALID_COMMAND_OPTION: | ||
4434 | ZFCP_LOG_NORMAL( | ||
4435 | "Invalid option 0x%x has been specified " | ||
4436 | "in QTCB bottom sent to the adapter %s\n", | ||
4437 | bottom->option, | ||
4438 | zfcp_get_busid_by_adapter(adapter)); | ||
4439 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 4257 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
4440 | retval = -EINVAL; | ||
4441 | break; | ||
4442 | |||
4443 | default: | ||
4444 | ZFCP_LOG_NORMAL( | ||
4445 | "bug: An unknown/unexpected FSF status 0x%08x " | ||
4446 | "was presented on the adapter %s\n", | ||
4447 | header->fsf_status, | ||
4448 | zfcp_get_busid_by_adapter(adapter)); | ||
4449 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4450 | retval = -EINVAL; | ||
4451 | break; | ||
4452 | } | ||
4453 | |||
4454 | skip_fsfstatus: | ||
4455 | return retval; | ||
4456 | } | 4258 | } |
4457 | 4259 | ||
4458 | static inline int | 4260 | static inline int |
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index 8b1a7d9c840f..598eba9baa31 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h | |||
@@ -22,6 +22,8 @@ | |||
22 | #ifndef FSF_H | 22 | #ifndef FSF_H |
23 | #define FSF_H | 23 | #define FSF_H |
24 | 24 | ||
25 | #include <linux/pfn.h> | ||
26 | |||
25 | #define FSF_QTCB_CURRENT_VERSION 0x00000001 | 27 | #define FSF_QTCB_CURRENT_VERSION 0x00000001 |
26 | 28 | ||
27 | /* FSF commands */ | 29 | /* FSF commands */ |
@@ -258,6 +260,16 @@ | |||
258 | #define FSF_UNIT_ACCESS_EXCLUSIVE 0x02000000 | 260 | #define FSF_UNIT_ACCESS_EXCLUSIVE 0x02000000 |
259 | #define FSF_UNIT_ACCESS_OUTBOUND_TRANSFER 0x10000000 | 261 | #define FSF_UNIT_ACCESS_OUTBOUND_TRANSFER 0x10000000 |
260 | 262 | ||
263 | /* FSF interface for CFDC */ | ||
264 | #define ZFCP_CFDC_MAX_SIZE 127 * 1024 | ||
265 | #define ZFCP_CFDC_PAGES PFN_UP(ZFCP_CFDC_MAX_SIZE) | ||
266 | |||
267 | struct zfcp_fsf_cfdc { | ||
268 | struct scatterlist sg[ZFCP_CFDC_PAGES]; | ||
269 | u32 command; | ||
270 | u32 option; | ||
271 | }; | ||
272 | |||
261 | struct fsf_queue_designator { | 273 | struct fsf_queue_designator { |
262 | u8 cssid; | 274 | u8 cssid; |
263 | u8 chpid; | 275 | u8 chpid; |