diff --git a/drivers/scsi/fnic/fdls_disc.c b/drivers/scsi/fnic/fdls_disc.c index 455426564ca0..554dea767885 100644 --- a/drivers/scsi/fnic/fdls_disc.c +++ b/drivers/scsi/fnic/fdls_disc.c @@ -4613,7 +4613,7 @@ void fnic_fdls_disc_start(struct fnic_iport_s *iport) if (!iport->usefip) { if (iport->flags & FNIC_FIRST_LINK_UP) { spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - fnic_scsi_fcpio_reset(iport->fnic); + fnic_fcpio_reset(iport->fnic); spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); iport->flags &= ~FNIC_FIRST_LINK_UP; @@ -5072,7 +5072,7 @@ void fnic_fdls_link_down(struct fnic_iport_s *iport) iport->fabric.flags = 0; spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - fnic_scsi_fcpio_reset(iport->fnic); + fnic_fcpio_reset(iport->fnic); spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); list_for_each_entry_safe(tport, next, &iport->tport_list, links) { FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, diff --git a/drivers/scsi/fnic/fip.c b/drivers/scsi/fnic/fip.c index ccd0da7d490f..132f00512ee1 100644 --- a/drivers/scsi/fnic/fip.c +++ b/drivers/scsi/fnic/fip.c @@ -737,7 +737,7 @@ void fnic_work_on_fip_timer(struct work_struct *work) if (memcmp(iport->selected_fcf.fcf_mac, zmac, ETH_ALEN) != 0) { if (iport->flags & FNIC_FIRST_LINK_UP) { - fnic_scsi_fcpio_reset(iport->fnic); + fnic_fcpio_reset(iport->fnic); iport->flags &= ~FNIC_FIRST_LINK_UP; } diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 42237eb3222f..8724d64f2525 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -30,7 +30,7 @@ #define DRV_NAME "fnic" #define DRV_DESCRIPTION "Cisco FCoE HBA Driver" -#define DRV_VERSION "1.8.0.2" +#define DRV_VERSION "1.8.0.3" #define PFX DRV_NAME ": " #define DFX DRV_NAME "%d: " @@ -438,6 +438,7 @@ struct fnic { struct list_head tx_queue; mempool_t *frame_pool; mempool_t *frame_elem_pool; + mempool_t *frame_recv_pool; struct work_struct tport_work; struct list_head tport_event_list; @@ -512,7 +513,6 @@ int fnic_host_reset(struct Scsi_Host *shost); void fnic_reset(struct Scsi_Host *shost); int fnic_issue_fc_host_lip(struct Scsi_Host *shost); void fnic_get_host_port_state(struct Scsi_Host *shost); -void fnic_scsi_fcpio_reset(struct fnic *fnic); int fnic_wq_copy_cmpl_handler(struct fnic *fnic, int copy_work_to_do, unsigned int cq_index); int fnic_wq_cmpl_handler(struct fnic *fnic, int); int fnic_flogi_reg_handler(struct fnic *fnic, u32); @@ -541,7 +541,8 @@ fnic_chk_state_flags_locked(struct fnic *fnic, unsigned long st_flags) } void __fnic_set_state_flags(struct fnic *, unsigned long, unsigned long); void fnic_dump_fchost_stats(struct Scsi_Host *, struct fc_host_statistics *); -void fnic_free_txq(struct list_head *head); +void fnic_free_txq(struct fnic *fnic); +void fnic_free_rxq(struct fnic *fnic); int fnic_get_desc_by_devid(struct pci_dev *pdev, char **desc, char **subsys_desc); void fnic_fdls_link_status_change(struct fnic *fnic, int linkup); diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index 405b341b73d7..063eb864a5cd 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -291,7 +291,7 @@ void fnic_handle_frame(struct work_struct *work) if (fnic->stop_rx_link_events) { list_del(&cur_frame->links); spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - kfree(cur_frame->fp); + mempool_free(cur_frame->fp, fnic->frame_recv_pool); mempool_free(cur_frame, fnic->frame_elem_pool); return; } @@ -317,7 +317,7 @@ void fnic_handle_frame(struct work_struct *work) fnic_fdls_recv_frame(&fnic->iport, cur_frame->fp, cur_frame->frame_len, fchdr_offset); - kfree(cur_frame->fp); + mempool_free(cur_frame->fp, fnic->frame_recv_pool); mempool_free(cur_frame, fnic->frame_elem_pool); } spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); @@ -337,8 +337,8 @@ void fnic_handle_fip_frame(struct work_struct *work) if (fnic->stop_rx_link_events) { list_del(&cur_frame->links); spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - kfree(cur_frame->fp); - kfree(cur_frame); + mempool_free(cur_frame->fp, fnic->frame_recv_pool); + mempool_free(cur_frame, fnic->frame_elem_pool); return; } @@ -355,8 +355,8 @@ void fnic_handle_fip_frame(struct work_struct *work) list_del(&cur_frame->links); if (fdls_fip_recv_frame(fnic, cur_frame->fp)) { - kfree(cur_frame->fp); - kfree(cur_frame); + mempool_free(cur_frame->fp, fnic->frame_recv_pool); + mempool_free(cur_frame, fnic->frame_elem_pool); } } spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); @@ -375,10 +375,10 @@ static inline int fnic_import_rq_eth_pkt(struct fnic *fnic, void *fp) eh = (struct ethhdr *) fp; if ((eh->h_proto == cpu_to_be16(ETH_P_FIP)) && (fnic->iport.usefip)) { - fip_fr_elem = (struct fnic_frame_list *) - kzalloc_obj(struct fnic_frame_list, GFP_ATOMIC); + fip_fr_elem = mempool_alloc(fnic->frame_elem_pool, GFP_ATOMIC); if (!fip_fr_elem) return 0; + memset(fip_fr_elem, 0, sizeof(struct fnic_frame_list)); fip_fr_elem->fp = fp; spin_lock_irqsave(&fnic->fnic_lock, flags); list_add_tail(&fip_fr_elem->links, &fnic->fip_frame_queue); @@ -519,13 +519,13 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc spin_unlock_irqrestore(&fnic->fnic_lock, flags); - frame_elem = mempool_alloc(fnic->frame_elem_pool, - GFP_ATOMIC | __GFP_ZERO); + frame_elem = mempool_alloc(fnic->frame_elem_pool, GFP_ATOMIC); if (!frame_elem) { FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, "Failed to allocate memory for frame elem"); goto drop; } + memset(frame_elem, 0, sizeof(struct fnic_frame_list)); frame_elem->fp = fp; frame_elem->rx_ethhdr_stripped = ethhdr_stripped; frame_elem->frame_len = bytes_written; @@ -538,7 +538,7 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc return; drop: - kfree(fp); + mempool_free(fp, fnic->frame_recv_pool); } static int fnic_rq_cmpl_handler_cont(struct vnic_dev *vdev, @@ -591,7 +591,7 @@ int fnic_alloc_rq_frame(struct vnic_rq *rq) int ret; len = FNIC_FRAME_HT_ROOM; - buf = kmalloc(len, GFP_ATOMIC); + buf = mempool_alloc(fnic->frame_recv_pool, GFP_ATOMIC); if (!buf) { FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, "Unable to allocate RQ buffer of size: %d\n", len); @@ -609,7 +609,7 @@ int fnic_alloc_rq_frame(struct vnic_rq *rq) fnic_queue_rq_desc(rq, buf, pa, len); return 0; free_buf: - kfree(buf); + mempool_free(buf, fnic->frame_recv_pool); return ret; } @@ -621,7 +621,7 @@ void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf) dma_unmap_single(&fnic->pdev->dev, buf->dma_addr, buf->len, DMA_FROM_DEVICE); - kfree(rq_buf); + mempool_free(rq_buf, fnic->frame_recv_pool); buf->os_buf = NULL; } @@ -704,13 +704,13 @@ fdls_send_fcoe_frame(struct fnic *fnic, void *frame, int frame_size, */ if ((fnic->state != FNIC_IN_FC_MODE) && (fnic->state != FNIC_IN_ETH_MODE)) { - frame_elem = mempool_alloc(fnic->frame_elem_pool, - GFP_ATOMIC | __GFP_ZERO); + frame_elem = mempool_alloc(fnic->frame_elem_pool, GFP_ATOMIC); if (!frame_elem) { FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, "Failed to allocate memory for frame elem"); return -ENOMEM; } + memset(frame_elem, 0, sizeof(struct fnic_frame_list)); FNIC_FCS_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, "Queueing FC frame: sid/did/type/oxid = 0x%x/0x%x/0x%x/0x%x\n", @@ -836,14 +836,34 @@ fnic_fdls_register_portid(struct fnic_iport_s *iport, u32 port_id, return 0; } -void fnic_free_txq(struct list_head *head) +void fnic_free_txq(struct fnic *fnic) { struct fnic_frame_list *cur_frame, *next; - list_for_each_entry_safe(cur_frame, next, head, links) { + list_for_each_entry_safe(cur_frame, next, &fnic->tx_queue, links) { list_del(&cur_frame->links); - kfree(cur_frame->fp); - kfree(cur_frame); + mempool_free(cur_frame->fp, fnic->frame_pool); + mempool_free(cur_frame, fnic->frame_elem_pool); + } +} + +void fnic_free_rxq(struct fnic *fnic) +{ + struct fnic_frame_list *cur_frame, *next; + + list_for_each_entry_safe(cur_frame, next, &fnic->frame_queue, links) { + list_del(&cur_frame->links); + mempool_free(cur_frame->fp, fnic->frame_recv_pool); + mempool_free(cur_frame, fnic->frame_elem_pool); + } + + if (fnic->config.flags & VFCF_FIP_CAPABLE) { + list_for_each_entry_safe(cur_frame, next, + &fnic->fip_frame_queue, links) { + list_del(&cur_frame->links); + mempool_free(cur_frame->fp, fnic->frame_recv_pool); + mempool_free(cur_frame, fnic->frame_elem_pool); + } } } @@ -898,7 +918,7 @@ void fnic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) dma_unmap_single(&fnic->pdev->dev, buf->dma_addr, buf->len, DMA_TO_DEVICE); - kfree(buf->os_buf); + mempool_free(buf->os_buf, fnic->frame_pool); buf->os_buf = NULL; } @@ -1108,3 +1128,53 @@ void fnic_reset_work_handler(struct work_struct *work) spin_unlock_irqrestore(&reset_fnic_list_lock, reset_fnic_list_lock_flags); } + +void fnic_fcpio_reset(struct fnic *fnic) +{ + unsigned long flags; + enum fnic_state old_state; + struct fnic_iport_s *iport = &fnic->iport; + DECLARE_COMPLETION_ONSTACK(fw_reset_done); + int time_remain; + + /* issue fw reset */ + spin_lock_irqsave(&fnic->fnic_lock, flags); + if (unlikely(fnic->state == FNIC_IN_FC_TRANS_ETH_MODE)) { + /* fw reset is in progress, poll for its completion */ + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "fnic is in unexpected state: %d for fw_reset\n", + fnic->state); + return; + } + + old_state = fnic->state; + fnic->state = FNIC_IN_FC_TRANS_ETH_MODE; + + fnic_update_mac_locked(fnic, iport->hwmac); + fnic->fw_reset_done = &fw_reset_done; + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "Issuing fw reset\n"); + if (fnic_fw_reset_handler(fnic)) { + spin_lock_irqsave(&fnic->fnic_lock, flags); + if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) + fnic->state = old_state; + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + } else { + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "Waiting for fw completion\n"); + time_remain = wait_for_completion_timeout(&fw_reset_done, + msecs_to_jiffies(FNIC_FW_RESET_TIMEOUT)); + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "Woken up after fw completion timeout\n"); + if (time_remain == 0) { + FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + "FW reset completion timed out after %d ms\n", + FNIC_FW_RESET_TIMEOUT); + } + atomic64_inc(&fnic->fnic_stats.reset_stats.fw_reset_timeouts); + } + fnic->fw_reset_done = NULL; +} diff --git a/drivers/scsi/fnic/fnic_fdls.h b/drivers/scsi/fnic/fnic_fdls.h index 531d0b37e450..e2959120c4f9 100644 --- a/drivers/scsi/fnic/fnic_fdls.h +++ b/drivers/scsi/fnic/fnic_fdls.h @@ -410,6 +410,7 @@ void fnic_fdls_add_tport(struct fnic_iport_s *iport, void fnic_fdls_remove_tport(struct fnic_iport_s *iport, struct fnic_tport_s *tport, unsigned long flags); +void fnic_fcpio_reset(struct fnic *fnic); /* fip.c */ void fnic_fcoe_send_vlan_req(struct fnic *fnic); @@ -422,7 +423,6 @@ void fnic_handle_fip_timer(struct timer_list *t); extern void fdls_fabric_timer_callback(struct timer_list *t); /* fnic_scsi.c */ -void fnic_scsi_fcpio_reset(struct fnic *fnic); extern void fdls_fabric_timer_callback(struct timer_list *t); void fnic_rport_exch_reset(struct fnic *fnic, u32 fcid); int fnic_fdls_register_portid(struct fnic_iport_s *iport, u32 port_id, diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 8b551b79e087..24d62c0874ac 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -40,6 +40,7 @@ static struct kmem_cache *fnic_sgl_cache[FNIC_SGL_NUM_CACHES]; static struct kmem_cache *fnic_io_req_cache; static struct kmem_cache *fdls_frame_cache; static struct kmem_cache *fdls_frame_elem_cache; +static struct kmem_cache *fdls_frame_recv_cache; static LIST_HEAD(fnic_list); static DEFINE_SPINLOCK(fnic_list_lock); static DEFINE_IDA(fnic_ida); @@ -554,6 +555,7 @@ static int fnic_cleanup(struct fnic *fnic) mempool_destroy(fnic->io_req_pool); mempool_destroy(fnic->frame_pool); mempool_destroy(fnic->frame_elem_pool); + mempool_destroy(fnic->frame_recv_pool); for (i = 0; i < FNIC_SGL_NUM_CACHES; i++) mempool_destroy(fnic->io_sgl_pool[i]); @@ -928,6 +930,14 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } fnic->frame_elem_pool = pool; + pool = mempool_create_slab_pool(FDLS_MIN_FRAMES, + fdls_frame_recv_cache); + if (!pool) { + err = -ENOMEM; + goto err_out_fdls_frame_recv_pool; + } + fnic->frame_recv_pool = pool; + /* setup vlan config, hw inserts vlan header */ fnic->vlan_hw_insert = 1; fnic->vlan_id = 0; @@ -1085,6 +1095,8 @@ err_out_alloc_rq_buf: } vnic_dev_notify_unset(fnic->vdev); err_out_fnic_notify_set: + mempool_destroy(fnic->frame_recv_pool); +err_out_fdls_frame_recv_pool: mempool_destroy(fnic->frame_elem_pool); err_out_fdls_frame_elem_pool: mempool_destroy(fnic->frame_pool); @@ -1157,7 +1169,6 @@ static void fnic_remove(struct pci_dev *pdev) timer_delete_sync(&fnic->enode_ka_timer); timer_delete_sync(&fnic->vn_ka_timer); - fnic_free_txq(&fnic->fip_frame_queue); fnic_fcoe_reset_vlans(fnic); } @@ -1177,8 +1188,8 @@ static void fnic_remove(struct pci_dev *pdev) list_del(&fnic->list); spin_unlock_irqrestore(&fnic_list_lock, flags); - fnic_free_txq(&fnic->frame_queue); - fnic_free_txq(&fnic->tx_queue); + fnic_free_rxq(fnic); + fnic_free_txq(fnic); vnic_dev_notify_unset(fnic->vdev); fnic_free_intr(fnic); @@ -1287,6 +1298,15 @@ static int __init fnic_init_module(void) goto err_create_fdls_frame_cache_elem; } + fdls_frame_recv_cache = kmem_cache_create("fdls_frame_recv", + FNIC_FRAME_HT_ROOM, + 0, SLAB_HWCACHE_ALIGN, NULL); + if (!fdls_frame_recv_cache) { + pr_err("fnic fdls frame recv cach create failed\n"); + err = -ENOMEM; + goto err_create_fdls_frame_recv_cache; + } + fnic_event_queue = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, "fnic_event_wq"); if (!fnic_event_queue) { @@ -1339,6 +1359,8 @@ err_create_fip_workq: if (pc_rscn_handling_feature_flag == PC_RSCN_HANDLING_FEATURE_ON) destroy_workqueue(reset_fnic_work_queue); err_create_reset_fnic_workq: + kmem_cache_destroy(fdls_frame_recv_cache); +err_create_fdls_frame_recv_cache: destroy_workqueue(fnic_event_queue); err_create_fnic_workq: kmem_cache_destroy(fdls_frame_elem_cache); diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 29d7aca06958..7e41bb8a7628 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -777,7 +777,7 @@ static int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic, */ if (ret) { spin_unlock_irqrestore(&fnic->fnic_lock, flags); - fnic_free_txq(&fnic->tx_queue); + fnic_free_txq(fnic); goto reset_cmpl_handler_end; } @@ -1972,15 +1972,11 @@ void fnic_scsi_unload(struct fnic *fnic) */ spin_lock_irqsave(&fnic->fnic_lock, flags); fnic->iport.state = FNIC_IPORT_STATE_LINK_WAIT; - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - - if (fdls_get_state(&fnic->iport.fabric) != FDLS_STATE_INIT) - fnic_scsi_fcpio_reset(fnic); - - spin_lock_irqsave(&fnic->fnic_lock, flags); fnic->in_remove = 1; spin_unlock_irqrestore(&fnic->fnic_lock, flags); + fnic_fcpio_reset(fnic); + fnic_flush_tport_event_list(fnic); fnic_delete_fcp_tports(fnic); } @@ -3040,54 +3036,3 @@ int fnic_eh_host_reset_handler(struct scsi_cmnd *sc) ret = fnic_host_reset(shost); return ret; } - - -void fnic_scsi_fcpio_reset(struct fnic *fnic) -{ - unsigned long flags; - enum fnic_state old_state; - struct fnic_iport_s *iport = &fnic->iport; - DECLARE_COMPLETION_ONSTACK(fw_reset_done); - int time_remain; - - /* issue fw reset */ - spin_lock_irqsave(&fnic->fnic_lock, flags); - if (unlikely(fnic->state == FNIC_IN_FC_TRANS_ETH_MODE)) { - /* fw reset is in progress, poll for its completion */ - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "fnic is in unexpected state: %d for fw_reset\n", - fnic->state); - return; - } - - old_state = fnic->state; - fnic->state = FNIC_IN_FC_TRANS_ETH_MODE; - - fnic_update_mac_locked(fnic, iport->hwmac); - fnic->fw_reset_done = &fw_reset_done; - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "Issuing fw reset\n"); - if (fnic_fw_reset_handler(fnic)) { - spin_lock_irqsave(&fnic->fnic_lock, flags); - if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) - fnic->state = old_state; - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - } else { - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "Waiting for fw completion\n"); - time_remain = wait_for_completion_timeout(&fw_reset_done, - msecs_to_jiffies(FNIC_FW_RESET_TIMEOUT)); - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "Woken up after fw completion timeout\n"); - if (time_remain == 0) { - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "FW reset completion timed out after %d ms)\n", - FNIC_FW_RESET_TIMEOUT); - } - atomic64_inc(&fnic->fnic_stats.reset_stats.fw_reset_timeouts); - } - fnic->fw_reset_done = NULL; -}