aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/scsi/zfcp_aux.c
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/scsi/zfcp_aux.c
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/scsi/zfcp_aux.c')
-rw-r--r--drivers/s390/scsi/zfcp_aux.c425
1 files changed, 29 insertions, 396 deletions
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