aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/scsi/zfcp_aux.c
diff options
context:
space:
mode:
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