aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorChristof Schmitt <christof.schmitt@de.ibm.com>2008-06-10 12:20:55 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-07-12 09:22:25 -0400
commit45633fdc9615f9fd2a0ae18e301562298b15abf3 (patch)
tree8a91c7fffaf55d484c333443735572b4fb0c0a48 /drivers/s390
parent24073b475d6d2bad8880434a16343ee1da816ea5 (diff)
[SCSI] zfcp: Move CFDC code to new file.
zfcp implements a device file to allow Linux guests changing the Access Control Tables stored in the adapter. The code for the device file has nothing to do with the other parts of the driver, so move it to a new file and cleanup the code while doing so. Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com> Signed-off-by: Swen Schillig <swen@vnet.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/scsi/Makefile2
-rw-r--r--drivers/s390/scsi/zfcp_aux.c425
-rw-r--r--drivers/s390/scsi/zfcp_cfdc.c259
-rw-r--r--drivers/s390/scsi/zfcp_def.h43
-rw-r--r--drivers/s390/scsi/zfcp_ext.h8
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c246
-rw-r--r--drivers/s390/scsi/zfcp_fsf.h12
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
5zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \ 5zfcp-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
9obj-$(CONFIG_ZFCP) += zfcp.o 9obj-$(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 */
44static int __init zfcp_module_init(void); 45static int __init zfcp_module_init(void);
45 46
46/* miscellaneous */
47static int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t);
48static void zfcp_sg_list_free(struct zfcp_sg_list *);
49static int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *,
50 void __user *, size_t);
51static int zfcp_sg_list_copy_to_user(void __user *,
52 struct zfcp_sg_list *, size_t);
53static 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
60static 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
67static 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 */
348static long
349zfcp_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 */
539static int
540zfcp_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 */
585static void
586zfcp_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 */
606static 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 */
629static int
630zfcp_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 */
667static int
668zfcp_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
953void 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
964int 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 */
41struct 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
51static 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
67static 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
83static 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
101static 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
131static 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
153static 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
163static 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
248static 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
255struct 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 */
541struct 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
571struct zfcp_fsf_req; 538struct 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 */
905struct 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 *,
86extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *); 86extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *);
87extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *, 87extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *,
88 struct fsf_qtcb_bottom_port *); 88 struct fsf_qtcb_bottom_port *);
89extern int zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **, 89extern 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);
91extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long); 91extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long);
92extern void zfcp_erp_start_timer(struct zfcp_fsf_req *); 92extern void zfcp_erp_start_timer(struct zfcp_fsf_req *);
93extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); 93extern 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 *);
167extern void zfcp_erp_unit_access_changed(struct zfcp_unit *, u8, void *); 167extern void zfcp_erp_unit_access_changed(struct zfcp_unit *, u8, void *);
168 168
169/******************************** AUX ****************************************/ 169/******************************** AUX ****************************************/
170extern void zfcp_sg_free_table(struct scatterlist *sg, int count);
171extern int zfcp_sg_setup_table(struct scatterlist *sg, int count);
170extern void zfcp_rec_dbf_event_thread(u8 id, struct zfcp_adapter *adapter); 172extern void zfcp_rec_dbf_event_thread(u8 id, struct zfcp_adapter *adapter);
171extern void zfcp_rec_dbf_event_thread_lock(u8 id, struct zfcp_adapter *adapter); 173extern void zfcp_rec_dbf_event_thread_lock(u8 id, struct zfcp_adapter *adapter);
172extern void zfcp_rec_dbf_event_adapter(u8 id, void *ref, struct zfcp_adapter *); 174extern 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 *);
201extern int zfcp_reqlist_isempty(struct zfcp_adapter *); 203extern int zfcp_reqlist_isempty(struct zfcp_adapter *);
202 204
205extern 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 *);
36static int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *); 36static int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *);
37static int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *); 37static int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *);
38static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *); 38static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *);
39static int zfcp_fsf_control_file_handler(struct zfcp_fsf_req *); 39static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *);
40static inline int zfcp_fsf_req_sbal_check( 40static inline int zfcp_fsf_req_sbal_check(
41 unsigned long *, struct zfcp_qdio_queue *, int); 41 unsigned long *, struct zfcp_qdio_queue *, int);
42static inline int zfcp_use_one_sbal( 42static 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 */
4186int 4186struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
4187zfcp_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 4254static 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 */
4306static int
4307zfcp_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
4454skip_fsfstatus:
4455 return retval;
4456} 4258}
4457 4259
4458static inline int 4260static 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
267struct zfcp_fsf_cfdc {
268 struct scatterlist sg[ZFCP_CFDC_PAGES];
269 u32 command;
270 u32 option;
271};
272
261struct fsf_queue_designator { 273struct fsf_queue_designator {
262 u8 cssid; 274 u8 cssid;
263 u8 chpid; 275 u8 chpid;