1f1c3b0fcSJames Smart /******************************************************************* 2f1c3b0fcSJames Smart * This file is part of the Emulex Linux Device Driver for * 3f1c3b0fcSJames Smart * Fibre Channel Host Bus Adapters. * 4ea4044e4SJustin Tee * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * 54ae2ebdeSJames Smart * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * 6f25e8e79SJames Smart * Copyright (C) 2009-2015 Emulex. All rights reserved. * 7f1c3b0fcSJames Smart * EMULEX and SLI are trademarks of Emulex. * 8d080abe0SJames Smart * www.broadcom.com * 9f1c3b0fcSJames Smart * * 10f1c3b0fcSJames Smart * This program is free software; you can redistribute it and/or * 11f1c3b0fcSJames Smart * modify it under the terms of version 2 of the GNU General * 12f1c3b0fcSJames Smart * Public License as published by the Free Software Foundation. * 13f1c3b0fcSJames Smart * This program is distributed in the hope that it will be useful. * 14f1c3b0fcSJames Smart * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * 15f1c3b0fcSJames Smart * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * 16f1c3b0fcSJames Smart * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * 17f1c3b0fcSJames Smart * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * 18f1c3b0fcSJames Smart * TO BE LEGALLY INVALID. See the GNU General Public License for * 19f1c3b0fcSJames Smart * more details, a copy of which can be found in the file COPYING * 20f1c3b0fcSJames Smart * included with this package. * 21f1c3b0fcSJames Smart *******************************************************************/ 22f1c3b0fcSJames Smart 23f1c3b0fcSJames Smart #include <linux/interrupt.h> 24f1c3b0fcSJames Smart #include <linux/mempool.h> 25f1c3b0fcSJames Smart #include <linux/pci.h> 265a0e3ad6STejun Heo #include <linux/slab.h> 27277e76f1SJames Smart #include <linux/delay.h> 287ad20aa9SJames Smart #include <linux/list.h> 29eb340948SJohannes Thumshirn #include <linux/bsg-lib.h> 30d2cc9bcdSJames Smart #include <linux/vmalloc.h> 31f1c3b0fcSJames Smart 32f1c3b0fcSJames Smart #include <scsi/scsi.h> 33f1c3b0fcSJames Smart #include <scsi/scsi_host.h> 34f1c3b0fcSJames Smart #include <scsi/scsi_transport_fc.h> 35f1c3b0fcSJames Smart #include <scsi/scsi_bsg_fc.h> 366a9c52cfSJames Smart #include <scsi/fc/fc_fs.h> 37f1c3b0fcSJames Smart 38f1c3b0fcSJames Smart #include "lpfc_hw4.h" 39f1c3b0fcSJames Smart #include "lpfc_hw.h" 40f1c3b0fcSJames Smart #include "lpfc_sli.h" 41f1c3b0fcSJames Smart #include "lpfc_sli4.h" 42f1c3b0fcSJames Smart #include "lpfc_nl.h" 434fede78fSJames Smart #include "lpfc_bsg.h" 44f1c3b0fcSJames Smart #include "lpfc_disc.h" 45f1c3b0fcSJames Smart #include "lpfc_scsi.h" 46f1c3b0fcSJames Smart #include "lpfc.h" 47f1c3b0fcSJames Smart #include "lpfc_logmsg.h" 48f1c3b0fcSJames Smart #include "lpfc_crtn.h" 49b76f2dc9SJames Smart #include "lpfc_debugfs.h" 50f1c3b0fcSJames Smart #include "lpfc_vport.h" 51f1c3b0fcSJames Smart #include "lpfc_version.h" 52f1c3b0fcSJames Smart 534cc0e56eSJames Smart struct lpfc_bsg_event { 544cc0e56eSJames Smart struct list_head node; 554cc0e56eSJames Smart struct kref kref; 564cc0e56eSJames Smart wait_queue_head_t wq; 574cc0e56eSJames Smart 584cc0e56eSJames Smart /* Event type and waiter identifiers */ 594cc0e56eSJames Smart uint32_t type_mask; 604cc0e56eSJames Smart uint32_t req_id; 614cc0e56eSJames Smart uint32_t reg_id; 624cc0e56eSJames Smart 634cc0e56eSJames Smart /* next two flags are here for the auto-delete logic */ 644cc0e56eSJames Smart unsigned long wait_time_stamp; 654cc0e56eSJames Smart int waiting; 664cc0e56eSJames Smart 674cc0e56eSJames Smart /* seen and not seen events */ 684cc0e56eSJames Smart struct list_head events_to_get; 694cc0e56eSJames Smart struct list_head events_to_see; 704cc0e56eSJames Smart 71a33c4f7bSJames Smart /* driver data associated with the job */ 72a33c4f7bSJames Smart void *dd_data; 734cc0e56eSJames Smart }; 744cc0e56eSJames Smart 754cc0e56eSJames Smart struct lpfc_bsg_iocb { 764cc0e56eSJames Smart struct lpfc_iocbq *cmdiocbq; 77a33c4f7bSJames Smart struct lpfc_dmabuf *rmp; 784cc0e56eSJames Smart struct lpfc_nodelist *ndlp; 794cc0e56eSJames Smart }; 804cc0e56eSJames Smart 813b5dd52aSJames Smart struct lpfc_bsg_mbox { 823b5dd52aSJames Smart LPFC_MBOXQ_t *pmboxq; 833b5dd52aSJames Smart MAILBOX_t *mb; 847ad20aa9SJames Smart struct lpfc_dmabuf *dmabuffers; /* for BIU diags */ 857a470277SJames Smart uint8_t *ext; /* extended mailbox data */ 867a470277SJames Smart uint32_t mbOffset; /* from app */ 877a470277SJames Smart uint32_t inExtWLen; /* from app */ 88c7495937SJames Smart uint32_t outExtWLen; /* from app */ 893b5dd52aSJames Smart }; 903b5dd52aSJames Smart 914cc0e56eSJames Smart #define TYPE_EVT 1 924cc0e56eSJames Smart #define TYPE_IOCB 2 933b5dd52aSJames Smart #define TYPE_MBOX 3 944cc0e56eSJames Smart struct bsg_job_data { 954cc0e56eSJames Smart uint32_t type; 9675cc8cfcSJohannes Thumshirn struct bsg_job *set_job; /* job waiting for this iocb to finish */ 974cc0e56eSJames Smart union { 984cc0e56eSJames Smart struct lpfc_bsg_event *evt; 994cc0e56eSJames Smart struct lpfc_bsg_iocb iocb; 1003b5dd52aSJames Smart struct lpfc_bsg_mbox mbox; 1014cc0e56eSJames Smart } context_un; 1024cc0e56eSJames Smart }; 1034cc0e56eSJames Smart 1044cc0e56eSJames Smart struct event_data { 1054cc0e56eSJames Smart struct list_head node; 1064cc0e56eSJames Smart uint32_t type; 1074cc0e56eSJames Smart uint32_t immed_dat; 1084cc0e56eSJames Smart void *data; 1094cc0e56eSJames Smart uint32_t len; 1104cc0e56eSJames Smart }; 1114cc0e56eSJames Smart 1123b5dd52aSJames Smart #define BUF_SZ_4K 4096 1134cc0e56eSJames Smart #define SLI_CT_ELX_LOOPBACK 0x10 1144cc0e56eSJames Smart 1154cc0e56eSJames Smart enum ELX_LOOPBACK_CMD { 1164cc0e56eSJames Smart ELX_LOOPBACK_XRI_SETUP, 1174cc0e56eSJames Smart ELX_LOOPBACK_DATA, 1184cc0e56eSJames Smart }; 1194cc0e56eSJames Smart 1203b5dd52aSJames Smart #define ELX_LOOPBACK_HEADER_SZ \ 1213b5dd52aSJames Smart (size_t)(&((struct lpfc_sli_ct_request *)NULL)->un) 1223b5dd52aSJames Smart 1234cc0e56eSJames Smart struct lpfc_dmabufext { 1244cc0e56eSJames Smart struct lpfc_dmabuf dma; 1254cc0e56eSJames Smart uint32_t size; 1264cc0e56eSJames Smart uint32_t flag; 1274cc0e56eSJames Smart }; 1284cc0e56eSJames Smart 129a33c4f7bSJames Smart static void 130a33c4f7bSJames Smart lpfc_free_bsg_buffers(struct lpfc_hba *phba, struct lpfc_dmabuf *mlist) 131a33c4f7bSJames Smart { 132a33c4f7bSJames Smart struct lpfc_dmabuf *mlast, *next_mlast; 133a33c4f7bSJames Smart 134a33c4f7bSJames Smart if (mlist) { 135a33c4f7bSJames Smart list_for_each_entry_safe(mlast, next_mlast, &mlist->list, 136a33c4f7bSJames Smart list) { 137a33c4f7bSJames Smart list_del(&mlast->list); 138bf21c9bbSJustin Tee lpfc_mbuf_free(phba, mlast->virt, mlast->phys); 139a33c4f7bSJames Smart kfree(mlast); 140a33c4f7bSJames Smart } 141a33c4f7bSJames Smart lpfc_mbuf_free(phba, mlist->virt, mlist->phys); 142a33c4f7bSJames Smart kfree(mlist); 143a33c4f7bSJames Smart } 144a33c4f7bSJames Smart return; 145a33c4f7bSJames Smart } 146a33c4f7bSJames Smart 147a33c4f7bSJames Smart static struct lpfc_dmabuf * 148a33c4f7bSJames Smart lpfc_alloc_bsg_buffers(struct lpfc_hba *phba, unsigned int size, 149a33c4f7bSJames Smart int outbound_buffers, struct ulp_bde64 *bpl, 150a33c4f7bSJames Smart int *bpl_entries) 151a33c4f7bSJames Smart { 152a33c4f7bSJames Smart struct lpfc_dmabuf *mlist = NULL; 153a33c4f7bSJames Smart struct lpfc_dmabuf *mp; 154a33c4f7bSJames Smart unsigned int bytes_left = size; 155a33c4f7bSJames Smart 156a33c4f7bSJames Smart /* Verify we can support the size specified */ 157a33c4f7bSJames Smart if (!size || (size > (*bpl_entries * LPFC_BPL_SIZE))) 158a33c4f7bSJames Smart return NULL; 159a33c4f7bSJames Smart 160a33c4f7bSJames Smart /* Determine the number of dma buffers to allocate */ 161a33c4f7bSJames Smart *bpl_entries = (size % LPFC_BPL_SIZE ? size/LPFC_BPL_SIZE + 1 : 162a33c4f7bSJames Smart size/LPFC_BPL_SIZE); 163a33c4f7bSJames Smart 164a33c4f7bSJames Smart /* Allocate dma buffer and place in BPL passed */ 165a33c4f7bSJames Smart while (bytes_left) { 166a33c4f7bSJames Smart /* Allocate dma buffer */ 167a33c4f7bSJames Smart mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 168a33c4f7bSJames Smart if (!mp) { 169a33c4f7bSJames Smart if (mlist) 170a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, mlist); 171a33c4f7bSJames Smart return NULL; 172a33c4f7bSJames Smart } 173a33c4f7bSJames Smart 174a33c4f7bSJames Smart INIT_LIST_HEAD(&mp->list); 175a33c4f7bSJames Smart mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys)); 176a33c4f7bSJames Smart 177a33c4f7bSJames Smart if (!mp->virt) { 178a33c4f7bSJames Smart kfree(mp); 179a33c4f7bSJames Smart if (mlist) 180a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, mlist); 181a33c4f7bSJames Smart return NULL; 182a33c4f7bSJames Smart } 183a33c4f7bSJames Smart 184a33c4f7bSJames Smart /* Queue it to a linked list */ 185a33c4f7bSJames Smart if (!mlist) 186a33c4f7bSJames Smart mlist = mp; 187a33c4f7bSJames Smart else 188a33c4f7bSJames Smart list_add_tail(&mp->list, &mlist->list); 189a33c4f7bSJames Smart 190a33c4f7bSJames Smart /* Add buffer to buffer pointer list */ 191a33c4f7bSJames Smart if (outbound_buffers) 192a33c4f7bSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; 193a33c4f7bSJames Smart else 194a33c4f7bSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; 195a33c4f7bSJames Smart bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys)); 196a33c4f7bSJames Smart bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys)); 197a33c4f7bSJames Smart bpl->tus.f.bdeSize = (uint16_t) 198a33c4f7bSJames Smart (bytes_left >= LPFC_BPL_SIZE ? LPFC_BPL_SIZE : 199a33c4f7bSJames Smart bytes_left); 200a33c4f7bSJames Smart bytes_left -= bpl->tus.f.bdeSize; 201a33c4f7bSJames Smart bpl->tus.w = le32_to_cpu(bpl->tus.w); 202a33c4f7bSJames Smart bpl++; 203a33c4f7bSJames Smart } 204a33c4f7bSJames Smart return mlist; 205a33c4f7bSJames Smart } 206a33c4f7bSJames Smart 207a33c4f7bSJames Smart static unsigned int 208a33c4f7bSJames Smart lpfc_bsg_copy_data(struct lpfc_dmabuf *dma_buffers, 209eb340948SJohannes Thumshirn struct bsg_buffer *bsg_buffers, 210a33c4f7bSJames Smart unsigned int bytes_to_transfer, int to_buffers) 211a33c4f7bSJames Smart { 212a33c4f7bSJames Smart 213a33c4f7bSJames Smart struct lpfc_dmabuf *mp; 214a33c4f7bSJames Smart unsigned int transfer_bytes, bytes_copied = 0; 215a33c4f7bSJames Smart unsigned int sg_offset, dma_offset; 216a33c4f7bSJames Smart unsigned char *dma_address, *sg_address; 217a33c4f7bSJames Smart LIST_HEAD(temp_list); 218d5ce53b7SJames Smart struct sg_mapping_iter miter; 219d5ce53b7SJames Smart unsigned long flags; 220d5ce53b7SJames Smart unsigned int sg_flags = SG_MITER_ATOMIC; 221d5ce53b7SJames Smart bool sg_valid; 222a33c4f7bSJames Smart 223a33c4f7bSJames Smart list_splice_init(&dma_buffers->list, &temp_list); 224a33c4f7bSJames Smart list_add(&dma_buffers->list, &temp_list); 225a33c4f7bSJames Smart sg_offset = 0; 226d5ce53b7SJames Smart if (to_buffers) 227d5ce53b7SJames Smart sg_flags |= SG_MITER_FROM_SG; 228d5ce53b7SJames Smart else 229d5ce53b7SJames Smart sg_flags |= SG_MITER_TO_SG; 230d5ce53b7SJames Smart sg_miter_start(&miter, bsg_buffers->sg_list, bsg_buffers->sg_cnt, 231d5ce53b7SJames Smart sg_flags); 232d5ce53b7SJames Smart local_irq_save(flags); 233d5ce53b7SJames Smart sg_valid = sg_miter_next(&miter); 234a33c4f7bSJames Smart list_for_each_entry(mp, &temp_list, list) { 235a33c4f7bSJames Smart dma_offset = 0; 236d5ce53b7SJames Smart while (bytes_to_transfer && sg_valid && 237a33c4f7bSJames Smart (dma_offset < LPFC_BPL_SIZE)) { 238a33c4f7bSJames Smart dma_address = mp->virt + dma_offset; 239a33c4f7bSJames Smart if (sg_offset) { 240a33c4f7bSJames Smart /* Continue previous partial transfer of sg */ 241d5ce53b7SJames Smart sg_address = miter.addr + sg_offset; 242d5ce53b7SJames Smart transfer_bytes = miter.length - sg_offset; 243a33c4f7bSJames Smart } else { 244d5ce53b7SJames Smart sg_address = miter.addr; 245d5ce53b7SJames Smart transfer_bytes = miter.length; 246a33c4f7bSJames Smart } 247a33c4f7bSJames Smart if (bytes_to_transfer < transfer_bytes) 248a33c4f7bSJames Smart transfer_bytes = bytes_to_transfer; 249a33c4f7bSJames Smart if (transfer_bytes > (LPFC_BPL_SIZE - dma_offset)) 250a33c4f7bSJames Smart transfer_bytes = LPFC_BPL_SIZE - dma_offset; 251a33c4f7bSJames Smart if (to_buffers) 252a33c4f7bSJames Smart memcpy(dma_address, sg_address, transfer_bytes); 253a33c4f7bSJames Smart else 254a33c4f7bSJames Smart memcpy(sg_address, dma_address, transfer_bytes); 255a33c4f7bSJames Smart dma_offset += transfer_bytes; 256a33c4f7bSJames Smart sg_offset += transfer_bytes; 257a33c4f7bSJames Smart bytes_to_transfer -= transfer_bytes; 258a33c4f7bSJames Smart bytes_copied += transfer_bytes; 259d5ce53b7SJames Smart if (sg_offset >= miter.length) { 260a33c4f7bSJames Smart sg_offset = 0; 261d5ce53b7SJames Smart sg_valid = sg_miter_next(&miter); 262a33c4f7bSJames Smart } 263a33c4f7bSJames Smart } 264a33c4f7bSJames Smart } 265d5ce53b7SJames Smart sg_miter_stop(&miter); 266d5ce53b7SJames Smart local_irq_restore(flags); 267a33c4f7bSJames Smart list_del_init(&dma_buffers->list); 268a33c4f7bSJames Smart list_splice(&temp_list, &dma_buffers->list); 269a33c4f7bSJames Smart return bytes_copied; 270a33c4f7bSJames Smart } 271a33c4f7bSJames Smart 272f1c3b0fcSJames Smart /** 2734cc0e56eSJames Smart * lpfc_bsg_send_mgmt_cmd_cmp - lpfc_bsg_send_mgmt_cmd's completion handler 2744cc0e56eSJames Smart * @phba: Pointer to HBA context object. 2754cc0e56eSJames Smart * @cmdiocbq: Pointer to command iocb. 2764cc0e56eSJames Smart * @rspiocbq: Pointer to response iocb. 2774cc0e56eSJames Smart * 2784cc0e56eSJames Smart * This function is the completion handler for iocbs issued using 2794cc0e56eSJames Smart * lpfc_bsg_send_mgmt_cmd function. This function is called by the 2804cc0e56eSJames Smart * ring event handler function without any lock held. This function 2814cc0e56eSJames Smart * can be called from both worker thread context and interrupt 2824cc0e56eSJames Smart * context. This function also can be called from another thread which 2834cc0e56eSJames Smart * cleans up the SLI layer objects. 2844cc0e56eSJames Smart * This function copies the contents of the response iocb to the 2854cc0e56eSJames Smart * response iocb memory object provided by the caller of 2864cc0e56eSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 2874cc0e56eSJames Smart * sleeps for the iocb completion. 2884cc0e56eSJames Smart **/ 2894cc0e56eSJames Smart static void 2904cc0e56eSJames Smart lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, 2914cc0e56eSJames Smart struct lpfc_iocbq *cmdiocbq, 2924cc0e56eSJames Smart struct lpfc_iocbq *rspiocbq) 2934cc0e56eSJames Smart { 2944cc0e56eSJames Smart struct bsg_job_data *dd_data; 29575cc8cfcSJohannes Thumshirn struct bsg_job *job; 29601e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 297a33c4f7bSJames Smart struct lpfc_dmabuf *bmp, *cmp, *rmp; 2984cc0e56eSJames Smart struct lpfc_nodelist *ndlp; 2994cc0e56eSJames Smart struct lpfc_bsg_iocb *iocb; 3004cc0e56eSJames Smart unsigned long flags; 3014cc0e56eSJames Smart int rc = 0; 30261910d6aSJames Smart u32 ulp_status, ulp_word4, total_data_placed; 3034cc0e56eSJames Smart 304d51cf5bdSJames Smart dd_data = cmdiocbq->context_un.dd_data; 305a33c4f7bSJames Smart 306a33c4f7bSJames Smart /* Determine if job has been aborted */ 3074cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 308a33c4f7bSJames Smart job = dd_data->set_job; 309a33c4f7bSJames Smart if (job) { 31001e0e15cSJohannes Thumshirn bsg_reply = job->reply; 311a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 312a33c4f7bSJames Smart job->dd_data = NULL; 3134cc0e56eSJames Smart } 314a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 3154cc0e56eSJames Smart 316b5a9b2dfSJames Smart /* Close the timeout handler abort window */ 317b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 318a680a929SJames Smart cmdiocbq->cmd_flag &= ~LPFC_IO_CMD_OUTSTANDING; 319b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 320b5a9b2dfSJames Smart 3214cc0e56eSJames Smart iocb = &dd_data->context_un.iocb; 322d51cf5bdSJames Smart ndlp = iocb->cmdiocbq->ndlp; 323a33c4f7bSJames Smart rmp = iocb->rmp; 324d51cf5bdSJames Smart cmp = cmdiocbq->cmd_dmabuf; 325d51cf5bdSJames Smart bmp = cmdiocbq->bpl_dmabuf; 32661910d6aSJames Smart ulp_status = get_job_ulpstatus(phba, rspiocbq); 32761910d6aSJames Smart ulp_word4 = get_job_word4(phba, rspiocbq); 32861910d6aSJames Smart total_data_placed = get_job_data_placed(phba, rspiocbq); 3294cc0e56eSJames Smart 330a33c4f7bSJames Smart /* Copy the completed data or set the error status */ 3314cc0e56eSJames Smart 332a33c4f7bSJames Smart if (job) { 33361910d6aSJames Smart if (ulp_status) { 33461910d6aSJames Smart if (ulp_status == IOSTAT_LOCAL_REJECT) { 33561910d6aSJames Smart switch (ulp_word4 & IOERR_PARAM_MASK) { 3364cc0e56eSJames Smart case IOERR_SEQUENCE_TIMEOUT: 3374cc0e56eSJames Smart rc = -ETIMEDOUT; 3384cc0e56eSJames Smart break; 3394cc0e56eSJames Smart case IOERR_INVALID_RPI: 3404cc0e56eSJames Smart rc = -EFAULT; 3414cc0e56eSJames Smart break; 3424cc0e56eSJames Smart default: 3434cc0e56eSJames Smart rc = -EACCES; 3444cc0e56eSJames Smart break; 3454cc0e56eSJames Smart } 346a33c4f7bSJames Smart } else { 3474cc0e56eSJames Smart rc = -EACCES; 348a33c4f7bSJames Smart } 349a33c4f7bSJames Smart } else { 35001e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 351a33c4f7bSJames Smart lpfc_bsg_copy_data(rmp, &job->reply_payload, 35261910d6aSJames Smart total_data_placed, 0); 353a33c4f7bSJames Smart } 354a33c4f7bSJames Smart } 3554cc0e56eSJames Smart 356a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 357a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, rmp); 3584cc0e56eSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 359a33c4f7bSJames Smart kfree(bmp); 3604cc0e56eSJames Smart lpfc_nlp_put(ndlp); 3614430f7fdSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 3624cc0e56eSJames Smart kfree(dd_data); 363a33c4f7bSJames Smart 364a33c4f7bSJames Smart /* Complete the job if the job is still active */ 365a33c4f7bSJames Smart 366a33c4f7bSJames Smart if (job) { 36701e0e15cSJohannes Thumshirn bsg_reply->result = rc; 36806548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 3691abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 370a33c4f7bSJames Smart } 3714cc0e56eSJames Smart return; 3724cc0e56eSJames Smart } 3734cc0e56eSJames Smart 3744cc0e56eSJames Smart /** 3754cc0e56eSJames Smart * lpfc_bsg_send_mgmt_cmd - send a CT command from a bsg request 376f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 3773b5dd52aSJames Smart **/ 378f1c3b0fcSJames Smart static int 37975cc8cfcSJohannes Thumshirn lpfc_bsg_send_mgmt_cmd(struct bsg_job *job) 380f1c3b0fcSJames Smart { 381cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 3821d69b122SJohannes Thumshirn struct lpfc_rport_data *rdata = fc_bsg_to_rport(job)->dd_data; 38361910d6aSJames Smart struct lpfc_hba *phba = vport->phba; 384f1c3b0fcSJames Smart struct lpfc_nodelist *ndlp = rdata->pnode; 38501e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 386f1c3b0fcSJames Smart struct ulp_bde64 *bpl = NULL; 387f1c3b0fcSJames Smart struct lpfc_iocbq *cmdiocbq = NULL; 388a33c4f7bSJames Smart struct lpfc_dmabuf *bmp = NULL, *cmp = NULL, *rmp = NULL; 38961910d6aSJames Smart int request_nseg, reply_nseg; 39061910d6aSJames Smart u32 num_entry; 3914cc0e56eSJames Smart struct bsg_job_data *dd_data; 392b5a9b2dfSJames Smart unsigned long flags; 3934cc0e56eSJames Smart uint32_t creg_val; 394f1c3b0fcSJames Smart int rc = 0; 395d439d286SJames Smart int iocb_stat; 39661910d6aSJames Smart u16 ulp_context; 397f1c3b0fcSJames Smart 398f1c3b0fcSJames Smart /* in case no data is transferred */ 39901e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 400f1c3b0fcSJames Smart 4014430f7fdSJames Smart if (ndlp->nlp_flag & NLP_ELS_SND_MASK) 4024430f7fdSJames Smart return -ENODEV; 4034430f7fdSJames Smart 4044cc0e56eSJames Smart /* allocate our bsg tracking structure */ 4054cc0e56eSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 4064cc0e56eSJames Smart if (!dd_data) { 4074cc0e56eSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 4084cc0e56eSJames Smart "2733 Failed allocation of dd_data\n"); 4094cc0e56eSJames Smart rc = -ENOMEM; 4104cc0e56eSJames Smart goto no_dd_data; 4114cc0e56eSJames Smart } 4124cc0e56eSJames Smart 413f1c3b0fcSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 414f1c3b0fcSJames Smart if (!cmdiocbq) { 415f1c3b0fcSJames Smart rc = -ENOMEM; 4164430f7fdSJames Smart goto free_dd; 417f1c3b0fcSJames Smart } 418f1c3b0fcSJames Smart 419a33c4f7bSJames Smart bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 420a33c4f7bSJames Smart if (!bmp) { 421f1c3b0fcSJames Smart rc = -ENOMEM; 422be858b65SJames Smart goto free_cmdiocbq; 423f1c3b0fcSJames Smart } 424a33c4f7bSJames Smart bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); 425a33c4f7bSJames Smart if (!bmp->virt) { 426a33c4f7bSJames Smart rc = -ENOMEM; 427a33c4f7bSJames Smart goto free_bmp; 428f1c3b0fcSJames Smart } 429f1c3b0fcSJames Smart 430a33c4f7bSJames Smart INIT_LIST_HEAD(&bmp->list); 431a33c4f7bSJames Smart 432a33c4f7bSJames Smart bpl = (struct ulp_bde64 *) bmp->virt; 433a33c4f7bSJames Smart request_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64); 434a33c4f7bSJames Smart cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len, 435a33c4f7bSJames Smart 1, bpl, &request_nseg); 436a33c4f7bSJames Smart if (!cmp) { 437a33c4f7bSJames Smart rc = -ENOMEM; 438a33c4f7bSJames Smart goto free_bmp; 439a33c4f7bSJames Smart } 440a33c4f7bSJames Smart lpfc_bsg_copy_data(cmp, &job->request_payload, 441a33c4f7bSJames Smart job->request_payload.payload_len, 1); 442a33c4f7bSJames Smart 443a33c4f7bSJames Smart bpl += request_nseg; 444a33c4f7bSJames Smart reply_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64) - request_nseg; 445a33c4f7bSJames Smart rmp = lpfc_alloc_bsg_buffers(phba, job->reply_payload.payload_len, 0, 446a33c4f7bSJames Smart bpl, &reply_nseg); 447a33c4f7bSJames Smart if (!rmp) { 448a33c4f7bSJames Smart rc = -ENOMEM; 449a33c4f7bSJames Smart goto free_cmp; 450f1c3b0fcSJames Smart } 451f1c3b0fcSJames Smart 45261910d6aSJames Smart num_entry = request_nseg + reply_nseg; 45361910d6aSJames Smart 4546d368e53SJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 45561910d6aSJames Smart ulp_context = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; 45661910d6aSJames Smart else 45761910d6aSJames Smart ulp_context = ndlp->nlp_rpi; 45861910d6aSJames Smart 45961910d6aSJames Smart lpfc_sli_prep_gen_req(phba, cmdiocbq, bmp, ulp_context, num_entry, 46061910d6aSJames Smart phba->fc_ratov * 2); 46161910d6aSJames Smart 46261910d6aSJames Smart cmdiocbq->num_bdes = num_entry; 463f1c3b0fcSJames Smart cmdiocbq->vport = phba->pport; 464d51cf5bdSJames Smart cmdiocbq->cmd_dmabuf = cmp; 465d51cf5bdSJames Smart cmdiocbq->bpl_dmabuf = bmp; 466a680a929SJames Smart cmdiocbq->cmd_flag |= LPFC_IO_LIBDFC; 467f1c3b0fcSJames Smart 468a680a929SJames Smart cmdiocbq->cmd_cmpl = lpfc_bsg_send_mgmt_cmd_cmp; 469d51cf5bdSJames Smart cmdiocbq->context_un.dd_data = dd_data; 4704430f7fdSJames Smart 4714cc0e56eSJames Smart dd_data->type = TYPE_IOCB; 472a33c4f7bSJames Smart dd_data->set_job = job; 4734cc0e56eSJames Smart dd_data->context_un.iocb.cmdiocbq = cmdiocbq; 474a33c4f7bSJames Smart dd_data->context_un.iocb.rmp = rmp; 475a33c4f7bSJames Smart job->dd_data = dd_data; 476f1c3b0fcSJames Smart 4774cc0e56eSJames Smart if (phba->cfg_poll & DISABLE_FCP_RING_INT) { 4789940b97bSJames Smart if (lpfc_readl(phba->HCregaddr, &creg_val)) { 4799940b97bSJames Smart rc = -EIO ; 480a33c4f7bSJames Smart goto free_rmp; 4819940b97bSJames Smart } 4824cc0e56eSJames Smart creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); 4834cc0e56eSJames Smart writel(creg_val, phba->HCregaddr); 4844cc0e56eSJames Smart readl(phba->HCregaddr); /* flush */ 4854cc0e56eSJames Smart } 4864cc0e56eSJames Smart 487d51cf5bdSJames Smart cmdiocbq->ndlp = lpfc_nlp_get(ndlp); 488d51cf5bdSJames Smart if (!cmdiocbq->ndlp) { 4894430f7fdSJames Smart rc = -ENODEV; 4904430f7fdSJames Smart goto free_rmp; 4914430f7fdSJames Smart } 492b5a9b2dfSJames Smart 4934430f7fdSJames Smart iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); 494b5a9b2dfSJames Smart if (iocb_stat == IOCB_SUCCESS) { 495b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 496b5a9b2dfSJames Smart /* make sure the I/O had not been completed yet */ 497a680a929SJames Smart if (cmdiocbq->cmd_flag & LPFC_IO_LIBDFC) { 498b5a9b2dfSJames Smart /* open up abort window to timeout handler */ 499a680a929SJames Smart cmdiocbq->cmd_flag |= LPFC_IO_CMD_OUTSTANDING; 500b5a9b2dfSJames Smart } 501b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 5024cc0e56eSJames Smart return 0; /* done for now */ 503b5a9b2dfSJames Smart } else if (iocb_stat == IOCB_BUSY) { 504d439d286SJames Smart rc = -EAGAIN; 505b5a9b2dfSJames Smart } else { 506d439d286SJames Smart rc = -EIO; 507b5a9b2dfSJames Smart } 5082a9bf3d0SJames Smart 5094cc0e56eSJames Smart /* iocb failed so cleanup */ 5104430f7fdSJames Smart lpfc_nlp_put(ndlp); 511f1c3b0fcSJames Smart 512a33c4f7bSJames Smart free_rmp: 513a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, rmp); 514a33c4f7bSJames Smart free_cmp: 515a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 516a33c4f7bSJames Smart free_bmp: 517a33c4f7bSJames Smart if (bmp->virt) 518f1c3b0fcSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 519a33c4f7bSJames Smart kfree(bmp); 520f1c3b0fcSJames Smart free_cmdiocbq: 521f1c3b0fcSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 5224430f7fdSJames Smart free_dd: 5234cc0e56eSJames Smart kfree(dd_data); 5244cc0e56eSJames Smart no_dd_data: 525f1c3b0fcSJames Smart /* make error code available to userspace */ 52601e0e15cSJohannes Thumshirn bsg_reply->result = rc; 5274cc0e56eSJames Smart job->dd_data = NULL; 5284cc0e56eSJames Smart return rc; 5294cc0e56eSJames Smart } 5304cc0e56eSJames Smart 5314cc0e56eSJames Smart /** 5324cc0e56eSJames Smart * lpfc_bsg_rport_els_cmp - lpfc_bsg_rport_els's completion handler 5334cc0e56eSJames Smart * @phba: Pointer to HBA context object. 5344cc0e56eSJames Smart * @cmdiocbq: Pointer to command iocb. 5354cc0e56eSJames Smart * @rspiocbq: Pointer to response iocb. 5364cc0e56eSJames Smart * 5374cc0e56eSJames Smart * This function is the completion handler for iocbs issued using 5384cc0e56eSJames Smart * lpfc_bsg_rport_els_cmp function. This function is called by the 5394cc0e56eSJames Smart * ring event handler function without any lock held. This function 5404cc0e56eSJames Smart * can be called from both worker thread context and interrupt 5414cc0e56eSJames Smart * context. This function also can be called from other thread which 5424cc0e56eSJames Smart * cleans up the SLI layer objects. 5433b5dd52aSJames Smart * This function copies the contents of the response iocb to the 5444cc0e56eSJames Smart * response iocb memory object provided by the caller of 5454cc0e56eSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 5464cc0e56eSJames Smart * sleeps for the iocb completion. 5474cc0e56eSJames Smart **/ 5484cc0e56eSJames Smart static void 5494cc0e56eSJames Smart lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba, 5504cc0e56eSJames Smart struct lpfc_iocbq *cmdiocbq, 5514cc0e56eSJames Smart struct lpfc_iocbq *rspiocbq) 5524cc0e56eSJames Smart { 5534cc0e56eSJames Smart struct bsg_job_data *dd_data; 55475cc8cfcSJohannes Thumshirn struct bsg_job *job; 55501e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 5564cc0e56eSJames Smart struct lpfc_nodelist *ndlp; 557a33c4f7bSJames Smart struct lpfc_dmabuf *pcmd = NULL, *prsp = NULL; 5584cc0e56eSJames Smart struct fc_bsg_ctels_reply *els_reply; 5594cc0e56eSJames Smart uint8_t *rjt_data; 5604cc0e56eSJames Smart unsigned long flags; 561a33c4f7bSJames Smart unsigned int rsp_size; 5624cc0e56eSJames Smart int rc = 0; 5630e082d92SJames Smart u32 ulp_status, ulp_word4, total_data_placed; 5644cc0e56eSJames Smart 565d51cf5bdSJames Smart dd_data = cmdiocbq->context_un.dd_data; 5664cc0e56eSJames Smart ndlp = dd_data->context_un.iocb.ndlp; 567d51cf5bdSJames Smart cmdiocbq->ndlp = ndlp; 5684cc0e56eSJames Smart 569a33c4f7bSJames Smart /* Determine if job has been aborted */ 570a33c4f7bSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 571a33c4f7bSJames Smart job = dd_data->set_job; 572a33c4f7bSJames Smart if (job) { 57301e0e15cSJohannes Thumshirn bsg_reply = job->reply; 574a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 575a33c4f7bSJames Smart job->dd_data = NULL; 576a33c4f7bSJames Smart } 577a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 5784cc0e56eSJames Smart 579b5a9b2dfSJames Smart /* Close the timeout handler abort window */ 580b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 581a680a929SJames Smart cmdiocbq->cmd_flag &= ~LPFC_IO_CMD_OUTSTANDING; 582b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 583b5a9b2dfSJames Smart 5840e082d92SJames Smart ulp_status = get_job_ulpstatus(phba, rspiocbq); 5850e082d92SJames Smart ulp_word4 = get_job_word4(phba, rspiocbq); 5860e082d92SJames Smart total_data_placed = get_job_data_placed(phba, rspiocbq); 587d51cf5bdSJames Smart pcmd = cmdiocbq->cmd_dmabuf; 588a33c4f7bSJames Smart prsp = (struct lpfc_dmabuf *)pcmd->list.next; 589a33c4f7bSJames Smart 590a33c4f7bSJames Smart /* Copy the completed job data or determine the job status if job is 591a33c4f7bSJames Smart * still active 592a33c4f7bSJames Smart */ 593a33c4f7bSJames Smart 594a33c4f7bSJames Smart if (job) { 5950e082d92SJames Smart if (ulp_status == IOSTAT_SUCCESS) { 5960e082d92SJames Smart rsp_size = total_data_placed; 59701e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 598a33c4f7bSJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 599a33c4f7bSJames Smart job->reply_payload.sg_cnt, 600a33c4f7bSJames Smart prsp->virt, 601a33c4f7bSJames Smart rsp_size); 6020e082d92SJames Smart } else if (ulp_status == IOSTAT_LS_RJT) { 60301e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 6044cc0e56eSJames Smart sizeof(struct fc_bsg_ctels_reply); 6054cc0e56eSJames Smart /* LS_RJT data returned in word 4 */ 6060e082d92SJames Smart rjt_data = (uint8_t *)&ulp_word4; 60701e0e15cSJohannes Thumshirn els_reply = &bsg_reply->reply_data.ctels_reply; 6084cc0e56eSJames Smart els_reply->status = FC_CTELS_STATUS_REJECT; 6094cc0e56eSJames Smart els_reply->rjt_data.action = rjt_data[3]; 6104cc0e56eSJames Smart els_reply->rjt_data.reason_code = rjt_data[2]; 6114cc0e56eSJames Smart els_reply->rjt_data.reason_explanation = rjt_data[1]; 6124cc0e56eSJames Smart els_reply->rjt_data.vendor_unique = rjt_data[0]; 6130e082d92SJames Smart } else if (ulp_status == IOSTAT_LOCAL_REJECT && 6140e082d92SJames Smart (ulp_word4 & IOERR_PARAM_MASK) == 6150e082d92SJames Smart IOERR_SEQUENCE_TIMEOUT) { 6160e082d92SJames Smart rc = -ETIMEDOUT; 617a33c4f7bSJames Smart } else { 6184cc0e56eSJames Smart rc = -EIO; 619a33c4f7bSJames Smart } 620a33c4f7bSJames Smart } 6214cc0e56eSJames Smart 622a33c4f7bSJames Smart lpfc_els_free_iocb(phba, cmdiocbq); 6234430f7fdSJames Smart 6244430f7fdSJames Smart lpfc_nlp_put(ndlp); 6254cc0e56eSJames Smart kfree(dd_data); 626a33c4f7bSJames Smart 627a33c4f7bSJames Smart /* Complete the job if the job is still active */ 628a33c4f7bSJames Smart 629a33c4f7bSJames Smart if (job) { 63001e0e15cSJohannes Thumshirn bsg_reply->result = rc; 63106548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 6321abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 633a33c4f7bSJames Smart } 6344cc0e56eSJames Smart return; 635f1c3b0fcSJames Smart } 636f1c3b0fcSJames Smart 637f1c3b0fcSJames Smart /** 638f1c3b0fcSJames Smart * lpfc_bsg_rport_els - send an ELS command from a bsg request 639f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 6403b5dd52aSJames Smart **/ 641f1c3b0fcSJames Smart static int 64275cc8cfcSJohannes Thumshirn lpfc_bsg_rport_els(struct bsg_job *job) 643f1c3b0fcSJames Smart { 644cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 645f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 6461d69b122SJohannes Thumshirn struct lpfc_rport_data *rdata = fc_bsg_to_rport(job)->dd_data; 647f1c3b0fcSJames Smart struct lpfc_nodelist *ndlp = rdata->pnode; 64801e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 64901e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 650f1c3b0fcSJames Smart uint32_t elscmd; 651f1c3b0fcSJames Smart uint32_t cmdsize; 652f1c3b0fcSJames Smart struct lpfc_iocbq *cmdiocbq; 653f1c3b0fcSJames Smart uint16_t rpi = 0; 6544cc0e56eSJames Smart struct bsg_job_data *dd_data; 655b5a9b2dfSJames Smart unsigned long flags; 6564cc0e56eSJames Smart uint32_t creg_val; 657f1c3b0fcSJames Smart int rc = 0; 658f1c3b0fcSJames Smart 659f1c3b0fcSJames Smart /* in case no data is transferred */ 66001e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 661f1c3b0fcSJames Smart 662a33c4f7bSJames Smart /* verify the els command is not greater than the 663a33c4f7bSJames Smart * maximum ELS transfer size. 664a33c4f7bSJames Smart */ 665a33c4f7bSJames Smart 666a33c4f7bSJames Smart if (job->request_payload.payload_len > FCELSSIZE) { 667a33c4f7bSJames Smart rc = -EINVAL; 668a33c4f7bSJames Smart goto no_dd_data; 669a33c4f7bSJames Smart } 670a33c4f7bSJames Smart 6714cc0e56eSJames Smart /* allocate our bsg tracking structure */ 6724cc0e56eSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 6734cc0e56eSJames Smart if (!dd_data) { 6744cc0e56eSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 6754cc0e56eSJames Smart "2735 Failed allocation of dd_data\n"); 6764cc0e56eSJames Smart rc = -ENOMEM; 6774cc0e56eSJames Smart goto no_dd_data; 6784cc0e56eSJames Smart } 6794cc0e56eSJames Smart 68001e0e15cSJohannes Thumshirn elscmd = bsg_request->rqst_data.r_els.els_code; 681a33c4f7bSJames Smart cmdsize = job->request_payload.payload_len; 682a33c4f7bSJames Smart 683f1c3b0fcSJames Smart if (!lpfc_nlp_get(ndlp)) { 684f1c3b0fcSJames Smart rc = -ENODEV; 6854cc0e56eSJames Smart goto free_dd_data; 686f1c3b0fcSJames Smart } 687f1c3b0fcSJames Smart 688a33c4f7bSJames Smart /* We will use the allocated dma buffers by prep els iocb for command 689a33c4f7bSJames Smart * and response to ensure if the job times out and the request is freed, 690a33c4f7bSJames Smart * we won't be dma into memory that is no longer allocated to for the 691a33c4f7bSJames Smart * request. 692a33c4f7bSJames Smart */ 6934cc0e56eSJames Smart cmdiocbq = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, 694f1c3b0fcSJames Smart ndlp->nlp_DID, elscmd); 695f1c3b0fcSJames Smart if (!cmdiocbq) { 6964cc0e56eSJames Smart rc = -EIO; 697a33c4f7bSJames Smart goto release_ndlp; 698f1c3b0fcSJames Smart } 699f1c3b0fcSJames Smart 700a33c4f7bSJames Smart /* Transfer the request payload to allocated command dma buffer */ 701a33c4f7bSJames Smart sg_copy_to_buffer(job->request_payload.sg_list, 702a33c4f7bSJames Smart job->request_payload.sg_cnt, 703d51cf5bdSJames Smart cmdiocbq->cmd_dmabuf->virt, 704d51cf5bdSJames Smart cmdsize); 705f1c3b0fcSJames Smart 7064430f7fdSJames Smart rpi = ndlp->nlp_rpi; 7074430f7fdSJames Smart 7083ef6d24cSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 7090e082d92SJames Smart bf_set(wqe_ctxt_tag, &cmdiocbq->wqe.generic.wqe_com, 7100e082d92SJames Smart phba->sli4_hba.rpi_ids[rpi]); 7113ef6d24cSJames Smart else 712f1c3b0fcSJames Smart cmdiocbq->iocb.ulpContext = rpi; 713a680a929SJames Smart cmdiocbq->cmd_flag |= LPFC_IO_LIBDFC; 714d51cf5bdSJames Smart cmdiocbq->context_un.dd_data = dd_data; 715d51cf5bdSJames Smart cmdiocbq->ndlp = ndlp; 716a680a929SJames Smart cmdiocbq->cmd_cmpl = lpfc_bsg_rport_els_cmp; 7174cc0e56eSJames Smart dd_data->type = TYPE_IOCB; 718a33c4f7bSJames Smart dd_data->set_job = job; 7194cc0e56eSJames Smart dd_data->context_un.iocb.cmdiocbq = cmdiocbq; 7204cc0e56eSJames Smart dd_data->context_un.iocb.ndlp = ndlp; 721a33c4f7bSJames Smart dd_data->context_un.iocb.rmp = NULL; 722a33c4f7bSJames Smart job->dd_data = dd_data; 723f1c3b0fcSJames Smart 7244cc0e56eSJames Smart if (phba->cfg_poll & DISABLE_FCP_RING_INT) { 7259940b97bSJames Smart if (lpfc_readl(phba->HCregaddr, &creg_val)) { 7269940b97bSJames Smart rc = -EIO; 7279940b97bSJames Smart goto linkdown_err; 7289940b97bSJames Smart } 7294cc0e56eSJames Smart creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); 7304cc0e56eSJames Smart writel(creg_val, phba->HCregaddr); 7314cc0e56eSJames Smart readl(phba->HCregaddr); /* flush */ 7324cc0e56eSJames Smart } 733a33c4f7bSJames Smart 7344430f7fdSJames Smart rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); 735b5a9b2dfSJames Smart if (rc == IOCB_SUCCESS) { 736b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 737b5a9b2dfSJames Smart /* make sure the I/O had not been completed/released */ 738a680a929SJames Smart if (cmdiocbq->cmd_flag & LPFC_IO_LIBDFC) { 739b5a9b2dfSJames Smart /* open up abort window to timeout handler */ 740a680a929SJames Smart cmdiocbq->cmd_flag |= LPFC_IO_CMD_OUTSTANDING; 741b5a9b2dfSJames Smart } 742b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 7434cc0e56eSJames Smart return 0; /* done for now */ 744b5a9b2dfSJames Smart } else if (rc == IOCB_BUSY) { 745d439d286SJames Smart rc = -EAGAIN; 746b5a9b2dfSJames Smart } else { 747d439d286SJames Smart rc = -EIO; 748b5a9b2dfSJames Smart } 749b5a9b2dfSJames Smart 7504430f7fdSJames Smart /* I/O issue failed. Cleanup resources. */ 7514cc0e56eSJames Smart 7529940b97bSJames Smart linkdown_err: 753a33c4f7bSJames Smart lpfc_els_free_iocb(phba, cmdiocbq); 754f1c3b0fcSJames Smart 755a33c4f7bSJames Smart release_ndlp: 756a33c4f7bSJames Smart lpfc_nlp_put(ndlp); 757f1c3b0fcSJames Smart 7584cc0e56eSJames Smart free_dd_data: 7594cc0e56eSJames Smart kfree(dd_data); 7604cc0e56eSJames Smart 7614cc0e56eSJames Smart no_dd_data: 762f1c3b0fcSJames Smart /* make error code available to userspace */ 76301e0e15cSJohannes Thumshirn bsg_reply->result = rc; 7644cc0e56eSJames Smart job->dd_data = NULL; 7654cc0e56eSJames Smart return rc; 766f1c3b0fcSJames Smart } 767f1c3b0fcSJames Smart 7683b5dd52aSJames Smart /** 7693b5dd52aSJames Smart * lpfc_bsg_event_free - frees an allocated event structure 7703b5dd52aSJames Smart * @kref: Pointer to a kref. 7713b5dd52aSJames Smart * 7723b5dd52aSJames Smart * Called from kref_put. Back cast the kref into an event structure address. 7733b5dd52aSJames Smart * Free any events to get, delete associated nodes, free any events to see, 7743b5dd52aSJames Smart * free any data then free the event itself. 7753b5dd52aSJames Smart **/ 776f1c3b0fcSJames Smart static void 7774cc0e56eSJames Smart lpfc_bsg_event_free(struct kref *kref) 778f1c3b0fcSJames Smart { 7794cc0e56eSJames Smart struct lpfc_bsg_event *evt = container_of(kref, struct lpfc_bsg_event, 7804cc0e56eSJames Smart kref); 781f1c3b0fcSJames Smart struct event_data *ed; 782f1c3b0fcSJames Smart 783f1c3b0fcSJames Smart list_del(&evt->node); 784f1c3b0fcSJames Smart 785f1c3b0fcSJames Smart while (!list_empty(&evt->events_to_get)) { 786f1c3b0fcSJames Smart ed = list_entry(evt->events_to_get.next, typeof(*ed), node); 787f1c3b0fcSJames Smart list_del(&ed->node); 788f1c3b0fcSJames Smart kfree(ed->data); 789f1c3b0fcSJames Smart kfree(ed); 790f1c3b0fcSJames Smart } 791f1c3b0fcSJames Smart 792f1c3b0fcSJames Smart while (!list_empty(&evt->events_to_see)) { 793f1c3b0fcSJames Smart ed = list_entry(evt->events_to_see.next, typeof(*ed), node); 794f1c3b0fcSJames Smart list_del(&ed->node); 795f1c3b0fcSJames Smart kfree(ed->data); 796f1c3b0fcSJames Smart kfree(ed); 797f1c3b0fcSJames Smart } 798f1c3b0fcSJames Smart 799a33c4f7bSJames Smart kfree(evt->dd_data); 800f1c3b0fcSJames Smart kfree(evt); 801f1c3b0fcSJames Smart } 802f1c3b0fcSJames Smart 8033b5dd52aSJames Smart /** 8043b5dd52aSJames Smart * lpfc_bsg_event_ref - increments the kref for an event 8053b5dd52aSJames Smart * @evt: Pointer to an event structure. 8063b5dd52aSJames Smart **/ 807f1c3b0fcSJames Smart static inline void 8084cc0e56eSJames Smart lpfc_bsg_event_ref(struct lpfc_bsg_event *evt) 809f1c3b0fcSJames Smart { 8104cc0e56eSJames Smart kref_get(&evt->kref); 811f1c3b0fcSJames Smart } 812f1c3b0fcSJames Smart 8133b5dd52aSJames Smart /** 8143b5dd52aSJames Smart * lpfc_bsg_event_unref - Uses kref_put to free an event structure 8153b5dd52aSJames Smart * @evt: Pointer to an event structure. 8163b5dd52aSJames Smart **/ 817f1c3b0fcSJames Smart static inline void 8184cc0e56eSJames Smart lpfc_bsg_event_unref(struct lpfc_bsg_event *evt) 819f1c3b0fcSJames Smart { 8204cc0e56eSJames Smart kref_put(&evt->kref, lpfc_bsg_event_free); 821f1c3b0fcSJames Smart } 822f1c3b0fcSJames Smart 8233b5dd52aSJames Smart /** 8243b5dd52aSJames Smart * lpfc_bsg_event_new - allocate and initialize a event structure 8253b5dd52aSJames Smart * @ev_mask: Mask of events. 8263b5dd52aSJames Smart * @ev_reg_id: Event reg id. 8273b5dd52aSJames Smart * @ev_req_id: Event request id. 8283b5dd52aSJames Smart **/ 8294cc0e56eSJames Smart static struct lpfc_bsg_event * 8304cc0e56eSJames Smart lpfc_bsg_event_new(uint32_t ev_mask, int ev_reg_id, uint32_t ev_req_id) 8314cc0e56eSJames Smart { 8324cc0e56eSJames Smart struct lpfc_bsg_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL); 833f1c3b0fcSJames Smart 8344cc0e56eSJames Smart if (!evt) 8354cc0e56eSJames Smart return NULL; 8364cc0e56eSJames Smart 8374cc0e56eSJames Smart INIT_LIST_HEAD(&evt->events_to_get); 8384cc0e56eSJames Smart INIT_LIST_HEAD(&evt->events_to_see); 8394cc0e56eSJames Smart evt->type_mask = ev_mask; 8404cc0e56eSJames Smart evt->req_id = ev_req_id; 8414cc0e56eSJames Smart evt->reg_id = ev_reg_id; 8424cc0e56eSJames Smart evt->wait_time_stamp = jiffies; 843a33c4f7bSJames Smart evt->dd_data = NULL; 8444cc0e56eSJames Smart init_waitqueue_head(&evt->wq); 8454cc0e56eSJames Smart kref_init(&evt->kref); 8464cc0e56eSJames Smart return evt; 8474cc0e56eSJames Smart } 8484cc0e56eSJames Smart 8493b5dd52aSJames Smart /** 8503b5dd52aSJames Smart * diag_cmd_data_free - Frees an lpfc dma buffer extension 8513b5dd52aSJames Smart * @phba: Pointer to HBA context object. 8523b5dd52aSJames Smart * @mlist: Pointer to an lpfc dma buffer extension. 8533b5dd52aSJames Smart **/ 8544cc0e56eSJames Smart static int 8553b5dd52aSJames Smart diag_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist) 8564cc0e56eSJames Smart { 8574cc0e56eSJames Smart struct lpfc_dmabufext *mlast; 8584cc0e56eSJames Smart struct pci_dev *pcidev; 8594cc0e56eSJames Smart struct list_head head, *curr, *next; 8604cc0e56eSJames Smart 8614cc0e56eSJames Smart if ((!mlist) || (!lpfc_is_link_up(phba) && 8624cc0e56eSJames Smart (phba->link_flag & LS_LOOPBACK_MODE))) { 8634cc0e56eSJames Smart return 0; 8644cc0e56eSJames Smart } 8654cc0e56eSJames Smart 8664cc0e56eSJames Smart pcidev = phba->pcidev; 8674cc0e56eSJames Smart list_add_tail(&head, &mlist->dma.list); 8684cc0e56eSJames Smart 8694cc0e56eSJames Smart list_for_each_safe(curr, next, &head) { 8704cc0e56eSJames Smart mlast = list_entry(curr, struct lpfc_dmabufext , dma.list); 8714cc0e56eSJames Smart if (mlast->dma.virt) 8724cc0e56eSJames Smart dma_free_coherent(&pcidev->dev, 8734cc0e56eSJames Smart mlast->size, 8744cc0e56eSJames Smart mlast->dma.virt, 8754cc0e56eSJames Smart mlast->dma.phys); 8764cc0e56eSJames Smart kfree(mlast); 8774cc0e56eSJames Smart } 8784cc0e56eSJames Smart return 0; 8794cc0e56eSJames Smart } 880f1c3b0fcSJames Smart 881ea085dabSLee Jones /* 882f1c3b0fcSJames Smart * lpfc_bsg_ct_unsol_event - process an unsolicited CT command 883f1c3b0fcSJames Smart * 884f1c3b0fcSJames Smart * This function is called when an unsolicited CT command is received. It 8854cc0e56eSJames Smart * forwards the event to any processes registered to receive CT events. 8863b5dd52aSJames Smart **/ 8874fede78fSJames Smart int 888f1c3b0fcSJames Smart lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, 889f1c3b0fcSJames Smart struct lpfc_iocbq *piocbq) 890f1c3b0fcSJames Smart { 891f1c3b0fcSJames Smart uint32_t evt_req_id = 0; 8929cefd6e7SJustin Tee u16 cmd; 893f1c3b0fcSJames Smart struct lpfc_dmabuf *dmabuf = NULL; 8944cc0e56eSJames Smart struct lpfc_bsg_event *evt; 895f1c3b0fcSJames Smart struct event_data *evt_dat = NULL; 896f1c3b0fcSJames Smart struct lpfc_iocbq *iocbq; 89761910d6aSJames Smart IOCB_t *iocb = NULL; 898f1c3b0fcSJames Smart size_t offset = 0; 899f1c3b0fcSJames Smart struct list_head head; 900f1c3b0fcSJames Smart struct ulp_bde64 *bde; 901f1c3b0fcSJames Smart dma_addr_t dma_addr; 902f1c3b0fcSJames Smart int i; 903d51cf5bdSJames Smart struct lpfc_dmabuf *bdeBuf1 = piocbq->cmd_dmabuf; 904d51cf5bdSJames Smart struct lpfc_dmabuf *bdeBuf2 = piocbq->bpl_dmabuf; 905f1c3b0fcSJames Smart struct lpfc_sli_ct_request *ct_req; 90675cc8cfcSJohannes Thumshirn struct bsg_job *job = NULL; 90701e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 908a33c4f7bSJames Smart struct bsg_job_data *dd_data = NULL; 9094fede78fSJames Smart unsigned long flags; 9104cc0e56eSJames Smart int size = 0; 91161910d6aSJames Smart u32 bde_count = 0; 912f1c3b0fcSJames Smart 913f1c3b0fcSJames Smart INIT_LIST_HEAD(&head); 914f1c3b0fcSJames Smart list_add_tail(&head, &piocbq->list); 915f1c3b0fcSJames Smart 91683adbba7SJames Smart ct_req = (struct lpfc_sli_ct_request *)bdeBuf1->virt; 917f1c3b0fcSJames Smart evt_req_id = ct_req->FsType; 9189cefd6e7SJustin Tee cmd = be16_to_cpu(ct_req->CommandResponse.bits.CmdRsp); 919f1c3b0fcSJames Smart 9204fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 921f1c3b0fcSJames Smart list_for_each_entry(evt, &phba->ct_ev_waiters, node) { 9224cc0e56eSJames Smart if (!(evt->type_mask & FC_REG_CT_EVENT) || 9234cc0e56eSJames Smart evt->req_id != evt_req_id) 924f1c3b0fcSJames Smart continue; 925f1c3b0fcSJames Smart 9264cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 9274cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 928f1c3b0fcSJames Smart evt_dat = kzalloc(sizeof(*evt_dat), GFP_KERNEL); 9294cc0e56eSJames Smart if (evt_dat == NULL) { 9304cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 9314cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 932f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 933f1c3b0fcSJames Smart "2614 Memory allocation failed for " 934f1c3b0fcSJames Smart "CT event\n"); 935f1c3b0fcSJames Smart break; 936f1c3b0fcSJames Smart } 937f1c3b0fcSJames Smart 938f1c3b0fcSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 939f1c3b0fcSJames Smart /* take accumulated byte count from the last iocbq */ 940f1c3b0fcSJames Smart iocbq = list_entry(head.prev, typeof(*iocbq), list); 94161910d6aSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 94261910d6aSJames Smart evt_dat->len = iocbq->wcqe_cmpl.total_data_placed; 94361910d6aSJames Smart else 944f1c3b0fcSJames Smart evt_dat->len = iocbq->iocb.unsli3.rcvsli3.acc_len; 945f1c3b0fcSJames Smart } else { 946f1c3b0fcSJames Smart list_for_each_entry(iocbq, &head, list) { 94761910d6aSJames Smart iocb = &iocbq->iocb; 94861910d6aSJames Smart for (i = 0; i < iocb->ulpBdeCount; 94961910d6aSJames Smart i++) 950f1c3b0fcSJames Smart evt_dat->len += 95161910d6aSJames Smart iocb->un.cont64[i].tus.f.bdeSize; 952f1c3b0fcSJames Smart } 953f1c3b0fcSJames Smart } 954f1c3b0fcSJames Smart 955f1c3b0fcSJames Smart evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL); 9564cc0e56eSJames Smart if (evt_dat->data == NULL) { 957f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 958f1c3b0fcSJames Smart "2615 Memory allocation failed for " 959f1c3b0fcSJames Smart "CT event data, size %d\n", 960f1c3b0fcSJames Smart evt_dat->len); 961f1c3b0fcSJames Smart kfree(evt_dat); 9624fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 9634cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 9644fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 965f1c3b0fcSJames Smart goto error_ct_unsol_exit; 966f1c3b0fcSJames Smart } 967f1c3b0fcSJames Smart 968f1c3b0fcSJames Smart list_for_each_entry(iocbq, &head, list) { 9694cc0e56eSJames Smart size = 0; 970f1c3b0fcSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 971d51cf5bdSJames Smart bdeBuf1 = iocbq->cmd_dmabuf; 972d51cf5bdSJames Smart bdeBuf2 = iocbq->bpl_dmabuf; 973f1c3b0fcSJames Smart } 97461910d6aSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 97561910d6aSJames Smart bde_count = iocbq->wcqe_cmpl.word3; 97661910d6aSJames Smart else 97761910d6aSJames Smart bde_count = iocbq->iocb.ulpBdeCount; 97861910d6aSJames Smart for (i = 0; i < bde_count; i++) { 979f1c3b0fcSJames Smart if (phba->sli3_options & 980f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED) { 981f1c3b0fcSJames Smart if (i == 0) { 98261910d6aSJames Smart size = iocbq->wqe.gen_req.bde.tus.f.bdeSize; 983f1c3b0fcSJames Smart dmabuf = bdeBuf1; 984f1c3b0fcSJames Smart } else if (i == 1) { 98561910d6aSJames Smart size = iocbq->unsol_rcv_len; 986f1c3b0fcSJames Smart dmabuf = bdeBuf2; 987f1c3b0fcSJames Smart } 988f1c3b0fcSJames Smart if ((offset + size) > evt_dat->len) 989f1c3b0fcSJames Smart size = evt_dat->len - offset; 990f1c3b0fcSJames Smart } else { 991f1c3b0fcSJames Smart size = iocbq->iocb.un.cont64[i]. 992f1c3b0fcSJames Smart tus.f.bdeSize; 993f1c3b0fcSJames Smart bde = &iocbq->iocb.un.cont64[i]; 994f1c3b0fcSJames Smart dma_addr = getPaddr(bde->addrHigh, 995f1c3b0fcSJames Smart bde->addrLow); 996f1c3b0fcSJames Smart dmabuf = lpfc_sli_ringpostbuf_get(phba, 997f1c3b0fcSJames Smart pring, dma_addr); 998f1c3b0fcSJames Smart } 999f1c3b0fcSJames Smart if (!dmabuf) { 1000f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_ERR, 1001f1c3b0fcSJames Smart LOG_LIBDFC, "2616 No dmabuf " 100232350664SJames Smart "found for iocbq x%px\n", 1003f1c3b0fcSJames Smart iocbq); 1004f1c3b0fcSJames Smart kfree(evt_dat->data); 1005f1c3b0fcSJames Smart kfree(evt_dat); 10064fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, 10074fede78fSJames Smart flags); 10084cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 10094fede78fSJames Smart spin_unlock_irqrestore( 10104fede78fSJames Smart &phba->ct_ev_lock, flags); 1011f1c3b0fcSJames Smart goto error_ct_unsol_exit; 1012f1c3b0fcSJames Smart } 1013f1c3b0fcSJames Smart memcpy((char *)(evt_dat->data) + offset, 1014f1c3b0fcSJames Smart dmabuf->virt, size); 1015f1c3b0fcSJames Smart offset += size; 1016f1c3b0fcSJames Smart if (evt_req_id != SLI_CT_ELX_LOOPBACK && 1017f1c3b0fcSJames Smart !(phba->sli3_options & 1018f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED)) { 1019f1c3b0fcSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, 1020f1c3b0fcSJames Smart dmabuf); 1021f1c3b0fcSJames Smart } else { 1022f1c3b0fcSJames Smart switch (cmd) { 10234cc0e56eSJames Smart case ELX_LOOPBACK_DATA: 10241b51197dSJames Smart if (phba->sli_rev < 10251b51197dSJames Smart LPFC_SLI_REV4) 10263b5dd52aSJames Smart diag_cmd_data_free(phba, 10271b51197dSJames Smart (struct lpfc_dmabufext 10281b51197dSJames Smart *)dmabuf); 10294cc0e56eSJames Smart break; 1030f1c3b0fcSJames Smart case ELX_LOOPBACK_XRI_SETUP: 10314cc0e56eSJames Smart if ((phba->sli_rev == 10324cc0e56eSJames Smart LPFC_SLI_REV2) || 10334cc0e56eSJames Smart (phba->sli3_options & 10344cc0e56eSJames Smart LPFC_SLI3_HBQ_ENABLED 10354cc0e56eSJames Smart )) { 10364cc0e56eSJames Smart lpfc_in_buf_free(phba, 10374cc0e56eSJames Smart dmabuf); 10384cc0e56eSJames Smart } else { 1039a680a929SJames Smart lpfc_sli3_post_buffer(phba, 1040f1c3b0fcSJames Smart pring, 1041f1c3b0fcSJames Smart 1); 10424cc0e56eSJames Smart } 1043f1c3b0fcSJames Smart break; 1044f1c3b0fcSJames Smart default: 1045f1c3b0fcSJames Smart if (!(phba->sli3_options & 1046f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED)) 1047a680a929SJames Smart lpfc_sli3_post_buffer(phba, 1048f1c3b0fcSJames Smart pring, 1049f1c3b0fcSJames Smart 1); 1050f1c3b0fcSJames Smart break; 1051f1c3b0fcSJames Smart } 1052f1c3b0fcSJames Smart } 1053f1c3b0fcSJames Smart } 1054f1c3b0fcSJames Smart } 1055f1c3b0fcSJames Smart 10564fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1057f1c3b0fcSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) { 1058f1c3b0fcSJames Smart evt_dat->immed_dat = phba->ctx_idx; 10596dd9e31cSJames Smart phba->ctx_idx = (phba->ctx_idx + 1) % LPFC_CT_CTX_MAX; 1060589a52d6SJames Smart /* Provide warning for over-run of the ct_ctx array */ 10616dd9e31cSJames Smart if (phba->ct_ctx[evt_dat->immed_dat].valid == 1062589a52d6SJames Smart UNSOL_VALID) 1063589a52d6SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, 1064589a52d6SJames Smart "2717 CT context array entry " 1065589a52d6SJames Smart "[%d] over-run: oxid:x%x, " 1066589a52d6SJames Smart "sid:x%x\n", phba->ctx_idx, 1067589a52d6SJames Smart phba->ct_ctx[ 1068589a52d6SJames Smart evt_dat->immed_dat].oxid, 1069589a52d6SJames Smart phba->ct_ctx[ 1070589a52d6SJames Smart evt_dat->immed_dat].SID); 10717851fe2cSJames Smart phba->ct_ctx[evt_dat->immed_dat].rxid = 107261910d6aSJames Smart get_job_ulpcontext(phba, piocbq); 10737851fe2cSJames Smart phba->ct_ctx[evt_dat->immed_dat].oxid = 107461910d6aSJames Smart get_job_rcvoxid(phba, piocbq); 1075f1c3b0fcSJames Smart phba->ct_ctx[evt_dat->immed_dat].SID = 107661910d6aSJames Smart bf_get(wqe_els_did, 107761910d6aSJames Smart &piocbq->wqe.xmit_els_rsp.wqe_dest); 10786dd9e31cSJames Smart phba->ct_ctx[evt_dat->immed_dat].valid = UNSOL_VALID; 1079f1c3b0fcSJames Smart } else 108061910d6aSJames Smart evt_dat->immed_dat = get_job_ulpcontext(phba, piocbq); 1081f1c3b0fcSJames Smart 1082f1c3b0fcSJames Smart evt_dat->type = FC_REG_CT_EVENT; 1083f1c3b0fcSJames Smart list_add(&evt_dat->node, &evt->events_to_see); 10844cc0e56eSJames Smart if (evt_req_id == SLI_CT_ELX_LOOPBACK) { 1085f1c3b0fcSJames Smart wake_up_interruptible(&evt->wq); 10864cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 1087f1c3b0fcSJames Smart break; 1088f1c3b0fcSJames Smart } 10894cc0e56eSJames Smart 10904cc0e56eSJames Smart list_move(evt->events_to_see.prev, &evt->events_to_get); 10914cc0e56eSJames Smart 1092a33c4f7bSJames Smart dd_data = (struct bsg_job_data *)evt->dd_data; 1093a33c4f7bSJames Smart job = dd_data->set_job; 1094a33c4f7bSJames Smart dd_data->set_job = NULL; 1095a33c4f7bSJames Smart lpfc_bsg_event_unref(evt); 10964cc0e56eSJames Smart if (job) { 109701e0e15cSJohannes Thumshirn bsg_reply = job->reply; 109801e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = size; 10994cc0e56eSJames Smart /* make error code available to userspace */ 110001e0e15cSJohannes Thumshirn bsg_reply->result = 0; 11014cc0e56eSJames Smart job->dd_data = NULL; 11024cc0e56eSJames Smart /* complete the job back to userspace */ 11034cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 110406548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 11051abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 11064cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 11074cc0e56eSJames Smart } 11084cc0e56eSJames Smart } 11094fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 1110f1c3b0fcSJames Smart 1111f1c3b0fcSJames Smart error_ct_unsol_exit: 1112f1c3b0fcSJames Smart if (!list_empty(&head)) 1113f1c3b0fcSJames Smart list_del(&head); 11141b51197dSJames Smart if ((phba->sli_rev < LPFC_SLI_REV4) && 11151b51197dSJames Smart (evt_req_id == SLI_CT_ELX_LOOPBACK)) 11164cc0e56eSJames Smart return 0; 11174fede78fSJames Smart return 1; 1118f1c3b0fcSJames Smart } 1119f1c3b0fcSJames Smart 1120f1c3b0fcSJames Smart /** 11216dd9e31cSJames Smart * lpfc_bsg_ct_unsol_abort - handler ct abort to management plane 11226dd9e31cSJames Smart * @phba: Pointer to HBA context object. 11236dd9e31cSJames Smart * @dmabuf: pointer to a dmabuf that describes the FC sequence 11246dd9e31cSJames Smart * 11256dd9e31cSJames Smart * This function handles abort to the CT command toward management plane 11266dd9e31cSJames Smart * for SLI4 port. 11276dd9e31cSJames Smart * 11286dd9e31cSJames Smart * If the pending context of a CT command to management plane present, clears 11296dd9e31cSJames Smart * such context and returns 1 for handled; otherwise, it returns 0 indicating 11306dd9e31cSJames Smart * no context exists. 11316dd9e31cSJames Smart **/ 11326dd9e31cSJames Smart int 11336dd9e31cSJames Smart lpfc_bsg_ct_unsol_abort(struct lpfc_hba *phba, struct hbq_dmabuf *dmabuf) 11346dd9e31cSJames Smart { 11356dd9e31cSJames Smart struct fc_frame_header fc_hdr; 11366dd9e31cSJames Smart struct fc_frame_header *fc_hdr_ptr = &fc_hdr; 11376dd9e31cSJames Smart int ctx_idx, handled = 0; 11386dd9e31cSJames Smart uint16_t oxid, rxid; 11396dd9e31cSJames Smart uint32_t sid; 11406dd9e31cSJames Smart 11416dd9e31cSJames Smart memcpy(fc_hdr_ptr, dmabuf->hbuf.virt, sizeof(struct fc_frame_header)); 11426dd9e31cSJames Smart sid = sli4_sid_from_fc_hdr(fc_hdr_ptr); 11436dd9e31cSJames Smart oxid = be16_to_cpu(fc_hdr_ptr->fh_ox_id); 11446dd9e31cSJames Smart rxid = be16_to_cpu(fc_hdr_ptr->fh_rx_id); 11456dd9e31cSJames Smart 11466dd9e31cSJames Smart for (ctx_idx = 0; ctx_idx < LPFC_CT_CTX_MAX; ctx_idx++) { 11476dd9e31cSJames Smart if (phba->ct_ctx[ctx_idx].valid != UNSOL_VALID) 11486dd9e31cSJames Smart continue; 11496dd9e31cSJames Smart if (phba->ct_ctx[ctx_idx].rxid != rxid) 11506dd9e31cSJames Smart continue; 11516dd9e31cSJames Smart if (phba->ct_ctx[ctx_idx].oxid != oxid) 11526dd9e31cSJames Smart continue; 11536dd9e31cSJames Smart if (phba->ct_ctx[ctx_idx].SID != sid) 11546dd9e31cSJames Smart continue; 11556dd9e31cSJames Smart phba->ct_ctx[ctx_idx].valid = UNSOL_INVALID; 11566dd9e31cSJames Smart handled = 1; 11576dd9e31cSJames Smart } 11586dd9e31cSJames Smart return handled; 11596dd9e31cSJames Smart } 11606dd9e31cSJames Smart 11616dd9e31cSJames Smart /** 11624cc0e56eSJames Smart * lpfc_bsg_hba_set_event - process a SET_EVENT bsg vendor command 1163f1c3b0fcSJames Smart * @job: SET_EVENT fc_bsg_job 11643b5dd52aSJames Smart **/ 1165f1c3b0fcSJames Smart static int 116675cc8cfcSJohannes Thumshirn lpfc_bsg_hba_set_event(struct bsg_job *job) 1167f1c3b0fcSJames Smart { 1168cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 1169f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 117001e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 1171f1c3b0fcSJames Smart struct set_ct_event *event_req; 11724cc0e56eSJames Smart struct lpfc_bsg_event *evt; 1173f1c3b0fcSJames Smart int rc = 0; 11744cc0e56eSJames Smart struct bsg_job_data *dd_data = NULL; 11754cc0e56eSJames Smart uint32_t ev_mask; 11764cc0e56eSJames Smart unsigned long flags; 1177f1c3b0fcSJames Smart 1178f1c3b0fcSJames Smart if (job->request_len < 1179f1c3b0fcSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct set_ct_event)) { 1180f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1181f1c3b0fcSJames Smart "2612 Received SET_CT_EVENT below minimum " 1182f1c3b0fcSJames Smart "size\n"); 11834cc0e56eSJames Smart rc = -EINVAL; 11844cc0e56eSJames Smart goto job_error; 11854cc0e56eSJames Smart } 11864cc0e56eSJames Smart 1187f1c3b0fcSJames Smart event_req = (struct set_ct_event *) 118801e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 11894cc0e56eSJames Smart ev_mask = ((uint32_t)(unsigned long)event_req->type_mask & 11904cc0e56eSJames Smart FC_REG_EVENT_MASK); 11914fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1192f1c3b0fcSJames Smart list_for_each_entry(evt, &phba->ct_ev_waiters, node) { 1193f1c3b0fcSJames Smart if (evt->reg_id == event_req->ev_reg_id) { 11944cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 1195f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 1196a33c4f7bSJames Smart dd_data = (struct bsg_job_data *)evt->dd_data; 1197f1c3b0fcSJames Smart break; 1198f1c3b0fcSJames Smart } 1199f1c3b0fcSJames Smart } 12004fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 1201f1c3b0fcSJames Smart 1202f1c3b0fcSJames Smart if (&evt->node == &phba->ct_ev_waiters) { 1203f1c3b0fcSJames Smart /* no event waiting struct yet - first call */ 1204a33c4f7bSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 1205a33c4f7bSJames Smart if (dd_data == NULL) { 1206a33c4f7bSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1207a33c4f7bSJames Smart "2734 Failed allocation of dd_data\n"); 1208a33c4f7bSJames Smart rc = -ENOMEM; 1209a33c4f7bSJames Smart goto job_error; 1210a33c4f7bSJames Smart } 12114cc0e56eSJames Smart evt = lpfc_bsg_event_new(ev_mask, event_req->ev_reg_id, 1212f1c3b0fcSJames Smart event_req->ev_req_id); 1213f1c3b0fcSJames Smart if (!evt) { 1214f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1215f1c3b0fcSJames Smart "2617 Failed allocation of event " 1216f1c3b0fcSJames Smart "waiter\n"); 12174cc0e56eSJames Smart rc = -ENOMEM; 12184cc0e56eSJames Smart goto job_error; 1219f1c3b0fcSJames Smart } 1220a33c4f7bSJames Smart dd_data->type = TYPE_EVT; 1221a33c4f7bSJames Smart dd_data->set_job = NULL; 1222a33c4f7bSJames Smart dd_data->context_un.evt = evt; 1223a33c4f7bSJames Smart evt->dd_data = (void *)dd_data; 12244fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1225f1c3b0fcSJames Smart list_add(&evt->node, &phba->ct_ev_waiters); 12264cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 1227f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 12284cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 12294cc0e56eSJames Smart } 1230f1c3b0fcSJames Smart 12314fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 12324cc0e56eSJames Smart evt->waiting = 1; 1233a33c4f7bSJames Smart dd_data->set_job = job; /* for unsolicited command */ 12344cc0e56eSJames Smart job->dd_data = dd_data; /* for fc transport timeout callback*/ 12354fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 12364cc0e56eSJames Smart return 0; /* call job done later */ 1237f1c3b0fcSJames Smart 12384cc0e56eSJames Smart job_error: 12394cc0e56eSJames Smart kfree(dd_data); 12404cc0e56eSJames Smart job->dd_data = NULL; 12414cc0e56eSJames Smart return rc; 1242f1c3b0fcSJames Smart } 1243f1c3b0fcSJames Smart 1244f1c3b0fcSJames Smart /** 12454cc0e56eSJames Smart * lpfc_bsg_hba_get_event - process a GET_EVENT bsg vendor command 1246f1c3b0fcSJames Smart * @job: GET_EVENT fc_bsg_job 12473b5dd52aSJames Smart **/ 1248f1c3b0fcSJames Smart static int 124975cc8cfcSJohannes Thumshirn lpfc_bsg_hba_get_event(struct bsg_job *job) 1250f1c3b0fcSJames Smart { 1251cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 1252f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 125301e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 125401e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 1255f1c3b0fcSJames Smart struct get_ct_event *event_req; 1256f1c3b0fcSJames Smart struct get_ct_event_reply *event_reply; 12579a803a74SJames Smart struct lpfc_bsg_event *evt, *evt_next; 1258f1c3b0fcSJames Smart struct event_data *evt_dat = NULL; 12594fede78fSJames Smart unsigned long flags; 12604cc0e56eSJames Smart uint32_t rc = 0; 1261f1c3b0fcSJames Smart 1262f1c3b0fcSJames Smart if (job->request_len < 1263f1c3b0fcSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct get_ct_event)) { 1264f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1265f1c3b0fcSJames Smart "2613 Received GET_CT_EVENT request below " 1266f1c3b0fcSJames Smart "minimum size\n"); 12674cc0e56eSJames Smart rc = -EINVAL; 12684cc0e56eSJames Smart goto job_error; 1269f1c3b0fcSJames Smart } 1270f1c3b0fcSJames Smart 1271f1c3b0fcSJames Smart event_req = (struct get_ct_event *) 127201e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 1273f1c3b0fcSJames Smart 1274f1c3b0fcSJames Smart event_reply = (struct get_ct_event_reply *) 127501e0e15cSJohannes Thumshirn bsg_reply->reply_data.vendor_reply.vendor_rsp; 12764fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 12779a803a74SJames Smart list_for_each_entry_safe(evt, evt_next, &phba->ct_ev_waiters, node) { 1278f1c3b0fcSJames Smart if (evt->reg_id == event_req->ev_reg_id) { 1279f1c3b0fcSJames Smart if (list_empty(&evt->events_to_get)) 1280f1c3b0fcSJames Smart break; 12814cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 1282f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 1283f1c3b0fcSJames Smart evt_dat = list_entry(evt->events_to_get.prev, 1284f1c3b0fcSJames Smart struct event_data, node); 1285f1c3b0fcSJames Smart list_del(&evt_dat->node); 1286f1c3b0fcSJames Smart break; 1287f1c3b0fcSJames Smart } 1288f1c3b0fcSJames Smart } 12894fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 1290f1c3b0fcSJames Smart 12914cc0e56eSJames Smart /* The app may continue to ask for event data until it gets 12924cc0e56eSJames Smart * an error indicating that there isn't anymore 12934cc0e56eSJames Smart */ 12944cc0e56eSJames Smart if (evt_dat == NULL) { 129501e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 1296f1c3b0fcSJames Smart rc = -ENOENT; 12974cc0e56eSJames Smart goto job_error; 1298f1c3b0fcSJames Smart } 1299f1c3b0fcSJames Smart 13004cc0e56eSJames Smart if (evt_dat->len > job->request_payload.payload_len) { 13014cc0e56eSJames Smart evt_dat->len = job->request_payload.payload_len; 1302f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1303f1c3b0fcSJames Smart "2618 Truncated event data at %d " 1304f1c3b0fcSJames Smart "bytes\n", 13054cc0e56eSJames Smart job->request_payload.payload_len); 1306f1c3b0fcSJames Smart } 1307f1c3b0fcSJames Smart 13084cc0e56eSJames Smart event_reply->type = evt_dat->type; 1309f1c3b0fcSJames Smart event_reply->immed_data = evt_dat->immed_dat; 1310f1c3b0fcSJames Smart if (evt_dat->len > 0) 131101e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 13124cc0e56eSJames Smart sg_copy_from_buffer(job->request_payload.sg_list, 13134cc0e56eSJames Smart job->request_payload.sg_cnt, 1314f1c3b0fcSJames Smart evt_dat->data, evt_dat->len); 1315f1c3b0fcSJames Smart else 131601e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 1317f1c3b0fcSJames Smart 13184cc0e56eSJames Smart if (evt_dat) { 1319f1c3b0fcSJames Smart kfree(evt_dat->data); 1320f1c3b0fcSJames Smart kfree(evt_dat); 13214cc0e56eSJames Smart } 13224cc0e56eSJames Smart 13234fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 13244cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 13254fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 13264cc0e56eSJames Smart job->dd_data = NULL; 132701e0e15cSJohannes Thumshirn bsg_reply->result = 0; 132806548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 13291abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 13304cc0e56eSJames Smart return 0; 1331f1c3b0fcSJames Smart 13324cc0e56eSJames Smart job_error: 13334cc0e56eSJames Smart job->dd_data = NULL; 133401e0e15cSJohannes Thumshirn bsg_reply->result = rc; 1335f1c3b0fcSJames Smart return rc; 1336f1c3b0fcSJames Smart } 1337f1c3b0fcSJames Smart 1338f1c3b0fcSJames Smart /** 13393b5dd52aSJames Smart * lpfc_issue_ct_rsp_cmp - lpfc_issue_ct_rsp's completion handler 13403b5dd52aSJames Smart * @phba: Pointer to HBA context object. 13413b5dd52aSJames Smart * @cmdiocbq: Pointer to command iocb. 13423b5dd52aSJames Smart * @rspiocbq: Pointer to response iocb. 13433b5dd52aSJames Smart * 13443b5dd52aSJames Smart * This function is the completion handler for iocbs issued using 13453b5dd52aSJames Smart * lpfc_issue_ct_rsp_cmp function. This function is called by the 13463b5dd52aSJames Smart * ring event handler function without any lock held. This function 13473b5dd52aSJames Smart * can be called from both worker thread context and interrupt 13483b5dd52aSJames Smart * context. This function also can be called from other thread which 13493b5dd52aSJames Smart * cleans up the SLI layer objects. 13503b5dd52aSJames Smart * This function copy the contents of the response iocb to the 13513b5dd52aSJames Smart * response iocb memory object provided by the caller of 13523b5dd52aSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 13533b5dd52aSJames Smart * sleeps for the iocb completion. 13543b5dd52aSJames Smart **/ 13553b5dd52aSJames Smart static void 13563b5dd52aSJames Smart lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba, 13573b5dd52aSJames Smart struct lpfc_iocbq *cmdiocbq, 13583b5dd52aSJames Smart struct lpfc_iocbq *rspiocbq) 13593b5dd52aSJames Smart { 13603b5dd52aSJames Smart struct bsg_job_data *dd_data; 136175cc8cfcSJohannes Thumshirn struct bsg_job *job; 136201e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 1363a33c4f7bSJames Smart struct lpfc_dmabuf *bmp, *cmp; 13643b5dd52aSJames Smart struct lpfc_nodelist *ndlp; 13653b5dd52aSJames Smart unsigned long flags; 13663b5dd52aSJames Smart int rc = 0; 13670e082d92SJames Smart u32 ulp_status, ulp_word4; 13683b5dd52aSJames Smart 1369d51cf5bdSJames Smart dd_data = cmdiocbq->context_un.dd_data; 1370a33c4f7bSJames Smart 1371a33c4f7bSJames Smart /* Determine if job has been aborted */ 13723b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1373a33c4f7bSJames Smart job = dd_data->set_job; 1374a33c4f7bSJames Smart if (job) { 1375a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 1376a33c4f7bSJames Smart job->dd_data = NULL; 13773b5dd52aSJames Smart } 1378a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 13793b5dd52aSJames Smart 1380b5a9b2dfSJames Smart /* Close the timeout handler abort window */ 1381b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 1382a680a929SJames Smart cmdiocbq->cmd_flag &= ~LPFC_IO_CMD_OUTSTANDING; 1383b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 1384b5a9b2dfSJames Smart 13853b5dd52aSJames Smart ndlp = dd_data->context_un.iocb.ndlp; 1386d51cf5bdSJames Smart cmp = cmdiocbq->cmd_dmabuf; 1387d51cf5bdSJames Smart bmp = cmdiocbq->bpl_dmabuf; 13880e082d92SJames Smart 13890e082d92SJames Smart ulp_status = get_job_ulpstatus(phba, rspiocbq); 13900e082d92SJames Smart ulp_word4 = get_job_word4(phba, rspiocbq); 13913b5dd52aSJames Smart 1392a33c4f7bSJames Smart /* Copy the completed job data or set the error status */ 13933b5dd52aSJames Smart 1394a33c4f7bSJames Smart if (job) { 139501e0e15cSJohannes Thumshirn bsg_reply = job->reply; 13960e082d92SJames Smart if (ulp_status) { 13970e082d92SJames Smart if (ulp_status == IOSTAT_LOCAL_REJECT) { 13980e082d92SJames Smart switch (ulp_word4 & IOERR_PARAM_MASK) { 13993b5dd52aSJames Smart case IOERR_SEQUENCE_TIMEOUT: 14003b5dd52aSJames Smart rc = -ETIMEDOUT; 14013b5dd52aSJames Smart break; 14023b5dd52aSJames Smart case IOERR_INVALID_RPI: 14033b5dd52aSJames Smart rc = -EFAULT; 14043b5dd52aSJames Smart break; 14053b5dd52aSJames Smart default: 14063b5dd52aSJames Smart rc = -EACCES; 14073b5dd52aSJames Smart break; 14083b5dd52aSJames Smart } 1409a33c4f7bSJames Smart } else { 14103b5dd52aSJames Smart rc = -EACCES; 1411a33c4f7bSJames Smart } 1412a33c4f7bSJames Smart } else { 141301e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 1414a33c4f7bSJames Smart } 1415a33c4f7bSJames Smart } 14163b5dd52aSJames Smart 1417a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 14183b5dd52aSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 1419a33c4f7bSJames Smart kfree(bmp); 14203b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 14213b5dd52aSJames Smart lpfc_nlp_put(ndlp); 14223b5dd52aSJames Smart kfree(dd_data); 1423a33c4f7bSJames Smart 1424a33c4f7bSJames Smart /* Complete the job if the job is still active */ 1425a33c4f7bSJames Smart 1426a33c4f7bSJames Smart if (job) { 142701e0e15cSJohannes Thumshirn bsg_reply->result = rc; 142806548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 14291abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 1430a33c4f7bSJames Smart } 14313b5dd52aSJames Smart return; 14323b5dd52aSJames Smart } 14333b5dd52aSJames Smart 14343b5dd52aSJames Smart /** 14353b5dd52aSJames Smart * lpfc_issue_ct_rsp - issue a ct response 14363b5dd52aSJames Smart * @phba: Pointer to HBA context object. 14373b5dd52aSJames Smart * @job: Pointer to the job object. 14383b5dd52aSJames Smart * @tag: tag index value into the ports context exchange array. 1439ea085dabSLee Jones * @cmp: Pointer to a cmp dma buffer descriptor. 1440ea085dabSLee Jones * @bmp: Pointer to a bmp dma buffer descriptor. 14413b5dd52aSJames Smart * @num_entry: Number of enties in the bde. 14423b5dd52aSJames Smart **/ 14433b5dd52aSJames Smart static int 144475cc8cfcSJohannes Thumshirn lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct bsg_job *job, uint32_t tag, 1445a33c4f7bSJames Smart struct lpfc_dmabuf *cmp, struct lpfc_dmabuf *bmp, 1446a33c4f7bSJames Smart int num_entry) 14473b5dd52aSJames Smart { 14483b5dd52aSJames Smart struct lpfc_iocbq *ctiocb = NULL; 14493b5dd52aSJames Smart int rc = 0; 14503b5dd52aSJames Smart struct lpfc_nodelist *ndlp = NULL; 14513b5dd52aSJames Smart struct bsg_job_data *dd_data; 1452b5a9b2dfSJames Smart unsigned long flags; 14533b5dd52aSJames Smart uint32_t creg_val; 145461910d6aSJames Smart u16 ulp_context, iotag; 14553b5dd52aSJames Smart 14564430f7fdSJames Smart ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID); 14574430f7fdSJames Smart if (!ndlp) { 14584430f7fdSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, 14594430f7fdSJames Smart "2721 ndlp null for oxid %x SID %x\n", 14604430f7fdSJames Smart phba->ct_ctx[tag].rxid, 14614430f7fdSJames Smart phba->ct_ctx[tag].SID); 14624430f7fdSJames Smart return IOCB_ERROR; 14634430f7fdSJames Smart } 14644430f7fdSJames Smart 14653b5dd52aSJames Smart /* allocate our bsg tracking structure */ 14663b5dd52aSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 14673b5dd52aSJames Smart if (!dd_data) { 14683b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 14693b5dd52aSJames Smart "2736 Failed allocation of dd_data\n"); 14703b5dd52aSJames Smart rc = -ENOMEM; 14713b5dd52aSJames Smart goto no_dd_data; 14723b5dd52aSJames Smart } 14733b5dd52aSJames Smart 14743b5dd52aSJames Smart /* Allocate buffer for command iocb */ 14753b5dd52aSJames Smart ctiocb = lpfc_sli_get_iocbq(phba); 14763b5dd52aSJames Smart if (!ctiocb) { 1477d439d286SJames Smart rc = -ENOMEM; 14783b5dd52aSJames Smart goto no_ctiocb; 14793b5dd52aSJames Smart } 14803b5dd52aSJames Smart 14813b5dd52aSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) { 14823b5dd52aSJames Smart /* Do not issue unsol response if oxid not marked as valid */ 14836dd9e31cSJames Smart if (phba->ct_ctx[tag].valid != UNSOL_VALID) { 14843b5dd52aSJames Smart rc = IOCB_ERROR; 14853b5dd52aSJames Smart goto issue_ct_rsp_exit; 14863b5dd52aSJames Smart } 1487589a52d6SJames Smart 148861910d6aSJames Smart lpfc_sli_prep_xmit_seq64(phba, ctiocb, bmp, 148961910d6aSJames Smart phba->sli4_hba.rpi_ids[ndlp->nlp_rpi], 149061910d6aSJames Smart phba->ct_ctx[tag].oxid, num_entry, 149161910d6aSJames Smart FC_RCTL_DD_SOL_CTL, 1, 149261910d6aSJames Smart CMD_XMIT_SEQUENCE64_WQE); 14936d368e53SJames Smart 14943b5dd52aSJames Smart /* The exchange is done, mark the entry as invalid */ 14956dd9e31cSJames Smart phba->ct_ctx[tag].valid = UNSOL_INVALID; 149661910d6aSJames Smart iotag = get_wqe_reqtag(ctiocb); 149761910d6aSJames Smart } else { 149861910d6aSJames Smart lpfc_sli_prep_xmit_seq64(phba, ctiocb, bmp, 0, tag, num_entry, 149961910d6aSJames Smart FC_RCTL_DD_SOL_CTL, 1, 150061910d6aSJames Smart CMD_XMIT_SEQUENCE64_CX); 150161910d6aSJames Smart ctiocb->num_bdes = num_entry; 150261910d6aSJames Smart iotag = ctiocb->iocb.ulpIoTag; 150361910d6aSJames Smart } 15043b5dd52aSJames Smart 150561910d6aSJames Smart ulp_context = get_job_ulpcontext(phba, ctiocb); 15063b5dd52aSJames Smart 15073b5dd52aSJames Smart /* Xmit CT response on exchange <xid> */ 15083b5dd52aSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_ELS, 15097851fe2cSJames Smart "2722 Xmit CT response on exchange x%x Data: x%x x%x x%x\n", 151061910d6aSJames Smart ulp_context, iotag, tag, phba->link_state); 15113b5dd52aSJames Smart 1512a680a929SJames Smart ctiocb->cmd_flag |= LPFC_IO_LIBDFC; 15133b5dd52aSJames Smart ctiocb->vport = phba->pport; 1514d51cf5bdSJames Smart ctiocb->context_un.dd_data = dd_data; 1515d51cf5bdSJames Smart ctiocb->cmd_dmabuf = cmp; 1516d51cf5bdSJames Smart ctiocb->bpl_dmabuf = bmp; 1517d51cf5bdSJames Smart ctiocb->ndlp = ndlp; 1518a680a929SJames Smart ctiocb->cmd_cmpl = lpfc_issue_ct_rsp_cmp; 1519a33c4f7bSJames Smart 15203b5dd52aSJames Smart dd_data->type = TYPE_IOCB; 1521a33c4f7bSJames Smart dd_data->set_job = job; 15223b5dd52aSJames Smart dd_data->context_un.iocb.cmdiocbq = ctiocb; 15234430f7fdSJames Smart dd_data->context_un.iocb.ndlp = lpfc_nlp_get(ndlp); 15244430f7fdSJames Smart if (!dd_data->context_un.iocb.ndlp) { 15254430f7fdSJames Smart rc = -IOCB_ERROR; 15264430f7fdSJames Smart goto issue_ct_rsp_exit; 15274430f7fdSJames Smart } 1528a33c4f7bSJames Smart dd_data->context_un.iocb.rmp = NULL; 1529a33c4f7bSJames Smart job->dd_data = dd_data; 15303b5dd52aSJames Smart 15313b5dd52aSJames Smart if (phba->cfg_poll & DISABLE_FCP_RING_INT) { 15329940b97bSJames Smart if (lpfc_readl(phba->HCregaddr, &creg_val)) { 15339940b97bSJames Smart rc = -IOCB_ERROR; 15349940b97bSJames Smart goto issue_ct_rsp_exit; 15359940b97bSJames Smart } 15363b5dd52aSJames Smart creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); 15373b5dd52aSJames Smart writel(creg_val, phba->HCregaddr); 15383b5dd52aSJames Smart readl(phba->HCregaddr); /* flush */ 15393b5dd52aSJames Smart } 15403b5dd52aSJames Smart 15413b5dd52aSJames Smart rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); 1542b5a9b2dfSJames Smart if (rc == IOCB_SUCCESS) { 1543b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 1544b5a9b2dfSJames Smart /* make sure the I/O had not been completed/released */ 1545a680a929SJames Smart if (ctiocb->cmd_flag & LPFC_IO_LIBDFC) { 1546b5a9b2dfSJames Smart /* open up abort window to timeout handler */ 1547a680a929SJames Smart ctiocb->cmd_flag |= LPFC_IO_CMD_OUTSTANDING; 1548b5a9b2dfSJames Smart } 1549b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 15503b5dd52aSJames Smart return 0; /* done for now */ 1551b5a9b2dfSJames Smart } 1552b5a9b2dfSJames Smart 1553b5a9b2dfSJames Smart /* iocb failed so cleanup */ 1554b5a9b2dfSJames Smart job->dd_data = NULL; 15554430f7fdSJames Smart lpfc_nlp_put(ndlp); 15563b5dd52aSJames Smart 15573b5dd52aSJames Smart issue_ct_rsp_exit: 15583b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, ctiocb); 15593b5dd52aSJames Smart no_ctiocb: 15603b5dd52aSJames Smart kfree(dd_data); 15613b5dd52aSJames Smart no_dd_data: 15623b5dd52aSJames Smart return rc; 15633b5dd52aSJames Smart } 15643b5dd52aSJames Smart 15653b5dd52aSJames Smart /** 15663b5dd52aSJames Smart * lpfc_bsg_send_mgmt_rsp - process a SEND_MGMT_RESP bsg vendor command 15673b5dd52aSJames Smart * @job: SEND_MGMT_RESP fc_bsg_job 15683b5dd52aSJames Smart **/ 15693b5dd52aSJames Smart static int 157075cc8cfcSJohannes Thumshirn lpfc_bsg_send_mgmt_rsp(struct bsg_job *job) 15713b5dd52aSJames Smart { 1572cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 15733b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 157401e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 157501e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 15763b5dd52aSJames Smart struct send_mgmt_resp *mgmt_resp = (struct send_mgmt_resp *) 157701e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 15783b5dd52aSJames Smart struct ulp_bde64 *bpl; 1579a33c4f7bSJames Smart struct lpfc_dmabuf *bmp = NULL, *cmp = NULL; 1580a33c4f7bSJames Smart int bpl_entries; 15813b5dd52aSJames Smart uint32_t tag = mgmt_resp->tag; 15823b5dd52aSJames Smart unsigned long reqbfrcnt = 15833b5dd52aSJames Smart (unsigned long)job->request_payload.payload_len; 15843b5dd52aSJames Smart int rc = 0; 15853b5dd52aSJames Smart 15863b5dd52aSJames Smart /* in case no data is transferred */ 158701e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 15883b5dd52aSJames Smart 15893b5dd52aSJames Smart if (!reqbfrcnt || (reqbfrcnt > (80 * BUF_SZ_4K))) { 15903b5dd52aSJames Smart rc = -ERANGE; 15913b5dd52aSJames Smart goto send_mgmt_rsp_exit; 15923b5dd52aSJames Smart } 15933b5dd52aSJames Smart 15943b5dd52aSJames Smart bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 15953b5dd52aSJames Smart if (!bmp) { 15963b5dd52aSJames Smart rc = -ENOMEM; 15973b5dd52aSJames Smart goto send_mgmt_rsp_exit; 15983b5dd52aSJames Smart } 15993b5dd52aSJames Smart 16003b5dd52aSJames Smart bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); 16013b5dd52aSJames Smart if (!bmp->virt) { 16023b5dd52aSJames Smart rc = -ENOMEM; 16033b5dd52aSJames Smart goto send_mgmt_rsp_free_bmp; 16043b5dd52aSJames Smart } 16053b5dd52aSJames Smart 16063b5dd52aSJames Smart INIT_LIST_HEAD(&bmp->list); 16073b5dd52aSJames Smart bpl = (struct ulp_bde64 *) bmp->virt; 1608a33c4f7bSJames Smart bpl_entries = (LPFC_BPL_SIZE/sizeof(struct ulp_bde64)); 1609a33c4f7bSJames Smart cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len, 1610a33c4f7bSJames Smart 1, bpl, &bpl_entries); 1611a33c4f7bSJames Smart if (!cmp) { 1612a33c4f7bSJames Smart rc = -ENOMEM; 1613a33c4f7bSJames Smart goto send_mgmt_rsp_free_bmp; 16143b5dd52aSJames Smart } 1615a33c4f7bSJames Smart lpfc_bsg_copy_data(cmp, &job->request_payload, 1616a33c4f7bSJames Smart job->request_payload.payload_len, 1); 16173b5dd52aSJames Smart 1618a33c4f7bSJames Smart rc = lpfc_issue_ct_rsp(phba, job, tag, cmp, bmp, bpl_entries); 16193b5dd52aSJames Smart 16203b5dd52aSJames Smart if (rc == IOCB_SUCCESS) 16213b5dd52aSJames Smart return 0; /* done for now */ 16223b5dd52aSJames Smart 16233b5dd52aSJames Smart rc = -EACCES; 1624a33c4f7bSJames Smart 1625a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 16263b5dd52aSJames Smart 16273b5dd52aSJames Smart send_mgmt_rsp_free_bmp: 1628a33c4f7bSJames Smart if (bmp->virt) 1629a33c4f7bSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 16303b5dd52aSJames Smart kfree(bmp); 16313b5dd52aSJames Smart send_mgmt_rsp_exit: 16323b5dd52aSJames Smart /* make error code available to userspace */ 163301e0e15cSJohannes Thumshirn bsg_reply->result = rc; 16343b5dd52aSJames Smart job->dd_data = NULL; 16353b5dd52aSJames Smart return rc; 16363b5dd52aSJames Smart } 16373b5dd52aSJames Smart 16383b5dd52aSJames Smart /** 16397ad20aa9SJames Smart * lpfc_bsg_diag_mode_enter - process preparing into device diag loopback mode 16407ad20aa9SJames Smart * @phba: Pointer to HBA context object. 16413b5dd52aSJames Smart * 16427ad20aa9SJames Smart * This function is responsible for preparing driver for diag loopback 16437ad20aa9SJames Smart * on device. 16443b5dd52aSJames Smart */ 16453b5dd52aSJames Smart static int 164688a2cfbbSJames Smart lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba) 16473b5dd52aSJames Smart { 16483b5dd52aSJames Smart struct lpfc_vport **vports; 16497ad20aa9SJames Smart struct Scsi_Host *shost; 16507ad20aa9SJames Smart struct lpfc_sli *psli; 1651895427bdSJames Smart struct lpfc_queue *qp = NULL; 16527ad20aa9SJames Smart struct lpfc_sli_ring *pring; 16533b5dd52aSJames Smart int i = 0; 16543b5dd52aSJames Smart 16557ad20aa9SJames Smart psli = &phba->sli; 16567ad20aa9SJames Smart if (!psli) 16577ad20aa9SJames Smart return -ENODEV; 16583b5dd52aSJames Smart 16593b5dd52aSJames Smart 16603b5dd52aSJames Smart if ((phba->link_state == LPFC_HBA_ERROR) || 16613b5dd52aSJames Smart (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || 16627ad20aa9SJames Smart (!(psli->sli_flag & LPFC_SLI_ACTIVE))) 16637ad20aa9SJames Smart return -EACCES; 16643b5dd52aSJames Smart 16653b5dd52aSJames Smart vports = lpfc_create_vport_work_array(phba); 16663b5dd52aSJames Smart if (vports) { 16673b5dd52aSJames Smart for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { 16683b5dd52aSJames Smart shost = lpfc_shost_from_vport(vports[i]); 16693b5dd52aSJames Smart scsi_block_requests(shost); 16703b5dd52aSJames Smart } 16713b5dd52aSJames Smart lpfc_destroy_vport_work_array(phba, vports); 16723b5dd52aSJames Smart } else { 16733b5dd52aSJames Smart shost = lpfc_shost_from_vport(phba->pport); 16743b5dd52aSJames Smart scsi_block_requests(shost); 16753b5dd52aSJames Smart } 16763b5dd52aSJames Smart 1677895427bdSJames Smart if (phba->sli_rev != LPFC_SLI_REV4) { 1678895427bdSJames Smart pring = &psli->sli3_ring[LPFC_FCP_RING]; 1679895427bdSJames Smart lpfc_emptyq_wait(phba, &pring->txcmplq, &phba->hbalock); 1680895427bdSJames Smart return 0; 1681895427bdSJames Smart } 1682895427bdSJames Smart list_for_each_entry(qp, &phba->sli4_hba.lpfc_wq_list, wq_list) { 1683895427bdSJames Smart pring = qp->pring; 1684895427bdSJames Smart if (!pring || (pring->ringno != LPFC_FCP_RING)) 1685895427bdSJames Smart continue; 1686895427bdSJames Smart if (!lpfc_emptyq_wait(phba, &pring->txcmplq, 1687895427bdSJames Smart &pring->ring_lock)) 16883b5dd52aSJames Smart break; 16893b5dd52aSJames Smart } 16907ad20aa9SJames Smart return 0; 16917ad20aa9SJames Smart } 16923b5dd52aSJames Smart 16937ad20aa9SJames Smart /** 16947ad20aa9SJames Smart * lpfc_bsg_diag_mode_exit - exit process from device diag loopback mode 16957ad20aa9SJames Smart * @phba: Pointer to HBA context object. 16967ad20aa9SJames Smart * 16977ad20aa9SJames Smart * This function is responsible for driver exit processing of setting up 16987ad20aa9SJames Smart * diag loopback mode on device. 16997ad20aa9SJames Smart */ 17007ad20aa9SJames Smart static void 17017ad20aa9SJames Smart lpfc_bsg_diag_mode_exit(struct lpfc_hba *phba) 17027ad20aa9SJames Smart { 17037ad20aa9SJames Smart struct Scsi_Host *shost; 17047ad20aa9SJames Smart struct lpfc_vport **vports; 17057ad20aa9SJames Smart int i; 17067ad20aa9SJames Smart 17077ad20aa9SJames Smart vports = lpfc_create_vport_work_array(phba); 17087ad20aa9SJames Smart if (vports) { 17097ad20aa9SJames Smart for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { 17107ad20aa9SJames Smart shost = lpfc_shost_from_vport(vports[i]); 17117ad20aa9SJames Smart scsi_unblock_requests(shost); 17127ad20aa9SJames Smart } 17137ad20aa9SJames Smart lpfc_destroy_vport_work_array(phba, vports); 17147ad20aa9SJames Smart } else { 17157ad20aa9SJames Smart shost = lpfc_shost_from_vport(phba->pport); 17167ad20aa9SJames Smart scsi_unblock_requests(shost); 17177ad20aa9SJames Smart } 17187ad20aa9SJames Smart return; 17197ad20aa9SJames Smart } 17207ad20aa9SJames Smart 17217ad20aa9SJames Smart /** 17227ad20aa9SJames Smart * lpfc_sli3_bsg_diag_loopback_mode - process an sli3 bsg vendor command 17237ad20aa9SJames Smart * @phba: Pointer to HBA context object. 17247ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_MODE 17257ad20aa9SJames Smart * 17267ad20aa9SJames Smart * This function is responsible for placing an sli3 port into diagnostic 17277ad20aa9SJames Smart * loopback mode in order to perform a diagnostic loopback test. 17287ad20aa9SJames Smart * All new scsi requests are blocked, a small delay is used to allow the 17297ad20aa9SJames Smart * scsi requests to complete then the link is brought down. If the link is 17307ad20aa9SJames Smart * is placed in loopback mode then scsi requests are again allowed 17317ad20aa9SJames Smart * so the scsi mid-layer doesn't give up on the port. 17327ad20aa9SJames Smart * All of this is done in-line. 17337ad20aa9SJames Smart */ 17347ad20aa9SJames Smart static int 173575cc8cfcSJohannes Thumshirn lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job) 17367ad20aa9SJames Smart { 173701e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 173801e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 17397ad20aa9SJames Smart struct diag_mode_set *loopback_mode; 17407ad20aa9SJames Smart uint32_t link_flags; 17417ad20aa9SJames Smart uint32_t timeout; 17421b51197dSJames Smart LPFC_MBOXQ_t *pmboxq = NULL; 1743b76f2dc9SJames Smart int mbxstatus = MBX_SUCCESS; 17447ad20aa9SJames Smart int i = 0; 17457ad20aa9SJames Smart int rc = 0; 17467ad20aa9SJames Smart 17477ad20aa9SJames Smart /* no data to return just the return code */ 174801e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 17497ad20aa9SJames Smart 17507ad20aa9SJames Smart if (job->request_len < sizeof(struct fc_bsg_request) + 17517ad20aa9SJames Smart sizeof(struct diag_mode_set)) { 17527ad20aa9SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 17537ad20aa9SJames Smart "2738 Received DIAG MODE request size:%d " 17547ad20aa9SJames Smart "below the minimum size:%d\n", 17557ad20aa9SJames Smart job->request_len, 17567ad20aa9SJames Smart (int)(sizeof(struct fc_bsg_request) + 17577ad20aa9SJames Smart sizeof(struct diag_mode_set))); 17587ad20aa9SJames Smart rc = -EINVAL; 17597ad20aa9SJames Smart goto job_error; 17607ad20aa9SJames Smart } 17617ad20aa9SJames Smart 176288a2cfbbSJames Smart rc = lpfc_bsg_diag_mode_enter(phba); 17637ad20aa9SJames Smart if (rc) 17647ad20aa9SJames Smart goto job_error; 17657ad20aa9SJames Smart 17667ad20aa9SJames Smart /* bring the link to diagnostic mode */ 17677ad20aa9SJames Smart loopback_mode = (struct diag_mode_set *) 176801e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 17697ad20aa9SJames Smart link_flags = loopback_mode->type; 17707ad20aa9SJames Smart timeout = loopback_mode->timeout * 100; 17717ad20aa9SJames Smart 17727ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 17737ad20aa9SJames Smart if (!pmboxq) { 17747ad20aa9SJames Smart rc = -ENOMEM; 17757ad20aa9SJames Smart goto loopback_mode_exit; 17767ad20aa9SJames Smart } 17773b5dd52aSJames Smart memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 17783b5dd52aSJames Smart pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK; 17793b5dd52aSJames Smart pmboxq->u.mb.mbxOwner = OWN_HOST; 17803b5dd52aSJames Smart 17813b5dd52aSJames Smart mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); 17823b5dd52aSJames Smart 17833b5dd52aSJames Smart if ((mbxstatus == MBX_SUCCESS) && (pmboxq->u.mb.mbxStatus == 0)) { 17843b5dd52aSJames Smart /* wait for link down before proceeding */ 17853b5dd52aSJames Smart i = 0; 17863b5dd52aSJames Smart while (phba->link_state != LPFC_LINK_DOWN) { 17873b5dd52aSJames Smart if (i++ > timeout) { 17883b5dd52aSJames Smart rc = -ETIMEDOUT; 17893b5dd52aSJames Smart goto loopback_mode_exit; 17903b5dd52aSJames Smart } 17913b5dd52aSJames Smart msleep(10); 17923b5dd52aSJames Smart } 17933b5dd52aSJames Smart 17943b5dd52aSJames Smart memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 17953b5dd52aSJames Smart if (link_flags == INTERNAL_LOOP_BACK) 17963b5dd52aSJames Smart pmboxq->u.mb.un.varInitLnk.link_flags = FLAGS_LOCAL_LB; 17973b5dd52aSJames Smart else 17983b5dd52aSJames Smart pmboxq->u.mb.un.varInitLnk.link_flags = 17993b5dd52aSJames Smart FLAGS_TOPOLOGY_MODE_LOOP; 18003b5dd52aSJames Smart 18013b5dd52aSJames Smart pmboxq->u.mb.mbxCommand = MBX_INIT_LINK; 18023b5dd52aSJames Smart pmboxq->u.mb.mbxOwner = OWN_HOST; 18033b5dd52aSJames Smart 18043b5dd52aSJames Smart mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, 18053b5dd52aSJames Smart LPFC_MBOX_TMO); 18063b5dd52aSJames Smart 18073b5dd52aSJames Smart if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) 18083b5dd52aSJames Smart rc = -ENODEV; 18093b5dd52aSJames Smart else { 18101b51197dSJames Smart spin_lock_irq(&phba->hbalock); 18113b5dd52aSJames Smart phba->link_flag |= LS_LOOPBACK_MODE; 18121b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 18133b5dd52aSJames Smart /* wait for the link attention interrupt */ 18143b5dd52aSJames Smart msleep(100); 18153b5dd52aSJames Smart 18163b5dd52aSJames Smart i = 0; 18173b5dd52aSJames Smart while (phba->link_state != LPFC_HBA_READY) { 18183b5dd52aSJames Smart if (i++ > timeout) { 18193b5dd52aSJames Smart rc = -ETIMEDOUT; 18203b5dd52aSJames Smart break; 18213b5dd52aSJames Smart } 18223b5dd52aSJames Smart 18233b5dd52aSJames Smart msleep(10); 18243b5dd52aSJames Smart } 18253b5dd52aSJames Smart } 18263b5dd52aSJames Smart 18273b5dd52aSJames Smart } else 18283b5dd52aSJames Smart rc = -ENODEV; 18293b5dd52aSJames Smart 18303b5dd52aSJames Smart loopback_mode_exit: 18317ad20aa9SJames Smart lpfc_bsg_diag_mode_exit(phba); 18323b5dd52aSJames Smart 18333b5dd52aSJames Smart /* 18343b5dd52aSJames Smart * Let SLI layer release mboxq if mbox command completed after timeout. 18353b5dd52aSJames Smart */ 18361b51197dSJames Smart if (pmboxq && mbxstatus != MBX_TIMEOUT) 18373b5dd52aSJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 18383b5dd52aSJames Smart 18393b5dd52aSJames Smart job_error: 18403b5dd52aSJames Smart /* make error code available to userspace */ 184101e0e15cSJohannes Thumshirn bsg_reply->result = rc; 18423b5dd52aSJames Smart /* complete the job back to userspace if no error */ 18433b5dd52aSJames Smart if (rc == 0) 184406548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 18451abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 18463b5dd52aSJames Smart return rc; 18473b5dd52aSJames Smart } 18483b5dd52aSJames Smart 18493b5dd52aSJames Smart /** 18507ad20aa9SJames Smart * lpfc_sli4_bsg_set_link_diag_state - set sli4 link diag state 18517ad20aa9SJames Smart * @phba: Pointer to HBA context object. 18527ad20aa9SJames Smart * @diag: Flag for set link to diag or nomral operation state. 18537ad20aa9SJames Smart * 18547ad20aa9SJames Smart * This function is responsible for issuing a sli4 mailbox command for setting 18557ad20aa9SJames Smart * link to either diag state or normal operation state. 18567ad20aa9SJames Smart */ 18577ad20aa9SJames Smart static int 18587ad20aa9SJames Smart lpfc_sli4_bsg_set_link_diag_state(struct lpfc_hba *phba, uint32_t diag) 18597ad20aa9SJames Smart { 18607ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq; 18617ad20aa9SJames Smart struct lpfc_mbx_set_link_diag_state *link_diag_state; 18627ad20aa9SJames Smart uint32_t req_len, alloc_len; 18637ad20aa9SJames Smart int mbxstatus = MBX_SUCCESS, rc; 18647ad20aa9SJames Smart 18657ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 18667ad20aa9SJames Smart if (!pmboxq) 18677ad20aa9SJames Smart return -ENOMEM; 18687ad20aa9SJames Smart 18697ad20aa9SJames Smart req_len = (sizeof(struct lpfc_mbx_set_link_diag_state) - 18707ad20aa9SJames Smart sizeof(struct lpfc_sli4_cfg_mhdr)); 18717ad20aa9SJames Smart alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, 18727ad20aa9SJames Smart LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE, 18737ad20aa9SJames Smart req_len, LPFC_SLI4_MBX_EMBED); 18747ad20aa9SJames Smart if (alloc_len != req_len) { 18757ad20aa9SJames Smart rc = -ENOMEM; 18767ad20aa9SJames Smart goto link_diag_state_set_out; 18777ad20aa9SJames Smart } 18781b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 18791b51197dSJames Smart "3128 Set link to diagnostic state:x%x (x%x/x%x)\n", 18801b51197dSJames Smart diag, phba->sli4_hba.lnk_info.lnk_tp, 18811b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_no); 18821b51197dSJames Smart 18837ad20aa9SJames Smart link_diag_state = &pmboxq->u.mqe.un.link_diag_state; 18849731592bSJames Smart bf_set(lpfc_mbx_set_diag_state_diag_bit_valid, &link_diag_state->u.req, 18859731592bSJames Smart LPFC_DIAG_STATE_DIAG_BIT_VALID_CHANGE); 18867ad20aa9SJames Smart bf_set(lpfc_mbx_set_diag_state_link_num, &link_diag_state->u.req, 18871b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_no); 18887ad20aa9SJames Smart bf_set(lpfc_mbx_set_diag_state_link_type, &link_diag_state->u.req, 18891b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_tp); 18907ad20aa9SJames Smart if (diag) 18917ad20aa9SJames Smart bf_set(lpfc_mbx_set_diag_state_diag, 18927ad20aa9SJames Smart &link_diag_state->u.req, 1); 18937ad20aa9SJames Smart else 18947ad20aa9SJames Smart bf_set(lpfc_mbx_set_diag_state_diag, 18957ad20aa9SJames Smart &link_diag_state->u.req, 0); 18967ad20aa9SJames Smart 18977ad20aa9SJames Smart mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); 18987ad20aa9SJames Smart 18997ad20aa9SJames Smart if ((mbxstatus == MBX_SUCCESS) && (pmboxq->u.mb.mbxStatus == 0)) 19007ad20aa9SJames Smart rc = 0; 19017ad20aa9SJames Smart else 19027ad20aa9SJames Smart rc = -ENODEV; 19037ad20aa9SJames Smart 19047ad20aa9SJames Smart link_diag_state_set_out: 19057ad20aa9SJames Smart if (pmboxq && (mbxstatus != MBX_TIMEOUT)) 19067ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 19077ad20aa9SJames Smart 19087ad20aa9SJames Smart return rc; 19097ad20aa9SJames Smart } 19107ad20aa9SJames Smart 19117ad20aa9SJames Smart /** 19129a66d990SJames Smart * lpfc_sli4_bsg_set_loopback_mode - set sli4 internal loopback diagnostic 19131b51197dSJames Smart * @phba: Pointer to HBA context object. 19149a66d990SJames Smart * @mode: loopback mode to set 19159a66d990SJames Smart * @link_no: link number for loopback mode to set 19161b51197dSJames Smart * 19171b51197dSJames Smart * This function is responsible for issuing a sli4 mailbox command for setting 19189a66d990SJames Smart * up loopback diagnostic for a link. 19191b51197dSJames Smart */ 19201b51197dSJames Smart static int 19219a66d990SJames Smart lpfc_sli4_bsg_set_loopback_mode(struct lpfc_hba *phba, int mode, 19229a66d990SJames Smart uint32_t link_no) 19231b51197dSJames Smart { 19241b51197dSJames Smart LPFC_MBOXQ_t *pmboxq; 19251b51197dSJames Smart uint32_t req_len, alloc_len; 19261b51197dSJames Smart struct lpfc_mbx_set_link_diag_loopback *link_diag_loopback; 19271b51197dSJames Smart int mbxstatus = MBX_SUCCESS, rc = 0; 19281b51197dSJames Smart 19291b51197dSJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 19301b51197dSJames Smart if (!pmboxq) 19311b51197dSJames Smart return -ENOMEM; 19321b51197dSJames Smart req_len = (sizeof(struct lpfc_mbx_set_link_diag_loopback) - 19331b51197dSJames Smart sizeof(struct lpfc_sli4_cfg_mhdr)); 19341b51197dSJames Smart alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, 19351b51197dSJames Smart LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK, 19361b51197dSJames Smart req_len, LPFC_SLI4_MBX_EMBED); 19371b51197dSJames Smart if (alloc_len != req_len) { 19381b51197dSJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 19391b51197dSJames Smart return -ENOMEM; 19401b51197dSJames Smart } 19411b51197dSJames Smart link_diag_loopback = &pmboxq->u.mqe.un.link_diag_loopback; 19421b51197dSJames Smart bf_set(lpfc_mbx_set_diag_state_link_num, 19439a66d990SJames Smart &link_diag_loopback->u.req, link_no); 19449a66d990SJames Smart 19459a66d990SJames Smart if (phba->sli4_hba.conf_trunk & (1 << link_no)) { 19461b51197dSJames Smart bf_set(lpfc_mbx_set_diag_state_link_type, 19479a66d990SJames Smart &link_diag_loopback->u.req, LPFC_LNK_FC_TRUNKED); 19489a66d990SJames Smart } else { 19499a66d990SJames Smart bf_set(lpfc_mbx_set_diag_state_link_type, 19509a66d990SJames Smart &link_diag_loopback->u.req, 19519a66d990SJames Smart phba->sli4_hba.lnk_info.lnk_tp); 19529a66d990SJames Smart } 19539a66d990SJames Smart 19541b51197dSJames Smart bf_set(lpfc_mbx_set_diag_lpbk_type, &link_diag_loopback->u.req, 19559a66d990SJames Smart mode); 19561b51197dSJames Smart 19571b51197dSJames Smart mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); 19581b51197dSJames Smart if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) { 19591b51197dSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 19601b51197dSJames Smart "3127 Failed setup loopback mode mailbox " 19611b51197dSJames Smart "command, rc:x%x, status:x%x\n", mbxstatus, 19621b51197dSJames Smart pmboxq->u.mb.mbxStatus); 19631b51197dSJames Smart rc = -ENODEV; 19641b51197dSJames Smart } 19651b51197dSJames Smart if (pmboxq && (mbxstatus != MBX_TIMEOUT)) 19661b51197dSJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 19671b51197dSJames Smart return rc; 19681b51197dSJames Smart } 19691b51197dSJames Smart 19701b51197dSJames Smart /** 19711b51197dSJames Smart * lpfc_sli4_diag_fcport_reg_setup - setup port registrations for diagnostic 19721b51197dSJames Smart * @phba: Pointer to HBA context object. 19731b51197dSJames Smart * 19741b51197dSJames Smart * This function set up SLI4 FC port registrations for diagnostic run, which 19751b51197dSJames Smart * includes all the rpis, vfi, and also vpi. 19761b51197dSJames Smart */ 19771b51197dSJames Smart static int 19781b51197dSJames Smart lpfc_sli4_diag_fcport_reg_setup(struct lpfc_hba *phba) 19791b51197dSJames Smart { 1980a645b8c1SJustin Tee if (test_bit(FC_VFI_REGISTERED, &phba->pport->fc_flag)) { 19811b51197dSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 19821b51197dSJames Smart "3136 Port still had vfi registered: " 19831b51197dSJames Smart "mydid:x%x, fcfi:%d, vfi:%d, vpi:%d\n", 19841b51197dSJames Smart phba->pport->fc_myDID, phba->fcf.fcfi, 19851b51197dSJames Smart phba->sli4_hba.vfi_ids[phba->pport->vfi], 19861b51197dSJames Smart phba->vpi_ids[phba->pport->vpi]); 19871b51197dSJames Smart return -EINVAL; 19881b51197dSJames Smart } 1989de05e484Sye xingchen return lpfc_issue_reg_vfi(phba->pport); 19901b51197dSJames Smart } 19911b51197dSJames Smart 19921b51197dSJames Smart /** 19937ad20aa9SJames Smart * lpfc_sli4_bsg_diag_loopback_mode - process an sli4 bsg vendor command 19947ad20aa9SJames Smart * @phba: Pointer to HBA context object. 19957ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_MODE 19967ad20aa9SJames Smart * 19977ad20aa9SJames Smart * This function is responsible for placing an sli4 port into diagnostic 19987ad20aa9SJames Smart * loopback mode in order to perform a diagnostic loopback test. 19997ad20aa9SJames Smart */ 20007ad20aa9SJames Smart static int 200175cc8cfcSJohannes Thumshirn lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job) 20027ad20aa9SJames Smart { 200301e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 200401e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 20057ad20aa9SJames Smart struct diag_mode_set *loopback_mode; 20069a66d990SJames Smart uint32_t link_flags, timeout, link_no; 20071b51197dSJames Smart int i, rc = 0; 20087ad20aa9SJames Smart 20097ad20aa9SJames Smart /* no data to return just the return code */ 201001e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 20117ad20aa9SJames Smart 20127ad20aa9SJames Smart if (job->request_len < sizeof(struct fc_bsg_request) + 20137ad20aa9SJames Smart sizeof(struct diag_mode_set)) { 20147ad20aa9SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 20157ad20aa9SJames Smart "3011 Received DIAG MODE request size:%d " 20167ad20aa9SJames Smart "below the minimum size:%d\n", 20177ad20aa9SJames Smart job->request_len, 20187ad20aa9SJames Smart (int)(sizeof(struct fc_bsg_request) + 20197ad20aa9SJames Smart sizeof(struct diag_mode_set))); 20207ad20aa9SJames Smart rc = -EINVAL; 20219a66d990SJames Smart goto job_done; 20229a66d990SJames Smart } 20239a66d990SJames Smart 20249a66d990SJames Smart loopback_mode = (struct diag_mode_set *) 20259a66d990SJames Smart bsg_request->rqst_data.h_vendor.vendor_cmd; 20269a66d990SJames Smart link_flags = loopback_mode->type; 20279a66d990SJames Smart timeout = loopback_mode->timeout * 100; 20289a66d990SJames Smart 20299a66d990SJames Smart if (loopback_mode->physical_link == -1) 20309a66d990SJames Smart link_no = phba->sli4_hba.lnk_info.lnk_no; 20319a66d990SJames Smart else 20329a66d990SJames Smart link_no = loopback_mode->physical_link; 20339a66d990SJames Smart 20349a66d990SJames Smart if (link_flags == DISABLE_LOOP_BACK) { 20359a66d990SJames Smart rc = lpfc_sli4_bsg_set_loopback_mode(phba, 20369a66d990SJames Smart LPFC_DIAG_LOOPBACK_TYPE_DISABLE, 20379a66d990SJames Smart link_no); 20389a66d990SJames Smart if (!rc) { 20399a66d990SJames Smart /* Unset the need disable bit */ 20409a66d990SJames Smart phba->sli4_hba.conf_trunk &= ~((1 << link_no) << 4); 20419a66d990SJames Smart } 20429a66d990SJames Smart goto job_done; 20439a66d990SJames Smart } else { 20449a66d990SJames Smart /* Check if we need to disable the loopback state */ 20459a66d990SJames Smart if (phba->sli4_hba.conf_trunk & ((1 << link_no) << 4)) { 20469a66d990SJames Smart rc = -EPERM; 20479a66d990SJames Smart goto job_done; 20489a66d990SJames Smart } 20497ad20aa9SJames Smart } 20507ad20aa9SJames Smart 205188a2cfbbSJames Smart rc = lpfc_bsg_diag_mode_enter(phba); 20527ad20aa9SJames Smart if (rc) 20539a66d990SJames Smart goto job_done; 20547ad20aa9SJames Smart 20551b51197dSJames Smart /* indicate we are in loobpack diagnostic mode */ 20561b51197dSJames Smart spin_lock_irq(&phba->hbalock); 20571b51197dSJames Smart phba->link_flag |= LS_LOOPBACK_MODE; 20581b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 20591b51197dSJames Smart 20601b51197dSJames Smart /* reset port to start frome scratch */ 20611b51197dSJames Smart rc = lpfc_selective_reset(phba); 20621b51197dSJames Smart if (rc) 20639a66d990SJames Smart goto job_done; 20641b51197dSJames Smart 20657ad20aa9SJames Smart /* bring the link to diagnostic mode */ 20661b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 20671b51197dSJames Smart "3129 Bring link to diagnostic state.\n"); 20687ad20aa9SJames Smart 20697ad20aa9SJames Smart rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1); 20701b51197dSJames Smart if (rc) { 20711b51197dSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 20721b51197dSJames Smart "3130 Failed to bring link to diagnostic " 20731b51197dSJames Smart "state, rc:x%x\n", rc); 20747ad20aa9SJames Smart goto loopback_mode_exit; 20751b51197dSJames Smart } 20767ad20aa9SJames Smart 20777ad20aa9SJames Smart /* wait for link down before proceeding */ 20787ad20aa9SJames Smart i = 0; 20797ad20aa9SJames Smart while (phba->link_state != LPFC_LINK_DOWN) { 20807ad20aa9SJames Smart if (i++ > timeout) { 20817ad20aa9SJames Smart rc = -ETIMEDOUT; 20821b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 20831b51197dSJames Smart "3131 Timeout waiting for link to " 20841b51197dSJames Smart "diagnostic mode, timeout:%d ms\n", 20851b51197dSJames Smart timeout * 10); 20867ad20aa9SJames Smart goto loopback_mode_exit; 20877ad20aa9SJames Smart } 20887ad20aa9SJames Smart msleep(10); 20897ad20aa9SJames Smart } 20907ad20aa9SJames Smart 20911b51197dSJames Smart /* set up loopback mode */ 20921b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 20931b51197dSJames Smart "3132 Set up loopback mode:x%x\n", link_flags); 20941b51197dSJames Smart 20959a66d990SJames Smart switch (link_flags) { 20969a66d990SJames Smart case INTERNAL_LOOP_BACK: 20979a66d990SJames Smart if (phba->sli4_hba.conf_trunk & (1 << link_no)) { 20989a66d990SJames Smart rc = lpfc_sli4_bsg_set_loopback_mode(phba, 20999a66d990SJames Smart LPFC_DIAG_LOOPBACK_TYPE_INTERNAL, 21009a66d990SJames Smart link_no); 21019a66d990SJames Smart } else { 21029a66d990SJames Smart /* Trunk is configured, but link is not in this trunk */ 21039a66d990SJames Smart if (phba->sli4_hba.conf_trunk) { 21049a66d990SJames Smart rc = -ELNRNG; 21059a66d990SJames Smart goto loopback_mode_exit; 21069a66d990SJames Smart } 21079a66d990SJames Smart 21089a66d990SJames Smart rc = lpfc_sli4_bsg_set_loopback_mode(phba, 21099a66d990SJames Smart LPFC_DIAG_LOOPBACK_TYPE_INTERNAL, 21109a66d990SJames Smart link_no); 21119a66d990SJames Smart } 21129a66d990SJames Smart 21139a66d990SJames Smart if (!rc) { 21149a66d990SJames Smart /* Set the need disable bit */ 21159a66d990SJames Smart phba->sli4_hba.conf_trunk |= (1 << link_no) << 4; 21169a66d990SJames Smart } 21179a66d990SJames Smart 21189a66d990SJames Smart break; 21199a66d990SJames Smart case EXTERNAL_LOOP_BACK: 21209a66d990SJames Smart if (phba->sli4_hba.conf_trunk & (1 << link_no)) { 21219a66d990SJames Smart rc = lpfc_sli4_bsg_set_loopback_mode(phba, 21229a66d990SJames Smart LPFC_DIAG_LOOPBACK_TYPE_EXTERNAL_TRUNKED, 21239a66d990SJames Smart link_no); 21249a66d990SJames Smart } else { 21259a66d990SJames Smart /* Trunk is configured, but link is not in this trunk */ 21269a66d990SJames Smart if (phba->sli4_hba.conf_trunk) { 21279a66d990SJames Smart rc = -ELNRNG; 21289a66d990SJames Smart goto loopback_mode_exit; 21299a66d990SJames Smart } 21309a66d990SJames Smart 21319a66d990SJames Smart rc = lpfc_sli4_bsg_set_loopback_mode(phba, 21329a66d990SJames Smart LPFC_DIAG_LOOPBACK_TYPE_SERDES, 21339a66d990SJames Smart link_no); 21349a66d990SJames Smart } 21359a66d990SJames Smart 21369a66d990SJames Smart if (!rc) { 21379a66d990SJames Smart /* Set the need disable bit */ 21389a66d990SJames Smart phba->sli4_hba.conf_trunk |= (1 << link_no) << 4; 21399a66d990SJames Smart } 21409a66d990SJames Smart 21419a66d990SJames Smart break; 21429a66d990SJames Smart default: 21431b51197dSJames Smart rc = -EINVAL; 21441b51197dSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 21451b51197dSJames Smart "3141 Loopback mode:x%x not supported\n", 21461b51197dSJames Smart link_flags); 21471b51197dSJames Smart goto loopback_mode_exit; 21481b51197dSJames Smart } 21491b51197dSJames Smart 21501b51197dSJames Smart if (!rc) { 21517ad20aa9SJames Smart /* wait for the link attention interrupt */ 21527ad20aa9SJames Smart msleep(100); 21537ad20aa9SJames Smart i = 0; 21541b51197dSJames Smart while (phba->link_state < LPFC_LINK_UP) { 21551b51197dSJames Smart if (i++ > timeout) { 21561b51197dSJames Smart rc = -ETIMEDOUT; 21571b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 21581b51197dSJames Smart "3137 Timeout waiting for link up " 21591b51197dSJames Smart "in loopback mode, timeout:%d ms\n", 21601b51197dSJames Smart timeout * 10); 21611b51197dSJames Smart break; 21621b51197dSJames Smart } 21631b51197dSJames Smart msleep(10); 21641b51197dSJames Smart } 21651b51197dSJames Smart } 21661b51197dSJames Smart 21671b51197dSJames Smart /* port resource registration setup for loopback diagnostic */ 21681b51197dSJames Smart if (!rc) { 21691b51197dSJames Smart /* set up a none zero myDID for loopback test */ 21701b51197dSJames Smart phba->pport->fc_myDID = 1; 21711b51197dSJames Smart rc = lpfc_sli4_diag_fcport_reg_setup(phba); 21721b51197dSJames Smart } else 21731b51197dSJames Smart goto loopback_mode_exit; 21741b51197dSJames Smart 21751b51197dSJames Smart if (!rc) { 21761b51197dSJames Smart /* wait for the port ready */ 21771b51197dSJames Smart msleep(100); 21781b51197dSJames Smart i = 0; 21797ad20aa9SJames Smart while (phba->link_state != LPFC_HBA_READY) { 21807ad20aa9SJames Smart if (i++ > timeout) { 21817ad20aa9SJames Smart rc = -ETIMEDOUT; 21821b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 21831b51197dSJames Smart "3133 Timeout waiting for port " 21841b51197dSJames Smart "loopback mode ready, timeout:%d ms\n", 21851b51197dSJames Smart timeout * 10); 21867ad20aa9SJames Smart break; 21877ad20aa9SJames Smart } 21887ad20aa9SJames Smart msleep(10); 21897ad20aa9SJames Smart } 21907ad20aa9SJames Smart } 21917ad20aa9SJames Smart 21927ad20aa9SJames Smart loopback_mode_exit: 21931b51197dSJames Smart /* clear loopback diagnostic mode */ 21941b51197dSJames Smart if (rc) { 21951b51197dSJames Smart spin_lock_irq(&phba->hbalock); 21961b51197dSJames Smart phba->link_flag &= ~LS_LOOPBACK_MODE; 21971b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 21981b51197dSJames Smart } 21997ad20aa9SJames Smart lpfc_bsg_diag_mode_exit(phba); 22007ad20aa9SJames Smart 22019a66d990SJames Smart job_done: 22027ad20aa9SJames Smart /* make error code available to userspace */ 220301e0e15cSJohannes Thumshirn bsg_reply->result = rc; 22047ad20aa9SJames Smart /* complete the job back to userspace if no error */ 22057ad20aa9SJames Smart if (rc == 0) 220606548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 22071abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 22087ad20aa9SJames Smart return rc; 22097ad20aa9SJames Smart } 22107ad20aa9SJames Smart 22117ad20aa9SJames Smart /** 22127ad20aa9SJames Smart * lpfc_bsg_diag_loopback_mode - bsg vendor command for diag loopback mode 22137ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_MODE 22147ad20aa9SJames Smart * 22157ad20aa9SJames Smart * This function is responsible for responding to check and dispatch bsg diag 22167ad20aa9SJames Smart * command from the user to proper driver action routines. 22177ad20aa9SJames Smart */ 22187ad20aa9SJames Smart static int 221975cc8cfcSJohannes Thumshirn lpfc_bsg_diag_loopback_mode(struct bsg_job *job) 22207ad20aa9SJames Smart { 22217ad20aa9SJames Smart struct Scsi_Host *shost; 22227ad20aa9SJames Smart struct lpfc_vport *vport; 22237ad20aa9SJames Smart struct lpfc_hba *phba; 22247ad20aa9SJames Smart int rc; 22257ad20aa9SJames Smart 2226cd21c605SJohannes Thumshirn shost = fc_bsg_to_shost(job); 22277ad20aa9SJames Smart if (!shost) 22287ad20aa9SJames Smart return -ENODEV; 2229cd21c605SJohannes Thumshirn vport = shost_priv(shost); 22307ad20aa9SJames Smart if (!vport) 22317ad20aa9SJames Smart return -ENODEV; 22327ad20aa9SJames Smart phba = vport->phba; 22337ad20aa9SJames Smart if (!phba) 22347ad20aa9SJames Smart return -ENODEV; 22357ad20aa9SJames Smart 22367ad20aa9SJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 22377ad20aa9SJames Smart rc = lpfc_sli3_bsg_diag_loopback_mode(phba, job); 2238719162bdSJames Smart else if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >= 22397ad20aa9SJames Smart LPFC_SLI_INTF_IF_TYPE_2) 22407ad20aa9SJames Smart rc = lpfc_sli4_bsg_diag_loopback_mode(phba, job); 22417ad20aa9SJames Smart else 22427ad20aa9SJames Smart rc = -ENODEV; 22437ad20aa9SJames Smart 22447ad20aa9SJames Smart return rc; 22457ad20aa9SJames Smart } 22467ad20aa9SJames Smart 22477ad20aa9SJames Smart /** 22487ad20aa9SJames Smart * lpfc_sli4_bsg_diag_mode_end - sli4 bsg vendor command for ending diag mode 22497ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_MODE_END 22507ad20aa9SJames Smart * 22517ad20aa9SJames Smart * This function is responsible for responding to check and dispatch bsg diag 22527ad20aa9SJames Smart * command from the user to proper driver action routines. 22537ad20aa9SJames Smart */ 22547ad20aa9SJames Smart static int 225575cc8cfcSJohannes Thumshirn lpfc_sli4_bsg_diag_mode_end(struct bsg_job *job) 22567ad20aa9SJames Smart { 225701e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 225801e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 22597ad20aa9SJames Smart struct Scsi_Host *shost; 22607ad20aa9SJames Smart struct lpfc_vport *vport; 22617ad20aa9SJames Smart struct lpfc_hba *phba; 22621b51197dSJames Smart struct diag_mode_set *loopback_mode_end_cmd; 22631b51197dSJames Smart uint32_t timeout; 22641b51197dSJames Smart int rc, i; 22657ad20aa9SJames Smart 2266cd21c605SJohannes Thumshirn shost = fc_bsg_to_shost(job); 22677ad20aa9SJames Smart if (!shost) 22687ad20aa9SJames Smart return -ENODEV; 2269cd21c605SJohannes Thumshirn vport = shost_priv(shost); 22707ad20aa9SJames Smart if (!vport) 22717ad20aa9SJames Smart return -ENODEV; 22727ad20aa9SJames Smart phba = vport->phba; 22737ad20aa9SJames Smart if (!phba) 22747ad20aa9SJames Smart return -ENODEV; 22757ad20aa9SJames Smart 22767ad20aa9SJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 22777ad20aa9SJames Smart return -ENODEV; 2278719162bdSJames Smart if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) < 22797ad20aa9SJames Smart LPFC_SLI_INTF_IF_TYPE_2) 22807ad20aa9SJames Smart return -ENODEV; 22817ad20aa9SJames Smart 22821b51197dSJames Smart /* clear loopback diagnostic mode */ 22831b51197dSJames Smart spin_lock_irq(&phba->hbalock); 22841b51197dSJames Smart phba->link_flag &= ~LS_LOOPBACK_MODE; 22851b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 22861b51197dSJames Smart loopback_mode_end_cmd = (struct diag_mode_set *) 228701e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 22881b51197dSJames Smart timeout = loopback_mode_end_cmd->timeout * 100; 22891b51197dSJames Smart 22907ad20aa9SJames Smart rc = lpfc_sli4_bsg_set_link_diag_state(phba, 0); 22911b51197dSJames Smart if (rc) { 22921b51197dSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 22931b51197dSJames Smart "3139 Failed to bring link to diagnostic " 22941b51197dSJames Smart "state, rc:x%x\n", rc); 22951b51197dSJames Smart goto loopback_mode_end_exit; 22961b51197dSJames Smart } 22977ad20aa9SJames Smart 22981b51197dSJames Smart /* wait for link down before proceeding */ 22991b51197dSJames Smart i = 0; 23001b51197dSJames Smart while (phba->link_state != LPFC_LINK_DOWN) { 23011b51197dSJames Smart if (i++ > timeout) { 23021b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 23031b51197dSJames Smart "3140 Timeout waiting for link to " 23041b51197dSJames Smart "diagnostic mode_end, timeout:%d ms\n", 23051b51197dSJames Smart timeout * 10); 23061b51197dSJames Smart /* there is nothing much we can do here */ 23071b51197dSJames Smart break; 23081b51197dSJames Smart } 23091b51197dSJames Smart msleep(10); 23101b51197dSJames Smart } 23117ad20aa9SJames Smart 23121b51197dSJames Smart /* reset port resource registrations */ 23131b51197dSJames Smart rc = lpfc_selective_reset(phba); 23141b51197dSJames Smart phba->pport->fc_myDID = 0; 23151b51197dSJames Smart 23161b51197dSJames Smart loopback_mode_end_exit: 23171b51197dSJames Smart /* make return code available to userspace */ 231801e0e15cSJohannes Thumshirn bsg_reply->result = rc; 23191b51197dSJames Smart /* complete the job back to userspace if no error */ 23201b51197dSJames Smart if (rc == 0) 232106548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 23221abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 23237ad20aa9SJames Smart return rc; 23247ad20aa9SJames Smart } 23257ad20aa9SJames Smart 23267ad20aa9SJames Smart /** 23277ad20aa9SJames Smart * lpfc_sli4_bsg_link_diag_test - sli4 bsg vendor command for diag link test 23287ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_LINK_TEST 23297ad20aa9SJames Smart * 23307ad20aa9SJames Smart * This function is to perform SLI4 diag link test request from the user 23317ad20aa9SJames Smart * applicaiton. 23327ad20aa9SJames Smart */ 23337ad20aa9SJames Smart static int 233475cc8cfcSJohannes Thumshirn lpfc_sli4_bsg_link_diag_test(struct bsg_job *job) 23357ad20aa9SJames Smart { 233601e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 233701e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 23387ad20aa9SJames Smart struct Scsi_Host *shost; 23397ad20aa9SJames Smart struct lpfc_vport *vport; 23407ad20aa9SJames Smart struct lpfc_hba *phba; 23417ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq; 23427ad20aa9SJames Smart struct sli4_link_diag *link_diag_test_cmd; 23437ad20aa9SJames Smart uint32_t req_len, alloc_len; 23447ad20aa9SJames Smart struct lpfc_mbx_run_link_diag_test *run_link_diag_test; 23457ad20aa9SJames Smart union lpfc_sli4_cfg_shdr *shdr; 23467ad20aa9SJames Smart uint32_t shdr_status, shdr_add_status; 23477ad20aa9SJames Smart struct diag_status *diag_status_reply; 2348e5fcb81dSDick Kennedy int mbxstatus, rc = -ENODEV, rc1 = 0; 23497ad20aa9SJames Smart 2350cd21c605SJohannes Thumshirn shost = fc_bsg_to_shost(job); 2351e5fcb81dSDick Kennedy if (!shost) 23527ad20aa9SJames Smart goto job_error; 23537ad20aa9SJames Smart 2354e5fcb81dSDick Kennedy vport = shost_priv(shost); 2355e5fcb81dSDick Kennedy if (!vport) 23567ad20aa9SJames Smart goto job_error; 2357e5fcb81dSDick Kennedy 2358e5fcb81dSDick Kennedy phba = vport->phba; 2359e5fcb81dSDick Kennedy if (!phba) 2360e5fcb81dSDick Kennedy goto job_error; 2361e5fcb81dSDick Kennedy 2362e5fcb81dSDick Kennedy 2363e5fcb81dSDick Kennedy if (phba->sli_rev < LPFC_SLI_REV4) 2364e5fcb81dSDick Kennedy goto job_error; 2365e5fcb81dSDick Kennedy 2366719162bdSJames Smart if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) < 2367e5fcb81dSDick Kennedy LPFC_SLI_INTF_IF_TYPE_2) 23687ad20aa9SJames Smart goto job_error; 23697ad20aa9SJames Smart 23707ad20aa9SJames Smart if (job->request_len < sizeof(struct fc_bsg_request) + 23717ad20aa9SJames Smart sizeof(struct sli4_link_diag)) { 23727ad20aa9SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 23737ad20aa9SJames Smart "3013 Received LINK DIAG TEST request " 23747ad20aa9SJames Smart " size:%d below the minimum size:%d\n", 23757ad20aa9SJames Smart job->request_len, 23767ad20aa9SJames Smart (int)(sizeof(struct fc_bsg_request) + 23777ad20aa9SJames Smart sizeof(struct sli4_link_diag))); 23787ad20aa9SJames Smart rc = -EINVAL; 23797ad20aa9SJames Smart goto job_error; 23807ad20aa9SJames Smart } 23817ad20aa9SJames Smart 238288a2cfbbSJames Smart rc = lpfc_bsg_diag_mode_enter(phba); 23837ad20aa9SJames Smart if (rc) 23847ad20aa9SJames Smart goto job_error; 23857ad20aa9SJames Smart 23867ad20aa9SJames Smart link_diag_test_cmd = (struct sli4_link_diag *) 238701e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 23887ad20aa9SJames Smart 23897ad20aa9SJames Smart rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1); 23907ad20aa9SJames Smart 23917ad20aa9SJames Smart if (rc) 23927ad20aa9SJames Smart goto job_error; 23937ad20aa9SJames Smart 23947ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 2395a1a553e3SJames Smart if (!pmboxq) { 2396a1a553e3SJames Smart rc = -ENOMEM; 23977ad20aa9SJames Smart goto link_diag_test_exit; 2398a1a553e3SJames Smart } 23997ad20aa9SJames Smart 24007ad20aa9SJames Smart req_len = (sizeof(struct lpfc_mbx_set_link_diag_state) - 24017ad20aa9SJames Smart sizeof(struct lpfc_sli4_cfg_mhdr)); 24027ad20aa9SJames Smart alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, 24037ad20aa9SJames Smart LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE, 24047ad20aa9SJames Smart req_len, LPFC_SLI4_MBX_EMBED); 2405e5fcb81dSDick Kennedy if (alloc_len != req_len) { 2406e5fcb81dSDick Kennedy rc = -ENOMEM; 24077ad20aa9SJames Smart goto link_diag_test_exit; 2408e5fcb81dSDick Kennedy } 240944ed33e6SGustavo A. R. Silva 24107ad20aa9SJames Smart run_link_diag_test = &pmboxq->u.mqe.un.link_diag_test; 24117ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_link_num, &run_link_diag_test->u.req, 24121b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_no); 24137ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_link_type, &run_link_diag_test->u.req, 24141b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_tp); 24157ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_test_id, &run_link_diag_test->u.req, 24167ad20aa9SJames Smart link_diag_test_cmd->test_id); 24177ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_loops, &run_link_diag_test->u.req, 24187ad20aa9SJames Smart link_diag_test_cmd->loops); 24197ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_test_ver, &run_link_diag_test->u.req, 24207ad20aa9SJames Smart link_diag_test_cmd->test_version); 24217ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_err_act, &run_link_diag_test->u.req, 24227ad20aa9SJames Smart link_diag_test_cmd->error_action); 24237ad20aa9SJames Smart 24247ad20aa9SJames Smart mbxstatus = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); 24257ad20aa9SJames Smart 24267ad20aa9SJames Smart shdr = (union lpfc_sli4_cfg_shdr *) 24277ad20aa9SJames Smart &pmboxq->u.mqe.un.sli4_config.header.cfg_shdr; 24287ad20aa9SJames Smart shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); 24297ad20aa9SJames Smart shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); 24307ad20aa9SJames Smart if (shdr_status || shdr_add_status || mbxstatus) { 24317ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 24327ad20aa9SJames Smart "3010 Run link diag test mailbox failed with " 24337ad20aa9SJames Smart "mbx_status x%x status x%x, add_status x%x\n", 24347ad20aa9SJames Smart mbxstatus, shdr_status, shdr_add_status); 24357ad20aa9SJames Smart } 24367ad20aa9SJames Smart 24377ad20aa9SJames Smart diag_status_reply = (struct diag_status *) 243801e0e15cSJohannes Thumshirn bsg_reply->reply_data.vendor_reply.vendor_rsp; 24397ad20aa9SJames Smart 2440feb3cc57SDick Kennedy if (job->reply_len < sizeof(*bsg_reply) + sizeof(*diag_status_reply)) { 24417ad20aa9SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 24427ad20aa9SJames Smart "3012 Received Run link diag test reply " 24437ad20aa9SJames Smart "below minimum size (%d): reply_len:%d\n", 2444feb3cc57SDick Kennedy (int)(sizeof(*bsg_reply) + 2445feb3cc57SDick Kennedy sizeof(*diag_status_reply)), 24467ad20aa9SJames Smart job->reply_len); 24477ad20aa9SJames Smart rc = -EINVAL; 24487ad20aa9SJames Smart goto job_error; 24497ad20aa9SJames Smart } 24507ad20aa9SJames Smart 24517ad20aa9SJames Smart diag_status_reply->mbox_status = mbxstatus; 24527ad20aa9SJames Smart diag_status_reply->shdr_status = shdr_status; 24537ad20aa9SJames Smart diag_status_reply->shdr_add_status = shdr_add_status; 24547ad20aa9SJames Smart 24557ad20aa9SJames Smart link_diag_test_exit: 2456e5fcb81dSDick Kennedy rc1 = lpfc_sli4_bsg_set_link_diag_state(phba, 0); 24577ad20aa9SJames Smart 24587ad20aa9SJames Smart if (pmboxq) 24597ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 24607ad20aa9SJames Smart 24617ad20aa9SJames Smart lpfc_bsg_diag_mode_exit(phba); 24627ad20aa9SJames Smart 24637ad20aa9SJames Smart job_error: 24647ad20aa9SJames Smart /* make error code available to userspace */ 2465e5fcb81dSDick Kennedy if (rc1 && !rc) 2466e5fcb81dSDick Kennedy rc = rc1; 246701e0e15cSJohannes Thumshirn bsg_reply->result = rc; 24687ad20aa9SJames Smart /* complete the job back to userspace if no error */ 24697ad20aa9SJames Smart if (rc == 0) 247006548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 24711abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 24727ad20aa9SJames Smart return rc; 24737ad20aa9SJames Smart } 24747ad20aa9SJames Smart 24757ad20aa9SJames Smart /** 24763b5dd52aSJames Smart * lpfcdiag_loop_self_reg - obtains a remote port login id 24773b5dd52aSJames Smart * @phba: Pointer to HBA context object 24783b5dd52aSJames Smart * @rpi: Pointer to a remote port login id 24793b5dd52aSJames Smart * 24803b5dd52aSJames Smart * This function obtains a remote port login id so the diag loopback test 24813b5dd52aSJames Smart * can send and receive its own unsolicited CT command. 24823b5dd52aSJames Smart **/ 24833b5dd52aSJames Smart static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t *rpi) 24843b5dd52aSJames Smart { 24853b5dd52aSJames Smart LPFC_MBOXQ_t *mbox; 24863b5dd52aSJames Smart struct lpfc_dmabuf *dmabuff; 24873b5dd52aSJames Smart int status; 24883b5dd52aSJames Smart 24893b5dd52aSJames Smart mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 24903b5dd52aSJames Smart if (!mbox) 2491d439d286SJames Smart return -ENOMEM; 24923b5dd52aSJames Smart 24931b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 24943b5dd52aSJames Smart status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID, 24951b51197dSJames Smart (uint8_t *)&phba->pport->fc_sparam, 24961b51197dSJames Smart mbox, *rpi); 24971b51197dSJames Smart else { 24981b51197dSJames Smart *rpi = lpfc_sli4_alloc_rpi(phba); 24999d3d340dSJames Smart if (*rpi == LPFC_RPI_ALLOC_ERROR) { 25009d3d340dSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 25019d3d340dSJames Smart return -EBUSY; 25029d3d340dSJames Smart } 25031b51197dSJames Smart status = lpfc_reg_rpi(phba, phba->pport->vpi, 25041b51197dSJames Smart phba->pport->fc_myDID, 25051b51197dSJames Smart (uint8_t *)&phba->pport->fc_sparam, 25061b51197dSJames Smart mbox, *rpi); 25071b51197dSJames Smart } 25081b51197dSJames Smart 25093b5dd52aSJames Smart if (status) { 25103b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 25114042629eSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 25124042629eSJames Smart lpfc_sli4_free_rpi(phba, *rpi); 2513d439d286SJames Smart return -ENOMEM; 25143b5dd52aSJames Smart } 25153b5dd52aSJames Smart 2516115d137aSJustin Tee dmabuff = mbox->ctx_buf; 25173e1f0718SJames Smart mbox->ctx_buf = NULL; 25183e1f0718SJames Smart mbox->ctx_ndlp = NULL; 25193b5dd52aSJames Smart status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); 25203b5dd52aSJames Smart 25213b5dd52aSJames Smart if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { 25223b5dd52aSJames Smart lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); 25233b5dd52aSJames Smart kfree(dmabuff); 25243b5dd52aSJames Smart if (status != MBX_TIMEOUT) 25253b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 25264042629eSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 25274042629eSJames Smart lpfc_sli4_free_rpi(phba, *rpi); 2528d439d286SJames Smart return -ENODEV; 25293b5dd52aSJames Smart } 25303b5dd52aSJames Smart 25311b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 25323b5dd52aSJames Smart *rpi = mbox->u.mb.un.varWords[0]; 25333b5dd52aSJames Smart 25343b5dd52aSJames Smart lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); 25353b5dd52aSJames Smart kfree(dmabuff); 25363b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 25373b5dd52aSJames Smart return 0; 25383b5dd52aSJames Smart } 25393b5dd52aSJames Smart 25403b5dd52aSJames Smart /** 25413b5dd52aSJames Smart * lpfcdiag_loop_self_unreg - unregs from the rpi 25423b5dd52aSJames Smart * @phba: Pointer to HBA context object 25433b5dd52aSJames Smart * @rpi: Remote port login id 25443b5dd52aSJames Smart * 25453b5dd52aSJames Smart * This function unregisters the rpi obtained in lpfcdiag_loop_self_reg 25463b5dd52aSJames Smart **/ 25473b5dd52aSJames Smart static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi) 25483b5dd52aSJames Smart { 25493b5dd52aSJames Smart LPFC_MBOXQ_t *mbox; 25503b5dd52aSJames Smart int status; 25513b5dd52aSJames Smart 25523b5dd52aSJames Smart /* Allocate mboxq structure */ 25533b5dd52aSJames Smart mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 25543b5dd52aSJames Smart if (mbox == NULL) 2555d439d286SJames Smart return -ENOMEM; 25563b5dd52aSJames Smart 25571b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 25583b5dd52aSJames Smart lpfc_unreg_login(phba, 0, rpi, mbox); 25591b51197dSJames Smart else 25601b51197dSJames Smart lpfc_unreg_login(phba, phba->pport->vpi, 25611b51197dSJames Smart phba->sli4_hba.rpi_ids[rpi], mbox); 25621b51197dSJames Smart 25633b5dd52aSJames Smart status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); 25643b5dd52aSJames Smart 25653b5dd52aSJames Smart if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { 25663b5dd52aSJames Smart if (status != MBX_TIMEOUT) 25673b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 2568d439d286SJames Smart return -EIO; 25693b5dd52aSJames Smart } 25703b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 25714042629eSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 25724042629eSJames Smart lpfc_sli4_free_rpi(phba, rpi); 25733b5dd52aSJames Smart return 0; 25743b5dd52aSJames Smart } 25753b5dd52aSJames Smart 25763b5dd52aSJames Smart /** 25773b5dd52aSJames Smart * lpfcdiag_loop_get_xri - obtains the transmit and receive ids 25783b5dd52aSJames Smart * @phba: Pointer to HBA context object 25793b5dd52aSJames Smart * @rpi: Remote port login id 25803b5dd52aSJames Smart * @txxri: Pointer to transmit exchange id 25813b5dd52aSJames Smart * @rxxri: Pointer to response exchabge id 25823b5dd52aSJames Smart * 25833b5dd52aSJames Smart * This function obtains the transmit and receive ids required to send 25843b5dd52aSJames Smart * an unsolicited ct command with a payload. A special lpfc FsType and CmdRsp 2585638eec06SColin Ian King * flags are used to the unsolicited response handler is able to process 25863b5dd52aSJames Smart * the ct command sent on the same port. 25873b5dd52aSJames Smart **/ 25883b5dd52aSJames Smart static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, 25893b5dd52aSJames Smart uint16_t *txxri, uint16_t * rxxri) 25903b5dd52aSJames Smart { 25913b5dd52aSJames Smart struct lpfc_bsg_event *evt; 25923b5dd52aSJames Smart struct lpfc_iocbq *cmdiocbq, *rspiocbq; 25933b5dd52aSJames Smart struct lpfc_dmabuf *dmabuf; 25943b5dd52aSJames Smart struct ulp_bde64 *bpl = NULL; 25953b5dd52aSJames Smart struct lpfc_sli_ct_request *ctreq = NULL; 25963b5dd52aSJames Smart int ret_val = 0; 2597d439d286SJames Smart int time_left; 25985a0916b4SJames Smart int iocb_stat = IOCB_SUCCESS; 25993b5dd52aSJames Smart unsigned long flags; 260061910d6aSJames Smart u32 status; 26013b5dd52aSJames Smart 26023b5dd52aSJames Smart *txxri = 0; 26033b5dd52aSJames Smart *rxxri = 0; 26043b5dd52aSJames Smart evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, 26053b5dd52aSJames Smart SLI_CT_ELX_LOOPBACK); 26063b5dd52aSJames Smart if (!evt) 2607d439d286SJames Smart return -ENOMEM; 26083b5dd52aSJames Smart 26093b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 26103b5dd52aSJames Smart list_add(&evt->node, &phba->ct_ev_waiters); 26113b5dd52aSJames Smart lpfc_bsg_event_ref(evt); 26123b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 26133b5dd52aSJames Smart 26143b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 26153b5dd52aSJames Smart rspiocbq = lpfc_sli_get_iocbq(phba); 26163b5dd52aSJames Smart 26173b5dd52aSJames Smart dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 26183b5dd52aSJames Smart if (dmabuf) { 26193b5dd52aSJames Smart dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys); 2620c7495937SJames Smart if (dmabuf->virt) { 26213b5dd52aSJames Smart INIT_LIST_HEAD(&dmabuf->list); 26223b5dd52aSJames Smart bpl = (struct ulp_bde64 *) dmabuf->virt; 26233b5dd52aSJames Smart memset(bpl, 0, sizeof(*bpl)); 26243b5dd52aSJames Smart ctreq = (struct lpfc_sli_ct_request *)(bpl + 1); 26253b5dd52aSJames Smart bpl->addrHigh = 2626c7495937SJames Smart le32_to_cpu(putPaddrHigh(dmabuf->phys + 2627c7495937SJames Smart sizeof(*bpl))); 26283b5dd52aSJames Smart bpl->addrLow = 2629c7495937SJames Smart le32_to_cpu(putPaddrLow(dmabuf->phys + 2630c7495937SJames Smart sizeof(*bpl))); 26313b5dd52aSJames Smart bpl->tus.f.bdeFlags = 0; 26323b5dd52aSJames Smart bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ; 26333b5dd52aSJames Smart bpl->tus.w = le32_to_cpu(bpl->tus.w); 26343b5dd52aSJames Smart } 2635c7495937SJames Smart } 26363b5dd52aSJames Smart 26373b5dd52aSJames Smart if (cmdiocbq == NULL || rspiocbq == NULL || 2638c7495937SJames Smart dmabuf == NULL || bpl == NULL || ctreq == NULL || 2639c7495937SJames Smart dmabuf->virt == NULL) { 2640d439d286SJames Smart ret_val = -ENOMEM; 26413b5dd52aSJames Smart goto err_get_xri_exit; 26423b5dd52aSJames Smart } 26433b5dd52aSJames Smart 26443b5dd52aSJames Smart memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); 26453b5dd52aSJames Smart 26463b5dd52aSJames Smart ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; 26473b5dd52aSJames Smart ctreq->RevisionId.bits.InId = 0; 26483b5dd52aSJames Smart ctreq->FsType = SLI_CT_ELX_LOOPBACK; 26493b5dd52aSJames Smart ctreq->FsSubType = 0; 26503b5dd52aSJames Smart ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_XRI_SETUP; 26513b5dd52aSJames Smart ctreq->CommandResponse.bits.Size = 0; 26523b5dd52aSJames Smart 2653d51cf5bdSJames Smart cmdiocbq->bpl_dmabuf = dmabuf; 2654a680a929SJames Smart cmdiocbq->cmd_flag |= LPFC_IO_LIBDFC; 26553b5dd52aSJames Smart cmdiocbq->vport = phba->pport; 2656a680a929SJames Smart cmdiocbq->cmd_cmpl = NULL; 26573b5dd52aSJames Smart 265861910d6aSJames Smart lpfc_sli_prep_xmit_seq64(phba, cmdiocbq, dmabuf, rpi, 0, 1, 265961910d6aSJames Smart FC_RCTL_DD_SOL_CTL, 0, CMD_XMIT_SEQUENCE64_CR); 266061910d6aSJames Smart 2661d439d286SJames Smart iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, 266261910d6aSJames Smart rspiocbq, (phba->fc_ratov * 2) 26633b5dd52aSJames Smart + LPFC_DRVR_TIMEOUT); 266461910d6aSJames Smart 266561910d6aSJames Smart status = get_job_ulpstatus(phba, rspiocbq); 266661910d6aSJames Smart if (iocb_stat != IOCB_SUCCESS || status != IOCB_SUCCESS) { 2667d439d286SJames Smart ret_val = -EIO; 26683b5dd52aSJames Smart goto err_get_xri_exit; 2669d439d286SJames Smart } 267061910d6aSJames Smart *txxri = get_job_ulpcontext(phba, rspiocbq); 26713b5dd52aSJames Smart 26723b5dd52aSJames Smart evt->waiting = 1; 26733b5dd52aSJames Smart evt->wait_time_stamp = jiffies; 2674d439d286SJames Smart time_left = wait_event_interruptible_timeout( 26753b5dd52aSJames Smart evt->wq, !list_empty(&evt->events_to_see), 2676256ec0d0SJames Smart msecs_to_jiffies(1000 * 2677256ec0d0SJames Smart ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT))); 26783b5dd52aSJames Smart if (list_empty(&evt->events_to_see)) 2679d439d286SJames Smart ret_val = (time_left) ? -EINTR : -ETIMEDOUT; 26803b5dd52aSJames Smart else { 26813b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 26823b5dd52aSJames Smart list_move(evt->events_to_see.prev, &evt->events_to_get); 26833b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 26843b5dd52aSJames Smart *rxxri = (list_entry(evt->events_to_get.prev, 26853b5dd52aSJames Smart typeof(struct event_data), 26863b5dd52aSJames Smart node))->immed_dat; 26873b5dd52aSJames Smart } 26883b5dd52aSJames Smart evt->waiting = 0; 26893b5dd52aSJames Smart 26903b5dd52aSJames Smart err_get_xri_exit: 26913b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 26923b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* release ref */ 26933b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* delete */ 26943b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 26953b5dd52aSJames Smart 26963b5dd52aSJames Smart if (dmabuf) { 26973b5dd52aSJames Smart if (dmabuf->virt) 26983b5dd52aSJames Smart lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); 26993b5dd52aSJames Smart kfree(dmabuf); 27003b5dd52aSJames Smart } 27013b5dd52aSJames Smart 2702d439d286SJames Smart if (cmdiocbq && (iocb_stat != IOCB_TIMEDOUT)) 27033b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 27043b5dd52aSJames Smart if (rspiocbq) 27053b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, rspiocbq); 27063b5dd52aSJames Smart return ret_val; 27073b5dd52aSJames Smart } 27083b5dd52aSJames Smart 27093b5dd52aSJames Smart /** 27107ad20aa9SJames Smart * lpfc_bsg_dma_page_alloc - allocate a bsg mbox page sized dma buffers 27117ad20aa9SJames Smart * @phba: Pointer to HBA context object 27127ad20aa9SJames Smart * 27132ea259eeSJames Smart * This function allocates BSG_MBOX_SIZE (4KB) page size dma buffer and 27149e03aa2fSJoe Perches * returns the pointer to the buffer. 27157ad20aa9SJames Smart **/ 27167ad20aa9SJames Smart static struct lpfc_dmabuf * 27177ad20aa9SJames Smart lpfc_bsg_dma_page_alloc(struct lpfc_hba *phba) 27187ad20aa9SJames Smart { 27197ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf; 27207ad20aa9SJames Smart struct pci_dev *pcidev = phba->pcidev; 27217ad20aa9SJames Smart 27227ad20aa9SJames Smart /* allocate dma buffer struct */ 27237ad20aa9SJames Smart dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 27247ad20aa9SJames Smart if (!dmabuf) 27257ad20aa9SJames Smart return NULL; 27267ad20aa9SJames Smart 27277ad20aa9SJames Smart INIT_LIST_HEAD(&dmabuf->list); 27287ad20aa9SJames Smart 27297ad20aa9SJames Smart /* now, allocate dma buffer */ 2730750afb08SLuis Chamberlain dmabuf->virt = dma_alloc_coherent(&pcidev->dev, BSG_MBOX_SIZE, 27317ad20aa9SJames Smart &(dmabuf->phys), GFP_KERNEL); 27327ad20aa9SJames Smart 27337ad20aa9SJames Smart if (!dmabuf->virt) { 27347ad20aa9SJames Smart kfree(dmabuf); 27357ad20aa9SJames Smart return NULL; 27367ad20aa9SJames Smart } 27377ad20aa9SJames Smart 27387ad20aa9SJames Smart return dmabuf; 27397ad20aa9SJames Smart } 27407ad20aa9SJames Smart 27417ad20aa9SJames Smart /** 27427ad20aa9SJames Smart * lpfc_bsg_dma_page_free - free a bsg mbox page sized dma buffer 27437ad20aa9SJames Smart * @phba: Pointer to HBA context object. 27447ad20aa9SJames Smart * @dmabuf: Pointer to the bsg mbox page sized dma buffer descriptor. 27457ad20aa9SJames Smart * 27467ad20aa9SJames Smart * This routine just simply frees a dma buffer and its associated buffer 27477ad20aa9SJames Smart * descriptor referred by @dmabuf. 27487ad20aa9SJames Smart **/ 27497ad20aa9SJames Smart static void 27507ad20aa9SJames Smart lpfc_bsg_dma_page_free(struct lpfc_hba *phba, struct lpfc_dmabuf *dmabuf) 27517ad20aa9SJames Smart { 27527ad20aa9SJames Smart struct pci_dev *pcidev = phba->pcidev; 27537ad20aa9SJames Smart 27547ad20aa9SJames Smart if (!dmabuf) 27557ad20aa9SJames Smart return; 27567ad20aa9SJames Smart 27577ad20aa9SJames Smart if (dmabuf->virt) 27587ad20aa9SJames Smart dma_free_coherent(&pcidev->dev, BSG_MBOX_SIZE, 27597ad20aa9SJames Smart dmabuf->virt, dmabuf->phys); 27607ad20aa9SJames Smart kfree(dmabuf); 27617ad20aa9SJames Smart return; 27627ad20aa9SJames Smart } 27637ad20aa9SJames Smart 27647ad20aa9SJames Smart /** 27657ad20aa9SJames Smart * lpfc_bsg_dma_page_list_free - free a list of bsg mbox page sized dma buffers 27667ad20aa9SJames Smart * @phba: Pointer to HBA context object. 27677ad20aa9SJames Smart * @dmabuf_list: Pointer to a list of bsg mbox page sized dma buffer descs. 27687ad20aa9SJames Smart * 27697ad20aa9SJames Smart * This routine just simply frees all dma buffers and their associated buffer 27707ad20aa9SJames Smart * descriptors referred by @dmabuf_list. 27717ad20aa9SJames Smart **/ 27727ad20aa9SJames Smart static void 27737ad20aa9SJames Smart lpfc_bsg_dma_page_list_free(struct lpfc_hba *phba, 27747ad20aa9SJames Smart struct list_head *dmabuf_list) 27757ad20aa9SJames Smart { 27767ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf, *next_dmabuf; 27777ad20aa9SJames Smart 27787ad20aa9SJames Smart if (list_empty(dmabuf_list)) 27797ad20aa9SJames Smart return; 27807ad20aa9SJames Smart 27817ad20aa9SJames Smart list_for_each_entry_safe(dmabuf, next_dmabuf, dmabuf_list, list) { 27827ad20aa9SJames Smart list_del_init(&dmabuf->list); 27837ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 27847ad20aa9SJames Smart } 27857ad20aa9SJames Smart return; 27867ad20aa9SJames Smart } 27877ad20aa9SJames Smart 27887ad20aa9SJames Smart /** 27893b5dd52aSJames Smart * diag_cmd_data_alloc - fills in a bde struct with dma buffers 27903b5dd52aSJames Smart * @phba: Pointer to HBA context object 27913b5dd52aSJames Smart * @bpl: Pointer to 64 bit bde structure 27923b5dd52aSJames Smart * @size: Number of bytes to process 27933b5dd52aSJames Smart * @nocopydata: Flag to copy user data into the allocated buffer 27943b5dd52aSJames Smart * 27953b5dd52aSJames Smart * This function allocates page size buffers and populates an lpfc_dmabufext. 27963b5dd52aSJames Smart * If allowed the user data pointed to with indataptr is copied into the kernel 27973b5dd52aSJames Smart * memory. The chained list of page size buffers is returned. 27983b5dd52aSJames Smart **/ 27993b5dd52aSJames Smart static struct lpfc_dmabufext * 28003b5dd52aSJames Smart diag_cmd_data_alloc(struct lpfc_hba *phba, 28013b5dd52aSJames Smart struct ulp_bde64 *bpl, uint32_t size, 28023b5dd52aSJames Smart int nocopydata) 28033b5dd52aSJames Smart { 28043b5dd52aSJames Smart struct lpfc_dmabufext *mlist = NULL; 28053b5dd52aSJames Smart struct lpfc_dmabufext *dmp; 28063b5dd52aSJames Smart int cnt, offset = 0, i = 0; 28073b5dd52aSJames Smart struct pci_dev *pcidev; 28083b5dd52aSJames Smart 28093b5dd52aSJames Smart pcidev = phba->pcidev; 28103b5dd52aSJames Smart 28113b5dd52aSJames Smart while (size) { 28123b5dd52aSJames Smart /* We get chunks of 4K */ 28133b5dd52aSJames Smart if (size > BUF_SZ_4K) 28143b5dd52aSJames Smart cnt = BUF_SZ_4K; 28153b5dd52aSJames Smart else 28163b5dd52aSJames Smart cnt = size; 28173b5dd52aSJames Smart 28183b5dd52aSJames Smart /* allocate struct lpfc_dmabufext buffer header */ 28193b5dd52aSJames Smart dmp = kmalloc(sizeof(struct lpfc_dmabufext), GFP_KERNEL); 28203b5dd52aSJames Smart if (!dmp) 28213b5dd52aSJames Smart goto out; 28223b5dd52aSJames Smart 28233b5dd52aSJames Smart INIT_LIST_HEAD(&dmp->dma.list); 28243b5dd52aSJames Smart 28253b5dd52aSJames Smart /* Queue it to a linked list */ 28263b5dd52aSJames Smart if (mlist) 28273b5dd52aSJames Smart list_add_tail(&dmp->dma.list, &mlist->dma.list); 28283b5dd52aSJames Smart else 28293b5dd52aSJames Smart mlist = dmp; 28303b5dd52aSJames Smart 28313b5dd52aSJames Smart /* allocate buffer */ 28323b5dd52aSJames Smart dmp->dma.virt = dma_alloc_coherent(&pcidev->dev, 28333b5dd52aSJames Smart cnt, 28343b5dd52aSJames Smart &(dmp->dma.phys), 28353b5dd52aSJames Smart GFP_KERNEL); 28363b5dd52aSJames Smart 28373b5dd52aSJames Smart if (!dmp->dma.virt) 28383b5dd52aSJames Smart goto out; 28393b5dd52aSJames Smart 28403b5dd52aSJames Smart dmp->size = cnt; 28413b5dd52aSJames Smart 28423b5dd52aSJames Smart if (nocopydata) { 28433b5dd52aSJames Smart bpl->tus.f.bdeFlags = 0; 28443b5dd52aSJames Smart } else { 28453b5dd52aSJames Smart memset((uint8_t *)dmp->dma.virt, 0, cnt); 28463b5dd52aSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; 28473b5dd52aSJames Smart } 28483b5dd52aSJames Smart 28493b5dd52aSJames Smart /* build buffer ptr list for IOCB */ 28503b5dd52aSJames Smart bpl->addrLow = le32_to_cpu(putPaddrLow(dmp->dma.phys)); 28513b5dd52aSJames Smart bpl->addrHigh = le32_to_cpu(putPaddrHigh(dmp->dma.phys)); 28523b5dd52aSJames Smart bpl->tus.f.bdeSize = (ushort) cnt; 28533b5dd52aSJames Smart bpl->tus.w = le32_to_cpu(bpl->tus.w); 28543b5dd52aSJames Smart bpl++; 28553b5dd52aSJames Smart 28563b5dd52aSJames Smart i++; 28573b5dd52aSJames Smart offset += cnt; 28583b5dd52aSJames Smart size -= cnt; 28593b5dd52aSJames Smart } 28603b5dd52aSJames Smart 2861a2fc4aefSJames Smart if (mlist) { 28623b5dd52aSJames Smart mlist->flag = i; 28633b5dd52aSJames Smart return mlist; 2864a2fc4aefSJames Smart } 28653b5dd52aSJames Smart out: 28663b5dd52aSJames Smart diag_cmd_data_free(phba, mlist); 28673b5dd52aSJames Smart return NULL; 28683b5dd52aSJames Smart } 28693b5dd52aSJames Smart 28703b5dd52aSJames Smart /** 287161910d6aSJames Smart * lpfcdiag_sli3_loop_post_rxbufs - post the receive buffers for an unsol CT cmd 28723b5dd52aSJames Smart * @phba: Pointer to HBA context object 28733b5dd52aSJames Smart * @rxxri: Receive exchange id 28743b5dd52aSJames Smart * @len: Number of data bytes 28753b5dd52aSJames Smart * 287625985edcSLucas De Marchi * This function allocates and posts a data buffer of sufficient size to receive 2877638eec06SColin Ian King * an unsolicited CT command. 28783b5dd52aSJames Smart **/ 287961910d6aSJames Smart static int lpfcdiag_sli3_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, 28803b5dd52aSJames Smart size_t len) 28813b5dd52aSJames Smart { 2882895427bdSJames Smart struct lpfc_sli_ring *pring; 28833b5dd52aSJames Smart struct lpfc_iocbq *cmdiocbq; 28843b5dd52aSJames Smart IOCB_t *cmd = NULL; 28853b5dd52aSJames Smart struct list_head head, *curr, *next; 28863b5dd52aSJames Smart struct lpfc_dmabuf *rxbmp; 28873b5dd52aSJames Smart struct lpfc_dmabuf *dmp; 28883b5dd52aSJames Smart struct lpfc_dmabuf *mp[2] = {NULL, NULL}; 28893b5dd52aSJames Smart struct ulp_bde64 *rxbpl = NULL; 28903b5dd52aSJames Smart uint32_t num_bde; 28913b5dd52aSJames Smart struct lpfc_dmabufext *rxbuffer = NULL; 28923b5dd52aSJames Smart int ret_val = 0; 2893d439d286SJames Smart int iocb_stat; 28943b5dd52aSJames Smart int i = 0; 28953b5dd52aSJames Smart 2896895427bdSJames Smart pring = lpfc_phba_elsring(phba); 2897895427bdSJames Smart 28983b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 28993b5dd52aSJames Smart rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 29003b5dd52aSJames Smart if (rxbmp != NULL) { 29013b5dd52aSJames Smart rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); 2902c7495937SJames Smart if (rxbmp->virt) { 29033b5dd52aSJames Smart INIT_LIST_HEAD(&rxbmp->list); 29043b5dd52aSJames Smart rxbpl = (struct ulp_bde64 *) rxbmp->virt; 29053b5dd52aSJames Smart rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0); 29063b5dd52aSJames Smart } 2907c7495937SJames Smart } 29083b5dd52aSJames Smart 29091234a6d5SDick Kennedy if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer || !pring) { 2910d439d286SJames Smart ret_val = -ENOMEM; 29113b5dd52aSJames Smart goto err_post_rxbufs_exit; 29123b5dd52aSJames Smart } 29133b5dd52aSJames Smart 29143b5dd52aSJames Smart /* Queue buffers for the receive exchange */ 29153b5dd52aSJames Smart num_bde = (uint32_t)rxbuffer->flag; 29163b5dd52aSJames Smart dmp = &rxbuffer->dma; 29173b5dd52aSJames Smart cmd = &cmdiocbq->iocb; 29183b5dd52aSJames Smart i = 0; 29193b5dd52aSJames Smart 29203b5dd52aSJames Smart INIT_LIST_HEAD(&head); 29213b5dd52aSJames Smart list_add_tail(&head, &dmp->list); 29223b5dd52aSJames Smart list_for_each_safe(curr, next, &head) { 29233b5dd52aSJames Smart mp[i] = list_entry(curr, struct lpfc_dmabuf, list); 29243b5dd52aSJames Smart list_del(curr); 29253b5dd52aSJames Smart 29263b5dd52aSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 29273b5dd52aSJames Smart mp[i]->buffer_tag = lpfc_sli_get_buffer_tag(phba); 29283b5dd52aSJames Smart cmd->un.quexri64cx.buff.bde.addrHigh = 29293b5dd52aSJames Smart putPaddrHigh(mp[i]->phys); 29303b5dd52aSJames Smart cmd->un.quexri64cx.buff.bde.addrLow = 29313b5dd52aSJames Smart putPaddrLow(mp[i]->phys); 29323b5dd52aSJames Smart cmd->un.quexri64cx.buff.bde.tus.f.bdeSize = 29333b5dd52aSJames Smart ((struct lpfc_dmabufext *)mp[i])->size; 29343b5dd52aSJames Smart cmd->un.quexri64cx.buff.buffer_tag = mp[i]->buffer_tag; 29353b5dd52aSJames Smart cmd->ulpCommand = CMD_QUE_XRI64_CX; 29363b5dd52aSJames Smart cmd->ulpPU = 0; 29373b5dd52aSJames Smart cmd->ulpLe = 1; 29383b5dd52aSJames Smart cmd->ulpBdeCount = 1; 29393b5dd52aSJames Smart cmd->unsli3.que_xri64cx_ext_words.ebde_count = 0; 29403b5dd52aSJames Smart 29413b5dd52aSJames Smart } else { 29423b5dd52aSJames Smart cmd->un.cont64[i].addrHigh = putPaddrHigh(mp[i]->phys); 29433b5dd52aSJames Smart cmd->un.cont64[i].addrLow = putPaddrLow(mp[i]->phys); 29443b5dd52aSJames Smart cmd->un.cont64[i].tus.f.bdeSize = 29453b5dd52aSJames Smart ((struct lpfc_dmabufext *)mp[i])->size; 29463b5dd52aSJames Smart cmd->ulpBdeCount = ++i; 29473b5dd52aSJames Smart 29483b5dd52aSJames Smart if ((--num_bde > 0) && (i < 2)) 29493b5dd52aSJames Smart continue; 29503b5dd52aSJames Smart 29513b5dd52aSJames Smart cmd->ulpCommand = CMD_QUE_XRI_BUF64_CX; 29523b5dd52aSJames Smart cmd->ulpLe = 1; 29533b5dd52aSJames Smart } 29543b5dd52aSJames Smart 29553b5dd52aSJames Smart cmd->ulpClass = CLASS3; 29563b5dd52aSJames Smart cmd->ulpContext = rxxri; 29573b5dd52aSJames Smart 2958d439d286SJames Smart iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 2959d439d286SJames Smart 0); 2960d439d286SJames Smart if (iocb_stat == IOCB_ERROR) { 29613b5dd52aSJames Smart diag_cmd_data_free(phba, 29623b5dd52aSJames Smart (struct lpfc_dmabufext *)mp[0]); 29633b5dd52aSJames Smart if (mp[1]) 29643b5dd52aSJames Smart diag_cmd_data_free(phba, 29653b5dd52aSJames Smart (struct lpfc_dmabufext *)mp[1]); 29663b5dd52aSJames Smart dmp = list_entry(next, struct lpfc_dmabuf, list); 2967d439d286SJames Smart ret_val = -EIO; 29683b5dd52aSJames Smart goto err_post_rxbufs_exit; 29693b5dd52aSJames Smart } 29703b5dd52aSJames Smart 29713b5dd52aSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, mp[0]); 29723b5dd52aSJames Smart if (mp[1]) { 29733b5dd52aSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, mp[1]); 29743b5dd52aSJames Smart mp[1] = NULL; 29753b5dd52aSJames Smart } 29763b5dd52aSJames Smart 29773b5dd52aSJames Smart /* The iocb was freed by lpfc_sli_issue_iocb */ 29783b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 29793b5dd52aSJames Smart if (!cmdiocbq) { 29803b5dd52aSJames Smart dmp = list_entry(next, struct lpfc_dmabuf, list); 2981d439d286SJames Smart ret_val = -EIO; 29823b5dd52aSJames Smart goto err_post_rxbufs_exit; 29833b5dd52aSJames Smart } 29843b5dd52aSJames Smart cmd = &cmdiocbq->iocb; 29853b5dd52aSJames Smart i = 0; 29863b5dd52aSJames Smart } 29873b5dd52aSJames Smart list_del(&head); 29883b5dd52aSJames Smart 29893b5dd52aSJames Smart err_post_rxbufs_exit: 29903b5dd52aSJames Smart 29913b5dd52aSJames Smart if (rxbmp) { 29923b5dd52aSJames Smart if (rxbmp->virt) 29933b5dd52aSJames Smart lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys); 29943b5dd52aSJames Smart kfree(rxbmp); 29953b5dd52aSJames Smart } 29963b5dd52aSJames Smart 29973b5dd52aSJames Smart if (cmdiocbq) 29983b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 29993b5dd52aSJames Smart return ret_val; 30003b5dd52aSJames Smart } 30013b5dd52aSJames Smart 30023b5dd52aSJames Smart /** 30037ad20aa9SJames Smart * lpfc_bsg_diag_loopback_run - run loopback on a port by issue ct cmd to itself 30043b5dd52aSJames Smart * @job: LPFC_BSG_VENDOR_DIAG_TEST fc_bsg_job 30053b5dd52aSJames Smart * 30063b5dd52aSJames Smart * This function receives a user data buffer to be transmitted and received on 30073b5dd52aSJames Smart * the same port, the link must be up and in loopback mode prior 30083b5dd52aSJames Smart * to being called. 30093b5dd52aSJames Smart * 1. A kernel buffer is allocated to copy the user data into. 30103b5dd52aSJames Smart * 2. The port registers with "itself". 30113b5dd52aSJames Smart * 3. The transmit and receive exchange ids are obtained. 30123b5dd52aSJames Smart * 4. The receive exchange id is posted. 30133b5dd52aSJames Smart * 5. A new els loopback event is created. 30143b5dd52aSJames Smart * 6. The command and response iocbs are allocated. 30153b5dd52aSJames Smart * 7. The cmd iocb FsType is set to elx loopback and the CmdRsp to looppback. 30163b5dd52aSJames Smart * 30173b5dd52aSJames Smart * This function is meant to be called n times while the port is in loopback 30183b5dd52aSJames Smart * so it is the apps responsibility to issue a reset to take the port out 30193b5dd52aSJames Smart * of loopback mode. 30203b5dd52aSJames Smart **/ 30213b5dd52aSJames Smart static int 302275cc8cfcSJohannes Thumshirn lpfc_bsg_diag_loopback_run(struct bsg_job *job) 30233b5dd52aSJames Smart { 3024cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 302501e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 30263b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 30273b5dd52aSJames Smart struct lpfc_bsg_event *evt; 30283b5dd52aSJames Smart struct event_data *evdat; 30293b5dd52aSJames Smart struct lpfc_sli *psli = &phba->sli; 30303b5dd52aSJames Smart uint32_t size; 30313b5dd52aSJames Smart uint32_t full_size; 30323b5dd52aSJames Smart size_t segment_len = 0, segment_offset = 0, current_offset = 0; 30334042629eSJames Smart uint16_t rpi = 0; 30341b51197dSJames Smart struct lpfc_iocbq *cmdiocbq, *rspiocbq = NULL; 303561910d6aSJames Smart union lpfc_wqe128 *cmdwqe, *rspwqe; 30363b5dd52aSJames Smart struct lpfc_sli_ct_request *ctreq; 30373b5dd52aSJames Smart struct lpfc_dmabuf *txbmp; 30383b5dd52aSJames Smart struct ulp_bde64 *txbpl = NULL; 30393b5dd52aSJames Smart struct lpfc_dmabufext *txbuffer = NULL; 30403b5dd52aSJames Smart struct list_head head; 30413b5dd52aSJames Smart struct lpfc_dmabuf *curr; 30421b51197dSJames Smart uint16_t txxri = 0, rxxri; 30433b5dd52aSJames Smart uint32_t num_bde; 30443b5dd52aSJames Smart uint8_t *ptr = NULL, *rx_databuf = NULL; 30453b5dd52aSJames Smart int rc = 0; 3046d439d286SJames Smart int time_left; 30475a0916b4SJames Smart int iocb_stat = IOCB_SUCCESS; 30483b5dd52aSJames Smart unsigned long flags; 30493b5dd52aSJames Smart void *dataout = NULL; 30503b5dd52aSJames Smart uint32_t total_mem; 30513b5dd52aSJames Smart 30523b5dd52aSJames Smart /* in case no data is returned return just the return code */ 305301e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 30543b5dd52aSJames Smart 30553b5dd52aSJames Smart if (job->request_len < 30563b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_test)) { 30573b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 30583b5dd52aSJames Smart "2739 Received DIAG TEST request below minimum " 30593b5dd52aSJames Smart "size\n"); 30603b5dd52aSJames Smart rc = -EINVAL; 30613b5dd52aSJames Smart goto loopback_test_exit; 30623b5dd52aSJames Smart } 30633b5dd52aSJames Smart 30643b5dd52aSJames Smart if (job->request_payload.payload_len != 30653b5dd52aSJames Smart job->reply_payload.payload_len) { 30663b5dd52aSJames Smart rc = -EINVAL; 30673b5dd52aSJames Smart goto loopback_test_exit; 30683b5dd52aSJames Smart } 30693b5dd52aSJames Smart 30703b5dd52aSJames Smart if ((phba->link_state == LPFC_HBA_ERROR) || 30713b5dd52aSJames Smart (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || 30723b5dd52aSJames Smart (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { 30733b5dd52aSJames Smart rc = -EACCES; 30743b5dd52aSJames Smart goto loopback_test_exit; 30753b5dd52aSJames Smart } 30763b5dd52aSJames Smart 30773b5dd52aSJames Smart if (!lpfc_is_link_up(phba) || !(phba->link_flag & LS_LOOPBACK_MODE)) { 30783b5dd52aSJames Smart rc = -EACCES; 30793b5dd52aSJames Smart goto loopback_test_exit; 30803b5dd52aSJames Smart } 30813b5dd52aSJames Smart 30823b5dd52aSJames Smart size = job->request_payload.payload_len; 30833b5dd52aSJames Smart full_size = size + ELX_LOOPBACK_HEADER_SZ; /* plus the header */ 30843b5dd52aSJames Smart 30853b5dd52aSJames Smart if ((size == 0) || (size > 80 * BUF_SZ_4K)) { 30863b5dd52aSJames Smart rc = -ERANGE; 30873b5dd52aSJames Smart goto loopback_test_exit; 30883b5dd52aSJames Smart } 30893b5dd52aSJames Smart 309063e801ceSJames Smart if (full_size >= BUF_SZ_4K) { 30913b5dd52aSJames Smart /* 30923b5dd52aSJames Smart * Allocate memory for ioctl data. If buffer is bigger than 64k, 30933b5dd52aSJames Smart * then we allocate 64k and re-use that buffer over and over to 30943b5dd52aSJames Smart * xfer the whole block. This is because Linux kernel has a 30953b5dd52aSJames Smart * problem allocating more than 120k of kernel space memory. Saw 30963b5dd52aSJames Smart * problem with GET_FCPTARGETMAPPING... 30973b5dd52aSJames Smart */ 30983b5dd52aSJames Smart if (size <= (64 * 1024)) 309963e801ceSJames Smart total_mem = full_size; 31003b5dd52aSJames Smart else 31013b5dd52aSJames Smart total_mem = 64 * 1024; 31023b5dd52aSJames Smart } else 31033b5dd52aSJames Smart /* Allocate memory for ioctl data */ 31043b5dd52aSJames Smart total_mem = BUF_SZ_4K; 31053b5dd52aSJames Smart 31063b5dd52aSJames Smart dataout = kmalloc(total_mem, GFP_KERNEL); 31073b5dd52aSJames Smart if (dataout == NULL) { 31083b5dd52aSJames Smart rc = -ENOMEM; 31093b5dd52aSJames Smart goto loopback_test_exit; 31103b5dd52aSJames Smart } 31113b5dd52aSJames Smart 31123b5dd52aSJames Smart ptr = dataout; 31133b5dd52aSJames Smart ptr += ELX_LOOPBACK_HEADER_SZ; 31143b5dd52aSJames Smart sg_copy_to_buffer(job->request_payload.sg_list, 31153b5dd52aSJames Smart job->request_payload.sg_cnt, 31163b5dd52aSJames Smart ptr, size); 31173b5dd52aSJames Smart rc = lpfcdiag_loop_self_reg(phba, &rpi); 3118d439d286SJames Smart if (rc) 31193b5dd52aSJames Smart goto loopback_test_exit; 31203b5dd52aSJames Smart 31211b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) { 31223b5dd52aSJames Smart rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri); 31233b5dd52aSJames Smart if (rc) { 31243b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 31253b5dd52aSJames Smart goto loopback_test_exit; 31263b5dd52aSJames Smart } 31273b5dd52aSJames Smart 312861910d6aSJames Smart rc = lpfcdiag_sli3_loop_post_rxbufs(phba, rxxri, full_size); 31293b5dd52aSJames Smart if (rc) { 31303b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 31313b5dd52aSJames Smart goto loopback_test_exit; 31323b5dd52aSJames Smart } 31331b51197dSJames Smart } 31343b5dd52aSJames Smart evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, 31353b5dd52aSJames Smart SLI_CT_ELX_LOOPBACK); 31363b5dd52aSJames Smart if (!evt) { 31373b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 31383b5dd52aSJames Smart rc = -ENOMEM; 31393b5dd52aSJames Smart goto loopback_test_exit; 31403b5dd52aSJames Smart } 31413b5dd52aSJames Smart 31423b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 31433b5dd52aSJames Smart list_add(&evt->node, &phba->ct_ev_waiters); 31443b5dd52aSJames Smart lpfc_bsg_event_ref(evt); 31453b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 31463b5dd52aSJames Smart 31473b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 31481b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 31493b5dd52aSJames Smart rspiocbq = lpfc_sli_get_iocbq(phba); 31503b5dd52aSJames Smart txbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 31513b5dd52aSJames Smart 31523b5dd52aSJames Smart if (txbmp) { 31533b5dd52aSJames Smart txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys); 3154c7495937SJames Smart if (txbmp->virt) { 31553b5dd52aSJames Smart INIT_LIST_HEAD(&txbmp->list); 31563b5dd52aSJames Smart txbpl = (struct ulp_bde64 *) txbmp->virt; 31573b5dd52aSJames Smart txbuffer = diag_cmd_data_alloc(phba, 31583b5dd52aSJames Smart txbpl, full_size, 0); 31593b5dd52aSJames Smart } 3160c7495937SJames Smart } 31613b5dd52aSJames Smart 31621b51197dSJames Smart if (!cmdiocbq || !txbmp || !txbpl || !txbuffer || !txbmp->virt) { 31631b51197dSJames Smart rc = -ENOMEM; 31641b51197dSJames Smart goto err_loopback_test_exit; 31651b51197dSJames Smart } 31661b51197dSJames Smart if ((phba->sli_rev < LPFC_SLI_REV4) && !rspiocbq) { 31673b5dd52aSJames Smart rc = -ENOMEM; 31683b5dd52aSJames Smart goto err_loopback_test_exit; 31693b5dd52aSJames Smart } 31703b5dd52aSJames Smart 317161910d6aSJames Smart cmdwqe = &cmdiocbq->wqe; 317216cc2ba7SMuhammad Usama Anjum memset(cmdwqe, 0, sizeof(*cmdwqe)); 317361910d6aSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) { 317461910d6aSJames Smart rspwqe = &rspiocbq->wqe; 317516cc2ba7SMuhammad Usama Anjum memset(rspwqe, 0, sizeof(*rspwqe)); 317661910d6aSJames Smart } 31773b5dd52aSJames Smart 31783b5dd52aSJames Smart INIT_LIST_HEAD(&head); 31793b5dd52aSJames Smart list_add_tail(&head, &txbuffer->dma.list); 31803b5dd52aSJames Smart list_for_each_entry(curr, &head, list) { 31813b5dd52aSJames Smart segment_len = ((struct lpfc_dmabufext *)curr)->size; 31823b5dd52aSJames Smart if (current_offset == 0) { 31833b5dd52aSJames Smart ctreq = curr->virt; 31843b5dd52aSJames Smart memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); 31853b5dd52aSJames Smart ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; 31863b5dd52aSJames Smart ctreq->RevisionId.bits.InId = 0; 31873b5dd52aSJames Smart ctreq->FsType = SLI_CT_ELX_LOOPBACK; 31883b5dd52aSJames Smart ctreq->FsSubType = 0; 31899cefd6e7SJustin Tee ctreq->CommandResponse.bits.CmdRsp = cpu_to_be16(ELX_LOOPBACK_DATA); 31909cefd6e7SJustin Tee ctreq->CommandResponse.bits.Size = cpu_to_be16(size); 31913b5dd52aSJames Smart segment_offset = ELX_LOOPBACK_HEADER_SZ; 31923b5dd52aSJames Smart } else 31933b5dd52aSJames Smart segment_offset = 0; 31943b5dd52aSJames Smart 31953b5dd52aSJames Smart BUG_ON(segment_offset >= segment_len); 31963b5dd52aSJames Smart memcpy(curr->virt + segment_offset, 31973b5dd52aSJames Smart ptr + current_offset, 31983b5dd52aSJames Smart segment_len - segment_offset); 31993b5dd52aSJames Smart 32003b5dd52aSJames Smart current_offset += segment_len - segment_offset; 32013b5dd52aSJames Smart BUG_ON(current_offset > size); 32023b5dd52aSJames Smart } 32033b5dd52aSJames Smart list_del(&head); 32043b5dd52aSJames Smart 32053b5dd52aSJames Smart /* Build the XMIT_SEQUENCE iocb */ 32063b5dd52aSJames Smart num_bde = (uint32_t)txbuffer->flag; 32073b5dd52aSJames Smart 320861910d6aSJames Smart cmdiocbq->num_bdes = num_bde; 3209a680a929SJames Smart cmdiocbq->cmd_flag |= LPFC_IO_LIBDFC; 3210a680a929SJames Smart cmdiocbq->cmd_flag |= LPFC_IO_LOOPBACK; 32113b5dd52aSJames Smart cmdiocbq->vport = phba->pport; 3212a680a929SJames Smart cmdiocbq->cmd_cmpl = NULL; 3213d51cf5bdSJames Smart cmdiocbq->bpl_dmabuf = txbmp; 321461910d6aSJames Smart 321561910d6aSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) { 321661910d6aSJames Smart lpfc_sli_prep_xmit_seq64(phba, cmdiocbq, txbmp, 0, txxri, 321761910d6aSJames Smart num_bde, FC_RCTL_DD_UNSOL_CTL, 1, 321861910d6aSJames Smart CMD_XMIT_SEQUENCE64_CX); 321961910d6aSJames Smart 322061910d6aSJames Smart } else { 322161910d6aSJames Smart lpfc_sli_prep_xmit_seq64(phba, cmdiocbq, txbmp, 322261910d6aSJames Smart phba->sli4_hba.rpi_ids[rpi], 0xffff, 322361910d6aSJames Smart full_size, FC_RCTL_DD_UNSOL_CTL, 1, 322461910d6aSJames Smart CMD_XMIT_SEQUENCE64_WQE); 322561910d6aSJames Smart cmdiocbq->sli4_xritag = NO_XRI; 322661910d6aSJames Smart } 322756134142SJames Smart 3228d439d286SJames Smart iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, 3229d439d286SJames Smart rspiocbq, (phba->fc_ratov * 2) + 3230d439d286SJames Smart LPFC_DRVR_TIMEOUT); 323161910d6aSJames Smart if (iocb_stat != IOCB_SUCCESS || 323261910d6aSJames Smart (phba->sli_rev < LPFC_SLI_REV4 && 323361910d6aSJames Smart (get_job_ulpstatus(phba, rspiocbq) != IOSTAT_SUCCESS))) { 32341b51197dSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 32351b51197dSJames Smart "3126 Failed loopback test issue iocb: " 32361b51197dSJames Smart "iocb_stat:x%x\n", iocb_stat); 32373b5dd52aSJames Smart rc = -EIO; 32383b5dd52aSJames Smart goto err_loopback_test_exit; 32393b5dd52aSJames Smart } 32403b5dd52aSJames Smart 32413b5dd52aSJames Smart evt->waiting = 1; 3242d439d286SJames Smart time_left = wait_event_interruptible_timeout( 32433b5dd52aSJames Smart evt->wq, !list_empty(&evt->events_to_see), 3244256ec0d0SJames Smart msecs_to_jiffies(1000 * 3245256ec0d0SJames Smart ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT))); 32463b5dd52aSJames Smart evt->waiting = 0; 32471b51197dSJames Smart if (list_empty(&evt->events_to_see)) { 3248d439d286SJames Smart rc = (time_left) ? -EINTR : -ETIMEDOUT; 32491b51197dSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 32501b51197dSJames Smart "3125 Not receiving unsolicited event, " 32511b51197dSJames Smart "rc:x%x\n", rc); 32521b51197dSJames Smart } else { 32533b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 32543b5dd52aSJames Smart list_move(evt->events_to_see.prev, &evt->events_to_get); 32553b5dd52aSJames Smart evdat = list_entry(evt->events_to_get.prev, 32563b5dd52aSJames Smart typeof(*evdat), node); 32573b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 32583b5dd52aSJames Smart rx_databuf = evdat->data; 32593b5dd52aSJames Smart if (evdat->len != full_size) { 32603b5dd52aSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 32613b5dd52aSJames Smart "1603 Loopback test did not receive expected " 32623b5dd52aSJames Smart "data length. actual length 0x%x expected " 32633b5dd52aSJames Smart "length 0x%x\n", 32643b5dd52aSJames Smart evdat->len, full_size); 32653b5dd52aSJames Smart rc = -EIO; 32663b5dd52aSJames Smart } else if (rx_databuf == NULL) 32673b5dd52aSJames Smart rc = -EIO; 32683b5dd52aSJames Smart else { 32693b5dd52aSJames Smart rc = IOCB_SUCCESS; 32703b5dd52aSJames Smart /* skip over elx loopback header */ 32713b5dd52aSJames Smart rx_databuf += ELX_LOOPBACK_HEADER_SZ; 327201e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 32733b5dd52aSJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 32743b5dd52aSJames Smart job->reply_payload.sg_cnt, 32753b5dd52aSJames Smart rx_databuf, size); 327601e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = size; 32773b5dd52aSJames Smart } 32783b5dd52aSJames Smart } 32793b5dd52aSJames Smart 32803b5dd52aSJames Smart err_loopback_test_exit: 32813b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 32823b5dd52aSJames Smart 32833b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 32843b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* release ref */ 32853b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* delete */ 32863b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 32873b5dd52aSJames Smart 32885a0916b4SJames Smart if ((cmdiocbq != NULL) && (iocb_stat != IOCB_TIMEDOUT)) 32893b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 32903b5dd52aSJames Smart 32913b5dd52aSJames Smart if (rspiocbq != NULL) 32923b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, rspiocbq); 32933b5dd52aSJames Smart 32943b5dd52aSJames Smart if (txbmp != NULL) { 32953b5dd52aSJames Smart if (txbpl != NULL) { 32963b5dd52aSJames Smart if (txbuffer != NULL) 32973b5dd52aSJames Smart diag_cmd_data_free(phba, txbuffer); 32983b5dd52aSJames Smart lpfc_mbuf_free(phba, txbmp->virt, txbmp->phys); 32993b5dd52aSJames Smart } 33003b5dd52aSJames Smart kfree(txbmp); 33013b5dd52aSJames Smart } 33023b5dd52aSJames Smart 33033b5dd52aSJames Smart loopback_test_exit: 33043b5dd52aSJames Smart kfree(dataout); 33053b5dd52aSJames Smart /* make error code available to userspace */ 330601e0e15cSJohannes Thumshirn bsg_reply->result = rc; 33073b5dd52aSJames Smart job->dd_data = NULL; 33083b5dd52aSJames Smart /* complete the job back to userspace if no error */ 33091b51197dSJames Smart if (rc == IOCB_SUCCESS) 331006548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 33111abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 33123b5dd52aSJames Smart return rc; 33133b5dd52aSJames Smart } 33143b5dd52aSJames Smart 33153b5dd52aSJames Smart /** 33163b5dd52aSJames Smart * lpfc_bsg_get_dfc_rev - process a GET_DFC_REV bsg vendor command 33173b5dd52aSJames Smart * @job: GET_DFC_REV fc_bsg_job 33183b5dd52aSJames Smart **/ 33193b5dd52aSJames Smart static int 332075cc8cfcSJohannes Thumshirn lpfc_bsg_get_dfc_rev(struct bsg_job *job) 33213b5dd52aSJames Smart { 3322cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 332301e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 33243b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 33253b5dd52aSJames Smart struct get_mgmt_rev_reply *event_reply; 33263b5dd52aSJames Smart int rc = 0; 33273b5dd52aSJames Smart 33283b5dd52aSJames Smart if (job->request_len < 33293b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev)) { 33303b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 33313b5dd52aSJames Smart "2740 Received GET_DFC_REV request below " 33323b5dd52aSJames Smart "minimum size\n"); 33333b5dd52aSJames Smart rc = -EINVAL; 33343b5dd52aSJames Smart goto job_error; 33353b5dd52aSJames Smart } 33363b5dd52aSJames Smart 33373b5dd52aSJames Smart event_reply = (struct get_mgmt_rev_reply *) 333801e0e15cSJohannes Thumshirn bsg_reply->reply_data.vendor_reply.vendor_rsp; 33393b5dd52aSJames Smart 3340feb3cc57SDick Kennedy if (job->reply_len < sizeof(*bsg_reply) + sizeof(*event_reply)) { 33413b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 33423b5dd52aSJames Smart "2741 Received GET_DFC_REV reply below " 33433b5dd52aSJames Smart "minimum size\n"); 33443b5dd52aSJames Smart rc = -EINVAL; 33453b5dd52aSJames Smart goto job_error; 33463b5dd52aSJames Smart } 33473b5dd52aSJames Smart 33483b5dd52aSJames Smart event_reply->info.a_Major = MANAGEMENT_MAJOR_REV; 33493b5dd52aSJames Smart event_reply->info.a_Minor = MANAGEMENT_MINOR_REV; 33503b5dd52aSJames Smart job_error: 335101e0e15cSJohannes Thumshirn bsg_reply->result = rc; 33523b5dd52aSJames Smart if (rc == 0) 335306548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 33541abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 33553b5dd52aSJames Smart return rc; 33563b5dd52aSJames Smart } 33573b5dd52aSJames Smart 33583b5dd52aSJames Smart /** 33597ad20aa9SJames Smart * lpfc_bsg_issue_mbox_cmpl - lpfc_bsg_issue_mbox mbox completion handler 33603b5dd52aSJames Smart * @phba: Pointer to HBA context object. 33613b5dd52aSJames Smart * @pmboxq: Pointer to mailbox command. 33623b5dd52aSJames Smart * 33633b5dd52aSJames Smart * This is completion handler function for mailbox commands issued from 33643b5dd52aSJames Smart * lpfc_bsg_issue_mbox function. This function is called by the 33653b5dd52aSJames Smart * mailbox event handler function with no lock held. This function 3366d51cf5bdSJames Smart * will wake up thread waiting on the wait queue pointed by dd_data 33673b5dd52aSJames Smart * of the mailbox. 33683b5dd52aSJames Smart **/ 33699ab9b134SRashika Kheria static void 33707ad20aa9SJames Smart lpfc_bsg_issue_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) 33713b5dd52aSJames Smart { 33723b5dd52aSJames Smart struct bsg_job_data *dd_data; 337301e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 337475cc8cfcSJohannes Thumshirn struct bsg_job *job; 33753b5dd52aSJames Smart uint32_t size; 33763b5dd52aSJames Smart unsigned long flags; 33777ad20aa9SJames Smart uint8_t *pmb, *pmb_buf; 33783b5dd52aSJames Smart 337985d77f91SJustin Tee dd_data = pmboxq->ctx_u.dd_data; 33803b5dd52aSJames Smart 33817ad20aa9SJames Smart /* 33827ad20aa9SJames Smart * The outgoing buffer is readily referred from the dma buffer, 33837ad20aa9SJames Smart * just need to get header part from mailboxq structure. 33847a470277SJames Smart */ 33857ad20aa9SJames Smart pmb = (uint8_t *)&pmboxq->u.mb; 33867ad20aa9SJames Smart pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb; 33877ad20aa9SJames Smart memcpy(pmb_buf, pmb, sizeof(MAILBOX_t)); 3388515e0aa2SJames Smart 3389a33c4f7bSJames Smart /* Determine if job has been aborted */ 3390a33c4f7bSJames Smart 3391a33c4f7bSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 3392a33c4f7bSJames Smart job = dd_data->set_job; 3393a33c4f7bSJames Smart if (job) { 3394a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 3395a33c4f7bSJames Smart job->dd_data = NULL; 3396a33c4f7bSJames Smart } 3397a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 3398a33c4f7bSJames Smart 3399a33c4f7bSJames Smart /* Copy the mailbox data to the job if it is still active */ 3400a33c4f7bSJames Smart 34015a6f133eSJames Smart if (job) { 340201e0e15cSJohannes Thumshirn bsg_reply = job->reply; 34037a470277SJames Smart size = job->reply_payload.payload_len; 340401e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 34053b5dd52aSJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 34063b5dd52aSJames Smart job->reply_payload.sg_cnt, 34077ad20aa9SJames Smart pmb_buf, size); 3408b6e3b9c6SJames Smart } 34097a470277SJames Smart 3410a33c4f7bSJames Smart dd_data->set_job = NULL; 34113b5dd52aSJames Smart mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool); 34127ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dd_data->context_un.mbox.dmabuffers); 34133b5dd52aSJames Smart kfree(dd_data); 34147ad20aa9SJames Smart 3415a33c4f7bSJames Smart /* Complete the job if the job is still active */ 3416a33c4f7bSJames Smart 34177ad20aa9SJames Smart if (job) { 341801e0e15cSJohannes Thumshirn bsg_reply->result = 0; 341906548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 34201abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 34217ad20aa9SJames Smart } 34223b5dd52aSJames Smart return; 34233b5dd52aSJames Smart } 34243b5dd52aSJames Smart 34253b5dd52aSJames Smart /** 34263b5dd52aSJames Smart * lpfc_bsg_check_cmd_access - test for a supported mailbox command 34273b5dd52aSJames Smart * @phba: Pointer to HBA context object. 34283b5dd52aSJames Smart * @mb: Pointer to a mailbox object. 34293b5dd52aSJames Smart * @vport: Pointer to a vport object. 34303b5dd52aSJames Smart * 34313b5dd52aSJames Smart * Some commands require the port to be offline, some may not be called from 34323b5dd52aSJames Smart * the application. 34333b5dd52aSJames Smart **/ 34343b5dd52aSJames Smart static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, 34353b5dd52aSJames Smart MAILBOX_t *mb, struct lpfc_vport *vport) 34363b5dd52aSJames Smart { 34373b5dd52aSJames Smart /* return negative error values for bsg job */ 34383b5dd52aSJames Smart switch (mb->mbxCommand) { 34393b5dd52aSJames Smart /* Offline only */ 34403b5dd52aSJames Smart case MBX_INIT_LINK: 34413b5dd52aSJames Smart case MBX_DOWN_LINK: 34423b5dd52aSJames Smart case MBX_CONFIG_LINK: 34433b5dd52aSJames Smart case MBX_CONFIG_RING: 34443b5dd52aSJames Smart case MBX_RESET_RING: 34453b5dd52aSJames Smart case MBX_UNREG_LOGIN: 34463b5dd52aSJames Smart case MBX_CLEAR_LA: 34473b5dd52aSJames Smart case MBX_DUMP_CONTEXT: 34483b5dd52aSJames Smart case MBX_RUN_DIAGS: 34493b5dd52aSJames Smart case MBX_RESTART: 34503b5dd52aSJames Smart case MBX_SET_MASK: 3451a645b8c1SJustin Tee if (!test_bit(FC_OFFLINE_MODE, &vport->fc_flag)) { 34523b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 34533b5dd52aSJames Smart "2743 Command 0x%x is illegal in on-line " 34543b5dd52aSJames Smart "state\n", 34553b5dd52aSJames Smart mb->mbxCommand); 34563b5dd52aSJames Smart return -EPERM; 34573b5dd52aSJames Smart } 3458e9a7c711SGustavo A. R. Silva break; 34593b5dd52aSJames Smart case MBX_WRITE_NV: 34603b5dd52aSJames Smart case MBX_WRITE_VPARMS: 34613b5dd52aSJames Smart case MBX_LOAD_SM: 34623b5dd52aSJames Smart case MBX_READ_NV: 34633b5dd52aSJames Smart case MBX_READ_CONFIG: 34643b5dd52aSJames Smart case MBX_READ_RCONFIG: 34653b5dd52aSJames Smart case MBX_READ_STATUS: 34663b5dd52aSJames Smart case MBX_READ_XRI: 34673b5dd52aSJames Smart case MBX_READ_REV: 34683b5dd52aSJames Smart case MBX_READ_LNK_STAT: 34693b5dd52aSJames Smart case MBX_DUMP_MEMORY: 34703b5dd52aSJames Smart case MBX_DOWN_LOAD: 34713b5dd52aSJames Smart case MBX_UPDATE_CFG: 34723b5dd52aSJames Smart case MBX_KILL_BOARD: 347306f35551SJames Smart case MBX_READ_TOPOLOGY: 34743b5dd52aSJames Smart case MBX_LOAD_AREA: 34753b5dd52aSJames Smart case MBX_LOAD_EXP_ROM: 34763b5dd52aSJames Smart case MBX_BEACON: 34773b5dd52aSJames Smart case MBX_DEL_LD_ENTRY: 34783b5dd52aSJames Smart case MBX_SET_DEBUG: 34793b5dd52aSJames Smart case MBX_WRITE_WWN: 34803b5dd52aSJames Smart case MBX_SLI4_CONFIG: 3481c7495937SJames Smart case MBX_READ_EVENT_LOG: 34823b5dd52aSJames Smart case MBX_READ_EVENT_LOG_STATUS: 34833b5dd52aSJames Smart case MBX_WRITE_EVENT_LOG: 34843b5dd52aSJames Smart case MBX_PORT_CAPABILITIES: 34853b5dd52aSJames Smart case MBX_PORT_IOV_CONTROL: 34867a470277SJames Smart case MBX_RUN_BIU_DIAG64: 34873b5dd52aSJames Smart break; 34883b5dd52aSJames Smart case MBX_SET_VARIABLE: 3489e2aed29fSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_INIT, 3490e2aed29fSJames Smart "1226 mbox: set_variable 0x%x, 0x%x\n", 3491e2aed29fSJames Smart mb->un.varWords[0], 3492e2aed29fSJames Smart mb->un.varWords[1]); 3493e2aed29fSJames Smart break; 34943b5dd52aSJames Smart case MBX_READ_SPARM64: 34953b5dd52aSJames Smart case MBX_REG_LOGIN: 34963b5dd52aSJames Smart case MBX_REG_LOGIN64: 34973b5dd52aSJames Smart case MBX_CONFIG_PORT: 34983b5dd52aSJames Smart case MBX_RUN_BIU_DIAG: 34993b5dd52aSJames Smart default: 35003b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 35013b5dd52aSJames Smart "2742 Unknown Command 0x%x\n", 35023b5dd52aSJames Smart mb->mbxCommand); 35033b5dd52aSJames Smart return -EPERM; 35043b5dd52aSJames Smart } 35053b5dd52aSJames Smart 35063b5dd52aSJames Smart return 0; /* ok */ 35073b5dd52aSJames Smart } 35083b5dd52aSJames Smart 35093b5dd52aSJames Smart /** 35103145d2d6SLee Jones * lpfc_bsg_mbox_ext_session_reset - clean up context of multi-buffer mbox session 35117ad20aa9SJames Smart * @phba: Pointer to HBA context object. 35127ad20aa9SJames Smart * 35137ad20aa9SJames Smart * This is routine clean up and reset BSG handling of multi-buffer mbox 35147ad20aa9SJames Smart * command session. 35157ad20aa9SJames Smart **/ 35167ad20aa9SJames Smart static void 35177ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(struct lpfc_hba *phba) 35187ad20aa9SJames Smart { 35197ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_IDLE) 35207ad20aa9SJames Smart return; 35217ad20aa9SJames Smart 35227ad20aa9SJames Smart /* free all memory, including dma buffers */ 35237ad20aa9SJames Smart lpfc_bsg_dma_page_list_free(phba, 35247ad20aa9SJames Smart &phba->mbox_ext_buf_ctx.ext_dmabuf_list); 35257ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, phba->mbox_ext_buf_ctx.mbx_dmabuf); 35267ad20aa9SJames Smart /* multi-buffer write mailbox command pass-through complete */ 35277ad20aa9SJames Smart memset((char *)&phba->mbox_ext_buf_ctx, 0, 35287ad20aa9SJames Smart sizeof(struct lpfc_mbox_ext_buf_ctx)); 35297ad20aa9SJames Smart INIT_LIST_HEAD(&phba->mbox_ext_buf_ctx.ext_dmabuf_list); 35307ad20aa9SJames Smart 35317ad20aa9SJames Smart return; 35327ad20aa9SJames Smart } 35337ad20aa9SJames Smart 35347ad20aa9SJames Smart /** 35357ad20aa9SJames Smart * lpfc_bsg_issue_mbox_ext_handle_job - job handler for multi-buffer mbox cmpl 35367ad20aa9SJames Smart * @phba: Pointer to HBA context object. 35377ad20aa9SJames Smart * @pmboxq: Pointer to mailbox command. 35387ad20aa9SJames Smart * 35397ad20aa9SJames Smart * This is routine handles BSG job for mailbox commands completions with 35407ad20aa9SJames Smart * multiple external buffers. 35417ad20aa9SJames Smart **/ 354275cc8cfcSJohannes Thumshirn static struct bsg_job * 35437ad20aa9SJames Smart lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) 35447ad20aa9SJames Smart { 35457ad20aa9SJames Smart struct bsg_job_data *dd_data; 354675cc8cfcSJohannes Thumshirn struct bsg_job *job; 354701e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 35487ad20aa9SJames Smart uint8_t *pmb, *pmb_buf; 35497ad20aa9SJames Smart unsigned long flags; 35507ad20aa9SJames Smart uint32_t size; 35517ad20aa9SJames Smart int rc = 0; 3552026abb87SJames Smart struct lpfc_dmabuf *dmabuf; 3553026abb87SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 3554026abb87SJames Smart uint8_t *pmbx; 35557ad20aa9SJames Smart 355685d77f91SJustin Tee dd_data = pmboxq->ctx_u.dd_data; 3557a33c4f7bSJames Smart 3558a33c4f7bSJames Smart /* Determine if job has been aborted */ 3559a33c4f7bSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 3560a33c4f7bSJames Smart job = dd_data->set_job; 3561a33c4f7bSJames Smart if (job) { 356201e0e15cSJohannes Thumshirn bsg_reply = job->reply; 3563a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 3564a33c4f7bSJames Smart job->dd_data = NULL; 35657ad20aa9SJames Smart } 3566a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 35677ad20aa9SJames Smart 35687ad20aa9SJames Smart /* 35697ad20aa9SJames Smart * The outgoing buffer is readily referred from the dma buffer, 35707ad20aa9SJames Smart * just need to get header part from mailboxq structure. 35717ad20aa9SJames Smart */ 3572a33c4f7bSJames Smart 35737ad20aa9SJames Smart pmb = (uint8_t *)&pmboxq->u.mb; 35747ad20aa9SJames Smart pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb; 3575026abb87SJames Smart /* Copy the byte swapped response mailbox back to the user */ 35767ad20aa9SJames Smart memcpy(pmb_buf, pmb, sizeof(MAILBOX_t)); 3577026abb87SJames Smart /* if there is any non-embedded extended data copy that too */ 3578026abb87SJames Smart dmabuf = phba->mbox_ext_buf_ctx.mbx_dmabuf; 3579026abb87SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; 3580026abb87SJames Smart if (!bsg_bf_get(lpfc_mbox_hdr_emb, 3581026abb87SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) { 3582026abb87SJames Smart pmbx = (uint8_t *)dmabuf->virt; 3583026abb87SJames Smart /* byte swap the extended data following the mailbox command */ 3584026abb87SJames Smart lpfc_sli_pcimem_bcopy(&pmbx[sizeof(MAILBOX_t)], 3585026abb87SJames Smart &pmbx[sizeof(MAILBOX_t)], 3586026abb87SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys.mse[0].buf_len); 3587026abb87SJames Smart } 35887ad20aa9SJames Smart 3589a33c4f7bSJames Smart /* Complete the job if the job is still active */ 3590a33c4f7bSJames Smart 35917ad20aa9SJames Smart if (job) { 35927ad20aa9SJames Smart size = job->reply_payload.payload_len; 359301e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 35947ad20aa9SJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 35957ad20aa9SJames Smart job->reply_payload.sg_cnt, 35967ad20aa9SJames Smart pmb_buf, size); 3597a33c4f7bSJames Smart 35987ad20aa9SJames Smart /* result for successful */ 359901e0e15cSJohannes Thumshirn bsg_reply->result = 0; 3600a33c4f7bSJames Smart 36017ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 36027afc0ce9SColin Ian King "2937 SLI_CONFIG ext-buffer mailbox command " 36037ad20aa9SJames Smart "(x%x/x%x) complete bsg job done, bsize:%d\n", 36047ad20aa9SJames Smart phba->mbox_ext_buf_ctx.nembType, 36057ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType, size); 3606b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, 3607b76f2dc9SJames Smart phba->mbox_ext_buf_ctx.nembType, 3608b76f2dc9SJames Smart phba->mbox_ext_buf_ctx.mboxType, 3609b76f2dc9SJames Smart dma_ebuf, sta_pos_addr, 3610b76f2dc9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf, 0); 3611a33c4f7bSJames Smart } else { 36127ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 36137afc0ce9SColin Ian King "2938 SLI_CONFIG ext-buffer mailbox " 36147ad20aa9SJames Smart "command (x%x/x%x) failure, rc:x%x\n", 36157ad20aa9SJames Smart phba->mbox_ext_buf_ctx.nembType, 36167ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType, rc); 3617a33c4f7bSJames Smart } 3618a33c4f7bSJames Smart 3619a33c4f7bSJames Smart 36207ad20aa9SJames Smart /* state change */ 36217ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_DONE; 36227ad20aa9SJames Smart kfree(dd_data); 36237ad20aa9SJames Smart return job; 36247ad20aa9SJames Smart } 36257ad20aa9SJames Smart 36267ad20aa9SJames Smart /** 36277ad20aa9SJames Smart * lpfc_bsg_issue_read_mbox_ext_cmpl - compl handler for multi-buffer read mbox 36287ad20aa9SJames Smart * @phba: Pointer to HBA context object. 36297ad20aa9SJames Smart * @pmboxq: Pointer to mailbox command. 36307ad20aa9SJames Smart * 36317ad20aa9SJames Smart * This is completion handler function for mailbox read commands with multiple 36327ad20aa9SJames Smart * external buffers. 36337ad20aa9SJames Smart **/ 36347ad20aa9SJames Smart static void 36357ad20aa9SJames Smart lpfc_bsg_issue_read_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) 36367ad20aa9SJames Smart { 363775cc8cfcSJohannes Thumshirn struct bsg_job *job; 36381abaede7SJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 36397ad20aa9SJames Smart 3640a33c4f7bSJames Smart job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq); 3641a33c4f7bSJames Smart 36427ad20aa9SJames Smart /* handle the BSG job with mailbox command */ 3643a33c4f7bSJames Smart if (!job) 36447ad20aa9SJames Smart pmboxq->u.mb.mbxStatus = MBXERR_ERROR; 36457ad20aa9SJames Smart 36467ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 36477afc0ce9SColin Ian King "2939 SLI_CONFIG ext-buffer rd mailbox command " 36487ad20aa9SJames Smart "complete, ctxState:x%x, mbxStatus:x%x\n", 36497ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus); 36507ad20aa9SJames Smart 36517ad20aa9SJames Smart if (pmboxq->u.mb.mbxStatus || phba->mbox_ext_buf_ctx.numBuf == 1) 36527ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 36537ad20aa9SJames Smart 36547ad20aa9SJames Smart /* free base driver mailbox structure memory */ 36557ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 36567ad20aa9SJames Smart 3657a33c4f7bSJames Smart /* if the job is still active, call job done */ 36581abaede7SJohannes Thumshirn if (job) { 36591abaede7SJohannes Thumshirn bsg_reply = job->reply; 366006548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 36611abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 36621abaede7SJohannes Thumshirn } 36637ad20aa9SJames Smart return; 36647ad20aa9SJames Smart } 36657ad20aa9SJames Smart 36667ad20aa9SJames Smart /** 36677ad20aa9SJames Smart * lpfc_bsg_issue_write_mbox_ext_cmpl - cmpl handler for multi-buffer write mbox 36687ad20aa9SJames Smart * @phba: Pointer to HBA context object. 36697ad20aa9SJames Smart * @pmboxq: Pointer to mailbox command. 36707ad20aa9SJames Smart * 36717ad20aa9SJames Smart * This is completion handler function for mailbox write commands with multiple 36727ad20aa9SJames Smart * external buffers. 36737ad20aa9SJames Smart **/ 36747ad20aa9SJames Smart static void 36757ad20aa9SJames Smart lpfc_bsg_issue_write_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) 36767ad20aa9SJames Smart { 367775cc8cfcSJohannes Thumshirn struct bsg_job *job; 36781abaede7SJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 36797ad20aa9SJames Smart 3680a33c4f7bSJames Smart job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq); 3681a33c4f7bSJames Smart 36827ad20aa9SJames Smart /* handle the BSG job with the mailbox command */ 3683a33c4f7bSJames Smart if (!job) 36847ad20aa9SJames Smart pmboxq->u.mb.mbxStatus = MBXERR_ERROR; 36857ad20aa9SJames Smart 36867ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 36877afc0ce9SColin Ian King "2940 SLI_CONFIG ext-buffer wr mailbox command " 36887ad20aa9SJames Smart "complete, ctxState:x%x, mbxStatus:x%x\n", 36897ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus); 36907ad20aa9SJames Smart 36917ad20aa9SJames Smart /* free all memory, including dma buffers */ 36927ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 36937ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 36947ad20aa9SJames Smart 3695a33c4f7bSJames Smart /* if the job is still active, call job done */ 36961abaede7SJohannes Thumshirn if (job) { 36971abaede7SJohannes Thumshirn bsg_reply = job->reply; 369806548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 36991abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 37001abaede7SJohannes Thumshirn } 37017ad20aa9SJames Smart 37027ad20aa9SJames Smart return; 37037ad20aa9SJames Smart } 37047ad20aa9SJames Smart 37057ad20aa9SJames Smart static void 37067ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(struct lpfc_hba *phba, enum nemb_type nemb_tp, 37077ad20aa9SJames Smart uint32_t index, struct lpfc_dmabuf *mbx_dmabuf, 37087ad20aa9SJames Smart struct lpfc_dmabuf *ext_dmabuf) 37097ad20aa9SJames Smart { 37107ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 37117ad20aa9SJames Smart 37127ad20aa9SJames Smart /* pointer to the start of mailbox command */ 37137ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)mbx_dmabuf->virt; 37147ad20aa9SJames Smart 37157ad20aa9SJames Smart if (nemb_tp == nemb_mse) { 37167ad20aa9SJames Smart if (index == 0) { 37177ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37187ad20aa9SJames Smart mse[index].pa_hi = 37197ad20aa9SJames Smart putPaddrHigh(mbx_dmabuf->phys + 37207ad20aa9SJames Smart sizeof(MAILBOX_t)); 37217ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37227ad20aa9SJames Smart mse[index].pa_lo = 37237ad20aa9SJames Smart putPaddrLow(mbx_dmabuf->phys + 37247ad20aa9SJames Smart sizeof(MAILBOX_t)); 37257ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 37267ad20aa9SJames Smart "2943 SLI_CONFIG(mse)[%d], " 37277ad20aa9SJames Smart "bufLen:%d, addrHi:x%x, addrLo:x%x\n", 37287ad20aa9SJames Smart index, 37297ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37307ad20aa9SJames Smart mse[index].buf_len, 37317ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37327ad20aa9SJames Smart mse[index].pa_hi, 37337ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37347ad20aa9SJames Smart mse[index].pa_lo); 37357ad20aa9SJames Smart } else { 37367ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37377ad20aa9SJames Smart mse[index].pa_hi = 37387ad20aa9SJames Smart putPaddrHigh(ext_dmabuf->phys); 37397ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37407ad20aa9SJames Smart mse[index].pa_lo = 37417ad20aa9SJames Smart putPaddrLow(ext_dmabuf->phys); 37427ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 37437ad20aa9SJames Smart "2944 SLI_CONFIG(mse)[%d], " 37447ad20aa9SJames Smart "bufLen:%d, addrHi:x%x, addrLo:x%x\n", 37457ad20aa9SJames Smart index, 37467ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37477ad20aa9SJames Smart mse[index].buf_len, 37487ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37497ad20aa9SJames Smart mse[index].pa_hi, 37507ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37517ad20aa9SJames Smart mse[index].pa_lo); 37527ad20aa9SJames Smart } 37537ad20aa9SJames Smart } else { 37547ad20aa9SJames Smart if (index == 0) { 37557ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 37567ad20aa9SJames Smart hbd[index].pa_hi = 37577ad20aa9SJames Smart putPaddrHigh(mbx_dmabuf->phys + 37587ad20aa9SJames Smart sizeof(MAILBOX_t)); 37597ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 37607ad20aa9SJames Smart hbd[index].pa_lo = 37617ad20aa9SJames Smart putPaddrLow(mbx_dmabuf->phys + 37627ad20aa9SJames Smart sizeof(MAILBOX_t)); 37637ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 37647ad20aa9SJames Smart "3007 SLI_CONFIG(hbd)[%d], " 37657ad20aa9SJames Smart "bufLen:%d, addrHi:x%x, addrLo:x%x\n", 37667ad20aa9SJames Smart index, 37677ad20aa9SJames Smart bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, 37687ad20aa9SJames Smart &sli_cfg_mbx->un. 37697ad20aa9SJames Smart sli_config_emb1_subsys.hbd[index]), 37707ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 37717ad20aa9SJames Smart hbd[index].pa_hi, 37727ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 37737ad20aa9SJames Smart hbd[index].pa_lo); 37747ad20aa9SJames Smart 37757ad20aa9SJames Smart } else { 37767ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 37777ad20aa9SJames Smart hbd[index].pa_hi = 37787ad20aa9SJames Smart putPaddrHigh(ext_dmabuf->phys); 37797ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 37807ad20aa9SJames Smart hbd[index].pa_lo = 37817ad20aa9SJames Smart putPaddrLow(ext_dmabuf->phys); 37827ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 37837ad20aa9SJames Smart "3008 SLI_CONFIG(hbd)[%d], " 37847ad20aa9SJames Smart "bufLen:%d, addrHi:x%x, addrLo:x%x\n", 37857ad20aa9SJames Smart index, 37867ad20aa9SJames Smart bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, 37877ad20aa9SJames Smart &sli_cfg_mbx->un. 37887ad20aa9SJames Smart sli_config_emb1_subsys.hbd[index]), 37897ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 37907ad20aa9SJames Smart hbd[index].pa_hi, 37917ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 37927ad20aa9SJames Smart hbd[index].pa_lo); 37937ad20aa9SJames Smart } 37947ad20aa9SJames Smart } 37957ad20aa9SJames Smart return; 37967ad20aa9SJames Smart } 37977ad20aa9SJames Smart 37987ad20aa9SJames Smart /** 37993145d2d6SLee Jones * lpfc_bsg_sli_cfg_read_cmd_ext - sli_config non-embedded mailbox cmd read 38007ad20aa9SJames Smart * @phba: Pointer to HBA context object. 3801ea085dabSLee Jones * @job: Pointer to the job object. 38027ad20aa9SJames Smart * @nemb_tp: Enumerate of non-embedded mailbox command type. 3803ea085dabSLee Jones * @dmabuf: Pointer to a DMA buffer descriptor. 38047ad20aa9SJames Smart * 38057ad20aa9SJames Smart * This routine performs SLI_CONFIG (0x9B) read mailbox command operation with 38063bfab8a0SJames Smart * non-embedded external buffers. 38077ad20aa9SJames Smart **/ 38087ad20aa9SJames Smart static int 380975cc8cfcSJohannes Thumshirn lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job, 38107ad20aa9SJames Smart enum nemb_type nemb_tp, 38117ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 38127ad20aa9SJames Smart { 381301e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 38147ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 38157ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 38167ad20aa9SJames Smart struct lpfc_dmabuf *curr_dmabuf, *next_dmabuf; 38177ad20aa9SJames Smart uint32_t ext_buf_cnt, ext_buf_index; 38187ad20aa9SJames Smart struct lpfc_dmabuf *ext_dmabuf = NULL; 38197ad20aa9SJames Smart struct bsg_job_data *dd_data = NULL; 38207ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq = NULL; 38217ad20aa9SJames Smart MAILBOX_t *pmb; 38227ad20aa9SJames Smart uint8_t *pmbx; 38237ad20aa9SJames Smart int rc, i; 38247ad20aa9SJames Smart 38257ad20aa9SJames Smart mbox_req = 382601e0e15cSJohannes Thumshirn (struct dfc_mbox_req *)bsg_request->rqst_data.h_vendor.vendor_cmd; 38277ad20aa9SJames Smart 38287ad20aa9SJames Smart /* pointer to the start of mailbox command */ 38297ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; 38307ad20aa9SJames Smart 38317ad20aa9SJames Smart if (nemb_tp == nemb_mse) { 38327ad20aa9SJames Smart ext_buf_cnt = bsg_bf_get(lpfc_mbox_hdr_mse_cnt, 38337ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr); 38347ad20aa9SJames Smart if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_MSE) { 38357ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 38367ad20aa9SJames Smart "2945 Handled SLI_CONFIG(mse) rd, " 38377ad20aa9SJames Smart "ext_buf_cnt(%d) out of range(%d)\n", 38387ad20aa9SJames Smart ext_buf_cnt, 38397ad20aa9SJames Smart LPFC_MBX_SLI_CONFIG_MAX_MSE); 38407ad20aa9SJames Smart rc = -ERANGE; 38417ad20aa9SJames Smart goto job_error; 38427ad20aa9SJames Smart } 38437ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 38447ad20aa9SJames Smart "2941 Handled SLI_CONFIG(mse) rd, " 38457ad20aa9SJames Smart "ext_buf_cnt:%d\n", ext_buf_cnt); 38467ad20aa9SJames Smart } else { 38477ad20aa9SJames Smart /* sanity check on interface type for support */ 384827d6ac0aSJames Smart if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) < 38497ad20aa9SJames Smart LPFC_SLI_INTF_IF_TYPE_2) { 38507ad20aa9SJames Smart rc = -ENODEV; 38517ad20aa9SJames Smart goto job_error; 38527ad20aa9SJames Smart } 38537ad20aa9SJames Smart /* nemb_tp == nemb_hbd */ 38547ad20aa9SJames Smart ext_buf_cnt = sli_cfg_mbx->un.sli_config_emb1_subsys.hbd_count; 38557ad20aa9SJames Smart if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_HBD) { 38567ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 38577ad20aa9SJames Smart "2946 Handled SLI_CONFIG(hbd) rd, " 38587ad20aa9SJames Smart "ext_buf_cnt(%d) out of range(%d)\n", 38597ad20aa9SJames Smart ext_buf_cnt, 38607ad20aa9SJames Smart LPFC_MBX_SLI_CONFIG_MAX_HBD); 38617ad20aa9SJames Smart rc = -ERANGE; 38627ad20aa9SJames Smart goto job_error; 38637ad20aa9SJames Smart } 38647ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 38657ad20aa9SJames Smart "2942 Handled SLI_CONFIG(hbd) rd, " 38667ad20aa9SJames Smart "ext_buf_cnt:%d\n", ext_buf_cnt); 38677ad20aa9SJames Smart } 38687ad20aa9SJames Smart 3869b76f2dc9SJames Smart /* before dma descriptor setup */ 3870b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_rd, dma_mbox, 3871b76f2dc9SJames Smart sta_pre_addr, dmabuf, ext_buf_cnt); 3872b76f2dc9SJames Smart 38737ad20aa9SJames Smart /* reject non-embedded mailbox command with none external buffer */ 38747ad20aa9SJames Smart if (ext_buf_cnt == 0) { 38757ad20aa9SJames Smart rc = -EPERM; 38767ad20aa9SJames Smart goto job_error; 38777ad20aa9SJames Smart } else if (ext_buf_cnt > 1) { 38787ad20aa9SJames Smart /* additional external read buffers */ 38797ad20aa9SJames Smart for (i = 1; i < ext_buf_cnt; i++) { 38807ad20aa9SJames Smart ext_dmabuf = lpfc_bsg_dma_page_alloc(phba); 38817ad20aa9SJames Smart if (!ext_dmabuf) { 38827ad20aa9SJames Smart rc = -ENOMEM; 38837ad20aa9SJames Smart goto job_error; 38847ad20aa9SJames Smart } 38857ad20aa9SJames Smart list_add_tail(&ext_dmabuf->list, 38867ad20aa9SJames Smart &phba->mbox_ext_buf_ctx.ext_dmabuf_list); 38877ad20aa9SJames Smart } 38887ad20aa9SJames Smart } 38897ad20aa9SJames Smart 38907ad20aa9SJames Smart /* bsg tracking structure */ 38917ad20aa9SJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 38927ad20aa9SJames Smart if (!dd_data) { 38937ad20aa9SJames Smart rc = -ENOMEM; 38947ad20aa9SJames Smart goto job_error; 38957ad20aa9SJames Smart } 38967ad20aa9SJames Smart 38977ad20aa9SJames Smart /* mailbox command structure for base driver */ 38987ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 38997ad20aa9SJames Smart if (!pmboxq) { 39007ad20aa9SJames Smart rc = -ENOMEM; 39017ad20aa9SJames Smart goto job_error; 39027ad20aa9SJames Smart } 39037ad20aa9SJames Smart memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 39047ad20aa9SJames Smart 39057ad20aa9SJames Smart /* for the first external buffer */ 39067ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 0, dmabuf, dmabuf); 39077ad20aa9SJames Smart 39087ad20aa9SJames Smart /* for the rest of external buffer descriptors if any */ 39097ad20aa9SJames Smart if (ext_buf_cnt > 1) { 39107ad20aa9SJames Smart ext_buf_index = 1; 39117ad20aa9SJames Smart list_for_each_entry_safe(curr_dmabuf, next_dmabuf, 39127ad20aa9SJames Smart &phba->mbox_ext_buf_ctx.ext_dmabuf_list, list) { 39137ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 39147ad20aa9SJames Smart ext_buf_index, dmabuf, 39157ad20aa9SJames Smart curr_dmabuf); 39167ad20aa9SJames Smart ext_buf_index++; 39177ad20aa9SJames Smart } 39187ad20aa9SJames Smart } 39197ad20aa9SJames Smart 3920b76f2dc9SJames Smart /* after dma descriptor setup */ 3921b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_rd, dma_mbox, 3922b76f2dc9SJames Smart sta_pos_addr, dmabuf, ext_buf_cnt); 3923b76f2dc9SJames Smart 39247ad20aa9SJames Smart /* construct base driver mbox command */ 39257ad20aa9SJames Smart pmb = &pmboxq->u.mb; 39267ad20aa9SJames Smart pmbx = (uint8_t *)dmabuf->virt; 39277ad20aa9SJames Smart memcpy(pmb, pmbx, sizeof(*pmb)); 39287ad20aa9SJames Smart pmb->mbxOwner = OWN_HOST; 39297ad20aa9SJames Smart pmboxq->vport = phba->pport; 39307ad20aa9SJames Smart 39317ad20aa9SJames Smart /* multi-buffer handling context */ 39327ad20aa9SJames Smart phba->mbox_ext_buf_ctx.nembType = nemb_tp; 39337ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType = mbox_rd; 39347ad20aa9SJames Smart phba->mbox_ext_buf_ctx.numBuf = ext_buf_cnt; 39357ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbxTag = mbox_req->extMboxTag; 39367ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum = mbox_req->extSeqNum; 39377ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf = dmabuf; 39387ad20aa9SJames Smart 39397ad20aa9SJames Smart /* callback for multi-buffer read mailbox command */ 39407ad20aa9SJames Smart pmboxq->mbox_cmpl = lpfc_bsg_issue_read_mbox_ext_cmpl; 39417ad20aa9SJames Smart 39427ad20aa9SJames Smart /* context fields to callback function */ 394385d77f91SJustin Tee pmboxq->ctx_u.dd_data = dd_data; 39447ad20aa9SJames Smart dd_data->type = TYPE_MBOX; 3945a33c4f7bSJames Smart dd_data->set_job = job; 39467ad20aa9SJames Smart dd_data->context_un.mbox.pmboxq = pmboxq; 39477ad20aa9SJames Smart dd_data->context_un.mbox.mb = (MAILBOX_t *)pmbx; 39487ad20aa9SJames Smart job->dd_data = dd_data; 39497ad20aa9SJames Smart 39507ad20aa9SJames Smart /* state change */ 39517ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT; 39527ad20aa9SJames Smart 3953026abb87SJames Smart /* 3954026abb87SJames Smart * Non-embedded mailbox subcommand data gets byte swapped here because 3955026abb87SJames Smart * the lower level driver code only does the first 64 mailbox words. 3956026abb87SJames Smart */ 3957026abb87SJames Smart if ((!bsg_bf_get(lpfc_mbox_hdr_emb, 3958026abb87SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) && 3959026abb87SJames Smart (nemb_tp == nemb_mse)) 3960026abb87SJames Smart lpfc_sli_pcimem_bcopy(&pmbx[sizeof(MAILBOX_t)], 3961026abb87SJames Smart &pmbx[sizeof(MAILBOX_t)], 3962026abb87SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 3963026abb87SJames Smart mse[0].buf_len); 3964026abb87SJames Smart 39657ad20aa9SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); 39667ad20aa9SJames Smart if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { 39677ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 39687ad20aa9SJames Smart "2947 Issued SLI_CONFIG ext-buffer " 39697afc0ce9SColin Ian King "mailbox command, rc:x%x\n", rc); 397088a2cfbbSJames Smart return SLI_CONFIG_HANDLED; 39717ad20aa9SJames Smart } 39727ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 39737ad20aa9SJames Smart "2948 Failed to issue SLI_CONFIG ext-buffer " 39747afc0ce9SColin Ian King "mailbox command, rc:x%x\n", rc); 39757ad20aa9SJames Smart rc = -EPIPE; 39767ad20aa9SJames Smart 39777ad20aa9SJames Smart job_error: 39787ad20aa9SJames Smart if (pmboxq) 39797ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 39807ad20aa9SJames Smart lpfc_bsg_dma_page_list_free(phba, 39817ad20aa9SJames Smart &phba->mbox_ext_buf_ctx.ext_dmabuf_list); 39827ad20aa9SJames Smart kfree(dd_data); 39837ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_IDLE; 39847ad20aa9SJames Smart return rc; 39857ad20aa9SJames Smart } 39867ad20aa9SJames Smart 39877ad20aa9SJames Smart /** 39887ad20aa9SJames Smart * lpfc_bsg_sli_cfg_write_cmd_ext - sli_config non-embedded mailbox cmd write 39897ad20aa9SJames Smart * @phba: Pointer to HBA context object. 3990ea085dabSLee Jones * @job: Pointer to the job object. 3991ea085dabSLee Jones * @nemb_tp: Enumerate of non-embedded mailbox command type. 3992ea085dabSLee Jones * @dmabuf: Pointer to a DMA buffer descriptor. 39937ad20aa9SJames Smart * 39947ad20aa9SJames Smart * This routine performs SLI_CONFIG (0x9B) write mailbox command operation with 39953bfab8a0SJames Smart * non-embedded external buffers. 39967ad20aa9SJames Smart **/ 39977ad20aa9SJames Smart static int 399875cc8cfcSJohannes Thumshirn lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job, 39997ad20aa9SJames Smart enum nemb_type nemb_tp, 40007ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 40017ad20aa9SJames Smart { 400201e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 400301e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 40047ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 40057ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 40067ad20aa9SJames Smart uint32_t ext_buf_cnt; 40077ad20aa9SJames Smart struct bsg_job_data *dd_data = NULL; 40087ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq = NULL; 40097ad20aa9SJames Smart MAILBOX_t *pmb; 40107ad20aa9SJames Smart uint8_t *mbx; 401188a2cfbbSJames Smart int rc = SLI_CONFIG_NOT_HANDLED, i; 40127ad20aa9SJames Smart 40137ad20aa9SJames Smart mbox_req = 401401e0e15cSJohannes Thumshirn (struct dfc_mbox_req *)bsg_request->rqst_data.h_vendor.vendor_cmd; 40157ad20aa9SJames Smart 40167ad20aa9SJames Smart /* pointer to the start of mailbox command */ 40177ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; 40187ad20aa9SJames Smart 40197ad20aa9SJames Smart if (nemb_tp == nemb_mse) { 40207ad20aa9SJames Smart ext_buf_cnt = bsg_bf_get(lpfc_mbox_hdr_mse_cnt, 40217ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr); 40227ad20aa9SJames Smart if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_MSE) { 40237ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 4024026abb87SJames Smart "2953 Failed SLI_CONFIG(mse) wr, " 40257ad20aa9SJames Smart "ext_buf_cnt(%d) out of range(%d)\n", 40267ad20aa9SJames Smart ext_buf_cnt, 40277ad20aa9SJames Smart LPFC_MBX_SLI_CONFIG_MAX_MSE); 40287ad20aa9SJames Smart return -ERANGE; 40297ad20aa9SJames Smart } 40307ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 40317ad20aa9SJames Smart "2949 Handled SLI_CONFIG(mse) wr, " 40327ad20aa9SJames Smart "ext_buf_cnt:%d\n", ext_buf_cnt); 40337ad20aa9SJames Smart } else { 40347ad20aa9SJames Smart /* sanity check on interface type for support */ 403527d6ac0aSJames Smart if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) < 40367ad20aa9SJames Smart LPFC_SLI_INTF_IF_TYPE_2) 40377ad20aa9SJames Smart return -ENODEV; 40387ad20aa9SJames Smart /* nemb_tp == nemb_hbd */ 40397ad20aa9SJames Smart ext_buf_cnt = sli_cfg_mbx->un.sli_config_emb1_subsys.hbd_count; 40407ad20aa9SJames Smart if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_HBD) { 40417ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 4042026abb87SJames Smart "2954 Failed SLI_CONFIG(hbd) wr, " 40437ad20aa9SJames Smart "ext_buf_cnt(%d) out of range(%d)\n", 40447ad20aa9SJames Smart ext_buf_cnt, 40457ad20aa9SJames Smart LPFC_MBX_SLI_CONFIG_MAX_HBD); 40467ad20aa9SJames Smart return -ERANGE; 40477ad20aa9SJames Smart } 40487ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 40497ad20aa9SJames Smart "2950 Handled SLI_CONFIG(hbd) wr, " 40507ad20aa9SJames Smart "ext_buf_cnt:%d\n", ext_buf_cnt); 40517ad20aa9SJames Smart } 40527ad20aa9SJames Smart 4053b76f2dc9SJames Smart /* before dma buffer descriptor setup */ 4054b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_wr, dma_mbox, 4055b76f2dc9SJames Smart sta_pre_addr, dmabuf, ext_buf_cnt); 4056b76f2dc9SJames Smart 40577ad20aa9SJames Smart if (ext_buf_cnt == 0) 40587ad20aa9SJames Smart return -EPERM; 40597ad20aa9SJames Smart 40607ad20aa9SJames Smart /* for the first external buffer */ 40617ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 0, dmabuf, dmabuf); 40627ad20aa9SJames Smart 4063b76f2dc9SJames Smart /* after dma descriptor setup */ 4064b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_wr, dma_mbox, 4065b76f2dc9SJames Smart sta_pos_addr, dmabuf, ext_buf_cnt); 4066b76f2dc9SJames Smart 40677ad20aa9SJames Smart /* log for looking forward */ 40687ad20aa9SJames Smart for (i = 1; i < ext_buf_cnt; i++) { 40697ad20aa9SJames Smart if (nemb_tp == nemb_mse) 40707ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 40717ad20aa9SJames Smart "2951 SLI_CONFIG(mse), buf[%d]-length:%d\n", 40727ad20aa9SJames Smart i, sli_cfg_mbx->un.sli_config_emb0_subsys. 40737ad20aa9SJames Smart mse[i].buf_len); 40747ad20aa9SJames Smart else 40757ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 40767ad20aa9SJames Smart "2952 SLI_CONFIG(hbd), buf[%d]-length:%d\n", 40777ad20aa9SJames Smart i, bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, 40787ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb1_subsys. 40797ad20aa9SJames Smart hbd[i])); 40807ad20aa9SJames Smart } 40817ad20aa9SJames Smart 40827ad20aa9SJames Smart /* multi-buffer handling context */ 40837ad20aa9SJames Smart phba->mbox_ext_buf_ctx.nembType = nemb_tp; 40847ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType = mbox_wr; 40857ad20aa9SJames Smart phba->mbox_ext_buf_ctx.numBuf = ext_buf_cnt; 40867ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbxTag = mbox_req->extMboxTag; 40877ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum = mbox_req->extSeqNum; 40887ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf = dmabuf; 40897ad20aa9SJames Smart 40907ad20aa9SJames Smart if (ext_buf_cnt == 1) { 40917ad20aa9SJames Smart /* bsg tracking structure */ 40927ad20aa9SJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 40937ad20aa9SJames Smart if (!dd_data) { 40947ad20aa9SJames Smart rc = -ENOMEM; 40957ad20aa9SJames Smart goto job_error; 40967ad20aa9SJames Smart } 40977ad20aa9SJames Smart 40987ad20aa9SJames Smart /* mailbox command structure for base driver */ 40997ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 41007ad20aa9SJames Smart if (!pmboxq) { 41017ad20aa9SJames Smart rc = -ENOMEM; 41027ad20aa9SJames Smart goto job_error; 41037ad20aa9SJames Smart } 41047ad20aa9SJames Smart memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 41057ad20aa9SJames Smart pmb = &pmboxq->u.mb; 41067ad20aa9SJames Smart mbx = (uint8_t *)dmabuf->virt; 41077ad20aa9SJames Smart memcpy(pmb, mbx, sizeof(*pmb)); 41087ad20aa9SJames Smart pmb->mbxOwner = OWN_HOST; 41097ad20aa9SJames Smart pmboxq->vport = phba->pport; 41107ad20aa9SJames Smart 41117ad20aa9SJames Smart /* callback for multi-buffer read mailbox command */ 41127ad20aa9SJames Smart pmboxq->mbox_cmpl = lpfc_bsg_issue_write_mbox_ext_cmpl; 41137ad20aa9SJames Smart 41147ad20aa9SJames Smart /* context fields to callback function */ 411585d77f91SJustin Tee pmboxq->ctx_u.dd_data = dd_data; 41167ad20aa9SJames Smart dd_data->type = TYPE_MBOX; 4117a33c4f7bSJames Smart dd_data->set_job = job; 41187ad20aa9SJames Smart dd_data->context_un.mbox.pmboxq = pmboxq; 41197ad20aa9SJames Smart dd_data->context_un.mbox.mb = (MAILBOX_t *)mbx; 41207ad20aa9SJames Smart job->dd_data = dd_data; 41217ad20aa9SJames Smart 41227ad20aa9SJames Smart /* state change */ 41237ad20aa9SJames Smart 4124a33c4f7bSJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT; 41257ad20aa9SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); 41267ad20aa9SJames Smart if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { 41277ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 41287ad20aa9SJames Smart "2955 Issued SLI_CONFIG ext-buffer " 41297afc0ce9SColin Ian King "mailbox command, rc:x%x\n", rc); 413088a2cfbbSJames Smart return SLI_CONFIG_HANDLED; 41317ad20aa9SJames Smart } 41327ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 41337ad20aa9SJames Smart "2956 Failed to issue SLI_CONFIG ext-buffer " 41347afc0ce9SColin Ian King "mailbox command, rc:x%x\n", rc); 41357ad20aa9SJames Smart rc = -EPIPE; 4136026abb87SJames Smart goto job_error; 41377ad20aa9SJames Smart } 41387ad20aa9SJames Smart 41393bfab8a0SJames Smart /* wait for additional external buffers */ 4140a33c4f7bSJames Smart 414101e0e15cSJohannes Thumshirn bsg_reply->result = 0; 414206548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 41431abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 414488a2cfbbSJames Smart return SLI_CONFIG_HANDLED; 414588a2cfbbSJames Smart 41467ad20aa9SJames Smart job_error: 41477ad20aa9SJames Smart if (pmboxq) 41487ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 41497ad20aa9SJames Smart kfree(dd_data); 41507ad20aa9SJames Smart 41517ad20aa9SJames Smart return rc; 41527ad20aa9SJames Smart } 41537ad20aa9SJames Smart 41547ad20aa9SJames Smart /** 41557ad20aa9SJames Smart * lpfc_bsg_handle_sli_cfg_mbox - handle sli-cfg mailbox cmd with ext buffer 41567ad20aa9SJames Smart * @phba: Pointer to HBA context object. 4157ea085dabSLee Jones * @job: Pointer to the job object. 4158ea085dabSLee Jones * @dmabuf: Pointer to a DMA buffer descriptor. 41597ad20aa9SJames Smart * 41607ad20aa9SJames Smart * This routine handles SLI_CONFIG (0x9B) mailbox command with non-embedded 41613bfab8a0SJames Smart * external buffers, including both 0x9B with non-embedded MSEs and 0x9B 41623bfab8a0SJames Smart * with embedded subsystem 0x1 and opcodes with external HBDs. 41637ad20aa9SJames Smart **/ 41647ad20aa9SJames Smart static int 416575cc8cfcSJohannes Thumshirn lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct bsg_job *job, 41667ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 41677ad20aa9SJames Smart { 41687ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 41697ad20aa9SJames Smart uint32_t subsys; 41707ad20aa9SJames Smart uint32_t opcode; 41717ad20aa9SJames Smart int rc = SLI_CONFIG_NOT_HANDLED; 41727ad20aa9SJames Smart 4173026abb87SJames Smart /* state change on new multi-buffer pass-through mailbox command */ 41747ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_HOST; 41757ad20aa9SJames Smart 41767ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; 41777ad20aa9SJames Smart 41787ad20aa9SJames Smart if (!bsg_bf_get(lpfc_mbox_hdr_emb, 41797ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) { 41807ad20aa9SJames Smart subsys = bsg_bf_get(lpfc_emb0_subcmnd_subsys, 41817ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys); 41827ad20aa9SJames Smart opcode = bsg_bf_get(lpfc_emb0_subcmnd_opcode, 41837ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys); 41847ad20aa9SJames Smart if (subsys == SLI_CONFIG_SUBSYS_FCOE) { 41857ad20aa9SJames Smart switch (opcode) { 41867ad20aa9SJames Smart case FCOE_OPCODE_READ_FCF: 41872a2719d3SJames Smart case FCOE_OPCODE_GET_DPORT_RESULTS: 41887ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 41897ad20aa9SJames Smart "2957 Handled SLI_CONFIG " 41907ad20aa9SJames Smart "subsys_fcoe, opcode:x%x\n", 41917ad20aa9SJames Smart opcode); 41927ad20aa9SJames Smart rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job, 41937ad20aa9SJames Smart nemb_mse, dmabuf); 41947ad20aa9SJames Smart break; 41957ad20aa9SJames Smart case FCOE_OPCODE_ADD_FCF: 41962a2719d3SJames Smart case FCOE_OPCODE_SET_DPORT_MODE: 41972a2719d3SJames Smart case LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE: 41987ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 41997ad20aa9SJames Smart "2958 Handled SLI_CONFIG " 42007ad20aa9SJames Smart "subsys_fcoe, opcode:x%x\n", 42017ad20aa9SJames Smart opcode); 42027ad20aa9SJames Smart rc = lpfc_bsg_sli_cfg_write_cmd_ext(phba, job, 42037ad20aa9SJames Smart nemb_mse, dmabuf); 42047ad20aa9SJames Smart break; 42057ad20aa9SJames Smart default: 42067ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4207026abb87SJames Smart "2959 Reject SLI_CONFIG " 42087ad20aa9SJames Smart "subsys_fcoe, opcode:x%x\n", 42097ad20aa9SJames Smart opcode); 4210026abb87SJames Smart rc = -EPERM; 4211026abb87SJames Smart break; 4212026abb87SJames Smart } 4213026abb87SJames Smart } else if (subsys == SLI_CONFIG_SUBSYS_COMN) { 4214026abb87SJames Smart switch (opcode) { 4215026abb87SJames Smart case COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES: 4216b99570ddSJames Smart case COMN_OPCODE_GET_CNTL_ATTRIBUTES: 4217c6377970SJames Smart case COMN_OPCODE_GET_PROFILE_CONFIG: 421845bc4427SDick Kennedy case COMN_OPCODE_SET_FEATURES: 4219026abb87SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4220026abb87SJames Smart "3106 Handled SLI_CONFIG " 42216b5151fdSJames Smart "subsys_comn, opcode:x%x\n", 4222026abb87SJames Smart opcode); 4223026abb87SJames Smart rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job, 4224026abb87SJames Smart nemb_mse, dmabuf); 4225026abb87SJames Smart break; 4226026abb87SJames Smart default: 4227026abb87SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4228026abb87SJames Smart "3107 Reject SLI_CONFIG " 42296b5151fdSJames Smart "subsys_comn, opcode:x%x\n", 4230026abb87SJames Smart opcode); 4231026abb87SJames Smart rc = -EPERM; 42327ad20aa9SJames Smart break; 42337ad20aa9SJames Smart } 42347ad20aa9SJames Smart } else { 42357ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4236026abb87SJames Smart "2977 Reject SLI_CONFIG " 42377ad20aa9SJames Smart "subsys:x%d, opcode:x%x\n", 42387ad20aa9SJames Smart subsys, opcode); 4239026abb87SJames Smart rc = -EPERM; 42407ad20aa9SJames Smart } 42417ad20aa9SJames Smart } else { 42427ad20aa9SJames Smart subsys = bsg_bf_get(lpfc_emb1_subcmnd_subsys, 42437ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb1_subsys); 42447ad20aa9SJames Smart opcode = bsg_bf_get(lpfc_emb1_subcmnd_opcode, 42457ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb1_subsys); 42467ad20aa9SJames Smart if (subsys == SLI_CONFIG_SUBSYS_COMN) { 42477ad20aa9SJames Smart switch (opcode) { 42487ad20aa9SJames Smart case COMN_OPCODE_READ_OBJECT: 42497ad20aa9SJames Smart case COMN_OPCODE_READ_OBJECT_LIST: 42507ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 42517ad20aa9SJames Smart "2960 Handled SLI_CONFIG " 42527ad20aa9SJames Smart "subsys_comn, opcode:x%x\n", 42537ad20aa9SJames Smart opcode); 42547ad20aa9SJames Smart rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job, 42557ad20aa9SJames Smart nemb_hbd, dmabuf); 42567ad20aa9SJames Smart break; 42577ad20aa9SJames Smart case COMN_OPCODE_WRITE_OBJECT: 42587ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 42597ad20aa9SJames Smart "2961 Handled SLI_CONFIG " 42607ad20aa9SJames Smart "subsys_comn, opcode:x%x\n", 42617ad20aa9SJames Smart opcode); 42627ad20aa9SJames Smart rc = lpfc_bsg_sli_cfg_write_cmd_ext(phba, job, 42637ad20aa9SJames Smart nemb_hbd, dmabuf); 42647ad20aa9SJames Smart break; 42657ad20aa9SJames Smart default: 42667ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 42677ad20aa9SJames Smart "2962 Not handled SLI_CONFIG " 42687ad20aa9SJames Smart "subsys_comn, opcode:x%x\n", 42697ad20aa9SJames Smart opcode); 42707ad20aa9SJames Smart rc = SLI_CONFIG_NOT_HANDLED; 42717ad20aa9SJames Smart break; 42727ad20aa9SJames Smart } 42737ad20aa9SJames Smart } else { 42747ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4275026abb87SJames Smart "2978 Not handled SLI_CONFIG " 42767ad20aa9SJames Smart "subsys:x%d, opcode:x%x\n", 42777ad20aa9SJames Smart subsys, opcode); 42787ad20aa9SJames Smart rc = SLI_CONFIG_NOT_HANDLED; 42797ad20aa9SJames Smart } 42807ad20aa9SJames Smart } 4281026abb87SJames Smart 4282026abb87SJames Smart /* state reset on not handled new multi-buffer mailbox command */ 4283026abb87SJames Smart if (rc != SLI_CONFIG_HANDLED) 4284026abb87SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_IDLE; 4285026abb87SJames Smart 42867ad20aa9SJames Smart return rc; 42877ad20aa9SJames Smart } 42887ad20aa9SJames Smart 42897ad20aa9SJames Smart /** 42903145d2d6SLee Jones * lpfc_bsg_mbox_ext_abort - request to abort mbox command with ext buffers 42917ad20aa9SJames Smart * @phba: Pointer to HBA context object. 42927ad20aa9SJames Smart * 42937ad20aa9SJames Smart * This routine is for requesting to abort a pass-through mailbox command with 42947ad20aa9SJames Smart * multiple external buffers due to error condition. 42957ad20aa9SJames Smart **/ 42967ad20aa9SJames Smart static void 42977ad20aa9SJames Smart lpfc_bsg_mbox_ext_abort(struct lpfc_hba *phba) 42987ad20aa9SJames Smart { 42997ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_PORT) 43007ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_ABTS; 43017ad20aa9SJames Smart else 43027ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 43037ad20aa9SJames Smart return; 43047ad20aa9SJames Smart } 43057ad20aa9SJames Smart 43067ad20aa9SJames Smart /** 43077ad20aa9SJames Smart * lpfc_bsg_read_ebuf_get - get the next mailbox read external buffer 43087ad20aa9SJames Smart * @phba: Pointer to HBA context object. 4309ea085dabSLee Jones * @job: Pointer to the job object. 43107ad20aa9SJames Smart * 43117ad20aa9SJames Smart * This routine extracts the next mailbox read external buffer back to 43127ad20aa9SJames Smart * user space through BSG. 43137ad20aa9SJames Smart **/ 43147ad20aa9SJames Smart static int 431575cc8cfcSJohannes Thumshirn lpfc_bsg_read_ebuf_get(struct lpfc_hba *phba, struct bsg_job *job) 43167ad20aa9SJames Smart { 431701e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 43187ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 43197ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf; 43207ad20aa9SJames Smart uint8_t *pbuf; 43217ad20aa9SJames Smart uint32_t size; 43227ad20aa9SJames Smart uint32_t index; 43237ad20aa9SJames Smart 43247ad20aa9SJames Smart index = phba->mbox_ext_buf_ctx.seqNum; 43257ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum++; 43267ad20aa9SJames Smart 43277ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *) 43287ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf->virt; 43297ad20aa9SJames Smart 43307ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.nembType == nemb_mse) { 43317ad20aa9SJames Smart size = bsg_bf_get(lpfc_mbox_sli_config_mse_len, 43327ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.mse[index]); 43337ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 43347ad20aa9SJames Smart "2963 SLI_CONFIG (mse) ext-buffer rd get " 43357ad20aa9SJames Smart "buffer[%d], size:%d\n", index, size); 43367ad20aa9SJames Smart } else { 43377ad20aa9SJames Smart size = bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, 43387ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb1_subsys.hbd[index]); 43397ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 43407ad20aa9SJames Smart "2964 SLI_CONFIG (hbd) ext-buffer rd get " 43417ad20aa9SJames Smart "buffer[%d], size:%d\n", index, size); 43427ad20aa9SJames Smart } 43437ad20aa9SJames Smart if (list_empty(&phba->mbox_ext_buf_ctx.ext_dmabuf_list)) 43447ad20aa9SJames Smart return -EPIPE; 43457ad20aa9SJames Smart dmabuf = list_first_entry(&phba->mbox_ext_buf_ctx.ext_dmabuf_list, 43467ad20aa9SJames Smart struct lpfc_dmabuf, list); 43477ad20aa9SJames Smart list_del_init(&dmabuf->list); 4348b76f2dc9SJames Smart 4349b76f2dc9SJames Smart /* after dma buffer descriptor setup */ 4350b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, phba->mbox_ext_buf_ctx.nembType, 4351b76f2dc9SJames Smart mbox_rd, dma_ebuf, sta_pos_addr, 4352b76f2dc9SJames Smart dmabuf, index); 4353b76f2dc9SJames Smart 43547ad20aa9SJames Smart pbuf = (uint8_t *)dmabuf->virt; 435501e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 43567ad20aa9SJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 43577ad20aa9SJames Smart job->reply_payload.sg_cnt, 43587ad20aa9SJames Smart pbuf, size); 43597ad20aa9SJames Smart 43607ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 43617ad20aa9SJames Smart 43627ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.seqNum == phba->mbox_ext_buf_ctx.numBuf) { 43637ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 43647ad20aa9SJames Smart "2965 SLI_CONFIG (hbd) ext-buffer rd mbox " 43657ad20aa9SJames Smart "command session done\n"); 43667ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 43677ad20aa9SJames Smart } 43687ad20aa9SJames Smart 436901e0e15cSJohannes Thumshirn bsg_reply->result = 0; 437006548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 43711abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 43727ad20aa9SJames Smart 43737ad20aa9SJames Smart return SLI_CONFIG_HANDLED; 43747ad20aa9SJames Smart } 43757ad20aa9SJames Smart 43767ad20aa9SJames Smart /** 43777ad20aa9SJames Smart * lpfc_bsg_write_ebuf_set - set the next mailbox write external buffer 43787ad20aa9SJames Smart * @phba: Pointer to HBA context object. 4379ea085dabSLee Jones * @job: Pointer to the job object. 43807ad20aa9SJames Smart * @dmabuf: Pointer to a DMA buffer descriptor. 43817ad20aa9SJames Smart * 43827ad20aa9SJames Smart * This routine sets up the next mailbox read external buffer obtained 43837ad20aa9SJames Smart * from user space through BSG. 43847ad20aa9SJames Smart **/ 43857ad20aa9SJames Smart static int 438675cc8cfcSJohannes Thumshirn lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct bsg_job *job, 43877ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 43887ad20aa9SJames Smart { 438901e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 43907ad20aa9SJames Smart struct bsg_job_data *dd_data = NULL; 43917ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq = NULL; 43927ad20aa9SJames Smart MAILBOX_t *pmb; 43937ad20aa9SJames Smart enum nemb_type nemb_tp; 43947ad20aa9SJames Smart uint8_t *pbuf; 43957ad20aa9SJames Smart uint32_t size; 43967ad20aa9SJames Smart uint32_t index; 43977ad20aa9SJames Smart int rc; 43987ad20aa9SJames Smart 43997ad20aa9SJames Smart index = phba->mbox_ext_buf_ctx.seqNum; 44007ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum++; 44017ad20aa9SJames Smart nemb_tp = phba->mbox_ext_buf_ctx.nembType; 44027ad20aa9SJames Smart 44037ad20aa9SJames Smart pbuf = (uint8_t *)dmabuf->virt; 44047ad20aa9SJames Smart size = job->request_payload.payload_len; 44057ad20aa9SJames Smart sg_copy_to_buffer(job->request_payload.sg_list, 44067ad20aa9SJames Smart job->request_payload.sg_cnt, 44077ad20aa9SJames Smart pbuf, size); 44087ad20aa9SJames Smart 44097ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.nembType == nemb_mse) { 44107ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 44117ad20aa9SJames Smart "2966 SLI_CONFIG (mse) ext-buffer wr set " 44127ad20aa9SJames Smart "buffer[%d], size:%d\n", 44137ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum, size); 44147ad20aa9SJames Smart 44157ad20aa9SJames Smart } else { 44167ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 44177ad20aa9SJames Smart "2967 SLI_CONFIG (hbd) ext-buffer wr set " 44187ad20aa9SJames Smart "buffer[%d], size:%d\n", 44197ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum, size); 44207ad20aa9SJames Smart 44217ad20aa9SJames Smart } 44227ad20aa9SJames Smart 44237ad20aa9SJames Smart /* set up external buffer descriptor and add to external buffer list */ 44247ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, index, 44257ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf, 44267ad20aa9SJames Smart dmabuf); 44277ad20aa9SJames Smart list_add_tail(&dmabuf->list, &phba->mbox_ext_buf_ctx.ext_dmabuf_list); 44287ad20aa9SJames Smart 4429b76f2dc9SJames Smart /* after write dma buffer */ 4430b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, phba->mbox_ext_buf_ctx.nembType, 4431b76f2dc9SJames Smart mbox_wr, dma_ebuf, sta_pos_addr, 4432b76f2dc9SJames Smart dmabuf, index); 4433b76f2dc9SJames Smart 44347ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.seqNum == phba->mbox_ext_buf_ctx.numBuf) { 44357ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 44367ad20aa9SJames Smart "2968 SLI_CONFIG ext-buffer wr all %d " 44377ad20aa9SJames Smart "ebuffers received\n", 44387ad20aa9SJames Smart phba->mbox_ext_buf_ctx.numBuf); 44399a1b0b9aSBo Wu 44409a1b0b9aSBo Wu dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 44419a1b0b9aSBo Wu if (!dd_data) { 44429a1b0b9aSBo Wu rc = -ENOMEM; 44439a1b0b9aSBo Wu goto job_error; 44449a1b0b9aSBo Wu } 44459a1b0b9aSBo Wu 44467ad20aa9SJames Smart /* mailbox command structure for base driver */ 44477ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 44487ad20aa9SJames Smart if (!pmboxq) { 44497ad20aa9SJames Smart rc = -ENOMEM; 44507ad20aa9SJames Smart goto job_error; 44517ad20aa9SJames Smart } 44527ad20aa9SJames Smart memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 44537ad20aa9SJames Smart pbuf = (uint8_t *)phba->mbox_ext_buf_ctx.mbx_dmabuf->virt; 44547ad20aa9SJames Smart pmb = &pmboxq->u.mb; 44557ad20aa9SJames Smart memcpy(pmb, pbuf, sizeof(*pmb)); 44567ad20aa9SJames Smart pmb->mbxOwner = OWN_HOST; 44577ad20aa9SJames Smart pmboxq->vport = phba->pport; 44587ad20aa9SJames Smart 44597ad20aa9SJames Smart /* callback for multi-buffer write mailbox command */ 44607ad20aa9SJames Smart pmboxq->mbox_cmpl = lpfc_bsg_issue_write_mbox_ext_cmpl; 44617ad20aa9SJames Smart 44627ad20aa9SJames Smart /* context fields to callback function */ 446385d77f91SJustin Tee pmboxq->ctx_u.dd_data = dd_data; 44647ad20aa9SJames Smart dd_data->type = TYPE_MBOX; 4465a33c4f7bSJames Smart dd_data->set_job = job; 44667ad20aa9SJames Smart dd_data->context_un.mbox.pmboxq = pmboxq; 44677ad20aa9SJames Smart dd_data->context_un.mbox.mb = (MAILBOX_t *)pbuf; 44687ad20aa9SJames Smart job->dd_data = dd_data; 44697ad20aa9SJames Smart 44707ad20aa9SJames Smart /* state change */ 44717ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT; 44727ad20aa9SJames Smart 44737ad20aa9SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); 44747ad20aa9SJames Smart if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { 44757ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 44767ad20aa9SJames Smart "2969 Issued SLI_CONFIG ext-buffer " 44777afc0ce9SColin Ian King "mailbox command, rc:x%x\n", rc); 447888a2cfbbSJames Smart return SLI_CONFIG_HANDLED; 44797ad20aa9SJames Smart } 44807ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 44817ad20aa9SJames Smart "2970 Failed to issue SLI_CONFIG ext-buffer " 44827afc0ce9SColin Ian King "mailbox command, rc:x%x\n", rc); 44837ad20aa9SJames Smart rc = -EPIPE; 44847ad20aa9SJames Smart goto job_error; 44857ad20aa9SJames Smart } 44867ad20aa9SJames Smart 44873bfab8a0SJames Smart /* wait for additional external buffers */ 448801e0e15cSJohannes Thumshirn bsg_reply->result = 0; 448906548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 44901abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 44917ad20aa9SJames Smart return SLI_CONFIG_HANDLED; 44927ad20aa9SJames Smart 44937ad20aa9SJames Smart job_error: 44949a1b0b9aSBo Wu if (pmboxq) 44959a1b0b9aSBo Wu mempool_free(pmboxq, phba->mbox_mem_pool); 44967ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 44977ad20aa9SJames Smart kfree(dd_data); 44987ad20aa9SJames Smart 44997ad20aa9SJames Smart return rc; 45007ad20aa9SJames Smart } 45017ad20aa9SJames Smart 45027ad20aa9SJames Smart /** 45037ad20aa9SJames Smart * lpfc_bsg_handle_sli_cfg_ebuf - handle ext buffer with sli-cfg mailbox cmd 45047ad20aa9SJames Smart * @phba: Pointer to HBA context object. 4505ea085dabSLee Jones * @job: Pointer to the job object. 4506ea085dabSLee Jones * @dmabuf: Pointer to a DMA buffer descriptor. 45077ad20aa9SJames Smart * 45087ad20aa9SJames Smart * This routine handles the external buffer with SLI_CONFIG (0x9B) mailbox 45097ad20aa9SJames Smart * command with multiple non-embedded external buffers. 45107ad20aa9SJames Smart **/ 45117ad20aa9SJames Smart static int 451275cc8cfcSJohannes Thumshirn lpfc_bsg_handle_sli_cfg_ebuf(struct lpfc_hba *phba, struct bsg_job *job, 45137ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 45147ad20aa9SJames Smart { 45157ad20aa9SJames Smart int rc; 45167ad20aa9SJames Smart 45177ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 45187ad20aa9SJames Smart "2971 SLI_CONFIG buffer (type:x%x)\n", 45197ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType); 45207ad20aa9SJames Smart 45217ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.mboxType == mbox_rd) { 45227ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state != LPFC_BSG_MBOX_DONE) { 45237ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 45247ad20aa9SJames Smart "2972 SLI_CONFIG rd buffer state " 45257ad20aa9SJames Smart "mismatch:x%x\n", 45267ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state); 45277ad20aa9SJames Smart lpfc_bsg_mbox_ext_abort(phba); 45287ad20aa9SJames Smart return -EPIPE; 45297ad20aa9SJames Smart } 45307ad20aa9SJames Smart rc = lpfc_bsg_read_ebuf_get(phba, job); 45317ad20aa9SJames Smart if (rc == SLI_CONFIG_HANDLED) 45327ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 45337ad20aa9SJames Smart } else { /* phba->mbox_ext_buf_ctx.mboxType == mbox_wr */ 45347ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state != LPFC_BSG_MBOX_HOST) { 45357ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 45367ad20aa9SJames Smart "2973 SLI_CONFIG wr buffer state " 45377ad20aa9SJames Smart "mismatch:x%x\n", 45387ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state); 45397ad20aa9SJames Smart lpfc_bsg_mbox_ext_abort(phba); 45407ad20aa9SJames Smart return -EPIPE; 45417ad20aa9SJames Smart } 45427ad20aa9SJames Smart rc = lpfc_bsg_write_ebuf_set(phba, job, dmabuf); 45437ad20aa9SJames Smart } 45447ad20aa9SJames Smart return rc; 45457ad20aa9SJames Smart } 45467ad20aa9SJames Smart 45477ad20aa9SJames Smart /** 45487ad20aa9SJames Smart * lpfc_bsg_handle_sli_cfg_ext - handle sli-cfg mailbox with external buffer 45497ad20aa9SJames Smart * @phba: Pointer to HBA context object. 4550ea085dabSLee Jones * @job: Pointer to the job object. 4551ea085dabSLee Jones * @dmabuf: Pointer to a DMA buffer descriptor. 45527ad20aa9SJames Smart * 45533bfab8a0SJames Smart * This routine checks and handles non-embedded multi-buffer SLI_CONFIG 45547ad20aa9SJames Smart * (0x9B) mailbox commands and external buffers. 45557ad20aa9SJames Smart **/ 45567ad20aa9SJames Smart static int 455775cc8cfcSJohannes Thumshirn lpfc_bsg_handle_sli_cfg_ext(struct lpfc_hba *phba, struct bsg_job *job, 45587ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 45597ad20aa9SJames Smart { 456001e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 45617ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 456288a2cfbbSJames Smart int rc = SLI_CONFIG_NOT_HANDLED; 45637ad20aa9SJames Smart 45647ad20aa9SJames Smart mbox_req = 456501e0e15cSJohannes Thumshirn (struct dfc_mbox_req *)bsg_request->rqst_data.h_vendor.vendor_cmd; 45667ad20aa9SJames Smart 45677ad20aa9SJames Smart /* mbox command with/without single external buffer */ 45687ad20aa9SJames Smart if (mbox_req->extMboxTag == 0 && mbox_req->extSeqNum == 0) 456988a2cfbbSJames Smart return rc; 45707ad20aa9SJames Smart 45717ad20aa9SJames Smart /* mbox command and first external buffer */ 45727ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_IDLE) { 45737ad20aa9SJames Smart if (mbox_req->extSeqNum == 1) { 45747ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 45757ad20aa9SJames Smart "2974 SLI_CONFIG mailbox: tag:%d, " 45767ad20aa9SJames Smart "seq:%d\n", mbox_req->extMboxTag, 45777ad20aa9SJames Smart mbox_req->extSeqNum); 45787ad20aa9SJames Smart rc = lpfc_bsg_handle_sli_cfg_mbox(phba, job, dmabuf); 45797ad20aa9SJames Smart return rc; 45807ad20aa9SJames Smart } else 45817ad20aa9SJames Smart goto sli_cfg_ext_error; 45827ad20aa9SJames Smart } 45837ad20aa9SJames Smart 45847ad20aa9SJames Smart /* 45857ad20aa9SJames Smart * handle additional external buffers 45867ad20aa9SJames Smart */ 45877ad20aa9SJames Smart 45887ad20aa9SJames Smart /* check broken pipe conditions */ 45897ad20aa9SJames Smart if (mbox_req->extMboxTag != phba->mbox_ext_buf_ctx.mbxTag) 45907ad20aa9SJames Smart goto sli_cfg_ext_error; 45917ad20aa9SJames Smart if (mbox_req->extSeqNum > phba->mbox_ext_buf_ctx.numBuf) 45927ad20aa9SJames Smart goto sli_cfg_ext_error; 45937ad20aa9SJames Smart if (mbox_req->extSeqNum != phba->mbox_ext_buf_ctx.seqNum + 1) 45947ad20aa9SJames Smart goto sli_cfg_ext_error; 45957ad20aa9SJames Smart 45967ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 45977ad20aa9SJames Smart "2975 SLI_CONFIG mailbox external buffer: " 45987ad20aa9SJames Smart "extSta:x%x, tag:%d, seq:%d\n", 45997ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state, mbox_req->extMboxTag, 46007ad20aa9SJames Smart mbox_req->extSeqNum); 46017ad20aa9SJames Smart rc = lpfc_bsg_handle_sli_cfg_ebuf(phba, job, dmabuf); 46027ad20aa9SJames Smart return rc; 46037ad20aa9SJames Smart 46047ad20aa9SJames Smart sli_cfg_ext_error: 46057ad20aa9SJames Smart /* all other cases, broken pipe */ 46067ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 46077ad20aa9SJames Smart "2976 SLI_CONFIG mailbox broken pipe: " 46087ad20aa9SJames Smart "ctxSta:x%x, ctxNumBuf:%d " 46097ad20aa9SJames Smart "ctxTag:%d, ctxSeq:%d, tag:%d, seq:%d\n", 46107ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state, 46117ad20aa9SJames Smart phba->mbox_ext_buf_ctx.numBuf, 46127ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbxTag, 46137ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum, 46147ad20aa9SJames Smart mbox_req->extMboxTag, mbox_req->extSeqNum); 46157ad20aa9SJames Smart 46167ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 46177ad20aa9SJames Smart 46187ad20aa9SJames Smart return -EPIPE; 46197ad20aa9SJames Smart } 46207ad20aa9SJames Smart 46217ad20aa9SJames Smart /** 46223b5dd52aSJames Smart * lpfc_bsg_issue_mbox - issues a mailbox command on behalf of an app 46233b5dd52aSJames Smart * @phba: Pointer to HBA context object. 4624ea085dabSLee Jones * @job: Pointer to the job object. 46253b5dd52aSJames Smart * @vport: Pointer to a vport object. 46263b5dd52aSJames Smart * 46273b5dd52aSJames Smart * Allocate a tracking object, mailbox command memory, get a mailbox 46283b5dd52aSJames Smart * from the mailbox pool, copy the caller mailbox command. 46293b5dd52aSJames Smart * 46303b5dd52aSJames Smart * If offline and the sli is active we need to poll for the command (port is 46313bfab8a0SJames Smart * being reset) and complete the job, otherwise issue the mailbox command and 46323b5dd52aSJames Smart * let our completion handler finish the command. 46333b5dd52aSJames Smart **/ 4634a2fc4aefSJames Smart static int 463575cc8cfcSJohannes Thumshirn lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct bsg_job *job, 46363b5dd52aSJames Smart struct lpfc_vport *vport) 46373b5dd52aSJames Smart { 463801e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 463901e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 46407a470277SJames Smart LPFC_MBOXQ_t *pmboxq = NULL; /* internal mailbox queue */ 46417a470277SJames Smart MAILBOX_t *pmb; /* shortcut to the pmboxq mailbox */ 46427a470277SJames Smart /* a 4k buffer to hold the mb and extended data from/to the bsg */ 46437ad20aa9SJames Smart uint8_t *pmbx = NULL; 46447a470277SJames Smart struct bsg_job_data *dd_data = NULL; /* bsg data tracking structure */ 46457ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf = NULL; 46467ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 4647b6e3b9c6SJames Smart struct READ_EVENT_LOG_VAR *rdEventLog; 4648b6e3b9c6SJames Smart uint32_t transmit_length, receive_length, mode; 46497ad20aa9SJames Smart struct lpfc_mbx_sli4_config *sli4_config; 4650b6e3b9c6SJames Smart struct lpfc_mbx_nembed_cmd *nembed_sge; 4651b6e3b9c6SJames Smart struct ulp_bde64 *bde; 46527a470277SJames Smart uint8_t *ext = NULL; 46533b5dd52aSJames Smart int rc = 0; 46547a470277SJames Smart uint8_t *from; 46557ad20aa9SJames Smart uint32_t size; 46567ad20aa9SJames Smart 46577a470277SJames Smart /* in case no data is transferred */ 465801e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 46597a470277SJames Smart 4660b6e3b9c6SJames Smart /* sanity check to protect driver */ 4661b6e3b9c6SJames Smart if (job->reply_payload.payload_len > BSG_MBOX_SIZE || 4662b6e3b9c6SJames Smart job->request_payload.payload_len > BSG_MBOX_SIZE) { 4663b6e3b9c6SJames Smart rc = -ERANGE; 4664b6e3b9c6SJames Smart goto job_done; 4665b6e3b9c6SJames Smart } 4666b6e3b9c6SJames Smart 46677ad20aa9SJames Smart /* 46687ad20aa9SJames Smart * Don't allow mailbox commands to be sent when blocked or when in 46697ad20aa9SJames Smart * the middle of discovery 46707ad20aa9SJames Smart */ 46717ad20aa9SJames Smart if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { 46727ad20aa9SJames Smart rc = -EAGAIN; 46737ad20aa9SJames Smart goto job_done; 46747ad20aa9SJames Smart } 46757ad20aa9SJames Smart 46767ad20aa9SJames Smart mbox_req = 467701e0e15cSJohannes Thumshirn (struct dfc_mbox_req *)bsg_request->rqst_data.h_vendor.vendor_cmd; 46787ad20aa9SJames Smart 46797a470277SJames Smart /* check if requested extended data lengths are valid */ 4680b6e3b9c6SJames Smart if ((mbox_req->inExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t)) || 4681b6e3b9c6SJames Smart (mbox_req->outExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t))) { 46827a470277SJames Smart rc = -ERANGE; 46837a470277SJames Smart goto job_done; 46847a470277SJames Smart } 46853b5dd52aSJames Smart 46867ad20aa9SJames Smart dmabuf = lpfc_bsg_dma_page_alloc(phba); 46877ad20aa9SJames Smart if (!dmabuf || !dmabuf->virt) { 46887ad20aa9SJames Smart rc = -ENOMEM; 46897ad20aa9SJames Smart goto job_done; 46907ad20aa9SJames Smart } 46917ad20aa9SJames Smart 46927ad20aa9SJames Smart /* Get the mailbox command or external buffer from BSG */ 46937ad20aa9SJames Smart pmbx = (uint8_t *)dmabuf->virt; 46947ad20aa9SJames Smart size = job->request_payload.payload_len; 46957ad20aa9SJames Smart sg_copy_to_buffer(job->request_payload.sg_list, 46967ad20aa9SJames Smart job->request_payload.sg_cnt, pmbx, size); 46977ad20aa9SJames Smart 46987ad20aa9SJames Smart /* Handle possible SLI_CONFIG with non-embedded payloads */ 46997ad20aa9SJames Smart if (phba->sli_rev == LPFC_SLI_REV4) { 47007ad20aa9SJames Smart rc = lpfc_bsg_handle_sli_cfg_ext(phba, job, dmabuf); 47017ad20aa9SJames Smart if (rc == SLI_CONFIG_HANDLED) 47027ad20aa9SJames Smart goto job_cont; 47037ad20aa9SJames Smart if (rc) 47047ad20aa9SJames Smart goto job_done; 47057ad20aa9SJames Smart /* SLI_CONFIG_NOT_HANDLED for other mailbox commands */ 47067ad20aa9SJames Smart } 47077ad20aa9SJames Smart 47087ad20aa9SJames Smart rc = lpfc_bsg_check_cmd_access(phba, (MAILBOX_t *)pmbx, vport); 47097ad20aa9SJames Smart if (rc != 0) 47107ad20aa9SJames Smart goto job_done; /* must be negative */ 47117ad20aa9SJames Smart 47123b5dd52aSJames Smart /* allocate our bsg tracking structure */ 47133b5dd52aSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 47143b5dd52aSJames Smart if (!dd_data) { 47153b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 47163b5dd52aSJames Smart "2727 Failed allocation of dd_data\n"); 47177a470277SJames Smart rc = -ENOMEM; 47187a470277SJames Smart goto job_done; 47193b5dd52aSJames Smart } 47203b5dd52aSJames Smart 47213b5dd52aSJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 47223b5dd52aSJames Smart if (!pmboxq) { 47237a470277SJames Smart rc = -ENOMEM; 47247a470277SJames Smart goto job_done; 47253b5dd52aSJames Smart } 47267a470277SJames Smart memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 47273b5dd52aSJames Smart 47283b5dd52aSJames Smart pmb = &pmboxq->u.mb; 47297ad20aa9SJames Smart memcpy(pmb, pmbx, sizeof(*pmb)); 47303b5dd52aSJames Smart pmb->mbxOwner = OWN_HOST; 47313b5dd52aSJames Smart pmboxq->vport = vport; 47323b5dd52aSJames Smart 4733c7495937SJames Smart /* If HBA encountered an error attention, allow only DUMP 4734c7495937SJames Smart * or RESTART mailbox commands until the HBA is restarted. 4735c7495937SJames Smart */ 4736c7495937SJames Smart if (phba->pport->stopped && 4737c7495937SJames Smart pmb->mbxCommand != MBX_DUMP_MEMORY && 4738c7495937SJames Smart pmb->mbxCommand != MBX_RESTART && 4739c7495937SJames Smart pmb->mbxCommand != MBX_WRITE_VPARMS && 4740c7495937SJames Smart pmb->mbxCommand != MBX_WRITE_WWN) 4741c7495937SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, 4742c7495937SJames Smart "2797 mbox: Issued mailbox cmd " 4743c7495937SJames Smart "0x%x while in stopped state.\n", 4744c7495937SJames Smart pmb->mbxCommand); 4745c7495937SJames Smart 47467a470277SJames Smart /* extended mailbox commands will need an extended buffer */ 4747c7495937SJames Smart if (mbox_req->inExtWLen || mbox_req->outExtWLen) { 47487ad20aa9SJames Smart from = pmbx; 47497ad20aa9SJames Smart ext = from + sizeof(MAILBOX_t); 4750115d137aSJustin Tee pmboxq->ext_buf = ext; 47517a470277SJames Smart pmboxq->in_ext_byte_len = 47527a470277SJames Smart mbox_req->inExtWLen * sizeof(uint32_t); 47537a470277SJames Smart pmboxq->out_ext_byte_len = 4754c7495937SJames Smart mbox_req->outExtWLen * sizeof(uint32_t); 47557a470277SJames Smart pmboxq->mbox_offset_word = mbox_req->mbOffset; 47567a470277SJames Smart } 47577a470277SJames Smart 47587a470277SJames Smart /* biu diag will need a kernel buffer to transfer the data 47597a470277SJames Smart * allocate our own buffer and setup the mailbox command to 47607a470277SJames Smart * use ours 47617a470277SJames Smart */ 47627a470277SJames Smart if (pmb->mbxCommand == MBX_RUN_BIU_DIAG64) { 4763b6e3b9c6SJames Smart transmit_length = pmb->un.varWords[1]; 4764b6e3b9c6SJames Smart receive_length = pmb->un.varWords[4]; 4765c7495937SJames Smart /* transmit length cannot be greater than receive length or 4766c7495937SJames Smart * mailbox extension size 4767c7495937SJames Smart */ 4768c7495937SJames Smart if ((transmit_length > receive_length) || 476988a2cfbbSJames Smart (transmit_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t))) { 4770c7495937SJames Smart rc = -ERANGE; 4771c7495937SJames Smart goto job_done; 4772c7495937SJames Smart } 47737a470277SJames Smart pmb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh = 47747ad20aa9SJames Smart putPaddrHigh(dmabuf->phys + sizeof(MAILBOX_t)); 47757a470277SJames Smart pmb->un.varBIUdiag.un.s2.xmit_bde64.addrLow = 47767ad20aa9SJames Smart putPaddrLow(dmabuf->phys + sizeof(MAILBOX_t)); 47777a470277SJames Smart 47787a470277SJames Smart pmb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh = 47797ad20aa9SJames Smart putPaddrHigh(dmabuf->phys + sizeof(MAILBOX_t) 47807ad20aa9SJames Smart + pmb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize); 47817a470277SJames Smart pmb->un.varBIUdiag.un.s2.rcv_bde64.addrLow = 47827ad20aa9SJames Smart putPaddrLow(dmabuf->phys + sizeof(MAILBOX_t) 47837ad20aa9SJames Smart + pmb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize); 4784c7495937SJames Smart } else if (pmb->mbxCommand == MBX_READ_EVENT_LOG) { 4785b6e3b9c6SJames Smart rdEventLog = &pmb->un.varRdEventLog; 4786b6e3b9c6SJames Smart receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize; 4787b6e3b9c6SJames Smart mode = bf_get(lpfc_event_log, rdEventLog); 4788c7495937SJames Smart 4789c7495937SJames Smart /* receive length cannot be greater than mailbox 4790c7495937SJames Smart * extension size 4791c7495937SJames Smart */ 479288a2cfbbSJames Smart if (receive_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t)) { 4793c7495937SJames Smart rc = -ERANGE; 4794c7495937SJames Smart goto job_done; 4795c7495937SJames Smart } 4796c7495937SJames Smart 4797c7495937SJames Smart /* mode zero uses a bde like biu diags command */ 4798c7495937SJames Smart if (mode == 0) { 47997ad20aa9SJames Smart pmb->un.varWords[3] = putPaddrLow(dmabuf->phys 48007ad20aa9SJames Smart + sizeof(MAILBOX_t)); 48017ad20aa9SJames Smart pmb->un.varWords[4] = putPaddrHigh(dmabuf->phys 48027ad20aa9SJames Smart + sizeof(MAILBOX_t)); 4803c7495937SJames Smart } 4804c7495937SJames Smart } else if (phba->sli_rev == LPFC_SLI_REV4) { 48053ef6d24cSJames Smart /* Let type 4 (well known data) through because the data is 48063ef6d24cSJames Smart * returned in varwords[4-8] 48073ef6d24cSJames Smart * otherwise check the recieve length and fetch the buffer addr 48083ef6d24cSJames Smart */ 48093ef6d24cSJames Smart if ((pmb->mbxCommand == MBX_DUMP_MEMORY) && 48103ef6d24cSJames Smart (pmb->un.varDmp.type != DMP_WELL_KNOWN)) { 4811c7495937SJames Smart /* rebuild the command for sli4 using our own buffers 4812c7495937SJames Smart * like we do for biu diags 4813c7495937SJames Smart */ 4814b6e3b9c6SJames Smart receive_length = pmb->un.varWords[2]; 4815c7495937SJames Smart /* receive length cannot be greater than mailbox 4816c7495937SJames Smart * extension size 4817c7495937SJames Smart */ 48187ad20aa9SJames Smart if (receive_length == 0) { 4819c7495937SJames Smart rc = -ERANGE; 4820c7495937SJames Smart goto job_done; 4821c7495937SJames Smart } 48227ad20aa9SJames Smart pmb->un.varWords[3] = putPaddrLow(dmabuf->phys 48237ad20aa9SJames Smart + sizeof(MAILBOX_t)); 48247ad20aa9SJames Smart pmb->un.varWords[4] = putPaddrHigh(dmabuf->phys 48257ad20aa9SJames Smart + sizeof(MAILBOX_t)); 4826c7495937SJames Smart } else if ((pmb->mbxCommand == MBX_UPDATE_CFG) && 4827c7495937SJames Smart pmb->un.varUpdateCfg.co) { 4828b6e3b9c6SJames Smart bde = (struct ulp_bde64 *)&pmb->un.varWords[4]; 4829c7495937SJames Smart 4830c7495937SJames Smart /* bde size cannot be greater than mailbox ext size */ 483188a2cfbbSJames Smart if (bde->tus.f.bdeSize > 483288a2cfbbSJames Smart BSG_MBOX_SIZE - sizeof(MAILBOX_t)) { 4833c7495937SJames Smart rc = -ERANGE; 4834c7495937SJames Smart goto job_done; 4835c7495937SJames Smart } 48367ad20aa9SJames Smart bde->addrHigh = putPaddrHigh(dmabuf->phys 48377ad20aa9SJames Smart + sizeof(MAILBOX_t)); 48387ad20aa9SJames Smart bde->addrLow = putPaddrLow(dmabuf->phys 48397ad20aa9SJames Smart + sizeof(MAILBOX_t)); 4840515e0aa2SJames Smart } else if (pmb->mbxCommand == MBX_SLI4_CONFIG) { 48417ad20aa9SJames Smart /* Handling non-embedded SLI_CONFIG mailbox command */ 48427ad20aa9SJames Smart sli4_config = &pmboxq->u.mqe.un.sli4_config; 48437ad20aa9SJames Smart if (!bf_get(lpfc_mbox_hdr_emb, 48447ad20aa9SJames Smart &sli4_config->header.cfg_mhdr)) { 48457ad20aa9SJames Smart /* rebuild the command for sli4 using our 48467ad20aa9SJames Smart * own buffers like we do for biu diags 4847515e0aa2SJames Smart */ 4848515e0aa2SJames Smart nembed_sge = (struct lpfc_mbx_nembed_cmd *) 4849515e0aa2SJames Smart &pmb->un.varWords[0]; 4850515e0aa2SJames Smart receive_length = nembed_sge->sge[0].length; 4851515e0aa2SJames Smart 48527ad20aa9SJames Smart /* receive length cannot be greater than 48537ad20aa9SJames Smart * mailbox extension size 4854515e0aa2SJames Smart */ 4855515e0aa2SJames Smart if ((receive_length == 0) || 485688a2cfbbSJames Smart (receive_length > 485788a2cfbbSJames Smart BSG_MBOX_SIZE - sizeof(MAILBOX_t))) { 4858515e0aa2SJames Smart rc = -ERANGE; 4859515e0aa2SJames Smart goto job_done; 4860515e0aa2SJames Smart } 4861515e0aa2SJames Smart 48627ad20aa9SJames Smart nembed_sge->sge[0].pa_hi = 48637ad20aa9SJames Smart putPaddrHigh(dmabuf->phys 48647ad20aa9SJames Smart + sizeof(MAILBOX_t)); 48657ad20aa9SJames Smart nembed_sge->sge[0].pa_lo = 48667ad20aa9SJames Smart putPaddrLow(dmabuf->phys 48677ad20aa9SJames Smart + sizeof(MAILBOX_t)); 4868515e0aa2SJames Smart } 4869c7495937SJames Smart } 4870c7495937SJames Smart } 4871c7495937SJames Smart 48727ad20aa9SJames Smart dd_data->context_un.mbox.dmabuffers = dmabuf; 48733b5dd52aSJames Smart 48743b5dd52aSJames Smart /* setup wake call as IOCB callback */ 48757ad20aa9SJames Smart pmboxq->mbox_cmpl = lpfc_bsg_issue_mbox_cmpl; 48767a470277SJames Smart 48773b5dd52aSJames Smart /* setup context field to pass wait_queue pointer to wake function */ 487885d77f91SJustin Tee pmboxq->ctx_u.dd_data = dd_data; 48793b5dd52aSJames Smart dd_data->type = TYPE_MBOX; 4880a33c4f7bSJames Smart dd_data->set_job = job; 48813b5dd52aSJames Smart dd_data->context_un.mbox.pmboxq = pmboxq; 48827ad20aa9SJames Smart dd_data->context_un.mbox.mb = (MAILBOX_t *)pmbx; 48837a470277SJames Smart dd_data->context_un.mbox.ext = ext; 48847a470277SJames Smart dd_data->context_un.mbox.mbOffset = mbox_req->mbOffset; 48857a470277SJames Smart dd_data->context_un.mbox.inExtWLen = mbox_req->inExtWLen; 4886c7495937SJames Smart dd_data->context_un.mbox.outExtWLen = mbox_req->outExtWLen; 48873b5dd52aSJames Smart job->dd_data = dd_data; 48887a470277SJames Smart 4889a645b8c1SJustin Tee if (test_bit(FC_OFFLINE_MODE, &vport->fc_flag) || 48907a470277SJames Smart (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { 48917a470277SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); 48927a470277SJames Smart if (rc != MBX_SUCCESS) { 48937a470277SJames Smart rc = (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; 48947a470277SJames Smart goto job_done; 48953b5dd52aSJames Smart } 48963b5dd52aSJames Smart 48977a470277SJames Smart /* job finished, copy the data */ 48987ad20aa9SJames Smart memcpy(pmbx, pmb, sizeof(*pmb)); 489901e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 49007a470277SJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 49017a470277SJames Smart job->reply_payload.sg_cnt, 49027ad20aa9SJames Smart pmbx, size); 49037a470277SJames Smart /* not waiting mbox already done */ 49047a470277SJames Smart rc = 0; 49057a470277SJames Smart goto job_done; 49067a470277SJames Smart } 49077a470277SJames Smart 49087a470277SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); 49097a470277SJames Smart if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) 49107a470277SJames Smart return 1; /* job started */ 49117a470277SJames Smart 49127a470277SJames Smart job_done: 49137a470277SJames Smart /* common exit for error or job completed inline */ 49147a470277SJames Smart if (pmboxq) 49157a470277SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 49167ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 49177a470277SJames Smart kfree(dd_data); 49187a470277SJames Smart 49197ad20aa9SJames Smart job_cont: 49207a470277SJames Smart return rc; 49213b5dd52aSJames Smart } 49223b5dd52aSJames Smart 49233b5dd52aSJames Smart /** 49243b5dd52aSJames Smart * lpfc_bsg_mbox_cmd - process an fc bsg LPFC_BSG_VENDOR_MBOX command 49253b5dd52aSJames Smart * @job: MBOX fc_bsg_job for LPFC_BSG_VENDOR_MBOX. 49263b5dd52aSJames Smart **/ 49273b5dd52aSJames Smart static int 492875cc8cfcSJohannes Thumshirn lpfc_bsg_mbox_cmd(struct bsg_job *job) 49293b5dd52aSJames Smart { 4930cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 493101e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 493201e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 49333b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 49347ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 49353b5dd52aSJames Smart int rc = 0; 49363b5dd52aSJames Smart 49377ad20aa9SJames Smart /* mix-and-match backward compatibility */ 493801e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 49393b5dd52aSJames Smart if (job->request_len < 49403b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct dfc_mbox_req)) { 49417ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 49421051e9b3SMasanari Iida "2737 Mix-and-match backward compatibility " 49437ad20aa9SJames Smart "between MBOX_REQ old size:%d and " 49447ad20aa9SJames Smart "new request size:%d\n", 49457ad20aa9SJames Smart (int)(job->request_len - 49467ad20aa9SJames Smart sizeof(struct fc_bsg_request)), 49477ad20aa9SJames Smart (int)sizeof(struct dfc_mbox_req)); 49487ad20aa9SJames Smart mbox_req = (struct dfc_mbox_req *) 494901e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 49507ad20aa9SJames Smart mbox_req->extMboxTag = 0; 49517ad20aa9SJames Smart mbox_req->extSeqNum = 0; 49523b5dd52aSJames Smart } 49533b5dd52aSJames Smart 49543b5dd52aSJames Smart rc = lpfc_bsg_issue_mbox(phba, job, vport); 49553b5dd52aSJames Smart 49563b5dd52aSJames Smart if (rc == 0) { 49573b5dd52aSJames Smart /* job done */ 495801e0e15cSJohannes Thumshirn bsg_reply->result = 0; 49593b5dd52aSJames Smart job->dd_data = NULL; 496006548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 49611abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 49623b5dd52aSJames Smart } else if (rc == 1) 49633b5dd52aSJames Smart /* job submitted, will complete later*/ 49643b5dd52aSJames Smart rc = 0; /* return zero, no error */ 49653b5dd52aSJames Smart else { 49663b5dd52aSJames Smart /* some error occurred */ 496701e0e15cSJohannes Thumshirn bsg_reply->result = rc; 49683b5dd52aSJames Smart job->dd_data = NULL; 49693b5dd52aSJames Smart } 49703b5dd52aSJames Smart 49713b5dd52aSJames Smart return rc; 49723b5dd52aSJames Smart } 49733b5dd52aSJames Smart 4974c691816eSJames Smart static int 497575cc8cfcSJohannes Thumshirn lpfc_forced_link_speed(struct bsg_job *job) 4976c691816eSJames Smart { 4977cd21c605SJohannes Thumshirn struct Scsi_Host *shost = fc_bsg_to_shost(job); 4978c691816eSJames Smart struct lpfc_vport *vport = shost_priv(shost); 4979c691816eSJames Smart struct lpfc_hba *phba = vport->phba; 498001e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 4981c691816eSJames Smart struct forced_link_speed_support_reply *forced_reply; 4982c691816eSJames Smart int rc = 0; 4983c691816eSJames Smart 4984c691816eSJames Smart if (job->request_len < 4985c691816eSJames Smart sizeof(struct fc_bsg_request) + 4986c691816eSJames Smart sizeof(struct get_forced_link_speed_support)) { 4987c691816eSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 4988c691816eSJames Smart "0048 Received FORCED_LINK_SPEED request " 4989c691816eSJames Smart "below minimum size\n"); 4990c691816eSJames Smart rc = -EINVAL; 4991c691816eSJames Smart goto job_error; 4992c691816eSJames Smart } 4993c691816eSJames Smart 4994c691816eSJames Smart forced_reply = (struct forced_link_speed_support_reply *) 499501e0e15cSJohannes Thumshirn bsg_reply->reply_data.vendor_reply.vendor_rsp; 4996c691816eSJames Smart 4997feb3cc57SDick Kennedy if (job->reply_len < sizeof(*bsg_reply) + sizeof(*forced_reply)) { 4998c691816eSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 4999c691816eSJames Smart "0049 Received FORCED_LINK_SPEED reply below " 5000c691816eSJames Smart "minimum size\n"); 5001c691816eSJames Smart rc = -EINVAL; 5002c691816eSJames Smart goto job_error; 5003c691816eSJames Smart } 5004c691816eSJames Smart 5005e780c942SJustin Tee forced_reply->supported = test_bit(HBA_FORCED_LINK_SPEED, 5006e780c942SJustin Tee &phba->hba_flag) 5007c691816eSJames Smart ? LPFC_FORCED_LINK_SPEED_SUPPORTED 5008c691816eSJames Smart : LPFC_FORCED_LINK_SPEED_NOT_SUPPORTED; 5009c691816eSJames Smart job_error: 501001e0e15cSJohannes Thumshirn bsg_reply->result = rc; 5011c691816eSJames Smart if (rc == 0) 501206548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 50131abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 5014c691816eSJames Smart return rc; 5015c691816eSJames Smart } 5016c691816eSJames Smart 5017e2aed29fSJames Smart /** 5018d2cc9bcdSJames Smart * lpfc_check_fwlog_support: Check FW log support on the adapter 5019d2cc9bcdSJames Smart * @phba: Pointer to HBA context object. 5020d2cc9bcdSJames Smart * 5021d2cc9bcdSJames Smart * Check if FW Logging support by the adapter 5022d2cc9bcdSJames Smart **/ 5023d2cc9bcdSJames Smart int 5024d2cc9bcdSJames Smart lpfc_check_fwlog_support(struct lpfc_hba *phba) 5025d2cc9bcdSJames Smart { 5026d2cc9bcdSJames Smart struct lpfc_ras_fwlog *ras_fwlog = NULL; 5027d2cc9bcdSJames Smart 5028d2cc9bcdSJames Smart ras_fwlog = &phba->ras_fwlog; 5029d2cc9bcdSJames Smart 5030af0c94afSYANG LI if (!ras_fwlog->ras_hwsupport) 5031d2cc9bcdSJames Smart return -EACCES; 5032af0c94afSYANG LI else if (!ras_fwlog->ras_enabled) 5033d2cc9bcdSJames Smart return -EPERM; 5034d2cc9bcdSJames Smart else 5035d2cc9bcdSJames Smart return 0; 5036d2cc9bcdSJames Smart } 5037d2cc9bcdSJames Smart 5038d2cc9bcdSJames Smart /** 5039d2cc9bcdSJames Smart * lpfc_bsg_get_ras_config: Get RAS configuration settings 5040d2cc9bcdSJames Smart * @job: fc_bsg_job to handle 5041d2cc9bcdSJames Smart * 5042d2cc9bcdSJames Smart * Get RAS configuration values set. 5043d2cc9bcdSJames Smart **/ 5044d2cc9bcdSJames Smart static int 5045d2cc9bcdSJames Smart lpfc_bsg_get_ras_config(struct bsg_job *job) 5046d2cc9bcdSJames Smart { 5047d2cc9bcdSJames Smart struct Scsi_Host *shost = fc_bsg_to_shost(job); 5048d2cc9bcdSJames Smart struct lpfc_vport *vport = shost_priv(shost); 5049d2cc9bcdSJames Smart struct fc_bsg_reply *bsg_reply = job->reply; 5050d2cc9bcdSJames Smart struct lpfc_hba *phba = vport->phba; 5051d2cc9bcdSJames Smart struct lpfc_bsg_get_ras_config_reply *ras_reply; 5052d2cc9bcdSJames Smart struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog; 5053d2cc9bcdSJames Smart int rc = 0; 5054d2cc9bcdSJames Smart 5055d2cc9bcdSJames Smart if (job->request_len < 5056d2cc9bcdSJames Smart sizeof(struct fc_bsg_request) + 5057d2cc9bcdSJames Smart sizeof(struct lpfc_bsg_ras_req)) { 5058d2cc9bcdSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 5059cb34990bSJames Smart "6192 FW_LOG request received " 5060d2cc9bcdSJames Smart "below minimum size\n"); 5061d2cc9bcdSJames Smart rc = -EINVAL; 5062d2cc9bcdSJames Smart goto ras_job_error; 5063d2cc9bcdSJames Smart } 5064d2cc9bcdSJames Smart 5065d2cc9bcdSJames Smart /* Check FW log status */ 5066d2cc9bcdSJames Smart rc = lpfc_check_fwlog_support(phba); 5067cb34990bSJames Smart if (rc) 5068d2cc9bcdSJames Smart goto ras_job_error; 5069d2cc9bcdSJames Smart 5070d2cc9bcdSJames Smart ras_reply = (struct lpfc_bsg_get_ras_config_reply *) 5071d2cc9bcdSJames Smart bsg_reply->reply_data.vendor_reply.vendor_rsp; 5072d2cc9bcdSJames Smart 5073d2cc9bcdSJames Smart /* Current logging state */ 5074f733a76eSJustin Tee spin_lock_irq(&phba->ras_fwlog_lock); 507595bfc6d8SJames Smart if (ras_fwlog->state == ACTIVE) 5076d2cc9bcdSJames Smart ras_reply->state = LPFC_RASLOG_STATE_RUNNING; 5077d2cc9bcdSJames Smart else 5078d2cc9bcdSJames Smart ras_reply->state = LPFC_RASLOG_STATE_STOPPED; 5079f733a76eSJustin Tee spin_unlock_irq(&phba->ras_fwlog_lock); 5080d2cc9bcdSJames Smart 5081d2cc9bcdSJames Smart ras_reply->log_level = phba->ras_fwlog.fw_loglevel; 5082d2cc9bcdSJames Smart ras_reply->log_buff_sz = phba->cfg_ras_fwlog_buffsize; 5083d2cc9bcdSJames Smart 5084d2cc9bcdSJames Smart ras_job_error: 5085d2cc9bcdSJames Smart /* make error code available to userspace */ 5086d2cc9bcdSJames Smart bsg_reply->result = rc; 5087d2cc9bcdSJames Smart 5088d2cc9bcdSJames Smart /* complete the job back to userspace */ 50896db51abbSJames Smart if (!rc) 50906db51abbSJames Smart bsg_job_done(job, bsg_reply->result, 50916db51abbSJames Smart bsg_reply->reply_payload_rcv_len); 5092d2cc9bcdSJames Smart return rc; 5093d2cc9bcdSJames Smart } 5094d2cc9bcdSJames Smart 5095d2cc9bcdSJames Smart /** 5096d2cc9bcdSJames Smart * lpfc_bsg_set_ras_config: Set FW logging parameters 5097d2cc9bcdSJames Smart * @job: fc_bsg_job to handle 5098d2cc9bcdSJames Smart * 5099d2cc9bcdSJames Smart * Set log-level parameters for FW-logging in host memory 5100d2cc9bcdSJames Smart **/ 5101d2cc9bcdSJames Smart static int 5102d2cc9bcdSJames Smart lpfc_bsg_set_ras_config(struct bsg_job *job) 5103d2cc9bcdSJames Smart { 5104d2cc9bcdSJames Smart struct Scsi_Host *shost = fc_bsg_to_shost(job); 5105d2cc9bcdSJames Smart struct lpfc_vport *vport = shost_priv(shost); 5106d2cc9bcdSJames Smart struct lpfc_hba *phba = vport->phba; 5107d2cc9bcdSJames Smart struct lpfc_bsg_set_ras_config_req *ras_req; 5108d2cc9bcdSJames Smart struct fc_bsg_request *bsg_request = job->request; 5109d2cc9bcdSJames Smart struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog; 5110d2cc9bcdSJames Smart struct fc_bsg_reply *bsg_reply = job->reply; 5111d2cc9bcdSJames Smart uint8_t action = 0, log_level = 0; 5112191e2f74SJames Smart int rc = 0, action_status = 0; 5113d2cc9bcdSJames Smart 5114d2cc9bcdSJames Smart if (job->request_len < 5115d2cc9bcdSJames Smart sizeof(struct fc_bsg_request) + 5116d2cc9bcdSJames Smart sizeof(struct lpfc_bsg_set_ras_config_req)) { 5117d2cc9bcdSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 5118d2cc9bcdSJames Smart "6182 Received RAS_LOG request " 5119d2cc9bcdSJames Smart "below minimum size\n"); 5120d2cc9bcdSJames Smart rc = -EINVAL; 5121d2cc9bcdSJames Smart goto ras_job_error; 5122d2cc9bcdSJames Smart } 5123d2cc9bcdSJames Smart 5124d2cc9bcdSJames Smart /* Check FW log status */ 5125d2cc9bcdSJames Smart rc = lpfc_check_fwlog_support(phba); 5126cb34990bSJames Smart if (rc) 5127d2cc9bcdSJames Smart goto ras_job_error; 5128d2cc9bcdSJames Smart 5129d2cc9bcdSJames Smart ras_req = (struct lpfc_bsg_set_ras_config_req *) 5130d2cc9bcdSJames Smart bsg_request->rqst_data.h_vendor.vendor_cmd; 5131d2cc9bcdSJames Smart action = ras_req->action; 5132d2cc9bcdSJames Smart log_level = ras_req->log_level; 5133d2cc9bcdSJames Smart 5134d2cc9bcdSJames Smart if (action == LPFC_RASACTION_STOP_LOGGING) { 5135d2cc9bcdSJames Smart /* Check if already disabled */ 5136f733a76eSJustin Tee spin_lock_irq(&phba->ras_fwlog_lock); 513795bfc6d8SJames Smart if (ras_fwlog->state != ACTIVE) { 5138f733a76eSJustin Tee spin_unlock_irq(&phba->ras_fwlog_lock); 5139d2cc9bcdSJames Smart rc = -ESRCH; 5140d2cc9bcdSJames Smart goto ras_job_error; 5141d2cc9bcdSJames Smart } 5142f733a76eSJustin Tee spin_unlock_irq(&phba->ras_fwlog_lock); 5143d2cc9bcdSJames Smart 5144d2cc9bcdSJames Smart /* Disable logging */ 5145d2cc9bcdSJames Smart lpfc_ras_stop_fwlog(phba); 5146d2cc9bcdSJames Smart } else { 5147d2cc9bcdSJames Smart /*action = LPFC_RASACTION_START_LOGGING*/ 5148191e2f74SJames Smart 5149191e2f74SJames Smart /* Even though FW-logging is active re-initialize 5150191e2f74SJames Smart * FW-logging with new log-level. Return status 5151191e2f74SJames Smart * "Logging already Running" to caller. 5152191e2f74SJames Smart **/ 5153f733a76eSJustin Tee spin_lock_irq(&phba->ras_fwlog_lock); 515495bfc6d8SJames Smart if (ras_fwlog->state != INACTIVE) 5155191e2f74SJames Smart action_status = -EINPROGRESS; 5156f733a76eSJustin Tee spin_unlock_irq(&phba->ras_fwlog_lock); 5157d2cc9bcdSJames Smart 5158d2cc9bcdSJames Smart /* Enable logging */ 5159d2cc9bcdSJames Smart rc = lpfc_sli4_ras_fwlog_init(phba, log_level, 5160d2cc9bcdSJames Smart LPFC_RAS_ENABLE_LOGGING); 5161191e2f74SJames Smart if (rc) { 5162d2cc9bcdSJames Smart rc = -EINVAL; 5163191e2f74SJames Smart goto ras_job_error; 5164191e2f74SJames Smart } 5165191e2f74SJames Smart 5166191e2f74SJames Smart /* Check if FW-logging is re-initialized */ 5167191e2f74SJames Smart if (action_status == -EINPROGRESS) 5168191e2f74SJames Smart rc = action_status; 5169d2cc9bcdSJames Smart } 5170d2cc9bcdSJames Smart ras_job_error: 5171d2cc9bcdSJames Smart /* make error code available to userspace */ 5172d2cc9bcdSJames Smart bsg_reply->result = rc; 5173d2cc9bcdSJames Smart 5174d2cc9bcdSJames Smart /* complete the job back to userspace */ 51756db51abbSJames Smart if (!rc) 5176d2cc9bcdSJames Smart bsg_job_done(job, bsg_reply->result, 5177d2cc9bcdSJames Smart bsg_reply->reply_payload_rcv_len); 5178d2cc9bcdSJames Smart 5179d2cc9bcdSJames Smart return rc; 5180d2cc9bcdSJames Smart } 5181d2cc9bcdSJames Smart 5182d2cc9bcdSJames Smart /** 5183d2cc9bcdSJames Smart * lpfc_bsg_get_ras_lwpd: Get log write position data 5184d2cc9bcdSJames Smart * @job: fc_bsg_job to handle 5185d2cc9bcdSJames Smart * 5186d2cc9bcdSJames Smart * Get Offset/Wrap count of the log message written 5187d2cc9bcdSJames Smart * in host memory 5188d2cc9bcdSJames Smart **/ 5189d2cc9bcdSJames Smart static int 5190d2cc9bcdSJames Smart lpfc_bsg_get_ras_lwpd(struct bsg_job *job) 5191d2cc9bcdSJames Smart { 5192d2cc9bcdSJames Smart struct Scsi_Host *shost = fc_bsg_to_shost(job); 5193d2cc9bcdSJames Smart struct lpfc_vport *vport = shost_priv(shost); 5194d2cc9bcdSJames Smart struct lpfc_bsg_get_ras_lwpd *ras_reply; 5195d2cc9bcdSJames Smart struct lpfc_hba *phba = vport->phba; 5196d2cc9bcdSJames Smart struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog; 5197d2cc9bcdSJames Smart struct fc_bsg_reply *bsg_reply = job->reply; 5198191e2f74SJames Smart u32 *lwpd_ptr = NULL; 5199d2cc9bcdSJames Smart int rc = 0; 5200d2cc9bcdSJames Smart 5201d2cc9bcdSJames Smart rc = lpfc_check_fwlog_support(phba); 5202cb34990bSJames Smart if (rc) 5203d2cc9bcdSJames Smart goto ras_job_error; 5204d2cc9bcdSJames Smart 5205d2cc9bcdSJames Smart if (job->request_len < 5206d2cc9bcdSJames Smart sizeof(struct fc_bsg_request) + 5207d2cc9bcdSJames Smart sizeof(struct lpfc_bsg_ras_req)) { 5208d2cc9bcdSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 5209d2cc9bcdSJames Smart "6183 Received RAS_LOG request " 5210d2cc9bcdSJames Smart "below minimum size\n"); 5211d2cc9bcdSJames Smart rc = -EINVAL; 5212d2cc9bcdSJames Smart goto ras_job_error; 5213d2cc9bcdSJames Smart } 5214d2cc9bcdSJames Smart 5215d2cc9bcdSJames Smart ras_reply = (struct lpfc_bsg_get_ras_lwpd *) 5216d2cc9bcdSJames Smart bsg_reply->reply_data.vendor_reply.vendor_rsp; 5217d2cc9bcdSJames Smart 5218cb34990bSJames Smart if (!ras_fwlog->lwpd.virt) { 5219cb34990bSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 5220cb34990bSJames Smart "6193 Restart FW Logging\n"); 52211165a5c2SJames Smart rc = -EINVAL; 52221165a5c2SJames Smart goto ras_job_error; 5223cb34990bSJames Smart } 5224cb34990bSJames Smart 5225191e2f74SJames Smart /* Get lwpd offset */ 5226191e2f74SJames Smart lwpd_ptr = (uint32_t *)(ras_fwlog->lwpd.virt); 5227191e2f74SJames Smart ras_reply->offset = be32_to_cpu(*lwpd_ptr & 0xffffffff); 5228d2cc9bcdSJames Smart 5229191e2f74SJames Smart /* Get wrap count */ 5230191e2f74SJames Smart ras_reply->wrap_count = be32_to_cpu(*(++lwpd_ptr) & 0xffffffff); 5231d2cc9bcdSJames Smart 5232d2cc9bcdSJames Smart ras_job_error: 5233d2cc9bcdSJames Smart /* make error code available to userspace */ 5234d2cc9bcdSJames Smart bsg_reply->result = rc; 5235d2cc9bcdSJames Smart 5236d2cc9bcdSJames Smart /* complete the job back to userspace */ 52376db51abbSJames Smart if (!rc) 52386db51abbSJames Smart bsg_job_done(job, bsg_reply->result, 52396db51abbSJames Smart bsg_reply->reply_payload_rcv_len); 5240d2cc9bcdSJames Smart 5241d2cc9bcdSJames Smart return rc; 5242d2cc9bcdSJames Smart } 5243d2cc9bcdSJames Smart 5244d2cc9bcdSJames Smart /** 5245d2cc9bcdSJames Smart * lpfc_bsg_get_ras_fwlog: Read FW log 5246d2cc9bcdSJames Smart * @job: fc_bsg_job to handle 5247d2cc9bcdSJames Smart * 5248d2cc9bcdSJames Smart * Copy the FW log into the passed buffer. 5249d2cc9bcdSJames Smart **/ 5250d2cc9bcdSJames Smart static int 5251d2cc9bcdSJames Smart lpfc_bsg_get_ras_fwlog(struct bsg_job *job) 5252d2cc9bcdSJames Smart { 5253d2cc9bcdSJames Smart struct Scsi_Host *shost = fc_bsg_to_shost(job); 5254d2cc9bcdSJames Smart struct lpfc_vport *vport = shost_priv(shost); 5255d2cc9bcdSJames Smart struct lpfc_hba *phba = vport->phba; 5256d2cc9bcdSJames Smart struct fc_bsg_request *bsg_request = job->request; 5257d2cc9bcdSJames Smart struct fc_bsg_reply *bsg_reply = job->reply; 5258d2cc9bcdSJames Smart struct lpfc_bsg_get_fwlog_req *ras_req; 5259191e2f74SJames Smart u32 rd_offset, rd_index, offset; 5260191e2f74SJames Smart void *src, *fwlog_buff; 5261d2cc9bcdSJames Smart struct lpfc_ras_fwlog *ras_fwlog = NULL; 5262d2cc9bcdSJames Smart struct lpfc_dmabuf *dmabuf, *next; 5263d2cc9bcdSJames Smart int rc = 0; 5264d2cc9bcdSJames Smart 5265d2cc9bcdSJames Smart ras_fwlog = &phba->ras_fwlog; 5266d2cc9bcdSJames Smart 5267d2cc9bcdSJames Smart rc = lpfc_check_fwlog_support(phba); 5268cb34990bSJames Smart if (rc) 5269d2cc9bcdSJames Smart goto ras_job_error; 5270d2cc9bcdSJames Smart 5271d2cc9bcdSJames Smart /* Logging to be stopped before reading */ 5272f733a76eSJustin Tee spin_lock_irq(&phba->ras_fwlog_lock); 527395bfc6d8SJames Smart if (ras_fwlog->state == ACTIVE) { 5274f733a76eSJustin Tee spin_unlock_irq(&phba->ras_fwlog_lock); 5275d2cc9bcdSJames Smart rc = -EINPROGRESS; 5276d2cc9bcdSJames Smart goto ras_job_error; 5277d2cc9bcdSJames Smart } 5278f733a76eSJustin Tee spin_unlock_irq(&phba->ras_fwlog_lock); 5279d2cc9bcdSJames Smart 5280d2cc9bcdSJames Smart if (job->request_len < 5281d2cc9bcdSJames Smart sizeof(struct fc_bsg_request) + 5282d2cc9bcdSJames Smart sizeof(struct lpfc_bsg_get_fwlog_req)) { 5283d2cc9bcdSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 5284d2cc9bcdSJames Smart "6184 Received RAS_LOG request " 5285d2cc9bcdSJames Smart "below minimum size\n"); 5286d2cc9bcdSJames Smart rc = -EINVAL; 5287d2cc9bcdSJames Smart goto ras_job_error; 5288d2cc9bcdSJames Smart } 5289d2cc9bcdSJames Smart 5290d2cc9bcdSJames Smart ras_req = (struct lpfc_bsg_get_fwlog_req *) 5291d2cc9bcdSJames Smart bsg_request->rqst_data.h_vendor.vendor_cmd; 5292d2cc9bcdSJames Smart rd_offset = ras_req->read_offset; 5293d2cc9bcdSJames Smart 5294d2cc9bcdSJames Smart /* Allocate memory to read fw log*/ 5295d2cc9bcdSJames Smart fwlog_buff = vmalloc(ras_req->read_size); 5296d2cc9bcdSJames Smart if (!fwlog_buff) { 5297d2cc9bcdSJames Smart rc = -ENOMEM; 5298d2cc9bcdSJames Smart goto ras_job_error; 5299d2cc9bcdSJames Smart } 5300d2cc9bcdSJames Smart 5301d2cc9bcdSJames Smart rd_index = (rd_offset / LPFC_RAS_MAX_ENTRY_SIZE); 5302d2cc9bcdSJames Smart offset = (rd_offset % LPFC_RAS_MAX_ENTRY_SIZE); 5303d2cc9bcdSJames Smart 5304d2cc9bcdSJames Smart list_for_each_entry_safe(dmabuf, next, 5305d2cc9bcdSJames Smart &ras_fwlog->fwlog_buff_list, list) { 5306d2cc9bcdSJames Smart 5307d2cc9bcdSJames Smart if (dmabuf->buffer_tag < rd_index) 5308d2cc9bcdSJames Smart continue; 5309d2cc9bcdSJames Smart 5310d2cc9bcdSJames Smart src = dmabuf->virt + offset; 5311191e2f74SJames Smart memcpy(fwlog_buff, src, ras_req->read_size); 5312d2cc9bcdSJames Smart break; 5313d2cc9bcdSJames Smart } 5314d2cc9bcdSJames Smart 5315d2cc9bcdSJames Smart bsg_reply->reply_payload_rcv_len = 5316d2cc9bcdSJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 5317d2cc9bcdSJames Smart job->reply_payload.sg_cnt, 5318d2cc9bcdSJames Smart fwlog_buff, ras_req->read_size); 5319d2cc9bcdSJames Smart 5320d2cc9bcdSJames Smart vfree(fwlog_buff); 5321d2cc9bcdSJames Smart 5322d2cc9bcdSJames Smart ras_job_error: 5323d2cc9bcdSJames Smart bsg_reply->result = rc; 53246db51abbSJames Smart if (!rc) 53256db51abbSJames Smart bsg_job_done(job, bsg_reply->result, 53266db51abbSJames Smart bsg_reply->reply_payload_rcv_len); 5327d2cc9bcdSJames Smart 5328d2cc9bcdSJames Smart return rc; 5329d2cc9bcdSJames Smart } 5330d2cc9bcdSJames Smart 53311dc5ec24SJames Smart static int 53321dc5ec24SJames Smart lpfc_get_trunk_info(struct bsg_job *job) 53331dc5ec24SJames Smart { 53341dc5ec24SJames Smart struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 53351dc5ec24SJames Smart struct lpfc_hba *phba = vport->phba; 53361dc5ec24SJames Smart struct fc_bsg_reply *bsg_reply = job->reply; 53371dc5ec24SJames Smart struct lpfc_trunk_info *event_reply; 53381dc5ec24SJames Smart int rc = 0; 53391dc5ec24SJames Smart 53401dc5ec24SJames Smart if (job->request_len < 53411dc5ec24SJames Smart sizeof(struct fc_bsg_request) + sizeof(struct get_trunk_info_req)) { 53421dc5ec24SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 53431dc5ec24SJames Smart "2744 Received GET TRUNK _INFO request below " 53441dc5ec24SJames Smart "minimum size\n"); 53451dc5ec24SJames Smart rc = -EINVAL; 53461dc5ec24SJames Smart goto job_error; 53471dc5ec24SJames Smart } 53481dc5ec24SJames Smart 53491dc5ec24SJames Smart event_reply = (struct lpfc_trunk_info *) 53501dc5ec24SJames Smart bsg_reply->reply_data.vendor_reply.vendor_rsp; 53511dc5ec24SJames Smart 5352feb3cc57SDick Kennedy if (job->reply_len < sizeof(*bsg_reply) + sizeof(*event_reply)) { 53531dc5ec24SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 53541dc5ec24SJames Smart "2728 Received GET TRUNK _INFO reply below " 53551dc5ec24SJames Smart "minimum size\n"); 53561dc5ec24SJames Smart rc = -EINVAL; 53571dc5ec24SJames Smart goto job_error; 53581dc5ec24SJames Smart } 53591dc5ec24SJames Smart if (event_reply == NULL) { 53601dc5ec24SJames Smart rc = -EINVAL; 53611dc5ec24SJames Smart goto job_error; 53621dc5ec24SJames Smart } 53631dc5ec24SJames Smart 53641dc5ec24SJames Smart bsg_bf_set(lpfc_trunk_info_link_status, event_reply, 53651dc5ec24SJames Smart (phba->link_state >= LPFC_LINK_UP) ? 1 : 0); 53661dc5ec24SJames Smart 53671dc5ec24SJames Smart bsg_bf_set(lpfc_trunk_info_trunk_active0, event_reply, 53681dc5ec24SJames Smart (phba->trunk_link.link0.state == LPFC_LINK_UP) ? 1 : 0); 53691dc5ec24SJames Smart 53701dc5ec24SJames Smart bsg_bf_set(lpfc_trunk_info_trunk_active1, event_reply, 53711dc5ec24SJames Smart (phba->trunk_link.link1.state == LPFC_LINK_UP) ? 1 : 0); 53721dc5ec24SJames Smart 53731dc5ec24SJames Smart bsg_bf_set(lpfc_trunk_info_trunk_active2, event_reply, 53741dc5ec24SJames Smart (phba->trunk_link.link2.state == LPFC_LINK_UP) ? 1 : 0); 53751dc5ec24SJames Smart 53761dc5ec24SJames Smart bsg_bf_set(lpfc_trunk_info_trunk_active3, event_reply, 53771dc5ec24SJames Smart (phba->trunk_link.link3.state == LPFC_LINK_UP) ? 1 : 0); 53781dc5ec24SJames Smart 53791dc5ec24SJames Smart bsg_bf_set(lpfc_trunk_info_trunk_config0, event_reply, 53801dc5ec24SJames Smart bf_get(lpfc_conf_trunk_port0, &phba->sli4_hba)); 53811dc5ec24SJames Smart 53821dc5ec24SJames Smart bsg_bf_set(lpfc_trunk_info_trunk_config1, event_reply, 53831dc5ec24SJames Smart bf_get(lpfc_conf_trunk_port1, &phba->sli4_hba)); 53841dc5ec24SJames Smart 53851dc5ec24SJames Smart bsg_bf_set(lpfc_trunk_info_trunk_config2, event_reply, 53861dc5ec24SJames Smart bf_get(lpfc_conf_trunk_port2, &phba->sli4_hba)); 53871dc5ec24SJames Smart 53881dc5ec24SJames Smart bsg_bf_set(lpfc_trunk_info_trunk_config3, event_reply, 53891dc5ec24SJames Smart bf_get(lpfc_conf_trunk_port3, &phba->sli4_hba)); 53901dc5ec24SJames Smart 53911dc5ec24SJames Smart event_reply->port_speed = phba->sli4_hba.link_state.speed / 1000; 53921dc5ec24SJames Smart event_reply->logical_speed = 5393b8e6f136SJames Smart phba->sli4_hba.link_state.logical_speed / 1000; 53941dc5ec24SJames Smart job_error: 53951dc5ec24SJames Smart bsg_reply->result = rc; 53966db51abbSJames Smart if (!rc) 53971dc5ec24SJames Smart bsg_job_done(job, bsg_reply->result, 53981dc5ec24SJames Smart bsg_reply->reply_payload_rcv_len); 53991dc5ec24SJames Smart return rc; 54001dc5ec24SJames Smart 54011dc5ec24SJames Smart } 5402d2cc9bcdSJames Smart 5403acbaa8c8SJames Smart static int 5404acbaa8c8SJames Smart lpfc_get_cgnbuf_info(struct bsg_job *job) 5405acbaa8c8SJames Smart { 5406acbaa8c8SJames Smart struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 5407acbaa8c8SJames Smart struct lpfc_hba *phba = vport->phba; 5408acbaa8c8SJames Smart struct fc_bsg_request *bsg_request = job->request; 5409acbaa8c8SJames Smart struct fc_bsg_reply *bsg_reply = job->reply; 5410acbaa8c8SJames Smart struct get_cgnbuf_info_req *cgnbuf_req; 5411acbaa8c8SJames Smart struct lpfc_cgn_info *cp; 5412acbaa8c8SJames Smart uint8_t *cgn_buff; 5413*3417c957SSherry Yang size_t size, cinfosz; 5414acbaa8c8SJames Smart int rc = 0; 5415acbaa8c8SJames Smart 5416acbaa8c8SJames Smart if (job->request_len < sizeof(struct fc_bsg_request) + 5417acbaa8c8SJames Smart sizeof(struct get_cgnbuf_info_req)) { 5418acbaa8c8SJames Smart rc = -ENOMEM; 5419acbaa8c8SJames Smart goto job_exit; 5420acbaa8c8SJames Smart } 5421acbaa8c8SJames Smart 5422acbaa8c8SJames Smart if (!phba->sli4_hba.pc_sli4_params.cmf) { 5423acbaa8c8SJames Smart rc = -ENOENT; 5424acbaa8c8SJames Smart goto job_exit; 5425acbaa8c8SJames Smart } 5426acbaa8c8SJames Smart 5427acbaa8c8SJames Smart if (!phba->cgn_i || !phba->cgn_i->virt) { 5428acbaa8c8SJames Smart rc = -ENOENT; 5429acbaa8c8SJames Smart goto job_exit; 5430acbaa8c8SJames Smart } 5431acbaa8c8SJames Smart 5432acbaa8c8SJames Smart cp = phba->cgn_i->virt; 5433acbaa8c8SJames Smart if (cp->cgn_info_version < LPFC_CGN_INFO_V3) { 5434acbaa8c8SJames Smart rc = -EPERM; 5435acbaa8c8SJames Smart goto job_exit; 5436acbaa8c8SJames Smart } 5437acbaa8c8SJames Smart 5438acbaa8c8SJames Smart cgnbuf_req = (struct get_cgnbuf_info_req *) 5439acbaa8c8SJames Smart bsg_request->rqst_data.h_vendor.vendor_cmd; 5440acbaa8c8SJames Smart 5441acbaa8c8SJames Smart /* For reset or size == 0 */ 5442acbaa8c8SJames Smart bsg_reply->reply_payload_rcv_len = 0; 5443acbaa8c8SJames Smart 5444acbaa8c8SJames Smart if (cgnbuf_req->reset == LPFC_BSG_CGN_RESET_STAT) { 5445acbaa8c8SJames Smart lpfc_init_congestion_stat(phba); 5446acbaa8c8SJames Smart goto job_exit; 5447acbaa8c8SJames Smart } 5448acbaa8c8SJames Smart 5449acbaa8c8SJames Smart /* We don't want to include the CRC at the end */ 5450acbaa8c8SJames Smart cinfosz = sizeof(struct lpfc_cgn_info) - sizeof(uint32_t); 5451acbaa8c8SJames Smart 5452acbaa8c8SJames Smart size = cgnbuf_req->read_size; 5453acbaa8c8SJames Smart if (!size) 5454acbaa8c8SJames Smart goto job_exit; 5455acbaa8c8SJames Smart 5456acbaa8c8SJames Smart if (size < cinfosz) { 5457acbaa8c8SJames Smart /* Just copy back what we can */ 5458acbaa8c8SJames Smart cinfosz = size; 5459acbaa8c8SJames Smart rc = -E2BIG; 5460acbaa8c8SJames Smart } 5461acbaa8c8SJames Smart 5462acbaa8c8SJames Smart /* Allocate memory to read congestion info */ 5463acbaa8c8SJames Smart cgn_buff = vmalloc(cinfosz); 5464acbaa8c8SJames Smart if (!cgn_buff) { 5465acbaa8c8SJames Smart rc = -ENOMEM; 5466acbaa8c8SJames Smart goto job_exit; 5467acbaa8c8SJames Smart } 5468acbaa8c8SJames Smart 5469acbaa8c8SJames Smart memcpy(cgn_buff, cp, cinfosz); 5470acbaa8c8SJames Smart 5471acbaa8c8SJames Smart bsg_reply->reply_payload_rcv_len = 5472acbaa8c8SJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 5473acbaa8c8SJames Smart job->reply_payload.sg_cnt, 5474acbaa8c8SJames Smart cgn_buff, cinfosz); 5475acbaa8c8SJames Smart 5476acbaa8c8SJames Smart vfree(cgn_buff); 5477acbaa8c8SJames Smart 5478acbaa8c8SJames Smart job_exit: 5479acbaa8c8SJames Smart bsg_reply->result = rc; 5480acbaa8c8SJames Smart if (!rc) 5481acbaa8c8SJames Smart bsg_job_done(job, bsg_reply->result, 5482acbaa8c8SJames Smart bsg_reply->reply_payload_rcv_len); 5483acbaa8c8SJames Smart else 5484acbaa8c8SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 5485acbaa8c8SJames Smart "2724 GET CGNBUF error: %d\n", rc); 5486acbaa8c8SJames Smart return rc; 5487acbaa8c8SJames Smart } 5488acbaa8c8SJames Smart 5489d2cc9bcdSJames Smart /** 5490f1c3b0fcSJames Smart * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job 5491f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 54923b5dd52aSJames Smart **/ 5493f1c3b0fcSJames Smart static int 549475cc8cfcSJohannes Thumshirn lpfc_bsg_hst_vendor(struct bsg_job *job) 5495f1c3b0fcSJames Smart { 549601e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 549701e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 549801e0e15cSJohannes Thumshirn int command = bsg_request->rqst_data.h_vendor.vendor_cmd[0]; 54994cc0e56eSJames Smart int rc; 5500f1c3b0fcSJames Smart 5501f1c3b0fcSJames Smart switch (command) { 5502f1c3b0fcSJames Smart case LPFC_BSG_VENDOR_SET_CT_EVENT: 55034cc0e56eSJames Smart rc = lpfc_bsg_hba_set_event(job); 5504f1c3b0fcSJames Smart break; 5505f1c3b0fcSJames Smart case LPFC_BSG_VENDOR_GET_CT_EVENT: 55064cc0e56eSJames Smart rc = lpfc_bsg_hba_get_event(job); 5507f1c3b0fcSJames Smart break; 55083b5dd52aSJames Smart case LPFC_BSG_VENDOR_SEND_MGMT_RESP: 55093b5dd52aSJames Smart rc = lpfc_bsg_send_mgmt_rsp(job); 55103b5dd52aSJames Smart break; 55113b5dd52aSJames Smart case LPFC_BSG_VENDOR_DIAG_MODE: 55127ad20aa9SJames Smart rc = lpfc_bsg_diag_loopback_mode(job); 55133b5dd52aSJames Smart break; 55147ad20aa9SJames Smart case LPFC_BSG_VENDOR_DIAG_MODE_END: 55157ad20aa9SJames Smart rc = lpfc_sli4_bsg_diag_mode_end(job); 55167ad20aa9SJames Smart break; 55177ad20aa9SJames Smart case LPFC_BSG_VENDOR_DIAG_RUN_LOOPBACK: 55187ad20aa9SJames Smart rc = lpfc_bsg_diag_loopback_run(job); 55197ad20aa9SJames Smart break; 55207ad20aa9SJames Smart case LPFC_BSG_VENDOR_LINK_DIAG_TEST: 55217ad20aa9SJames Smart rc = lpfc_sli4_bsg_link_diag_test(job); 55223b5dd52aSJames Smart break; 55233b5dd52aSJames Smart case LPFC_BSG_VENDOR_GET_MGMT_REV: 55243b5dd52aSJames Smart rc = lpfc_bsg_get_dfc_rev(job); 55253b5dd52aSJames Smart break; 55263b5dd52aSJames Smart case LPFC_BSG_VENDOR_MBOX: 55273b5dd52aSJames Smart rc = lpfc_bsg_mbox_cmd(job); 55283b5dd52aSJames Smart break; 5529c691816eSJames Smart case LPFC_BSG_VENDOR_FORCED_LINK_SPEED: 5530c691816eSJames Smart rc = lpfc_forced_link_speed(job); 5531c691816eSJames Smart break; 5532d2cc9bcdSJames Smart case LPFC_BSG_VENDOR_RAS_GET_LWPD: 5533d2cc9bcdSJames Smart rc = lpfc_bsg_get_ras_lwpd(job); 5534d2cc9bcdSJames Smart break; 5535d2cc9bcdSJames Smart case LPFC_BSG_VENDOR_RAS_GET_FWLOG: 5536d2cc9bcdSJames Smart rc = lpfc_bsg_get_ras_fwlog(job); 5537d2cc9bcdSJames Smart break; 5538d2cc9bcdSJames Smart case LPFC_BSG_VENDOR_RAS_GET_CONFIG: 5539d2cc9bcdSJames Smart rc = lpfc_bsg_get_ras_config(job); 5540d2cc9bcdSJames Smart break; 5541d2cc9bcdSJames Smart case LPFC_BSG_VENDOR_RAS_SET_CONFIG: 5542d2cc9bcdSJames Smart rc = lpfc_bsg_set_ras_config(job); 5543d2cc9bcdSJames Smart break; 55441dc5ec24SJames Smart case LPFC_BSG_VENDOR_GET_TRUNK_INFO: 55451dc5ec24SJames Smart rc = lpfc_get_trunk_info(job); 55461dc5ec24SJames Smart break; 5547acbaa8c8SJames Smart case LPFC_BSG_VENDOR_GET_CGNBUF_INFO: 5548acbaa8c8SJames Smart rc = lpfc_get_cgnbuf_info(job); 5549acbaa8c8SJames Smart break; 5550f1c3b0fcSJames Smart default: 55514cc0e56eSJames Smart rc = -EINVAL; 555201e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 55534cc0e56eSJames Smart /* make error code available to userspace */ 555401e0e15cSJohannes Thumshirn bsg_reply->result = rc; 55554cc0e56eSJames Smart break; 5556f1c3b0fcSJames Smart } 55574cc0e56eSJames Smart 55584cc0e56eSJames Smart return rc; 5559f1c3b0fcSJames Smart } 5560f1c3b0fcSJames Smart 5561f1c3b0fcSJames Smart /** 5562f1c3b0fcSJames Smart * lpfc_bsg_request - handle a bsg request from the FC transport 5563d2cc9bcdSJames Smart * @job: bsg_job to handle 55643b5dd52aSJames Smart **/ 5565f1c3b0fcSJames Smart int 556675cc8cfcSJohannes Thumshirn lpfc_bsg_request(struct bsg_job *job) 5567f1c3b0fcSJames Smart { 556801e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 556901e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 5570f1c3b0fcSJames Smart uint32_t msgcode; 55714cc0e56eSJames Smart int rc; 5572f1c3b0fcSJames Smart 557301e0e15cSJohannes Thumshirn msgcode = bsg_request->msgcode; 5574f1c3b0fcSJames Smart switch (msgcode) { 5575f1c3b0fcSJames Smart case FC_BSG_HST_VENDOR: 5576f1c3b0fcSJames Smart rc = lpfc_bsg_hst_vendor(job); 5577f1c3b0fcSJames Smart break; 5578f1c3b0fcSJames Smart case FC_BSG_RPT_ELS: 5579f1c3b0fcSJames Smart rc = lpfc_bsg_rport_els(job); 5580f1c3b0fcSJames Smart break; 5581f1c3b0fcSJames Smart case FC_BSG_RPT_CT: 55824cc0e56eSJames Smart rc = lpfc_bsg_send_mgmt_cmd(job); 5583f1c3b0fcSJames Smart break; 5584f1c3b0fcSJames Smart default: 55854cc0e56eSJames Smart rc = -EINVAL; 558601e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 55874cc0e56eSJames Smart /* make error code available to userspace */ 558801e0e15cSJohannes Thumshirn bsg_reply->result = rc; 5589f1c3b0fcSJames Smart break; 5590f1c3b0fcSJames Smart } 5591f1c3b0fcSJames Smart 5592f1c3b0fcSJames Smart return rc; 5593f1c3b0fcSJames Smart } 5594f1c3b0fcSJames Smart 5595f1c3b0fcSJames Smart /** 5596f1c3b0fcSJames Smart * lpfc_bsg_timeout - handle timeout of a bsg request from the FC transport 5597d2cc9bcdSJames Smart * @job: bsg_job that has timed out 5598f1c3b0fcSJames Smart * 5599f1c3b0fcSJames Smart * This function just aborts the job's IOCB. The aborted IOCB will return to 5600f1c3b0fcSJames Smart * the waiting function which will handle passing the error back to userspace 56013b5dd52aSJames Smart **/ 5602f1c3b0fcSJames Smart int 560375cc8cfcSJohannes Thumshirn lpfc_bsg_timeout(struct bsg_job *job) 5604f1c3b0fcSJames Smart { 5605cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 5606f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 56074cc0e56eSJames Smart struct lpfc_iocbq *cmdiocb; 5608895427bdSJames Smart struct lpfc_sli_ring *pring; 56094cc0e56eSJames Smart struct bsg_job_data *dd_data; 56104cc0e56eSJames Smart unsigned long flags; 5611a33c4f7bSJames Smart int rc = 0; 5612a33c4f7bSJames Smart LIST_HEAD(completions); 5613a33c4f7bSJames Smart struct lpfc_iocbq *check_iocb, *next_iocb; 5614a33c4f7bSJames Smart 5615895427bdSJames Smart pring = lpfc_phba_elsring(phba); 56161234a6d5SDick Kennedy if (unlikely(!pring)) 56171234a6d5SDick Kennedy return -EIO; 5618895427bdSJames Smart 5619a33c4f7bSJames Smart /* if job's driver data is NULL, the command completed or is in the 5620a33c4f7bSJames Smart * the process of completing. In this case, return status to request 5621a33c4f7bSJames Smart * so the timeout is retried. This avoids double completion issues 5622a33c4f7bSJames Smart * and the request will be pulled off the timer queue when the 5623a33c4f7bSJames Smart * command's completion handler executes. Otherwise, prevent the 5624a33c4f7bSJames Smart * command's completion handler from executing the job done callback 5625a33c4f7bSJames Smart * and continue processing to abort the outstanding the command. 5626a33c4f7bSJames Smart */ 5627f1c3b0fcSJames Smart 56284cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 56294cc0e56eSJames Smart dd_data = (struct bsg_job_data *)job->dd_data; 5630a33c4f7bSJames Smart if (dd_data) { 5631a33c4f7bSJames Smart dd_data->set_job = NULL; 5632a33c4f7bSJames Smart job->dd_data = NULL; 5633a33c4f7bSJames Smart } else { 56344cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 5635a33c4f7bSJames Smart return -EAGAIN; 56364cc0e56eSJames Smart } 56374cc0e56eSJames Smart 56384cc0e56eSJames Smart switch (dd_data->type) { 56394cc0e56eSJames Smart case TYPE_IOCB: 5640a33c4f7bSJames Smart /* Check to see if IOCB was issued to the port or not. If not, 5641a33c4f7bSJames Smart * remove it from the txq queue and call cancel iocbs. 5642a33c4f7bSJames Smart * Otherwise, call abort iotag 5643a33c4f7bSJames Smart */ 5644a33c4f7bSJames Smart cmdiocb = dd_data->context_un.iocb.cmdiocbq; 5645b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 5646b5a9b2dfSJames Smart 5647b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 5648b5a9b2dfSJames Smart /* make sure the I/O abort window is still open */ 5649a680a929SJames Smart if (!(cmdiocb->cmd_flag & LPFC_IO_CMD_OUTSTANDING)) { 5650b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 5651b5a9b2dfSJames Smart return -EAGAIN; 5652b5a9b2dfSJames Smart } 5653a33c4f7bSJames Smart list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq, 5654a33c4f7bSJames Smart list) { 5655a33c4f7bSJames Smart if (check_iocb == cmdiocb) { 5656a33c4f7bSJames Smart list_move_tail(&check_iocb->list, &completions); 5657a33c4f7bSJames Smart break; 5658a33c4f7bSJames Smart } 5659a33c4f7bSJames Smart } 5660a33c4f7bSJames Smart if (list_empty(&completions)) 5661db7531d2SJames Smart lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb, NULL); 5662b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 5663a33c4f7bSJames Smart if (!list_empty(&completions)) { 5664a33c4f7bSJames Smart lpfc_sli_cancel_iocbs(phba, &completions, 5665a33c4f7bSJames Smart IOSTAT_LOCAL_REJECT, 5666a33c4f7bSJames Smart IOERR_SLI_ABORTED); 5667a33c4f7bSJames Smart } 56684cc0e56eSJames Smart break; 5669a33c4f7bSJames Smart 56704cc0e56eSJames Smart case TYPE_EVT: 56714cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 56724cc0e56eSJames Smart break; 5673a33c4f7bSJames Smart 56743b5dd52aSJames Smart case TYPE_MBOX: 5675a33c4f7bSJames Smart /* Update the ext buf ctx state if needed */ 5676a33c4f7bSJames Smart 56777ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_PORT) 56787ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_ABTS; 5679a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 56803b5dd52aSJames Smart break; 56814cc0e56eSJames Smart default: 56824cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 56834cc0e56eSJames Smart break; 56844cc0e56eSJames Smart } 5685f1c3b0fcSJames Smart 56864cc0e56eSJames Smart /* scsi transport fc fc_bsg_job_timeout expects a zero return code, 56874cc0e56eSJames Smart * otherwise an error message will be displayed on the console 56884cc0e56eSJames Smart * so always return success (zero) 56894cc0e56eSJames Smart */ 5690a33c4f7bSJames Smart return rc; 5691f1c3b0fcSJames Smart } 5692