aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/cxgb3i/cxgb3i_ddp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/cxgb3i/cxgb3i_ddp.c')
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_ddp.c242
1 files changed, 117 insertions, 125 deletions
diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.c b/drivers/scsi/cxgb3i/cxgb3i_ddp.c
index 4eb6f5593b3e..bb1eebf654cf 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_ddp.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_ddp.c
@@ -66,9 +66,6 @@ static unsigned char ddp_page_order[DDP_PGIDX_MAX] = {0, 1, 2, 4};
66static unsigned char ddp_page_shift[DDP_PGIDX_MAX] = {12, 13, 14, 16}; 66static unsigned char ddp_page_shift[DDP_PGIDX_MAX] = {12, 13, 14, 16};
67static unsigned char page_idx = DDP_PGIDX_MAX; 67static unsigned char page_idx = DDP_PGIDX_MAX;
68 68
69static LIST_HEAD(cxgb3i_ddp_list);
70static DEFINE_RWLOCK(cxgb3i_ddp_rwlock);
71
72/* 69/*
73 * functions to program the pagepod in h/w 70 * functions to program the pagepod in h/w
74 */ 71 */
@@ -113,8 +110,8 @@ static int set_ddp_map(struct cxgb3i_ddp_info *ddp, struct pagepod_hdr *hdr,
113 return 0; 110 return 0;
114} 111}
115 112
116static int clear_ddp_map(struct cxgb3i_ddp_info *ddp, unsigned int idx, 113static void clear_ddp_map(struct cxgb3i_ddp_info *ddp, unsigned int tag,
117 unsigned int npods) 114 unsigned int idx, unsigned int npods)
118{ 115{
119 unsigned int pm_addr = (idx << PPOD_SIZE_SHIFT) + ddp->llimit; 116 unsigned int pm_addr = (idx << PPOD_SIZE_SHIFT) + ddp->llimit;
120 int i; 117 int i;
@@ -122,13 +119,17 @@ static int clear_ddp_map(struct cxgb3i_ddp_info *ddp, unsigned int idx,
122 for (i = 0; i < npods; i++, idx++, pm_addr += PPOD_SIZE) { 119 for (i = 0; i < npods; i++, idx++, pm_addr += PPOD_SIZE) {
123 struct sk_buff *skb = ddp->gl_skb[idx]; 120 struct sk_buff *skb = ddp->gl_skb[idx];
124 121
122 if (!skb) {
123 ddp_log_error("ddp tag 0x%x, 0x%x, %d/%u, skb NULL.\n",
124 tag, idx, i, npods);
125 continue;
126 }
125 ddp->gl_skb[idx] = NULL; 127 ddp->gl_skb[idx] = NULL;
126 memset((skb->head + sizeof(struct ulp_mem_io)), 0, PPOD_SIZE); 128 memset((skb->head + sizeof(struct ulp_mem_io)), 0, PPOD_SIZE);
127 ulp_mem_io_set_hdr(skb, pm_addr); 129 ulp_mem_io_set_hdr(skb, pm_addr);
128 skb->priority = CPL_PRIORITY_CONTROL; 130 skb->priority = CPL_PRIORITY_CONTROL;
129 cxgb3_ofld_send(ddp->tdev, skb); 131 cxgb3_ofld_send(ddp->tdev, skb);
130 } 132 }
131 return 0;
132} 133}
133 134
134static inline int ddp_find_unused_entries(struct cxgb3i_ddp_info *ddp, 135static inline int ddp_find_unused_entries(struct cxgb3i_ddp_info *ddp,
@@ -453,15 +454,15 @@ void cxgb3i_ddp_tag_release(struct t3cdev *tdev, u32 tag)
453 struct cxgb3i_gather_list *gl = ddp->gl_map[idx]; 454 struct cxgb3i_gather_list *gl = ddp->gl_map[idx];
454 unsigned int npods; 455 unsigned int npods;
455 456
456 if (!gl) { 457 if (!gl || !gl->nelem) {
457 ddp_log_error("release ddp 0x%x, idx 0x%x, gl NULL.\n", 458 ddp_log_error("release 0x%x, idx 0x%x, gl 0x%p, %u.\n",
458 tag, idx); 459 tag, idx, gl, gl ? gl->nelem : 0);
459 return; 460 return;
460 } 461 }
461 npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT; 462 npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT;
462 ddp_log_debug("ddp tag 0x%x, release idx 0x%x, npods %u.\n", 463 ddp_log_debug("ddp tag 0x%x, release idx 0x%x, npods %u.\n",
463 tag, idx, npods); 464 tag, idx, npods);
464 clear_ddp_map(ddp, idx, npods); 465 clear_ddp_map(ddp, tag, idx, npods);
465 ddp_unmark_entries(ddp, idx, npods); 466 ddp_unmark_entries(ddp, idx, npods);
466 cxgb3i_ddp_release_gl(gl, ddp->pdev); 467 cxgb3i_ddp_release_gl(gl, ddp->pdev);
467 } else 468 } else
@@ -564,7 +565,87 @@ int cxgb3i_setup_conn_digest(struct t3cdev *tdev, unsigned int tid,
564} 565}
565EXPORT_SYMBOL_GPL(cxgb3i_setup_conn_digest); 566EXPORT_SYMBOL_GPL(cxgb3i_setup_conn_digest);
566 567
567static int ddp_init(struct t3cdev *tdev) 568
569/**
570 * cxgb3i_adapter_ddp_info - read the adapter's ddp information
571 * @tdev: t3cdev adapter
572 * @tformat: tag format
573 * @txsz: max tx pdu payload size, filled in by this func.
574 * @rxsz: max rx pdu payload size, filled in by this func.
575 * setup the tag format for a given iscsi entity
576 */
577int cxgb3i_adapter_ddp_info(struct t3cdev *tdev,
578 struct cxgb3i_tag_format *tformat,
579 unsigned int *txsz, unsigned int *rxsz)
580{
581 struct cxgb3i_ddp_info *ddp;
582 unsigned char idx_bits;
583
584 if (!tformat)
585 return -EINVAL;
586
587 if (!tdev->ulp_iscsi)
588 return -EINVAL;
589
590 ddp = (struct cxgb3i_ddp_info *)tdev->ulp_iscsi;
591
592 idx_bits = 32 - tformat->sw_bits;
593 tformat->rsvd_bits = ddp->idx_bits;
594 tformat->rsvd_shift = PPOD_IDX_SHIFT;
595 tformat->rsvd_mask = (1 << tformat->rsvd_bits) - 1;
596
597 ddp_log_info("tag format: sw %u, rsvd %u,%u, mask 0x%x.\n",
598 tformat->sw_bits, tformat->rsvd_bits,
599 tformat->rsvd_shift, tformat->rsvd_mask);
600
601 *txsz = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD,
602 ddp->max_txsz - ISCSI_PDU_NONPAYLOAD_LEN);
603 *rxsz = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD,
604 ddp->max_rxsz - ISCSI_PDU_NONPAYLOAD_LEN);
605 ddp_log_info("max payload size: %u/%u, %u/%u.\n",
606 *txsz, ddp->max_txsz, *rxsz, ddp->max_rxsz);
607 return 0;
608}
609EXPORT_SYMBOL_GPL(cxgb3i_adapter_ddp_info);
610
611/**
612 * ddp_release - release the cxgb3 adapter's ddp resource
613 * @tdev: t3cdev adapter
614 * release all the resource held by the ddp pagepod manager for a given
615 * adapter if needed
616 */
617static void ddp_release(struct t3cdev *tdev)
618{
619 int i = 0;
620 struct cxgb3i_ddp_info *ddp = (struct cxgb3i_ddp_info *)tdev->ulp_iscsi;
621
622 ddp_log_info("t3dev 0x%p, release ddp 0x%p.\n", tdev, ddp);
623
624 if (ddp) {
625 tdev->ulp_iscsi = NULL;
626 while (i < ddp->nppods) {
627 struct cxgb3i_gather_list *gl = ddp->gl_map[i];
628 if (gl) {
629 int npods = (gl->nelem + PPOD_PAGES_MAX - 1)
630 >> PPOD_PAGES_SHIFT;
631 ddp_log_info("t3dev 0x%p, ddp %d + %d.\n",
632 tdev, i, npods);
633 kfree(gl);
634 ddp_free_gl_skb(ddp, i, npods);
635 i += npods;
636 } else
637 i++;
638 }
639 cxgb3i_free_big_mem(ddp);
640 }
641}
642
643/**
644 * ddp_init - initialize the cxgb3 adapter's ddp resource
645 * @tdev: t3cdev adapter
646 * initialize the ddp pagepod manager for a given adapter
647 */
648static void ddp_init(struct t3cdev *tdev)
568{ 649{
569 struct cxgb3i_ddp_info *ddp; 650 struct cxgb3i_ddp_info *ddp;
570 struct ulp_iscsi_info uinfo; 651 struct ulp_iscsi_info uinfo;
@@ -572,6 +653,12 @@ static int ddp_init(struct t3cdev *tdev)
572 int i, err; 653 int i, err;
573 static int vers_printed; 654 static int vers_printed;
574 655
656 if (tdev->ulp_iscsi) {
657 ddp_log_warn("t3dev 0x%p, ddp 0x%p already set up.\n",
658 tdev, tdev->ulp_iscsi);
659 return;
660 }
661
575 if (!vers_printed) { 662 if (!vers_printed) {
576 printk(KERN_INFO "%s", version); 663 printk(KERN_INFO "%s", version);
577 vers_printed = 1; 664 vers_printed = 1;
@@ -581,7 +668,7 @@ static int ddp_init(struct t3cdev *tdev)
581 if (err < 0) { 668 if (err < 0) {
582 ddp_log_error("%s, failed to get iscsi param err=%d.\n", 669 ddp_log_error("%s, failed to get iscsi param err=%d.\n",
583 tdev->name, err); 670 tdev->name, err);
584 return err; 671 return;
585 } 672 }
586 673
587 ppmax = (uinfo.ulimit - uinfo.llimit + 1) >> PPOD_SIZE_SHIFT; 674 ppmax = (uinfo.ulimit - uinfo.llimit + 1) >> PPOD_SIZE_SHIFT;
@@ -598,7 +685,7 @@ static int ddp_init(struct t3cdev *tdev)
598 if (!ddp) { 685 if (!ddp) {
599 ddp_log_warn("%s unable to alloc ddp 0x%d, ddp disabled.\n", 686 ddp_log_warn("%s unable to alloc ddp 0x%d, ddp disabled.\n",
600 tdev->name, ppmax); 687 tdev->name, ppmax);
601 return 0; 688 return;
602 } 689 }
603 ddp->gl_map = (struct cxgb3i_gather_list **)(ddp + 1); 690 ddp->gl_map = (struct cxgb3i_gather_list **)(ddp + 1);
604 ddp->gl_skb = (struct sk_buff **)(((char *)ddp->gl_map) + 691 ddp->gl_skb = (struct sk_buff **)(((char *)ddp->gl_map) +
@@ -632,141 +719,46 @@ static int ddp_init(struct t3cdev *tdev)
632 719
633 tdev->ulp_iscsi = ddp; 720 tdev->ulp_iscsi = ddp;
634 721
635 /* add to the list */ 722 ddp_log_info("tdev 0x%p, nppods %u, bits %u, mask 0x%x,0x%x pkt %u/%u,"
636 write_lock(&cxgb3i_ddp_rwlock); 723 " %u/%u.\n",
637 list_add_tail(&ddp->list, &cxgb3i_ddp_list); 724 tdev, ppmax, ddp->idx_bits, ddp->idx_mask,
638 write_unlock(&cxgb3i_ddp_rwlock); 725 ddp->rsvd_tag_mask, ddp->max_txsz, uinfo.max_txsz,
639
640 ddp_log_info("nppods %u (0x%x ~ 0x%x), bits %u, mask 0x%x,0x%x "
641 "pkt %u/%u, %u/%u.\n",
642 ppmax, ddp->llimit, ddp->ulimit, ddp->idx_bits,
643 ddp->idx_mask, ddp->rsvd_tag_mask,
644 ddp->max_txsz, uinfo.max_txsz,
645 ddp->max_rxsz, uinfo.max_rxsz); 726 ddp->max_rxsz, uinfo.max_rxsz);
646 return 0; 727 return;
647 728
648free_ddp_map: 729free_ddp_map:
649 cxgb3i_free_big_mem(ddp); 730 cxgb3i_free_big_mem(ddp);
650 return err;
651} 731}
652 732
653/** 733static struct cxgb3_client t3c_ddp_client = {
654 * cxgb3i_adapter_ddp_init - initialize the adapter's ddp resource 734 .name = "iscsiddp_cxgb3",
655 * @tdev: t3cdev adapter 735 .add = ddp_init,
656 * @tformat: tag format 736 .remove = ddp_release,
657 * @txsz: max tx pdu payload size, filled in by this func. 737};
658 * @rxsz: max rx pdu payload size, filled in by this func.
659 * initialize the ddp pagepod manager for a given adapter if needed and
660 * setup the tag format for a given iscsi entity
661 */
662int cxgb3i_adapter_ddp_init(struct t3cdev *tdev,
663 struct cxgb3i_tag_format *tformat,
664 unsigned int *txsz, unsigned int *rxsz)
665{
666 struct cxgb3i_ddp_info *ddp;
667 unsigned char idx_bits;
668
669 if (!tformat)
670 return -EINVAL;
671
672 if (!tdev->ulp_iscsi) {
673 int err = ddp_init(tdev);
674 if (err < 0)
675 return err;
676 }
677 ddp = (struct cxgb3i_ddp_info *)tdev->ulp_iscsi;
678
679 idx_bits = 32 - tformat->sw_bits;
680 tformat->rsvd_bits = ddp->idx_bits;
681 tformat->rsvd_shift = PPOD_IDX_SHIFT;
682 tformat->rsvd_mask = (1 << tformat->rsvd_bits) - 1;
683
684 ddp_log_info("tag format: sw %u, rsvd %u,%u, mask 0x%x.\n",
685 tformat->sw_bits, tformat->rsvd_bits,
686 tformat->rsvd_shift, tformat->rsvd_mask);
687
688 *txsz = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD,
689 ddp->max_txsz - ISCSI_PDU_NONPAYLOAD_LEN);
690 *rxsz = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD,
691 ddp->max_rxsz - ISCSI_PDU_NONPAYLOAD_LEN);
692 ddp_log_info("max payload size: %u/%u, %u/%u.\n",
693 *txsz, ddp->max_txsz, *rxsz, ddp->max_rxsz);
694 return 0;
695}
696EXPORT_SYMBOL_GPL(cxgb3i_adapter_ddp_init);
697
698static void ddp_release(struct cxgb3i_ddp_info *ddp)
699{
700 int i = 0;
701 struct t3cdev *tdev = ddp->tdev;
702
703 tdev->ulp_iscsi = NULL;
704 while (i < ddp->nppods) {
705 struct cxgb3i_gather_list *gl = ddp->gl_map[i];
706 if (gl) {
707 int npods = (gl->nelem + PPOD_PAGES_MAX - 1)
708 >> PPOD_PAGES_SHIFT;
709
710 kfree(gl);
711 ddp_free_gl_skb(ddp, i, npods);
712 } else
713 i++;
714 }
715 cxgb3i_free_big_mem(ddp);
716}
717
718/**
719 * cxgb3i_adapter_ddp_cleanup - release the adapter's ddp resource
720 * @tdev: t3cdev adapter
721 * release all the resource held by the ddp pagepod manager for a given
722 * adapter if needed
723 */
724void cxgb3i_adapter_ddp_cleanup(struct t3cdev *tdev)
725{
726 struct cxgb3i_ddp_info *ddp;
727
728 /* remove from the list */
729 write_lock(&cxgb3i_ddp_rwlock);
730 list_for_each_entry(ddp, &cxgb3i_ddp_list, list) {
731 if (ddp->tdev == tdev) {
732 list_del(&ddp->list);
733 break;
734 }
735 }
736 write_unlock(&cxgb3i_ddp_rwlock);
737
738 if (ddp)
739 ddp_release(ddp);
740}
741EXPORT_SYMBOL_GPL(cxgb3i_adapter_ddp_cleanup);
742 738
743/** 739/**
744 * cxgb3i_ddp_init_module - module init entry point 740 * cxgb3i_ddp_init_module - module init entry point
745 * initialize any driver wide global data structures 741 * initialize any driver wide global data structures and register with the
742 * cxgb3 module
746 */ 743 */
747static int __init cxgb3i_ddp_init_module(void) 744static int __init cxgb3i_ddp_init_module(void)
748{ 745{
749 page_idx = cxgb3i_ddp_find_page_index(PAGE_SIZE); 746 page_idx = cxgb3i_ddp_find_page_index(PAGE_SIZE);
750 ddp_log_info("system PAGE_SIZE %lu, ddp idx %u.\n", 747 ddp_log_info("system PAGE_SIZE %lu, ddp idx %u.\n",
751 PAGE_SIZE, page_idx); 748 PAGE_SIZE, page_idx);
749
750 cxgb3_register_client(&t3c_ddp_client);
752 return 0; 751 return 0;
753} 752}
754 753
755/** 754/**
756 * cxgb3i_ddp_exit_module - module cleanup/exit entry point 755 * cxgb3i_ddp_exit_module - module cleanup/exit entry point
757 * go through the ddp list and release any resource held. 756 * go through the ddp list, unregister with the cxgb3 module and release
757 * any resource held.
758 */ 758 */
759static void __exit cxgb3i_ddp_exit_module(void) 759static void __exit cxgb3i_ddp_exit_module(void)
760{ 760{
761 struct cxgb3i_ddp_info *ddp; 761 cxgb3_unregister_client(&t3c_ddp_client);
762
763 /* release all ddp manager if there is any */
764 write_lock(&cxgb3i_ddp_rwlock);
765 list_for_each_entry(ddp, &cxgb3i_ddp_list, list) {
766 list_del(&ddp->list);
767 ddp_release(ddp);
768 }
769 write_unlock(&cxgb3i_ddp_rwlock);
770} 762}
771 763
772module_init(cxgb3i_ddp_init_module); 764module_init(cxgb3i_ddp_init_module);