aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorChris Leech <christopher.leech@intel.com>2009-11-20 17:54:47 -0500
committerJames Bottomley <James.Bottomley@suse.de>2009-12-04 13:01:54 -0500
commit859b7b649ab58ee5cbfb761491317d5b315c1b0f (patch)
tree8827d80feead5e90c12d31885b735068b693b40f /drivers/scsi
parent70d919fbd9ab78f3eca5ea7bd060fefd7b508641 (diff)
[SCSI] fcoe: allow SCSI-FCP to be processed directly in softirq context
Allow FCP frames to bypass the FCoE receive processing threads and handle them directly in softirq context, if they are received on the correct CPU. This preserves the queuing to threads for scaling out receive processing to multiple CPUs, but allows FCoE-aware multi-queue network drivers that direct frames to the originating CPUs to handle FCP processing with less scheduling latency. Only FCP is handled directly, because libfc makes use of mutexes in ELS handling routines. The bulk of this change is just moving the FCoE receive processing out of the receive thread function, leaving behind just the thread and queue management. The interesting bits are in fcoe_rcv() Signed-off-by: Chris Leech <christopher.leech@intel.com> Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/fcoe/fcoe.c245
1 files changed, 135 insertions, 110 deletions
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 4a43b74c0d27..32298ed60614 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -109,6 +109,7 @@ static struct fc_seq *fcoe_elsct_send(struct fc_lport *,
109 struct fc_frame *, 109 struct fc_frame *,
110 void *), 110 void *),
111 void *, u32 timeout); 111 void *, u32 timeout);
112static void fcoe_recv_frame(struct sk_buff *skb);
112 113
113module_param_call(create, fcoe_create, NULL, NULL, S_IWUSR); 114module_param_call(create, fcoe_create, NULL, NULL, S_IWUSR);
114__MODULE_PARM_TYPE(create, "string"); 115__MODULE_PARM_TYPE(create, "string");
@@ -1241,11 +1242,25 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
1241 * this skb. We also have this receive thread locked, 1242 * this skb. We also have this receive thread locked,
1242 * so we're free to queue skbs into it's queue. 1243 * so we're free to queue skbs into it's queue.
1243 */ 1244 */
1244 __skb_queue_tail(&fps->fcoe_rx_list, skb);
1245 if (fps->fcoe_rx_list.qlen == 1)
1246 wake_up_process(fps->thread);
1247 1245
1248 spin_unlock_bh(&fps->fcoe_rx_list.lock); 1246 /* If this is a SCSI-FCP frame, and this is already executing on the
1247 * correct CPU, and the queue for this CPU is empty, then go ahead
1248 * and process the frame directly in the softirq context.
1249 * This lets us process completions without context switching from the
1250 * NET_RX softirq, to our receive processing thread, and then back to
1251 * BLOCK softirq context.
1252 */
1253 if (fh->fh_type == FC_TYPE_FCP &&
1254 cpu == smp_processor_id() &&
1255 skb_queue_empty(&fps->fcoe_rx_list)) {
1256 spin_unlock_bh(&fps->fcoe_rx_list.lock);
1257 fcoe_recv_frame(skb);
1258 } else {
1259 __skb_queue_tail(&fps->fcoe_rx_list, skb);
1260 if (fps->fcoe_rx_list.qlen == 1)
1261 wake_up_process(fps->thread);
1262 spin_unlock_bh(&fps->fcoe_rx_list.lock);
1263 }
1249 1264
1250 return 0; 1265 return 0;
1251err: 1266err:
@@ -1503,26 +1518,134 @@ static void fcoe_percpu_flush_done(struct sk_buff *skb)
1503} 1518}
1504 1519
1505/** 1520/**
1506 * fcoe_percpu_receive_thread() - The per-CPU packet receive thread 1521 * fcoe_recv_frame() - process a single received frame
1507 * @arg: The per-CPU context 1522 * @skb: frame to process
1508 *
1509 * Return: 0 for success
1510 */ 1523 */
1511int fcoe_percpu_receive_thread(void *arg) 1524static void fcoe_recv_frame(struct sk_buff *skb)
1512{ 1525{
1513 struct fcoe_percpu_s *p = arg;
1514 u32 fr_len; 1526 u32 fr_len;
1515 struct fc_lport *lport; 1527 struct fc_lport *lport;
1516 struct fcoe_rcv_info *fr; 1528 struct fcoe_rcv_info *fr;
1517 struct fcoe_dev_stats *stats; 1529 struct fcoe_dev_stats *stats;
1518 struct fc_frame_header *fh; 1530 struct fc_frame_header *fh;
1519 struct sk_buff *skb;
1520 struct fcoe_crc_eof crc_eof; 1531 struct fcoe_crc_eof crc_eof;
1521 struct fc_frame *fp; 1532 struct fc_frame *fp;
1522 u8 *mac = NULL; 1533 u8 *mac = NULL;
1523 struct fcoe_port *port; 1534 struct fcoe_port *port;
1524 struct fcoe_hdr *hp; 1535 struct fcoe_hdr *hp;
1525 1536
1537 fr = fcoe_dev_from_skb(skb);
1538 lport = fr->fr_dev;
1539 if (unlikely(!lport)) {
1540 if (skb->destructor != fcoe_percpu_flush_done)
1541 FCOE_NETDEV_DBG(skb->dev, "NULL lport in skb");
1542 kfree_skb(skb);
1543 return;
1544 }
1545
1546 FCOE_NETDEV_DBG(skb->dev, "skb_info: len:%d data_len:%d "
1547 "head:%p data:%p tail:%p end:%p sum:%d dev:%s",
1548 skb->len, skb->data_len,
1549 skb->head, skb->data, skb_tail_pointer(skb),
1550 skb_end_pointer(skb), skb->csum,
1551 skb->dev ? skb->dev->name : "<NULL>");
1552
1553 /*
1554 * Save source MAC address before discarding header.
1555 */
1556 port = lport_priv(lport);
1557 if (skb_is_nonlinear(skb))
1558 skb_linearize(skb); /* not ideal */
1559 mac = eth_hdr(skb)->h_source;
1560
1561 /*
1562 * Frame length checks and setting up the header pointers
1563 * was done in fcoe_rcv already.
1564 */
1565 hp = (struct fcoe_hdr *) skb_network_header(skb);
1566 fh = (struct fc_frame_header *) skb_transport_header(skb);
1567
1568 stats = fc_lport_get_stats(lport);
1569 if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) {
1570 if (stats->ErrorFrames < 5)
1571 printk(KERN_WARNING "fcoe: FCoE version "
1572 "mismatch: The frame has "
1573 "version %x, but the "
1574 "initiator supports version "
1575 "%x\n", FC_FCOE_DECAPS_VER(hp),
1576 FC_FCOE_VER);
1577 stats->ErrorFrames++;
1578 kfree_skb(skb);
1579 return;
1580 }
1581
1582 skb_pull(skb, sizeof(struct fcoe_hdr));
1583 fr_len = skb->len - sizeof(struct fcoe_crc_eof);
1584
1585 stats->RxFrames++;
1586 stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
1587
1588 fp = (struct fc_frame *)skb;
1589 fc_frame_init(fp);
1590 fr_dev(fp) = lport;
1591 fr_sof(fp) = hp->fcoe_sof;
1592
1593 /* Copy out the CRC and EOF trailer for access */
1594 if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) {
1595 kfree_skb(skb);
1596 return;
1597 }
1598 fr_eof(fp) = crc_eof.fcoe_eof;
1599 fr_crc(fp) = crc_eof.fcoe_crc32;
1600 if (pskb_trim(skb, fr_len)) {
1601 kfree_skb(skb);
1602 return;
1603 }
1604
1605 /*
1606 * We only check CRC if no offload is available and if it is
1607 * it's solicited data, in which case, the FCP layer would
1608 * check it during the copy.
1609 */
1610 if (lport->crc_offload &&
1611 skb->ip_summed == CHECKSUM_UNNECESSARY)
1612 fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
1613 else
1614 fr_flags(fp) |= FCPHF_CRC_UNCHECKED;
1615
1616 fh = fc_frame_header_get(fp);
1617 if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA &&
1618 fh->fh_type == FC_TYPE_FCP) {
1619 fc_exch_recv(lport, fp);
1620 return;
1621 }
1622 if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) {
1623 if (le32_to_cpu(fr_crc(fp)) !=
1624 ~crc32(~0, skb->data, fr_len)) {
1625 if (stats->InvalidCRCCount < 5)
1626 printk(KERN_WARNING "fcoe: dropping "
1627 "frame with CRC error\n");
1628 stats->InvalidCRCCount++;
1629 stats->ErrorFrames++;
1630 fc_frame_free(fp);
1631 return;
1632 }
1633 fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
1634 }
1635 fc_exch_recv(lport, fp);
1636}
1637
1638/**
1639 * fcoe_percpu_receive_thread() - The per-CPU packet receive thread
1640 * @arg: The per-CPU context
1641 *
1642 * Return: 0 for success
1643 */
1644int fcoe_percpu_receive_thread(void *arg)
1645{
1646 struct fcoe_percpu_s *p = arg;
1647 struct sk_buff *skb;
1648
1526 set_user_nice(current, -20); 1649 set_user_nice(current, -20);
1527 1650
1528 while (!kthread_should_stop()) { 1651 while (!kthread_should_stop()) {
@@ -1538,105 +1661,7 @@ int fcoe_percpu_receive_thread(void *arg)
1538 spin_lock_bh(&p->fcoe_rx_list.lock); 1661 spin_lock_bh(&p->fcoe_rx_list.lock);
1539 } 1662 }
1540 spin_unlock_bh(&p->fcoe_rx_list.lock); 1663 spin_unlock_bh(&p->fcoe_rx_list.lock);
1541 fr = fcoe_dev_from_skb(skb); 1664 fcoe_recv_frame(skb);
1542 lport = fr->fr_dev;
1543 if (unlikely(!lport)) {
1544 if (skb->destructor != fcoe_percpu_flush_done)
1545 FCOE_NETDEV_DBG(skb->dev, "NULL lport in skb");
1546 kfree_skb(skb);
1547 continue;
1548 }
1549
1550 FCOE_NETDEV_DBG(skb->dev, "skb_info: len:%d data_len:%d "
1551 "head:%p data:%p tail:%p end:%p sum:%d dev:%s",
1552 skb->len, skb->data_len,
1553 skb->head, skb->data, skb_tail_pointer(skb),
1554 skb_end_pointer(skb), skb->csum,
1555 skb->dev ? skb->dev->name : "<NULL>");
1556
1557 /*
1558 * Save source MAC address before discarding header.
1559 */
1560 port = lport_priv(lport);
1561 if (skb_is_nonlinear(skb))
1562 skb_linearize(skb); /* not ideal */
1563 mac = eth_hdr(skb)->h_source;
1564
1565 /*
1566 * Frame length checks and setting up the header pointers
1567 * was done in fcoe_rcv already.
1568 */
1569 hp = (struct fcoe_hdr *) skb_network_header(skb);
1570 fh = (struct fc_frame_header *) skb_transport_header(skb);
1571
1572 stats = fc_lport_get_stats(lport);
1573 if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) {
1574 if (stats->ErrorFrames < 5)
1575 printk(KERN_WARNING "fcoe: FCoE version "
1576 "mismatch: The frame has "
1577 "version %x, but the "
1578 "initiator supports version "
1579 "%x\n", FC_FCOE_DECAPS_VER(hp),
1580 FC_FCOE_VER);
1581 stats->ErrorFrames++;
1582 kfree_skb(skb);
1583 continue;
1584 }
1585
1586 skb_pull(skb, sizeof(struct fcoe_hdr));
1587 fr_len = skb->len - sizeof(struct fcoe_crc_eof);
1588
1589 stats->RxFrames++;
1590 stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
1591
1592 fp = (struct fc_frame *)skb;
1593 fc_frame_init(fp);
1594 fr_dev(fp) = lport;
1595 fr_sof(fp) = hp->fcoe_sof;
1596
1597 /* Copy out the CRC and EOF trailer for access */
1598 if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) {
1599 kfree_skb(skb);
1600 continue;
1601 }
1602 fr_eof(fp) = crc_eof.fcoe_eof;
1603 fr_crc(fp) = crc_eof.fcoe_crc32;
1604 if (pskb_trim(skb, fr_len)) {
1605 kfree_skb(skb);
1606 continue;
1607 }
1608
1609 /*
1610 * We only check CRC if no offload is available and if it is
1611 * it's solicited data, in which case, the FCP layer would
1612 * check it during the copy.
1613 */
1614 if (lport->crc_offload &&
1615 skb->ip_summed == CHECKSUM_UNNECESSARY)
1616 fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
1617 else
1618 fr_flags(fp) |= FCPHF_CRC_UNCHECKED;
1619
1620 fh = fc_frame_header_get(fp);
1621 if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA &&
1622 fh->fh_type == FC_TYPE_FCP) {
1623 fc_exch_recv(lport, fp);
1624 continue;
1625 }
1626 if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) {
1627 if (le32_to_cpu(fr_crc(fp)) !=
1628 ~crc32(~0, skb->data, fr_len)) {
1629 if (stats->InvalidCRCCount < 5)
1630 printk(KERN_WARNING "fcoe: dropping "
1631 "frame with CRC error\n");
1632 stats->InvalidCRCCount++;
1633 stats->ErrorFrames++;
1634 fc_frame_free(fp);
1635 continue;
1636 }
1637 fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
1638 }
1639 fc_exch_recv(lport, fp);
1640 } 1665 }
1641 return 0; 1666 return 0;
1642} 1667}