1f1c3b0fcSJames Smart /******************************************************************* 2f1c3b0fcSJames Smart * This file is part of the Emulex Linux Device Driver for * 3f1c3b0fcSJames Smart * Fibre Channel Host Bus Adapters. * 4b99570ddSJames Smart * Copyright (C) 2009-2012 Emulex. All rights reserved. * 5f1c3b0fcSJames Smart * EMULEX and SLI are trademarks of Emulex. * 6f1c3b0fcSJames Smart * www.emulex.com * 7f1c3b0fcSJames Smart * * 8f1c3b0fcSJames Smart * This program is free software; you can redistribute it and/or * 9f1c3b0fcSJames Smart * modify it under the terms of version 2 of the GNU General * 10f1c3b0fcSJames Smart * Public License as published by the Free Software Foundation. * 11f1c3b0fcSJames Smart * This program is distributed in the hope that it will be useful. * 12f1c3b0fcSJames Smart * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * 13f1c3b0fcSJames Smart * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * 14f1c3b0fcSJames Smart * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * 15f1c3b0fcSJames Smart * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * 16f1c3b0fcSJames Smart * TO BE LEGALLY INVALID. See the GNU General Public License for * 17f1c3b0fcSJames Smart * more details, a copy of which can be found in the file COPYING * 18f1c3b0fcSJames Smart * included with this package. * 19f1c3b0fcSJames Smart *******************************************************************/ 20f1c3b0fcSJames Smart 21f1c3b0fcSJames Smart #include <linux/interrupt.h> 22f1c3b0fcSJames Smart #include <linux/mempool.h> 23f1c3b0fcSJames Smart #include <linux/pci.h> 245a0e3ad6STejun Heo #include <linux/slab.h> 25277e76f1SJames Smart #include <linux/delay.h> 267ad20aa9SJames Smart #include <linux/list.h> 27f1c3b0fcSJames Smart 28f1c3b0fcSJames Smart #include <scsi/scsi.h> 29f1c3b0fcSJames Smart #include <scsi/scsi_host.h> 30f1c3b0fcSJames Smart #include <scsi/scsi_transport_fc.h> 31f1c3b0fcSJames Smart #include <scsi/scsi_bsg_fc.h> 326a9c52cfSJames Smart #include <scsi/fc/fc_fs.h> 33f1c3b0fcSJames Smart 34f1c3b0fcSJames Smart #include "lpfc_hw4.h" 35f1c3b0fcSJames Smart #include "lpfc_hw.h" 36f1c3b0fcSJames Smart #include "lpfc_sli.h" 37f1c3b0fcSJames Smart #include "lpfc_sli4.h" 38f1c3b0fcSJames Smart #include "lpfc_nl.h" 394fede78fSJames Smart #include "lpfc_bsg.h" 40f1c3b0fcSJames Smart #include "lpfc_disc.h" 41f1c3b0fcSJames Smart #include "lpfc_scsi.h" 42f1c3b0fcSJames Smart #include "lpfc.h" 43f1c3b0fcSJames Smart #include "lpfc_logmsg.h" 44f1c3b0fcSJames Smart #include "lpfc_crtn.h" 45b76f2dc9SJames Smart #include "lpfc_debugfs.h" 46f1c3b0fcSJames Smart #include "lpfc_vport.h" 47f1c3b0fcSJames Smart #include "lpfc_version.h" 48f1c3b0fcSJames Smart 494cc0e56eSJames Smart struct lpfc_bsg_event { 504cc0e56eSJames Smart struct list_head node; 514cc0e56eSJames Smart struct kref kref; 524cc0e56eSJames Smart wait_queue_head_t wq; 534cc0e56eSJames Smart 544cc0e56eSJames Smart /* Event type and waiter identifiers */ 554cc0e56eSJames Smart uint32_t type_mask; 564cc0e56eSJames Smart uint32_t req_id; 574cc0e56eSJames Smart uint32_t reg_id; 584cc0e56eSJames Smart 594cc0e56eSJames Smart /* next two flags are here for the auto-delete logic */ 604cc0e56eSJames Smart unsigned long wait_time_stamp; 614cc0e56eSJames Smart int waiting; 624cc0e56eSJames Smart 634cc0e56eSJames Smart /* seen and not seen events */ 644cc0e56eSJames Smart struct list_head events_to_get; 654cc0e56eSJames Smart struct list_head events_to_see; 664cc0e56eSJames Smart 67*a33c4f7bSJames Smart /* driver data associated with the job */ 68*a33c4f7bSJames Smart void *dd_data; 694cc0e56eSJames Smart }; 704cc0e56eSJames Smart 714cc0e56eSJames Smart struct lpfc_bsg_iocb { 724cc0e56eSJames Smart struct lpfc_iocbq *cmdiocbq; 73*a33c4f7bSJames Smart struct lpfc_dmabuf *rmp; 744cc0e56eSJames Smart struct lpfc_nodelist *ndlp; 754cc0e56eSJames Smart }; 764cc0e56eSJames Smart 773b5dd52aSJames Smart struct lpfc_bsg_mbox { 783b5dd52aSJames Smart LPFC_MBOXQ_t *pmboxq; 793b5dd52aSJames Smart MAILBOX_t *mb; 807ad20aa9SJames Smart struct lpfc_dmabuf *dmabuffers; /* for BIU diags */ 817a470277SJames Smart uint8_t *ext; /* extended mailbox data */ 827a470277SJames Smart uint32_t mbOffset; /* from app */ 837a470277SJames Smart uint32_t inExtWLen; /* from app */ 84c7495937SJames Smart uint32_t outExtWLen; /* from app */ 853b5dd52aSJames Smart }; 863b5dd52aSJames Smart 87e2aed29fSJames Smart #define MENLO_DID 0x0000FC0E 88e2aed29fSJames Smart 89e2aed29fSJames Smart struct lpfc_bsg_menlo { 90e2aed29fSJames Smart struct lpfc_iocbq *cmdiocbq; 91*a33c4f7bSJames Smart struct lpfc_dmabuf *rmp; 92e2aed29fSJames Smart }; 93e2aed29fSJames Smart 944cc0e56eSJames Smart #define TYPE_EVT 1 954cc0e56eSJames Smart #define TYPE_IOCB 2 963b5dd52aSJames Smart #define TYPE_MBOX 3 97e2aed29fSJames Smart #define TYPE_MENLO 4 984cc0e56eSJames Smart struct bsg_job_data { 994cc0e56eSJames Smart uint32_t type; 100*a33c4f7bSJames Smart struct fc_bsg_job *set_job; /* job waiting for this iocb to finish */ 1014cc0e56eSJames Smart union { 1024cc0e56eSJames Smart struct lpfc_bsg_event *evt; 1034cc0e56eSJames Smart struct lpfc_bsg_iocb iocb; 1043b5dd52aSJames Smart struct lpfc_bsg_mbox mbox; 105e2aed29fSJames Smart struct lpfc_bsg_menlo menlo; 1064cc0e56eSJames Smart } context_un; 1074cc0e56eSJames Smart }; 1084cc0e56eSJames Smart 1094cc0e56eSJames Smart struct event_data { 1104cc0e56eSJames Smart struct list_head node; 1114cc0e56eSJames Smart uint32_t type; 1124cc0e56eSJames Smart uint32_t immed_dat; 1134cc0e56eSJames Smart void *data; 1144cc0e56eSJames Smart uint32_t len; 1154cc0e56eSJames Smart }; 1164cc0e56eSJames Smart 1173b5dd52aSJames Smart #define BUF_SZ_4K 4096 1184cc0e56eSJames Smart #define SLI_CT_ELX_LOOPBACK 0x10 1194cc0e56eSJames Smart 1204cc0e56eSJames Smart enum ELX_LOOPBACK_CMD { 1214cc0e56eSJames Smart ELX_LOOPBACK_XRI_SETUP, 1224cc0e56eSJames Smart ELX_LOOPBACK_DATA, 1234cc0e56eSJames Smart }; 1244cc0e56eSJames Smart 1253b5dd52aSJames Smart #define ELX_LOOPBACK_HEADER_SZ \ 1263b5dd52aSJames Smart (size_t)(&((struct lpfc_sli_ct_request *)NULL)->un) 1273b5dd52aSJames Smart 1284cc0e56eSJames Smart struct lpfc_dmabufext { 1294cc0e56eSJames Smart struct lpfc_dmabuf dma; 1304cc0e56eSJames Smart uint32_t size; 1314cc0e56eSJames Smart uint32_t flag; 1324cc0e56eSJames Smart }; 1334cc0e56eSJames Smart 134*a33c4f7bSJames Smart static void 135*a33c4f7bSJames Smart lpfc_free_bsg_buffers(struct lpfc_hba *phba, struct lpfc_dmabuf *mlist) 136*a33c4f7bSJames Smart { 137*a33c4f7bSJames Smart struct lpfc_dmabuf *mlast, *next_mlast; 138*a33c4f7bSJames Smart 139*a33c4f7bSJames Smart if (mlist) { 140*a33c4f7bSJames Smart list_for_each_entry_safe(mlast, next_mlast, &mlist->list, 141*a33c4f7bSJames Smart list) { 142*a33c4f7bSJames Smart lpfc_mbuf_free(phba, mlast->virt, mlast->phys); 143*a33c4f7bSJames Smart list_del(&mlast->list); 144*a33c4f7bSJames Smart kfree(mlast); 145*a33c4f7bSJames Smart } 146*a33c4f7bSJames Smart lpfc_mbuf_free(phba, mlist->virt, mlist->phys); 147*a33c4f7bSJames Smart kfree(mlist); 148*a33c4f7bSJames Smart } 149*a33c4f7bSJames Smart return; 150*a33c4f7bSJames Smart } 151*a33c4f7bSJames Smart 152*a33c4f7bSJames Smart static struct lpfc_dmabuf * 153*a33c4f7bSJames Smart lpfc_alloc_bsg_buffers(struct lpfc_hba *phba, unsigned int size, 154*a33c4f7bSJames Smart int outbound_buffers, struct ulp_bde64 *bpl, 155*a33c4f7bSJames Smart int *bpl_entries) 156*a33c4f7bSJames Smart { 157*a33c4f7bSJames Smart struct lpfc_dmabuf *mlist = NULL; 158*a33c4f7bSJames Smart struct lpfc_dmabuf *mp; 159*a33c4f7bSJames Smart unsigned int bytes_left = size; 160*a33c4f7bSJames Smart 161*a33c4f7bSJames Smart /* Verify we can support the size specified */ 162*a33c4f7bSJames Smart if (!size || (size > (*bpl_entries * LPFC_BPL_SIZE))) 163*a33c4f7bSJames Smart return NULL; 164*a33c4f7bSJames Smart 165*a33c4f7bSJames Smart /* Determine the number of dma buffers to allocate */ 166*a33c4f7bSJames Smart *bpl_entries = (size % LPFC_BPL_SIZE ? size/LPFC_BPL_SIZE + 1 : 167*a33c4f7bSJames Smart size/LPFC_BPL_SIZE); 168*a33c4f7bSJames Smart 169*a33c4f7bSJames Smart /* Allocate dma buffer and place in BPL passed */ 170*a33c4f7bSJames Smart while (bytes_left) { 171*a33c4f7bSJames Smart /* Allocate dma buffer */ 172*a33c4f7bSJames Smart mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 173*a33c4f7bSJames Smart if (!mp) { 174*a33c4f7bSJames Smart if (mlist) 175*a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, mlist); 176*a33c4f7bSJames Smart return NULL; 177*a33c4f7bSJames Smart } 178*a33c4f7bSJames Smart 179*a33c4f7bSJames Smart INIT_LIST_HEAD(&mp->list); 180*a33c4f7bSJames Smart mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys)); 181*a33c4f7bSJames Smart 182*a33c4f7bSJames Smart if (!mp->virt) { 183*a33c4f7bSJames Smart kfree(mp); 184*a33c4f7bSJames Smart if (mlist) 185*a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, mlist); 186*a33c4f7bSJames Smart return NULL; 187*a33c4f7bSJames Smart } 188*a33c4f7bSJames Smart 189*a33c4f7bSJames Smart /* Queue it to a linked list */ 190*a33c4f7bSJames Smart if (!mlist) 191*a33c4f7bSJames Smart mlist = mp; 192*a33c4f7bSJames Smart else 193*a33c4f7bSJames Smart list_add_tail(&mp->list, &mlist->list); 194*a33c4f7bSJames Smart 195*a33c4f7bSJames Smart /* Add buffer to buffer pointer list */ 196*a33c4f7bSJames Smart if (outbound_buffers) 197*a33c4f7bSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; 198*a33c4f7bSJames Smart else 199*a33c4f7bSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; 200*a33c4f7bSJames Smart bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys)); 201*a33c4f7bSJames Smart bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys)); 202*a33c4f7bSJames Smart bpl->tus.f.bdeSize = (uint16_t) 203*a33c4f7bSJames Smart (bytes_left >= LPFC_BPL_SIZE ? LPFC_BPL_SIZE : 204*a33c4f7bSJames Smart bytes_left); 205*a33c4f7bSJames Smart bytes_left -= bpl->tus.f.bdeSize; 206*a33c4f7bSJames Smart bpl->tus.w = le32_to_cpu(bpl->tus.w); 207*a33c4f7bSJames Smart bpl++; 208*a33c4f7bSJames Smart } 209*a33c4f7bSJames Smart return mlist; 210*a33c4f7bSJames Smart } 211*a33c4f7bSJames Smart 212*a33c4f7bSJames Smart static unsigned int 213*a33c4f7bSJames Smart lpfc_bsg_copy_data(struct lpfc_dmabuf *dma_buffers, 214*a33c4f7bSJames Smart struct fc_bsg_buffer *bsg_buffers, 215*a33c4f7bSJames Smart unsigned int bytes_to_transfer, int to_buffers) 216*a33c4f7bSJames Smart { 217*a33c4f7bSJames Smart 218*a33c4f7bSJames Smart struct lpfc_dmabuf *mp; 219*a33c4f7bSJames Smart unsigned int transfer_bytes, bytes_copied = 0; 220*a33c4f7bSJames Smart unsigned int sg_offset, dma_offset; 221*a33c4f7bSJames Smart unsigned char *dma_address, *sg_address; 222*a33c4f7bSJames Smart struct scatterlist *sgel; 223*a33c4f7bSJames Smart LIST_HEAD(temp_list); 224*a33c4f7bSJames Smart 225*a33c4f7bSJames Smart 226*a33c4f7bSJames Smart list_splice_init(&dma_buffers->list, &temp_list); 227*a33c4f7bSJames Smart list_add(&dma_buffers->list, &temp_list); 228*a33c4f7bSJames Smart sg_offset = 0; 229*a33c4f7bSJames Smart sgel = bsg_buffers->sg_list; 230*a33c4f7bSJames Smart list_for_each_entry(mp, &temp_list, list) { 231*a33c4f7bSJames Smart dma_offset = 0; 232*a33c4f7bSJames Smart while (bytes_to_transfer && sgel && 233*a33c4f7bSJames Smart (dma_offset < LPFC_BPL_SIZE)) { 234*a33c4f7bSJames Smart dma_address = mp->virt + dma_offset; 235*a33c4f7bSJames Smart if (sg_offset) { 236*a33c4f7bSJames Smart /* Continue previous partial transfer of sg */ 237*a33c4f7bSJames Smart sg_address = sg_virt(sgel) + sg_offset; 238*a33c4f7bSJames Smart transfer_bytes = sgel->length - sg_offset; 239*a33c4f7bSJames Smart } else { 240*a33c4f7bSJames Smart sg_address = sg_virt(sgel); 241*a33c4f7bSJames Smart transfer_bytes = sgel->length; 242*a33c4f7bSJames Smart } 243*a33c4f7bSJames Smart if (bytes_to_transfer < transfer_bytes) 244*a33c4f7bSJames Smart transfer_bytes = bytes_to_transfer; 245*a33c4f7bSJames Smart if (transfer_bytes > (LPFC_BPL_SIZE - dma_offset)) 246*a33c4f7bSJames Smart transfer_bytes = LPFC_BPL_SIZE - dma_offset; 247*a33c4f7bSJames Smart if (to_buffers) 248*a33c4f7bSJames Smart memcpy(dma_address, sg_address, transfer_bytes); 249*a33c4f7bSJames Smart else 250*a33c4f7bSJames Smart memcpy(sg_address, dma_address, transfer_bytes); 251*a33c4f7bSJames Smart dma_offset += transfer_bytes; 252*a33c4f7bSJames Smart sg_offset += transfer_bytes; 253*a33c4f7bSJames Smart bytes_to_transfer -= transfer_bytes; 254*a33c4f7bSJames Smart bytes_copied += transfer_bytes; 255*a33c4f7bSJames Smart if (sg_offset >= sgel->length) { 256*a33c4f7bSJames Smart sg_offset = 0; 257*a33c4f7bSJames Smart sgel = sg_next(sgel); 258*a33c4f7bSJames Smart } 259*a33c4f7bSJames Smart } 260*a33c4f7bSJames Smart } 261*a33c4f7bSJames Smart list_del_init(&dma_buffers->list); 262*a33c4f7bSJames Smart list_splice(&temp_list, &dma_buffers->list); 263*a33c4f7bSJames Smart return bytes_copied; 264*a33c4f7bSJames Smart } 265*a33c4f7bSJames Smart 266f1c3b0fcSJames Smart /** 2674cc0e56eSJames Smart * lpfc_bsg_send_mgmt_cmd_cmp - lpfc_bsg_send_mgmt_cmd's completion handler 2684cc0e56eSJames Smart * @phba: Pointer to HBA context object. 2694cc0e56eSJames Smart * @cmdiocbq: Pointer to command iocb. 2704cc0e56eSJames Smart * @rspiocbq: Pointer to response iocb. 2714cc0e56eSJames Smart * 2724cc0e56eSJames Smart * This function is the completion handler for iocbs issued using 2734cc0e56eSJames Smart * lpfc_bsg_send_mgmt_cmd function. This function is called by the 2744cc0e56eSJames Smart * ring event handler function without any lock held. This function 2754cc0e56eSJames Smart * can be called from both worker thread context and interrupt 2764cc0e56eSJames Smart * context. This function also can be called from another thread which 2774cc0e56eSJames Smart * cleans up the SLI layer objects. 2784cc0e56eSJames Smart * This function copies the contents of the response iocb to the 2794cc0e56eSJames Smart * response iocb memory object provided by the caller of 2804cc0e56eSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 2814cc0e56eSJames Smart * sleeps for the iocb completion. 2824cc0e56eSJames Smart **/ 2834cc0e56eSJames Smart static void 2844cc0e56eSJames Smart lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, 2854cc0e56eSJames Smart struct lpfc_iocbq *cmdiocbq, 2864cc0e56eSJames Smart struct lpfc_iocbq *rspiocbq) 2874cc0e56eSJames Smart { 2884cc0e56eSJames Smart struct bsg_job_data *dd_data; 2894cc0e56eSJames Smart struct fc_bsg_job *job; 2904cc0e56eSJames Smart IOCB_t *rsp; 291*a33c4f7bSJames Smart struct lpfc_dmabuf *bmp, *cmp, *rmp; 2924cc0e56eSJames Smart struct lpfc_nodelist *ndlp; 2934cc0e56eSJames Smart struct lpfc_bsg_iocb *iocb; 2944cc0e56eSJames Smart unsigned long flags; 295*a33c4f7bSJames Smart unsigned int rsp_size; 2964cc0e56eSJames Smart int rc = 0; 2974cc0e56eSJames Smart 298*a33c4f7bSJames Smart dd_data = cmdiocbq->context1; 299*a33c4f7bSJames Smart 300*a33c4f7bSJames Smart /* Determine if job has been aborted */ 3014cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 302*a33c4f7bSJames Smart job = dd_data->set_job; 303*a33c4f7bSJames Smart if (job) { 304*a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 305*a33c4f7bSJames Smart job->dd_data = NULL; 3064cc0e56eSJames Smart } 307*a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 3084cc0e56eSJames Smart 3094cc0e56eSJames Smart iocb = &dd_data->context_un.iocb; 310*a33c4f7bSJames Smart ndlp = iocb->ndlp; 311*a33c4f7bSJames Smart rmp = iocb->rmp; 312*a33c4f7bSJames Smart cmp = cmdiocbq->context2; 313*a33c4f7bSJames Smart bmp = cmdiocbq->context3; 3144cc0e56eSJames Smart rsp = &rspiocbq->iocb; 3154cc0e56eSJames Smart 316*a33c4f7bSJames Smart /* Copy the completed data or set the error status */ 3174cc0e56eSJames Smart 318*a33c4f7bSJames Smart if (job) { 3194cc0e56eSJames Smart if (rsp->ulpStatus) { 3204cc0e56eSJames Smart if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { 321e3d2b802SJames Smart switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) { 3224cc0e56eSJames Smart case IOERR_SEQUENCE_TIMEOUT: 3234cc0e56eSJames Smart rc = -ETIMEDOUT; 3244cc0e56eSJames Smart break; 3254cc0e56eSJames Smart case IOERR_INVALID_RPI: 3264cc0e56eSJames Smart rc = -EFAULT; 3274cc0e56eSJames Smart break; 3284cc0e56eSJames Smart default: 3294cc0e56eSJames Smart rc = -EACCES; 3304cc0e56eSJames Smart break; 3314cc0e56eSJames Smart } 332*a33c4f7bSJames Smart } else { 3334cc0e56eSJames Smart rc = -EACCES; 334*a33c4f7bSJames Smart } 335*a33c4f7bSJames Smart } else { 336*a33c4f7bSJames Smart rsp_size = rsp->un.genreq64.bdl.bdeSize; 3374cc0e56eSJames Smart job->reply->reply_payload_rcv_len = 338*a33c4f7bSJames Smart lpfc_bsg_copy_data(rmp, &job->reply_payload, 339*a33c4f7bSJames Smart rsp_size, 0); 340*a33c4f7bSJames Smart } 341*a33c4f7bSJames Smart } 3424cc0e56eSJames Smart 343*a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 344*a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, rmp); 3454cc0e56eSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 346*a33c4f7bSJames Smart kfree(bmp); 3474cc0e56eSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 3484cc0e56eSJames Smart lpfc_nlp_put(ndlp); 3494cc0e56eSJames Smart kfree(dd_data); 350*a33c4f7bSJames Smart 351*a33c4f7bSJames Smart /* Complete the job if the job is still active */ 352*a33c4f7bSJames Smart 353*a33c4f7bSJames Smart if (job) { 3544cc0e56eSJames Smart job->reply->result = rc; 3554cc0e56eSJames Smart job->job_done(job); 356*a33c4f7bSJames Smart } 3574cc0e56eSJames Smart return; 3584cc0e56eSJames Smart } 3594cc0e56eSJames Smart 3604cc0e56eSJames Smart /** 3614cc0e56eSJames Smart * lpfc_bsg_send_mgmt_cmd - send a CT command from a bsg request 362f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 3633b5dd52aSJames Smart **/ 364f1c3b0fcSJames Smart static int 3654cc0e56eSJames Smart lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job) 366f1c3b0fcSJames Smart { 367f1c3b0fcSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 368f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 369f1c3b0fcSJames Smart struct lpfc_rport_data *rdata = job->rport->dd_data; 370f1c3b0fcSJames Smart struct lpfc_nodelist *ndlp = rdata->pnode; 371f1c3b0fcSJames Smart struct ulp_bde64 *bpl = NULL; 372f1c3b0fcSJames Smart uint32_t timeout; 373f1c3b0fcSJames Smart struct lpfc_iocbq *cmdiocbq = NULL; 374f1c3b0fcSJames Smart IOCB_t *cmd; 375*a33c4f7bSJames Smart struct lpfc_dmabuf *bmp = NULL, *cmp = NULL, *rmp = NULL; 376f1c3b0fcSJames Smart int request_nseg; 377f1c3b0fcSJames Smart int reply_nseg; 3784cc0e56eSJames Smart struct bsg_job_data *dd_data; 3794cc0e56eSJames Smart uint32_t creg_val; 380f1c3b0fcSJames Smart int rc = 0; 381d439d286SJames Smart int iocb_stat; 382f1c3b0fcSJames Smart 383f1c3b0fcSJames Smart /* in case no data is transferred */ 384f1c3b0fcSJames Smart job->reply->reply_payload_rcv_len = 0; 385f1c3b0fcSJames Smart 3864cc0e56eSJames Smart /* allocate our bsg tracking structure */ 3874cc0e56eSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 3884cc0e56eSJames Smart if (!dd_data) { 3894cc0e56eSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 3904cc0e56eSJames Smart "2733 Failed allocation of dd_data\n"); 3914cc0e56eSJames Smart rc = -ENOMEM; 3924cc0e56eSJames Smart goto no_dd_data; 3934cc0e56eSJames Smart } 3944cc0e56eSJames Smart 395f1c3b0fcSJames Smart if (!lpfc_nlp_get(ndlp)) { 3964cc0e56eSJames Smart rc = -ENODEV; 3974cc0e56eSJames Smart goto no_ndlp; 3984cc0e56eSJames Smart } 3994cc0e56eSJames Smart 400f1c3b0fcSJames Smart if (ndlp->nlp_flag & NLP_ELS_SND_MASK) { 401f1c3b0fcSJames Smart rc = -ENODEV; 402*a33c4f7bSJames Smart goto free_ndlp; 403f1c3b0fcSJames Smart } 404f1c3b0fcSJames Smart 405f1c3b0fcSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 406f1c3b0fcSJames Smart if (!cmdiocbq) { 407f1c3b0fcSJames Smart rc = -ENOMEM; 408*a33c4f7bSJames Smart goto free_ndlp; 409f1c3b0fcSJames Smart } 410f1c3b0fcSJames Smart 4114cc0e56eSJames Smart cmd = &cmdiocbq->iocb; 412*a33c4f7bSJames Smart 413*a33c4f7bSJames Smart bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 414*a33c4f7bSJames Smart if (!bmp) { 415f1c3b0fcSJames Smart rc = -ENOMEM; 416be858b65SJames Smart goto free_cmdiocbq; 417f1c3b0fcSJames Smart } 418*a33c4f7bSJames Smart bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); 419*a33c4f7bSJames Smart if (!bmp->virt) { 420*a33c4f7bSJames Smart rc = -ENOMEM; 421*a33c4f7bSJames Smart goto free_bmp; 422f1c3b0fcSJames Smart } 423f1c3b0fcSJames Smart 424*a33c4f7bSJames Smart INIT_LIST_HEAD(&bmp->list); 425*a33c4f7bSJames Smart 426*a33c4f7bSJames Smart bpl = (struct ulp_bde64 *) bmp->virt; 427*a33c4f7bSJames Smart request_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64); 428*a33c4f7bSJames Smart cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len, 429*a33c4f7bSJames Smart 1, bpl, &request_nseg); 430*a33c4f7bSJames Smart if (!cmp) { 431*a33c4f7bSJames Smart rc = -ENOMEM; 432*a33c4f7bSJames Smart goto free_bmp; 433*a33c4f7bSJames Smart } 434*a33c4f7bSJames Smart lpfc_bsg_copy_data(cmp, &job->request_payload, 435*a33c4f7bSJames Smart job->request_payload.payload_len, 1); 436*a33c4f7bSJames Smart 437*a33c4f7bSJames Smart bpl += request_nseg; 438*a33c4f7bSJames Smart reply_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64) - request_nseg; 439*a33c4f7bSJames Smart rmp = lpfc_alloc_bsg_buffers(phba, job->reply_payload.payload_len, 0, 440*a33c4f7bSJames Smart bpl, &reply_nseg); 441*a33c4f7bSJames Smart if (!rmp) { 442*a33c4f7bSJames Smart rc = -ENOMEM; 443*a33c4f7bSJames Smart goto free_cmp; 444f1c3b0fcSJames Smart } 445f1c3b0fcSJames Smart 446f1c3b0fcSJames Smart cmd->un.genreq64.bdl.ulpIoTag32 = 0; 447f1c3b0fcSJames Smart cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); 448f1c3b0fcSJames Smart cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); 449f1c3b0fcSJames Smart cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 450f1c3b0fcSJames Smart cmd->un.genreq64.bdl.bdeSize = 451f1c3b0fcSJames Smart (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); 452f1c3b0fcSJames Smart cmd->ulpCommand = CMD_GEN_REQUEST64_CR; 453f1c3b0fcSJames Smart cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); 454f1c3b0fcSJames Smart cmd->un.genreq64.w5.hcsw.Dfctl = 0; 4556a9c52cfSJames Smart cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; 4566a9c52cfSJames Smart cmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT; 457f1c3b0fcSJames Smart cmd->ulpBdeCount = 1; 458f1c3b0fcSJames Smart cmd->ulpLe = 1; 459f1c3b0fcSJames Smart cmd->ulpClass = CLASS3; 460f1c3b0fcSJames Smart cmd->ulpContext = ndlp->nlp_rpi; 4616d368e53SJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 4626d368e53SJames Smart cmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; 463f1c3b0fcSJames Smart cmd->ulpOwner = OWN_CHIP; 464f1c3b0fcSJames Smart cmdiocbq->vport = phba->pport; 4654cc0e56eSJames Smart cmdiocbq->context3 = bmp; 466f1c3b0fcSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 467f1c3b0fcSJames Smart timeout = phba->fc_ratov * 2; 4684cc0e56eSJames Smart cmd->ulpTimeout = timeout; 469f1c3b0fcSJames Smart 4704cc0e56eSJames Smart cmdiocbq->iocb_cmpl = lpfc_bsg_send_mgmt_cmd_cmp; 471*a33c4f7bSJames Smart cmdiocbq->context1 = dd_data; 472*a33c4f7bSJames Smart cmdiocbq->context2 = cmp; 473*a33c4f7bSJames Smart cmdiocbq->context3 = bmp; 4744cc0e56eSJames Smart dd_data->type = TYPE_IOCB; 475*a33c4f7bSJames Smart dd_data->set_job = job; 4764cc0e56eSJames Smart dd_data->context_un.iocb.cmdiocbq = cmdiocbq; 477*a33c4f7bSJames Smart dd_data->context_un.iocb.ndlp = ndlp; 478*a33c4f7bSJames Smart dd_data->context_un.iocb.rmp = rmp; 479*a33c4f7bSJames Smart job->dd_data = dd_data; 480f1c3b0fcSJames Smart 4814cc0e56eSJames Smart if (phba->cfg_poll & DISABLE_FCP_RING_INT) { 4829940b97bSJames Smart if (lpfc_readl(phba->HCregaddr, &creg_val)) { 4839940b97bSJames Smart rc = -EIO ; 484*a33c4f7bSJames Smart goto free_rmp; 4859940b97bSJames Smart } 4864cc0e56eSJames Smart creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); 4874cc0e56eSJames Smart writel(creg_val, phba->HCregaddr); 4884cc0e56eSJames Smart readl(phba->HCregaddr); /* flush */ 4894cc0e56eSJames Smart } 4904cc0e56eSJames Smart 491d439d286SJames Smart iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); 492d439d286SJames Smart if (iocb_stat == IOCB_SUCCESS) 4934cc0e56eSJames Smart return 0; /* done for now */ 494d439d286SJames Smart else if (iocb_stat == IOCB_BUSY) 495d439d286SJames Smart rc = -EAGAIN; 4962a9bf3d0SJames Smart else 497d439d286SJames Smart rc = -EIO; 4982a9bf3d0SJames Smart 4994cc0e56eSJames Smart /* iocb failed so cleanup */ 500f1c3b0fcSJames Smart 501*a33c4f7bSJames Smart free_rmp: 502*a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, rmp); 503*a33c4f7bSJames Smart free_cmp: 504*a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 505*a33c4f7bSJames Smart free_bmp: 506*a33c4f7bSJames Smart if (bmp->virt) 507f1c3b0fcSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 508*a33c4f7bSJames Smart kfree(bmp); 509f1c3b0fcSJames Smart free_cmdiocbq: 510f1c3b0fcSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 5114cc0e56eSJames Smart free_ndlp: 512f1c3b0fcSJames Smart lpfc_nlp_put(ndlp); 5134cc0e56eSJames Smart no_ndlp: 5144cc0e56eSJames Smart kfree(dd_data); 5154cc0e56eSJames Smart no_dd_data: 516f1c3b0fcSJames Smart /* make error code available to userspace */ 517f1c3b0fcSJames Smart job->reply->result = rc; 5184cc0e56eSJames Smart job->dd_data = NULL; 5194cc0e56eSJames Smart return rc; 5204cc0e56eSJames Smart } 5214cc0e56eSJames Smart 5224cc0e56eSJames Smart /** 5234cc0e56eSJames Smart * lpfc_bsg_rport_els_cmp - lpfc_bsg_rport_els's completion handler 5244cc0e56eSJames Smart * @phba: Pointer to HBA context object. 5254cc0e56eSJames Smart * @cmdiocbq: Pointer to command iocb. 5264cc0e56eSJames Smart * @rspiocbq: Pointer to response iocb. 5274cc0e56eSJames Smart * 5284cc0e56eSJames Smart * This function is the completion handler for iocbs issued using 5294cc0e56eSJames Smart * lpfc_bsg_rport_els_cmp function. This function is called by the 5304cc0e56eSJames Smart * ring event handler function without any lock held. This function 5314cc0e56eSJames Smart * can be called from both worker thread context and interrupt 5324cc0e56eSJames Smart * context. This function also can be called from other thread which 5334cc0e56eSJames Smart * cleans up the SLI layer objects. 5343b5dd52aSJames Smart * This function copies the contents of the response iocb to the 5354cc0e56eSJames Smart * response iocb memory object provided by the caller of 5364cc0e56eSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 5374cc0e56eSJames Smart * sleeps for the iocb completion. 5384cc0e56eSJames Smart **/ 5394cc0e56eSJames Smart static void 5404cc0e56eSJames Smart lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba, 5414cc0e56eSJames Smart struct lpfc_iocbq *cmdiocbq, 5424cc0e56eSJames Smart struct lpfc_iocbq *rspiocbq) 5434cc0e56eSJames Smart { 5444cc0e56eSJames Smart struct bsg_job_data *dd_data; 5454cc0e56eSJames Smart struct fc_bsg_job *job; 5464cc0e56eSJames Smart IOCB_t *rsp; 5474cc0e56eSJames Smart struct lpfc_nodelist *ndlp; 548*a33c4f7bSJames Smart struct lpfc_dmabuf *pcmd = NULL, *prsp = NULL; 5494cc0e56eSJames Smart struct fc_bsg_ctels_reply *els_reply; 5504cc0e56eSJames Smart uint8_t *rjt_data; 5514cc0e56eSJames Smart unsigned long flags; 552*a33c4f7bSJames Smart unsigned int rsp_size; 5534cc0e56eSJames Smart int rc = 0; 5544cc0e56eSJames Smart 5554cc0e56eSJames Smart dd_data = cmdiocbq->context1; 5564cc0e56eSJames Smart ndlp = dd_data->context_un.iocb.ndlp; 557*a33c4f7bSJames Smart cmdiocbq->context1 = ndlp; 5584cc0e56eSJames Smart 559*a33c4f7bSJames Smart /* Determine if job has been aborted */ 560*a33c4f7bSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 561*a33c4f7bSJames Smart job = dd_data->set_job; 562*a33c4f7bSJames Smart if (job) { 563*a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 564*a33c4f7bSJames Smart job->dd_data = NULL; 565*a33c4f7bSJames Smart } 566*a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 5674cc0e56eSJames Smart 568*a33c4f7bSJames Smart rsp = &rspiocbq->iocb; 569*a33c4f7bSJames Smart pcmd = (struct lpfc_dmabuf *)cmdiocbq->context2; 570*a33c4f7bSJames Smart prsp = (struct lpfc_dmabuf *)pcmd->list.next; 571*a33c4f7bSJames Smart 572*a33c4f7bSJames Smart /* Copy the completed job data or determine the job status if job is 573*a33c4f7bSJames Smart * still active 574*a33c4f7bSJames Smart */ 575*a33c4f7bSJames Smart 576*a33c4f7bSJames Smart if (job) { 577*a33c4f7bSJames Smart if (rsp->ulpStatus == IOSTAT_SUCCESS) { 578*a33c4f7bSJames Smart rsp_size = rsp->un.elsreq64.bdl.bdeSize; 5794cc0e56eSJames Smart job->reply->reply_payload_rcv_len = 580*a33c4f7bSJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 581*a33c4f7bSJames Smart job->reply_payload.sg_cnt, 582*a33c4f7bSJames Smart prsp->virt, 583*a33c4f7bSJames Smart rsp_size); 584*a33c4f7bSJames Smart } else if (rsp->ulpStatus == IOSTAT_LS_RJT) { 5854cc0e56eSJames Smart job->reply->reply_payload_rcv_len = 5864cc0e56eSJames Smart sizeof(struct fc_bsg_ctels_reply); 5874cc0e56eSJames Smart /* LS_RJT data returned in word 4 */ 5884cc0e56eSJames Smart rjt_data = (uint8_t *)&rsp->un.ulpWord[4]; 5894cc0e56eSJames Smart els_reply = &job->reply->reply_data.ctels_reply; 5904cc0e56eSJames Smart els_reply->status = FC_CTELS_STATUS_REJECT; 5914cc0e56eSJames Smart els_reply->rjt_data.action = rjt_data[3]; 5924cc0e56eSJames Smart els_reply->rjt_data.reason_code = rjt_data[2]; 5934cc0e56eSJames Smart els_reply->rjt_data.reason_explanation = rjt_data[1]; 5944cc0e56eSJames Smart els_reply->rjt_data.vendor_unique = rjt_data[0]; 595*a33c4f7bSJames Smart } else { 5964cc0e56eSJames Smart rc = -EIO; 597*a33c4f7bSJames Smart } 598*a33c4f7bSJames Smart } 5994cc0e56eSJames Smart 6004cc0e56eSJames Smart lpfc_nlp_put(ndlp); 601*a33c4f7bSJames Smart lpfc_els_free_iocb(phba, cmdiocbq); 6024cc0e56eSJames Smart kfree(dd_data); 603*a33c4f7bSJames Smart 604*a33c4f7bSJames Smart /* Complete the job if the job is still active */ 605*a33c4f7bSJames Smart 606*a33c4f7bSJames Smart if (job) { 6074cc0e56eSJames Smart job->reply->result = rc; 608f1c3b0fcSJames Smart job->job_done(job); 609*a33c4f7bSJames Smart } 6104cc0e56eSJames Smart return; 611f1c3b0fcSJames Smart } 612f1c3b0fcSJames Smart 613f1c3b0fcSJames Smart /** 614f1c3b0fcSJames Smart * lpfc_bsg_rport_els - send an ELS command from a bsg request 615f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 6163b5dd52aSJames Smart **/ 617f1c3b0fcSJames Smart static int 618f1c3b0fcSJames Smart lpfc_bsg_rport_els(struct fc_bsg_job *job) 619f1c3b0fcSJames Smart { 620f1c3b0fcSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 621f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 622f1c3b0fcSJames Smart struct lpfc_rport_data *rdata = job->rport->dd_data; 623f1c3b0fcSJames Smart struct lpfc_nodelist *ndlp = rdata->pnode; 624f1c3b0fcSJames Smart uint32_t elscmd; 625f1c3b0fcSJames Smart uint32_t cmdsize; 626f1c3b0fcSJames Smart uint32_t rspsize; 627f1c3b0fcSJames Smart struct lpfc_iocbq *cmdiocbq; 628f1c3b0fcSJames Smart uint16_t rpi = 0; 6294cc0e56eSJames Smart struct bsg_job_data *dd_data; 6304cc0e56eSJames Smart uint32_t creg_val; 631f1c3b0fcSJames Smart int rc = 0; 632f1c3b0fcSJames Smart 633f1c3b0fcSJames Smart /* in case no data is transferred */ 634f1c3b0fcSJames Smart job->reply->reply_payload_rcv_len = 0; 635f1c3b0fcSJames Smart 636*a33c4f7bSJames Smart /* verify the els command is not greater than the 637*a33c4f7bSJames Smart * maximum ELS transfer size. 638*a33c4f7bSJames Smart */ 639*a33c4f7bSJames Smart 640*a33c4f7bSJames Smart if (job->request_payload.payload_len > FCELSSIZE) { 641*a33c4f7bSJames Smart rc = -EINVAL; 642*a33c4f7bSJames Smart goto no_dd_data; 643*a33c4f7bSJames Smart } 644*a33c4f7bSJames Smart 6454cc0e56eSJames Smart /* allocate our bsg tracking structure */ 6464cc0e56eSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 6474cc0e56eSJames Smart if (!dd_data) { 6484cc0e56eSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 6494cc0e56eSJames Smart "2735 Failed allocation of dd_data\n"); 6504cc0e56eSJames Smart rc = -ENOMEM; 6514cc0e56eSJames Smart goto no_dd_data; 6524cc0e56eSJames Smart } 6534cc0e56eSJames Smart 654*a33c4f7bSJames Smart elscmd = job->request->rqst_data.r_els.els_code; 655*a33c4f7bSJames Smart cmdsize = job->request_payload.payload_len; 656*a33c4f7bSJames Smart rspsize = job->reply_payload.payload_len; 657*a33c4f7bSJames Smart 658f1c3b0fcSJames Smart if (!lpfc_nlp_get(ndlp)) { 659f1c3b0fcSJames Smart rc = -ENODEV; 6604cc0e56eSJames Smart goto free_dd_data; 661f1c3b0fcSJames Smart } 662f1c3b0fcSJames Smart 663*a33c4f7bSJames Smart /* We will use the allocated dma buffers by prep els iocb for command 664*a33c4f7bSJames Smart * and response to ensure if the job times out and the request is freed, 665*a33c4f7bSJames Smart * we won't be dma into memory that is no longer allocated to for the 666*a33c4f7bSJames Smart * request. 667*a33c4f7bSJames Smart */ 668f1c3b0fcSJames Smart 6694cc0e56eSJames Smart cmdiocbq = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, 670f1c3b0fcSJames Smart ndlp->nlp_DID, elscmd); 671f1c3b0fcSJames Smart if (!cmdiocbq) { 6724cc0e56eSJames Smart rc = -EIO; 673*a33c4f7bSJames Smart goto release_ndlp; 674f1c3b0fcSJames Smart } 675f1c3b0fcSJames Smart 676*a33c4f7bSJames Smart rpi = ndlp->nlp_rpi; 677f1c3b0fcSJames Smart 678*a33c4f7bSJames Smart /* Transfer the request payload to allocated command dma buffer */ 679f1c3b0fcSJames Smart 680*a33c4f7bSJames Smart sg_copy_to_buffer(job->request_payload.sg_list, 681*a33c4f7bSJames Smart job->request_payload.sg_cnt, 682*a33c4f7bSJames Smart ((struct lpfc_dmabuf *)cmdiocbq->context2)->virt, 683*a33c4f7bSJames Smart cmdsize); 684f1c3b0fcSJames Smart 6853ef6d24cSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 6863ef6d24cSJames Smart cmdiocbq->iocb.ulpContext = phba->sli4_hba.rpi_ids[rpi]; 6873ef6d24cSJames Smart else 688f1c3b0fcSJames Smart cmdiocbq->iocb.ulpContext = rpi; 689f1c3b0fcSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 6904cc0e56eSJames Smart cmdiocbq->context1 = dd_data; 69193d1379eSJames Smart cmdiocbq->context_un.ndlp = ndlp; 692*a33c4f7bSJames Smart cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp; 6934cc0e56eSJames Smart dd_data->type = TYPE_IOCB; 694*a33c4f7bSJames Smart dd_data->set_job = job; 6954cc0e56eSJames Smart dd_data->context_un.iocb.cmdiocbq = cmdiocbq; 6964cc0e56eSJames Smart dd_data->context_un.iocb.ndlp = ndlp; 697*a33c4f7bSJames Smart dd_data->context_un.iocb.rmp = NULL; 698*a33c4f7bSJames Smart job->dd_data = dd_data; 699f1c3b0fcSJames Smart 7004cc0e56eSJames Smart if (phba->cfg_poll & DISABLE_FCP_RING_INT) { 7019940b97bSJames Smart if (lpfc_readl(phba->HCregaddr, &creg_val)) { 7029940b97bSJames Smart rc = -EIO; 7039940b97bSJames Smart goto linkdown_err; 7049940b97bSJames Smart } 7054cc0e56eSJames Smart creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); 7064cc0e56eSJames Smart writel(creg_val, phba->HCregaddr); 7074cc0e56eSJames Smart readl(phba->HCregaddr); /* flush */ 7084cc0e56eSJames Smart } 709*a33c4f7bSJames Smart 7104cc0e56eSJames Smart rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); 711*a33c4f7bSJames Smart 7124cc0e56eSJames Smart if (rc == IOCB_SUCCESS) 7134cc0e56eSJames Smart return 0; /* done for now */ 7142a9bf3d0SJames Smart else if (rc == IOCB_BUSY) 715d439d286SJames Smart rc = -EAGAIN; 7162a9bf3d0SJames Smart else 717d439d286SJames Smart rc = -EIO; 7184cc0e56eSJames Smart 7199940b97bSJames Smart linkdown_err: 720f1c3b0fcSJames Smart 721*a33c4f7bSJames Smart cmdiocbq->context1 = ndlp; 722*a33c4f7bSJames Smart lpfc_els_free_iocb(phba, cmdiocbq); 723f1c3b0fcSJames Smart 724*a33c4f7bSJames Smart release_ndlp: 725*a33c4f7bSJames Smart lpfc_nlp_put(ndlp); 726f1c3b0fcSJames Smart 7274cc0e56eSJames Smart free_dd_data: 7284cc0e56eSJames Smart kfree(dd_data); 7294cc0e56eSJames Smart 7304cc0e56eSJames Smart no_dd_data: 731f1c3b0fcSJames Smart /* make error code available to userspace */ 732f1c3b0fcSJames Smart job->reply->result = rc; 7334cc0e56eSJames Smart job->dd_data = NULL; 7344cc0e56eSJames Smart return rc; 735f1c3b0fcSJames Smart } 736f1c3b0fcSJames Smart 7373b5dd52aSJames Smart /** 7383b5dd52aSJames Smart * lpfc_bsg_event_free - frees an allocated event structure 7393b5dd52aSJames Smart * @kref: Pointer to a kref. 7403b5dd52aSJames Smart * 7413b5dd52aSJames Smart * Called from kref_put. Back cast the kref into an event structure address. 7423b5dd52aSJames Smart * Free any events to get, delete associated nodes, free any events to see, 7433b5dd52aSJames Smart * free any data then free the event itself. 7443b5dd52aSJames Smart **/ 745f1c3b0fcSJames Smart static void 7464cc0e56eSJames Smart lpfc_bsg_event_free(struct kref *kref) 747f1c3b0fcSJames Smart { 7484cc0e56eSJames Smart struct lpfc_bsg_event *evt = container_of(kref, struct lpfc_bsg_event, 7494cc0e56eSJames Smart kref); 750f1c3b0fcSJames Smart struct event_data *ed; 751f1c3b0fcSJames Smart 752f1c3b0fcSJames Smart list_del(&evt->node); 753f1c3b0fcSJames Smart 754f1c3b0fcSJames Smart while (!list_empty(&evt->events_to_get)) { 755f1c3b0fcSJames Smart ed = list_entry(evt->events_to_get.next, typeof(*ed), node); 756f1c3b0fcSJames Smart list_del(&ed->node); 757f1c3b0fcSJames Smart kfree(ed->data); 758f1c3b0fcSJames Smart kfree(ed); 759f1c3b0fcSJames Smart } 760f1c3b0fcSJames Smart 761f1c3b0fcSJames Smart while (!list_empty(&evt->events_to_see)) { 762f1c3b0fcSJames Smart ed = list_entry(evt->events_to_see.next, typeof(*ed), node); 763f1c3b0fcSJames Smart list_del(&ed->node); 764f1c3b0fcSJames Smart kfree(ed->data); 765f1c3b0fcSJames Smart kfree(ed); 766f1c3b0fcSJames Smart } 767f1c3b0fcSJames Smart 768*a33c4f7bSJames Smart kfree(evt->dd_data); 769f1c3b0fcSJames Smart kfree(evt); 770f1c3b0fcSJames Smart } 771f1c3b0fcSJames Smart 7723b5dd52aSJames Smart /** 7733b5dd52aSJames Smart * lpfc_bsg_event_ref - increments the kref for an event 7743b5dd52aSJames Smart * @evt: Pointer to an event structure. 7753b5dd52aSJames Smart **/ 776f1c3b0fcSJames Smart static inline void 7774cc0e56eSJames Smart lpfc_bsg_event_ref(struct lpfc_bsg_event *evt) 778f1c3b0fcSJames Smart { 7794cc0e56eSJames Smart kref_get(&evt->kref); 780f1c3b0fcSJames Smart } 781f1c3b0fcSJames Smart 7823b5dd52aSJames Smart /** 7833b5dd52aSJames Smart * lpfc_bsg_event_unref - Uses kref_put to free an event structure 7843b5dd52aSJames Smart * @evt: Pointer to an event structure. 7853b5dd52aSJames Smart **/ 786f1c3b0fcSJames Smart static inline void 7874cc0e56eSJames Smart lpfc_bsg_event_unref(struct lpfc_bsg_event *evt) 788f1c3b0fcSJames Smart { 7894cc0e56eSJames Smart kref_put(&evt->kref, lpfc_bsg_event_free); 790f1c3b0fcSJames Smart } 791f1c3b0fcSJames Smart 7923b5dd52aSJames Smart /** 7933b5dd52aSJames Smart * lpfc_bsg_event_new - allocate and initialize a event structure 7943b5dd52aSJames Smart * @ev_mask: Mask of events. 7953b5dd52aSJames Smart * @ev_reg_id: Event reg id. 7963b5dd52aSJames Smart * @ev_req_id: Event request id. 7973b5dd52aSJames Smart **/ 7984cc0e56eSJames Smart static struct lpfc_bsg_event * 7994cc0e56eSJames Smart lpfc_bsg_event_new(uint32_t ev_mask, int ev_reg_id, uint32_t ev_req_id) 8004cc0e56eSJames Smart { 8014cc0e56eSJames Smart struct lpfc_bsg_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL); 802f1c3b0fcSJames Smart 8034cc0e56eSJames Smart if (!evt) 8044cc0e56eSJames Smart return NULL; 8054cc0e56eSJames Smart 8064cc0e56eSJames Smart INIT_LIST_HEAD(&evt->events_to_get); 8074cc0e56eSJames Smart INIT_LIST_HEAD(&evt->events_to_see); 8084cc0e56eSJames Smart evt->type_mask = ev_mask; 8094cc0e56eSJames Smart evt->req_id = ev_req_id; 8104cc0e56eSJames Smart evt->reg_id = ev_reg_id; 8114cc0e56eSJames Smart evt->wait_time_stamp = jiffies; 812*a33c4f7bSJames Smart evt->dd_data = NULL; 8134cc0e56eSJames Smart init_waitqueue_head(&evt->wq); 8144cc0e56eSJames Smart kref_init(&evt->kref); 8154cc0e56eSJames Smart return evt; 8164cc0e56eSJames Smart } 8174cc0e56eSJames Smart 8183b5dd52aSJames Smart /** 8193b5dd52aSJames Smart * diag_cmd_data_free - Frees an lpfc dma buffer extension 8203b5dd52aSJames Smart * @phba: Pointer to HBA context object. 8213b5dd52aSJames Smart * @mlist: Pointer to an lpfc dma buffer extension. 8223b5dd52aSJames Smart **/ 8234cc0e56eSJames Smart static int 8243b5dd52aSJames Smart diag_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist) 8254cc0e56eSJames Smart { 8264cc0e56eSJames Smart struct lpfc_dmabufext *mlast; 8274cc0e56eSJames Smart struct pci_dev *pcidev; 8284cc0e56eSJames Smart struct list_head head, *curr, *next; 8294cc0e56eSJames Smart 8304cc0e56eSJames Smart if ((!mlist) || (!lpfc_is_link_up(phba) && 8314cc0e56eSJames Smart (phba->link_flag & LS_LOOPBACK_MODE))) { 8324cc0e56eSJames Smart return 0; 8334cc0e56eSJames Smart } 8344cc0e56eSJames Smart 8354cc0e56eSJames Smart pcidev = phba->pcidev; 8364cc0e56eSJames Smart list_add_tail(&head, &mlist->dma.list); 8374cc0e56eSJames Smart 8384cc0e56eSJames Smart list_for_each_safe(curr, next, &head) { 8394cc0e56eSJames Smart mlast = list_entry(curr, struct lpfc_dmabufext , dma.list); 8404cc0e56eSJames Smart if (mlast->dma.virt) 8414cc0e56eSJames Smart dma_free_coherent(&pcidev->dev, 8424cc0e56eSJames Smart mlast->size, 8434cc0e56eSJames Smart mlast->dma.virt, 8444cc0e56eSJames Smart mlast->dma.phys); 8454cc0e56eSJames Smart kfree(mlast); 8464cc0e56eSJames Smart } 8474cc0e56eSJames Smart return 0; 8484cc0e56eSJames Smart } 849f1c3b0fcSJames Smart 850f1c3b0fcSJames Smart /** 851f1c3b0fcSJames Smart * lpfc_bsg_ct_unsol_event - process an unsolicited CT command 852f1c3b0fcSJames Smart * @phba: 853f1c3b0fcSJames Smart * @pring: 854f1c3b0fcSJames Smart * @piocbq: 855f1c3b0fcSJames Smart * 856f1c3b0fcSJames Smart * This function is called when an unsolicited CT command is received. It 8574cc0e56eSJames Smart * forwards the event to any processes registered to receive CT events. 8583b5dd52aSJames Smart **/ 8594fede78fSJames Smart int 860f1c3b0fcSJames Smart lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, 861f1c3b0fcSJames Smart struct lpfc_iocbq *piocbq) 862f1c3b0fcSJames Smart { 863f1c3b0fcSJames Smart uint32_t evt_req_id = 0; 864f1c3b0fcSJames Smart uint32_t cmd; 865f1c3b0fcSJames Smart uint32_t len; 866f1c3b0fcSJames Smart struct lpfc_dmabuf *dmabuf = NULL; 8674cc0e56eSJames Smart struct lpfc_bsg_event *evt; 868f1c3b0fcSJames Smart struct event_data *evt_dat = NULL; 869f1c3b0fcSJames Smart struct lpfc_iocbq *iocbq; 870f1c3b0fcSJames Smart size_t offset = 0; 871f1c3b0fcSJames Smart struct list_head head; 872f1c3b0fcSJames Smart struct ulp_bde64 *bde; 873f1c3b0fcSJames Smart dma_addr_t dma_addr; 874f1c3b0fcSJames Smart int i; 875f1c3b0fcSJames Smart struct lpfc_dmabuf *bdeBuf1 = piocbq->context2; 876f1c3b0fcSJames Smart struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; 877f1c3b0fcSJames Smart struct lpfc_hbq_entry *hbqe; 878f1c3b0fcSJames Smart struct lpfc_sli_ct_request *ct_req; 8794cc0e56eSJames Smart struct fc_bsg_job *job = NULL; 880*a33c4f7bSJames Smart struct bsg_job_data *dd_data = NULL; 8814fede78fSJames Smart unsigned long flags; 8824cc0e56eSJames Smart int size = 0; 883f1c3b0fcSJames Smart 884f1c3b0fcSJames Smart INIT_LIST_HEAD(&head); 885f1c3b0fcSJames Smart list_add_tail(&head, &piocbq->list); 886f1c3b0fcSJames Smart 887f1c3b0fcSJames Smart if (piocbq->iocb.ulpBdeCount == 0 || 888f1c3b0fcSJames Smart piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0) 889f1c3b0fcSJames Smart goto error_ct_unsol_exit; 890f1c3b0fcSJames Smart 8914cc0e56eSJames Smart if (phba->link_state == LPFC_HBA_ERROR || 8924cc0e56eSJames Smart (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) 8934cc0e56eSJames Smart goto error_ct_unsol_exit; 8944cc0e56eSJames Smart 895f1c3b0fcSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) 896f1c3b0fcSJames Smart dmabuf = bdeBuf1; 897f1c3b0fcSJames Smart else { 898f1c3b0fcSJames Smart dma_addr = getPaddr(piocbq->iocb.un.cont64[0].addrHigh, 899f1c3b0fcSJames Smart piocbq->iocb.un.cont64[0].addrLow); 900f1c3b0fcSJames Smart dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr); 901f1c3b0fcSJames Smart } 9024cc0e56eSJames Smart if (dmabuf == NULL) 9034cc0e56eSJames Smart goto error_ct_unsol_exit; 904f1c3b0fcSJames Smart ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt; 905f1c3b0fcSJames Smart evt_req_id = ct_req->FsType; 906f1c3b0fcSJames Smart cmd = ct_req->CommandResponse.bits.CmdRsp; 907f1c3b0fcSJames Smart len = ct_req->CommandResponse.bits.Size; 908f1c3b0fcSJames Smart if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) 909f1c3b0fcSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, dmabuf); 910f1c3b0fcSJames Smart 9114fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 912f1c3b0fcSJames Smart list_for_each_entry(evt, &phba->ct_ev_waiters, node) { 9134cc0e56eSJames Smart if (!(evt->type_mask & FC_REG_CT_EVENT) || 9144cc0e56eSJames Smart evt->req_id != evt_req_id) 915f1c3b0fcSJames Smart continue; 916f1c3b0fcSJames Smart 9174cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 9184cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 919f1c3b0fcSJames Smart evt_dat = kzalloc(sizeof(*evt_dat), GFP_KERNEL); 9204cc0e56eSJames Smart if (evt_dat == NULL) { 9214cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 9224cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 923f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 924f1c3b0fcSJames Smart "2614 Memory allocation failed for " 925f1c3b0fcSJames Smart "CT event\n"); 926f1c3b0fcSJames Smart break; 927f1c3b0fcSJames Smart } 928f1c3b0fcSJames Smart 929f1c3b0fcSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 930f1c3b0fcSJames Smart /* take accumulated byte count from the last iocbq */ 931f1c3b0fcSJames Smart iocbq = list_entry(head.prev, typeof(*iocbq), list); 932f1c3b0fcSJames Smart evt_dat->len = iocbq->iocb.unsli3.rcvsli3.acc_len; 933f1c3b0fcSJames Smart } else { 934f1c3b0fcSJames Smart list_for_each_entry(iocbq, &head, list) { 935f1c3b0fcSJames Smart for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) 936f1c3b0fcSJames Smart evt_dat->len += 937f1c3b0fcSJames Smart iocbq->iocb.un.cont64[i].tus.f.bdeSize; 938f1c3b0fcSJames Smart } 939f1c3b0fcSJames Smart } 940f1c3b0fcSJames Smart 941f1c3b0fcSJames Smart evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL); 9424cc0e56eSJames Smart if (evt_dat->data == NULL) { 943f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 944f1c3b0fcSJames Smart "2615 Memory allocation failed for " 945f1c3b0fcSJames Smart "CT event data, size %d\n", 946f1c3b0fcSJames Smart evt_dat->len); 947f1c3b0fcSJames Smart kfree(evt_dat); 9484fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 9494cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 9504fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 951f1c3b0fcSJames Smart goto error_ct_unsol_exit; 952f1c3b0fcSJames Smart } 953f1c3b0fcSJames Smart 954f1c3b0fcSJames Smart list_for_each_entry(iocbq, &head, list) { 9554cc0e56eSJames Smart size = 0; 956f1c3b0fcSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 957f1c3b0fcSJames Smart bdeBuf1 = iocbq->context2; 958f1c3b0fcSJames Smart bdeBuf2 = iocbq->context3; 959f1c3b0fcSJames Smart } 960f1c3b0fcSJames Smart for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) { 961f1c3b0fcSJames Smart if (phba->sli3_options & 962f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED) { 963f1c3b0fcSJames Smart if (i == 0) { 964f1c3b0fcSJames Smart hbqe = (struct lpfc_hbq_entry *) 965f1c3b0fcSJames Smart &iocbq->iocb.un.ulpWord[0]; 966f1c3b0fcSJames Smart size = hbqe->bde.tus.f.bdeSize; 967f1c3b0fcSJames Smart dmabuf = bdeBuf1; 968f1c3b0fcSJames Smart } else if (i == 1) { 969f1c3b0fcSJames Smart hbqe = (struct lpfc_hbq_entry *) 970f1c3b0fcSJames Smart &iocbq->iocb.unsli3. 971f1c3b0fcSJames Smart sli3Words[4]; 972f1c3b0fcSJames Smart size = hbqe->bde.tus.f.bdeSize; 973f1c3b0fcSJames Smart dmabuf = bdeBuf2; 974f1c3b0fcSJames Smart } 975f1c3b0fcSJames Smart if ((offset + size) > evt_dat->len) 976f1c3b0fcSJames Smart size = evt_dat->len - offset; 977f1c3b0fcSJames Smart } else { 978f1c3b0fcSJames Smart size = iocbq->iocb.un.cont64[i]. 979f1c3b0fcSJames Smart tus.f.bdeSize; 980f1c3b0fcSJames Smart bde = &iocbq->iocb.un.cont64[i]; 981f1c3b0fcSJames Smart dma_addr = getPaddr(bde->addrHigh, 982f1c3b0fcSJames Smart bde->addrLow); 983f1c3b0fcSJames Smart dmabuf = lpfc_sli_ringpostbuf_get(phba, 984f1c3b0fcSJames Smart pring, dma_addr); 985f1c3b0fcSJames Smart } 986f1c3b0fcSJames Smart if (!dmabuf) { 987f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_ERR, 988f1c3b0fcSJames Smart LOG_LIBDFC, "2616 No dmabuf " 989f1c3b0fcSJames Smart "found for iocbq 0x%p\n", 990f1c3b0fcSJames Smart iocbq); 991f1c3b0fcSJames Smart kfree(evt_dat->data); 992f1c3b0fcSJames Smart kfree(evt_dat); 9934fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, 9944fede78fSJames Smart flags); 9954cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 9964fede78fSJames Smart spin_unlock_irqrestore( 9974fede78fSJames Smart &phba->ct_ev_lock, flags); 998f1c3b0fcSJames Smart goto error_ct_unsol_exit; 999f1c3b0fcSJames Smart } 1000f1c3b0fcSJames Smart memcpy((char *)(evt_dat->data) + offset, 1001f1c3b0fcSJames Smart dmabuf->virt, size); 1002f1c3b0fcSJames Smart offset += size; 1003f1c3b0fcSJames Smart if (evt_req_id != SLI_CT_ELX_LOOPBACK && 1004f1c3b0fcSJames Smart !(phba->sli3_options & 1005f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED)) { 1006f1c3b0fcSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, 1007f1c3b0fcSJames Smart dmabuf); 1008f1c3b0fcSJames Smart } else { 1009f1c3b0fcSJames Smart switch (cmd) { 10104cc0e56eSJames Smart case ELX_LOOPBACK_DATA: 10111b51197dSJames Smart if (phba->sli_rev < 10121b51197dSJames Smart LPFC_SLI_REV4) 10133b5dd52aSJames Smart diag_cmd_data_free(phba, 10141b51197dSJames Smart (struct lpfc_dmabufext 10151b51197dSJames Smart *)dmabuf); 10164cc0e56eSJames Smart break; 1017f1c3b0fcSJames Smart case ELX_LOOPBACK_XRI_SETUP: 10184cc0e56eSJames Smart if ((phba->sli_rev == 10194cc0e56eSJames Smart LPFC_SLI_REV2) || 10204cc0e56eSJames Smart (phba->sli3_options & 10214cc0e56eSJames Smart LPFC_SLI3_HBQ_ENABLED 10224cc0e56eSJames Smart )) { 10234cc0e56eSJames Smart lpfc_in_buf_free(phba, 10244cc0e56eSJames Smart dmabuf); 10254cc0e56eSJames Smart } else { 1026f1c3b0fcSJames Smart lpfc_post_buffer(phba, 1027f1c3b0fcSJames Smart pring, 1028f1c3b0fcSJames Smart 1); 10294cc0e56eSJames Smart } 1030f1c3b0fcSJames Smart break; 1031f1c3b0fcSJames Smart default: 1032f1c3b0fcSJames Smart if (!(phba->sli3_options & 1033f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED)) 1034f1c3b0fcSJames Smart lpfc_post_buffer(phba, 1035f1c3b0fcSJames Smart pring, 1036f1c3b0fcSJames Smart 1); 1037f1c3b0fcSJames Smart break; 1038f1c3b0fcSJames Smart } 1039f1c3b0fcSJames Smart } 1040f1c3b0fcSJames Smart } 1041f1c3b0fcSJames Smart } 1042f1c3b0fcSJames Smart 10434fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1044f1c3b0fcSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) { 1045f1c3b0fcSJames Smart evt_dat->immed_dat = phba->ctx_idx; 10466dd9e31cSJames Smart phba->ctx_idx = (phba->ctx_idx + 1) % LPFC_CT_CTX_MAX; 1047589a52d6SJames Smart /* Provide warning for over-run of the ct_ctx array */ 10486dd9e31cSJames Smart if (phba->ct_ctx[evt_dat->immed_dat].valid == 1049589a52d6SJames Smart UNSOL_VALID) 1050589a52d6SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, 1051589a52d6SJames Smart "2717 CT context array entry " 1052589a52d6SJames Smart "[%d] over-run: oxid:x%x, " 1053589a52d6SJames Smart "sid:x%x\n", phba->ctx_idx, 1054589a52d6SJames Smart phba->ct_ctx[ 1055589a52d6SJames Smart evt_dat->immed_dat].oxid, 1056589a52d6SJames Smart phba->ct_ctx[ 1057589a52d6SJames Smart evt_dat->immed_dat].SID); 10587851fe2cSJames Smart phba->ct_ctx[evt_dat->immed_dat].rxid = 1059f1c3b0fcSJames Smart piocbq->iocb.ulpContext; 10607851fe2cSJames Smart phba->ct_ctx[evt_dat->immed_dat].oxid = 10617851fe2cSJames Smart piocbq->iocb.unsli3.rcvsli3.ox_id; 1062f1c3b0fcSJames Smart phba->ct_ctx[evt_dat->immed_dat].SID = 1063f1c3b0fcSJames Smart piocbq->iocb.un.rcvels.remoteID; 10646dd9e31cSJames Smart phba->ct_ctx[evt_dat->immed_dat].valid = UNSOL_VALID; 1065f1c3b0fcSJames Smart } else 1066f1c3b0fcSJames Smart evt_dat->immed_dat = piocbq->iocb.ulpContext; 1067f1c3b0fcSJames Smart 1068f1c3b0fcSJames Smart evt_dat->type = FC_REG_CT_EVENT; 1069f1c3b0fcSJames Smart list_add(&evt_dat->node, &evt->events_to_see); 10704cc0e56eSJames Smart if (evt_req_id == SLI_CT_ELX_LOOPBACK) { 1071f1c3b0fcSJames Smart wake_up_interruptible(&evt->wq); 10724cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 1073f1c3b0fcSJames Smart break; 1074f1c3b0fcSJames Smart } 10754cc0e56eSJames Smart 10764cc0e56eSJames Smart list_move(evt->events_to_see.prev, &evt->events_to_get); 10774cc0e56eSJames Smart 1078*a33c4f7bSJames Smart dd_data = (struct bsg_job_data *)evt->dd_data; 1079*a33c4f7bSJames Smart job = dd_data->set_job; 1080*a33c4f7bSJames Smart dd_data->set_job = NULL; 1081*a33c4f7bSJames Smart lpfc_bsg_event_unref(evt); 10824cc0e56eSJames Smart if (job) { 10834cc0e56eSJames Smart job->reply->reply_payload_rcv_len = size; 10844cc0e56eSJames Smart /* make error code available to userspace */ 10854cc0e56eSJames Smart job->reply->result = 0; 10864cc0e56eSJames Smart job->dd_data = NULL; 10874cc0e56eSJames Smart /* complete the job back to userspace */ 10884cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 10894cc0e56eSJames Smart job->job_done(job); 10904cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 10914cc0e56eSJames Smart } 10924cc0e56eSJames Smart } 10934fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 1094f1c3b0fcSJames Smart 1095f1c3b0fcSJames Smart error_ct_unsol_exit: 1096f1c3b0fcSJames Smart if (!list_empty(&head)) 1097f1c3b0fcSJames Smart list_del(&head); 10981b51197dSJames Smart if ((phba->sli_rev < LPFC_SLI_REV4) && 10991b51197dSJames Smart (evt_req_id == SLI_CT_ELX_LOOPBACK)) 11004cc0e56eSJames Smart return 0; 11014fede78fSJames Smart return 1; 1102f1c3b0fcSJames Smart } 1103f1c3b0fcSJames Smart 1104f1c3b0fcSJames Smart /** 11056dd9e31cSJames Smart * lpfc_bsg_ct_unsol_abort - handler ct abort to management plane 11066dd9e31cSJames Smart * @phba: Pointer to HBA context object. 11076dd9e31cSJames Smart * @dmabuf: pointer to a dmabuf that describes the FC sequence 11086dd9e31cSJames Smart * 11096dd9e31cSJames Smart * This function handles abort to the CT command toward management plane 11106dd9e31cSJames Smart * for SLI4 port. 11116dd9e31cSJames Smart * 11126dd9e31cSJames Smart * If the pending context of a CT command to management plane present, clears 11136dd9e31cSJames Smart * such context and returns 1 for handled; otherwise, it returns 0 indicating 11146dd9e31cSJames Smart * no context exists. 11156dd9e31cSJames Smart **/ 11166dd9e31cSJames Smart int 11176dd9e31cSJames Smart lpfc_bsg_ct_unsol_abort(struct lpfc_hba *phba, struct hbq_dmabuf *dmabuf) 11186dd9e31cSJames Smart { 11196dd9e31cSJames Smart struct fc_frame_header fc_hdr; 11206dd9e31cSJames Smart struct fc_frame_header *fc_hdr_ptr = &fc_hdr; 11216dd9e31cSJames Smart int ctx_idx, handled = 0; 11226dd9e31cSJames Smart uint16_t oxid, rxid; 11236dd9e31cSJames Smart uint32_t sid; 11246dd9e31cSJames Smart 11256dd9e31cSJames Smart memcpy(fc_hdr_ptr, dmabuf->hbuf.virt, sizeof(struct fc_frame_header)); 11266dd9e31cSJames Smart sid = sli4_sid_from_fc_hdr(fc_hdr_ptr); 11276dd9e31cSJames Smart oxid = be16_to_cpu(fc_hdr_ptr->fh_ox_id); 11286dd9e31cSJames Smart rxid = be16_to_cpu(fc_hdr_ptr->fh_rx_id); 11296dd9e31cSJames Smart 11306dd9e31cSJames Smart for (ctx_idx = 0; ctx_idx < LPFC_CT_CTX_MAX; ctx_idx++) { 11316dd9e31cSJames Smart if (phba->ct_ctx[ctx_idx].valid != UNSOL_VALID) 11326dd9e31cSJames Smart continue; 11336dd9e31cSJames Smart if (phba->ct_ctx[ctx_idx].rxid != rxid) 11346dd9e31cSJames Smart continue; 11356dd9e31cSJames Smart if (phba->ct_ctx[ctx_idx].oxid != oxid) 11366dd9e31cSJames Smart continue; 11376dd9e31cSJames Smart if (phba->ct_ctx[ctx_idx].SID != sid) 11386dd9e31cSJames Smart continue; 11396dd9e31cSJames Smart phba->ct_ctx[ctx_idx].valid = UNSOL_INVALID; 11406dd9e31cSJames Smart handled = 1; 11416dd9e31cSJames Smart } 11426dd9e31cSJames Smart return handled; 11436dd9e31cSJames Smart } 11446dd9e31cSJames Smart 11456dd9e31cSJames Smart /** 11464cc0e56eSJames Smart * lpfc_bsg_hba_set_event - process a SET_EVENT bsg vendor command 1147f1c3b0fcSJames Smart * @job: SET_EVENT fc_bsg_job 11483b5dd52aSJames Smart **/ 1149f1c3b0fcSJames Smart static int 11504cc0e56eSJames Smart lpfc_bsg_hba_set_event(struct fc_bsg_job *job) 1151f1c3b0fcSJames Smart { 1152f1c3b0fcSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 1153f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 1154f1c3b0fcSJames Smart struct set_ct_event *event_req; 11554cc0e56eSJames Smart struct lpfc_bsg_event *evt; 1156f1c3b0fcSJames Smart int rc = 0; 11574cc0e56eSJames Smart struct bsg_job_data *dd_data = NULL; 11584cc0e56eSJames Smart uint32_t ev_mask; 11594cc0e56eSJames Smart unsigned long flags; 1160f1c3b0fcSJames Smart 1161f1c3b0fcSJames Smart if (job->request_len < 1162f1c3b0fcSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct set_ct_event)) { 1163f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1164f1c3b0fcSJames Smart "2612 Received SET_CT_EVENT below minimum " 1165f1c3b0fcSJames Smart "size\n"); 11664cc0e56eSJames Smart rc = -EINVAL; 11674cc0e56eSJames Smart goto job_error; 11684cc0e56eSJames Smart } 11694cc0e56eSJames Smart 1170f1c3b0fcSJames Smart event_req = (struct set_ct_event *) 1171f1c3b0fcSJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 11724cc0e56eSJames Smart ev_mask = ((uint32_t)(unsigned long)event_req->type_mask & 11734cc0e56eSJames Smart FC_REG_EVENT_MASK); 11744fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1175f1c3b0fcSJames Smart list_for_each_entry(evt, &phba->ct_ev_waiters, node) { 1176f1c3b0fcSJames Smart if (evt->reg_id == event_req->ev_reg_id) { 11774cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 1178f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 1179*a33c4f7bSJames Smart dd_data = (struct bsg_job_data *)evt->dd_data; 1180f1c3b0fcSJames Smart break; 1181f1c3b0fcSJames Smart } 1182f1c3b0fcSJames Smart } 11834fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 1184f1c3b0fcSJames Smart 1185f1c3b0fcSJames Smart if (&evt->node == &phba->ct_ev_waiters) { 1186f1c3b0fcSJames Smart /* no event waiting struct yet - first call */ 1187*a33c4f7bSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 1188*a33c4f7bSJames Smart if (dd_data == NULL) { 1189*a33c4f7bSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1190*a33c4f7bSJames Smart "2734 Failed allocation of dd_data\n"); 1191*a33c4f7bSJames Smart rc = -ENOMEM; 1192*a33c4f7bSJames Smart goto job_error; 1193*a33c4f7bSJames Smart } 11944cc0e56eSJames Smart evt = lpfc_bsg_event_new(ev_mask, event_req->ev_reg_id, 1195f1c3b0fcSJames Smart event_req->ev_req_id); 1196f1c3b0fcSJames Smart if (!evt) { 1197f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1198f1c3b0fcSJames Smart "2617 Failed allocation of event " 1199f1c3b0fcSJames Smart "waiter\n"); 12004cc0e56eSJames Smart rc = -ENOMEM; 12014cc0e56eSJames Smart goto job_error; 1202f1c3b0fcSJames Smart } 1203*a33c4f7bSJames Smart dd_data->type = TYPE_EVT; 1204*a33c4f7bSJames Smart dd_data->set_job = NULL; 1205*a33c4f7bSJames Smart dd_data->context_un.evt = evt; 1206*a33c4f7bSJames Smart evt->dd_data = (void *)dd_data; 12074fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1208f1c3b0fcSJames Smart list_add(&evt->node, &phba->ct_ev_waiters); 12094cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 1210f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 12114cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 12124cc0e56eSJames Smart } 1213f1c3b0fcSJames Smart 12144fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 12154cc0e56eSJames Smart evt->waiting = 1; 1216*a33c4f7bSJames Smart dd_data->set_job = job; /* for unsolicited command */ 12174cc0e56eSJames Smart job->dd_data = dd_data; /* for fc transport timeout callback*/ 12184fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 12194cc0e56eSJames Smart return 0; /* call job done later */ 1220f1c3b0fcSJames Smart 12214cc0e56eSJames Smart job_error: 12224cc0e56eSJames Smart if (dd_data != NULL) 12234cc0e56eSJames Smart kfree(dd_data); 1224f1c3b0fcSJames Smart 12254cc0e56eSJames Smart job->dd_data = NULL; 12264cc0e56eSJames Smart return rc; 1227f1c3b0fcSJames Smart } 1228f1c3b0fcSJames Smart 1229f1c3b0fcSJames Smart /** 12304cc0e56eSJames Smart * lpfc_bsg_hba_get_event - process a GET_EVENT bsg vendor command 1231f1c3b0fcSJames Smart * @job: GET_EVENT fc_bsg_job 12323b5dd52aSJames Smart **/ 1233f1c3b0fcSJames Smart static int 12344cc0e56eSJames Smart lpfc_bsg_hba_get_event(struct fc_bsg_job *job) 1235f1c3b0fcSJames Smart { 1236f1c3b0fcSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 1237f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 1238f1c3b0fcSJames Smart struct get_ct_event *event_req; 1239f1c3b0fcSJames Smart struct get_ct_event_reply *event_reply; 12404cc0e56eSJames Smart struct lpfc_bsg_event *evt; 1241f1c3b0fcSJames Smart struct event_data *evt_dat = NULL; 12424fede78fSJames Smart unsigned long flags; 12434cc0e56eSJames Smart uint32_t rc = 0; 1244f1c3b0fcSJames Smart 1245f1c3b0fcSJames Smart if (job->request_len < 1246f1c3b0fcSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct get_ct_event)) { 1247f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1248f1c3b0fcSJames Smart "2613 Received GET_CT_EVENT request below " 1249f1c3b0fcSJames Smart "minimum size\n"); 12504cc0e56eSJames Smart rc = -EINVAL; 12514cc0e56eSJames Smart goto job_error; 1252f1c3b0fcSJames Smart } 1253f1c3b0fcSJames Smart 1254f1c3b0fcSJames Smart event_req = (struct get_ct_event *) 1255f1c3b0fcSJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 1256f1c3b0fcSJames Smart 1257f1c3b0fcSJames Smart event_reply = (struct get_ct_event_reply *) 1258f1c3b0fcSJames Smart job->reply->reply_data.vendor_reply.vendor_rsp; 12594fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1260f1c3b0fcSJames Smart list_for_each_entry(evt, &phba->ct_ev_waiters, node) { 1261f1c3b0fcSJames Smart if (evt->reg_id == event_req->ev_reg_id) { 1262f1c3b0fcSJames Smart if (list_empty(&evt->events_to_get)) 1263f1c3b0fcSJames Smart break; 12644cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 1265f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 1266f1c3b0fcSJames Smart evt_dat = list_entry(evt->events_to_get.prev, 1267f1c3b0fcSJames Smart struct event_data, node); 1268f1c3b0fcSJames Smart list_del(&evt_dat->node); 1269f1c3b0fcSJames Smart break; 1270f1c3b0fcSJames Smart } 1271f1c3b0fcSJames Smart } 12724fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 1273f1c3b0fcSJames Smart 12744cc0e56eSJames Smart /* The app may continue to ask for event data until it gets 12754cc0e56eSJames Smart * an error indicating that there isn't anymore 12764cc0e56eSJames Smart */ 12774cc0e56eSJames Smart if (evt_dat == NULL) { 1278f1c3b0fcSJames Smart job->reply->reply_payload_rcv_len = 0; 1279f1c3b0fcSJames Smart rc = -ENOENT; 12804cc0e56eSJames Smart goto job_error; 1281f1c3b0fcSJames Smart } 1282f1c3b0fcSJames Smart 12834cc0e56eSJames Smart if (evt_dat->len > job->request_payload.payload_len) { 12844cc0e56eSJames Smart evt_dat->len = job->request_payload.payload_len; 1285f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1286f1c3b0fcSJames Smart "2618 Truncated event data at %d " 1287f1c3b0fcSJames Smart "bytes\n", 12884cc0e56eSJames Smart job->request_payload.payload_len); 1289f1c3b0fcSJames Smart } 1290f1c3b0fcSJames Smart 12914cc0e56eSJames Smart event_reply->type = evt_dat->type; 1292f1c3b0fcSJames Smart event_reply->immed_data = evt_dat->immed_dat; 1293f1c3b0fcSJames Smart if (evt_dat->len > 0) 1294f1c3b0fcSJames Smart job->reply->reply_payload_rcv_len = 12954cc0e56eSJames Smart sg_copy_from_buffer(job->request_payload.sg_list, 12964cc0e56eSJames Smart job->request_payload.sg_cnt, 1297f1c3b0fcSJames Smart evt_dat->data, evt_dat->len); 1298f1c3b0fcSJames Smart else 1299f1c3b0fcSJames Smart job->reply->reply_payload_rcv_len = 0; 1300f1c3b0fcSJames Smart 13014cc0e56eSJames Smart if (evt_dat) { 1302f1c3b0fcSJames Smart kfree(evt_dat->data); 1303f1c3b0fcSJames Smart kfree(evt_dat); 13044cc0e56eSJames Smart } 13054cc0e56eSJames Smart 13064fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 13074cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 13084fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 13094cc0e56eSJames Smart job->dd_data = NULL; 13104cc0e56eSJames Smart job->reply->result = 0; 1311f1c3b0fcSJames Smart job->job_done(job); 13124cc0e56eSJames Smart return 0; 1313f1c3b0fcSJames Smart 13144cc0e56eSJames Smart job_error: 13154cc0e56eSJames Smart job->dd_data = NULL; 13164cc0e56eSJames Smart job->reply->result = rc; 1317f1c3b0fcSJames Smart return rc; 1318f1c3b0fcSJames Smart } 1319f1c3b0fcSJames Smart 1320f1c3b0fcSJames Smart /** 13213b5dd52aSJames Smart * lpfc_issue_ct_rsp_cmp - lpfc_issue_ct_rsp's completion handler 13223b5dd52aSJames Smart * @phba: Pointer to HBA context object. 13233b5dd52aSJames Smart * @cmdiocbq: Pointer to command iocb. 13243b5dd52aSJames Smart * @rspiocbq: Pointer to response iocb. 13253b5dd52aSJames Smart * 13263b5dd52aSJames Smart * This function is the completion handler for iocbs issued using 13273b5dd52aSJames Smart * lpfc_issue_ct_rsp_cmp function. This function is called by the 13283b5dd52aSJames Smart * ring event handler function without any lock held. This function 13293b5dd52aSJames Smart * can be called from both worker thread context and interrupt 13303b5dd52aSJames Smart * context. This function also can be called from other thread which 13313b5dd52aSJames Smart * cleans up the SLI layer objects. 13323b5dd52aSJames Smart * This function copy the contents of the response iocb to the 13333b5dd52aSJames Smart * response iocb memory object provided by the caller of 13343b5dd52aSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 13353b5dd52aSJames Smart * sleeps for the iocb completion. 13363b5dd52aSJames Smart **/ 13373b5dd52aSJames Smart static void 13383b5dd52aSJames Smart lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba, 13393b5dd52aSJames Smart struct lpfc_iocbq *cmdiocbq, 13403b5dd52aSJames Smart struct lpfc_iocbq *rspiocbq) 13413b5dd52aSJames Smart { 13423b5dd52aSJames Smart struct bsg_job_data *dd_data; 13433b5dd52aSJames Smart struct fc_bsg_job *job; 13443b5dd52aSJames Smart IOCB_t *rsp; 1345*a33c4f7bSJames Smart struct lpfc_dmabuf *bmp, *cmp; 13463b5dd52aSJames Smart struct lpfc_nodelist *ndlp; 13473b5dd52aSJames Smart unsigned long flags; 13483b5dd52aSJames Smart int rc = 0; 13493b5dd52aSJames Smart 1350*a33c4f7bSJames Smart dd_data = cmdiocbq->context1; 1351*a33c4f7bSJames Smart 1352*a33c4f7bSJames Smart /* Determine if job has been aborted */ 13533b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1354*a33c4f7bSJames Smart job = dd_data->set_job; 1355*a33c4f7bSJames Smart if (job) { 1356*a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 1357*a33c4f7bSJames Smart job->dd_data = NULL; 13583b5dd52aSJames Smart } 1359*a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 13603b5dd52aSJames Smart 13613b5dd52aSJames Smart ndlp = dd_data->context_un.iocb.ndlp; 1362*a33c4f7bSJames Smart cmp = cmdiocbq->context2; 1363*a33c4f7bSJames Smart bmp = cmdiocbq->context3; 1364*a33c4f7bSJames Smart rsp = &rspiocbq->iocb; 13653b5dd52aSJames Smart 1366*a33c4f7bSJames Smart /* Copy the completed job data or set the error status */ 13673b5dd52aSJames Smart 1368*a33c4f7bSJames Smart if (job) { 13693b5dd52aSJames Smart if (rsp->ulpStatus) { 13703b5dd52aSJames Smart if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { 1371e3d2b802SJames Smart switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) { 13723b5dd52aSJames Smart case IOERR_SEQUENCE_TIMEOUT: 13733b5dd52aSJames Smart rc = -ETIMEDOUT; 13743b5dd52aSJames Smart break; 13753b5dd52aSJames Smart case IOERR_INVALID_RPI: 13763b5dd52aSJames Smart rc = -EFAULT; 13773b5dd52aSJames Smart break; 13783b5dd52aSJames Smart default: 13793b5dd52aSJames Smart rc = -EACCES; 13803b5dd52aSJames Smart break; 13813b5dd52aSJames Smart } 1382*a33c4f7bSJames Smart } else { 13833b5dd52aSJames Smart rc = -EACCES; 1384*a33c4f7bSJames Smart } 1385*a33c4f7bSJames Smart } else { 1386*a33c4f7bSJames Smart job->reply->reply_payload_rcv_len = 0; 1387*a33c4f7bSJames Smart } 1388*a33c4f7bSJames Smart } 13893b5dd52aSJames Smart 1390*a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 13913b5dd52aSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 1392*a33c4f7bSJames Smart kfree(bmp); 13933b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 13943b5dd52aSJames Smart lpfc_nlp_put(ndlp); 13953b5dd52aSJames Smart kfree(dd_data); 1396*a33c4f7bSJames Smart 1397*a33c4f7bSJames Smart /* Complete the job if the job is still active */ 1398*a33c4f7bSJames Smart 1399*a33c4f7bSJames Smart if (job) { 14003b5dd52aSJames Smart job->reply->result = rc; 14013b5dd52aSJames Smart job->job_done(job); 1402*a33c4f7bSJames Smart } 14033b5dd52aSJames Smart return; 14043b5dd52aSJames Smart } 14053b5dd52aSJames Smart 14063b5dd52aSJames Smart /** 14073b5dd52aSJames Smart * lpfc_issue_ct_rsp - issue a ct response 14083b5dd52aSJames Smart * @phba: Pointer to HBA context object. 14093b5dd52aSJames Smart * @job: Pointer to the job object. 14103b5dd52aSJames Smart * @tag: tag index value into the ports context exchange array. 14113b5dd52aSJames Smart * @bmp: Pointer to a dma buffer descriptor. 14123b5dd52aSJames Smart * @num_entry: Number of enties in the bde. 14133b5dd52aSJames Smart **/ 14143b5dd52aSJames Smart static int 14153b5dd52aSJames Smart lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag, 1416*a33c4f7bSJames Smart struct lpfc_dmabuf *cmp, struct lpfc_dmabuf *bmp, 1417*a33c4f7bSJames Smart int num_entry) 14183b5dd52aSJames Smart { 14193b5dd52aSJames Smart IOCB_t *icmd; 14203b5dd52aSJames Smart struct lpfc_iocbq *ctiocb = NULL; 14213b5dd52aSJames Smart int rc = 0; 14223b5dd52aSJames Smart struct lpfc_nodelist *ndlp = NULL; 14233b5dd52aSJames Smart struct bsg_job_data *dd_data; 14243b5dd52aSJames Smart uint32_t creg_val; 14253b5dd52aSJames Smart 14263b5dd52aSJames Smart /* allocate our bsg tracking structure */ 14273b5dd52aSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 14283b5dd52aSJames Smart if (!dd_data) { 14293b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 14303b5dd52aSJames Smart "2736 Failed allocation of dd_data\n"); 14313b5dd52aSJames Smart rc = -ENOMEM; 14323b5dd52aSJames Smart goto no_dd_data; 14333b5dd52aSJames Smart } 14343b5dd52aSJames Smart 14353b5dd52aSJames Smart /* Allocate buffer for command iocb */ 14363b5dd52aSJames Smart ctiocb = lpfc_sli_get_iocbq(phba); 14373b5dd52aSJames Smart if (!ctiocb) { 1438d439d286SJames Smart rc = -ENOMEM; 14393b5dd52aSJames Smart goto no_ctiocb; 14403b5dd52aSJames Smart } 14413b5dd52aSJames Smart 14423b5dd52aSJames Smart icmd = &ctiocb->iocb; 14433b5dd52aSJames Smart icmd->un.xseq64.bdl.ulpIoTag32 = 0; 14443b5dd52aSJames Smart icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(bmp->phys); 14453b5dd52aSJames Smart icmd->un.xseq64.bdl.addrLow = putPaddrLow(bmp->phys); 14463b5dd52aSJames Smart icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 14473b5dd52aSJames Smart icmd->un.xseq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64)); 14483b5dd52aSJames Smart icmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); 14493b5dd52aSJames Smart icmd->un.xseq64.w5.hcsw.Dfctl = 0; 14503b5dd52aSJames Smart icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_SOL_CTL; 14513b5dd52aSJames Smart icmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; 14523b5dd52aSJames Smart 14533b5dd52aSJames Smart /* Fill in rest of iocb */ 14543b5dd52aSJames Smart icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; 14553b5dd52aSJames Smart icmd->ulpBdeCount = 1; 14563b5dd52aSJames Smart icmd->ulpLe = 1; 14573b5dd52aSJames Smart icmd->ulpClass = CLASS3; 14583b5dd52aSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) { 14593b5dd52aSJames Smart /* Do not issue unsol response if oxid not marked as valid */ 14606dd9e31cSJames Smart if (phba->ct_ctx[tag].valid != UNSOL_VALID) { 14613b5dd52aSJames Smart rc = IOCB_ERROR; 14623b5dd52aSJames Smart goto issue_ct_rsp_exit; 14633b5dd52aSJames Smart } 14647851fe2cSJames Smart icmd->ulpContext = phba->ct_ctx[tag].rxid; 14657851fe2cSJames Smart icmd->unsli3.rcvsli3.ox_id = phba->ct_ctx[tag].oxid; 14663b5dd52aSJames Smart ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID); 14673b5dd52aSJames Smart if (!ndlp) { 14683b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, 14693b5dd52aSJames Smart "2721 ndlp null for oxid %x SID %x\n", 14703b5dd52aSJames Smart icmd->ulpContext, 14713b5dd52aSJames Smart phba->ct_ctx[tag].SID); 14723b5dd52aSJames Smart rc = IOCB_ERROR; 14733b5dd52aSJames Smart goto issue_ct_rsp_exit; 14743b5dd52aSJames Smart } 1475589a52d6SJames Smart 1476589a52d6SJames Smart /* Check if the ndlp is active */ 1477589a52d6SJames Smart if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { 1478*a33c4f7bSJames Smart rc = IOCB_ERROR; 1479589a52d6SJames Smart goto issue_ct_rsp_exit; 1480589a52d6SJames Smart } 1481589a52d6SJames Smart 1482589a52d6SJames Smart /* get a refernece count so the ndlp doesn't go away while 1483589a52d6SJames Smart * we respond 1484589a52d6SJames Smart */ 1485589a52d6SJames Smart if (!lpfc_nlp_get(ndlp)) { 1486*a33c4f7bSJames Smart rc = IOCB_ERROR; 1487589a52d6SJames Smart goto issue_ct_rsp_exit; 1488589a52d6SJames Smart } 1489589a52d6SJames Smart 14907851fe2cSJames Smart icmd->un.ulpWord[3] = 14916d368e53SJames Smart phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; 14926d368e53SJames Smart 14933b5dd52aSJames Smart /* The exchange is done, mark the entry as invalid */ 14946dd9e31cSJames Smart phba->ct_ctx[tag].valid = UNSOL_INVALID; 14953b5dd52aSJames Smart } else 14963b5dd52aSJames Smart icmd->ulpContext = (ushort) tag; 14973b5dd52aSJames Smart 14983b5dd52aSJames Smart icmd->ulpTimeout = phba->fc_ratov * 2; 14993b5dd52aSJames Smart 15003b5dd52aSJames Smart /* Xmit CT response on exchange <xid> */ 15013b5dd52aSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_ELS, 15027851fe2cSJames Smart "2722 Xmit CT response on exchange x%x Data: x%x x%x x%x\n", 15037851fe2cSJames Smart icmd->ulpContext, icmd->ulpIoTag, tag, phba->link_state); 15043b5dd52aSJames Smart 15053b5dd52aSJames Smart ctiocb->iocb_cmpl = NULL; 15063b5dd52aSJames Smart ctiocb->iocb_flag |= LPFC_IO_LIBDFC; 15073b5dd52aSJames Smart ctiocb->vport = phba->pport; 1508*a33c4f7bSJames Smart ctiocb->context1 = dd_data; 1509*a33c4f7bSJames Smart ctiocb->context2 = cmp; 15103b5dd52aSJames Smart ctiocb->context3 = bmp; 15113b5dd52aSJames Smart ctiocb->iocb_cmpl = lpfc_issue_ct_rsp_cmp; 1512*a33c4f7bSJames Smart 15133b5dd52aSJames Smart dd_data->type = TYPE_IOCB; 1514*a33c4f7bSJames Smart dd_data->set_job = job; 15153b5dd52aSJames Smart dd_data->context_un.iocb.cmdiocbq = ctiocb; 15163b5dd52aSJames Smart dd_data->context_un.iocb.ndlp = ndlp; 1517*a33c4f7bSJames Smart dd_data->context_un.iocb.rmp = NULL; 1518*a33c4f7bSJames Smart job->dd_data = dd_data; 15193b5dd52aSJames Smart 15203b5dd52aSJames Smart if (phba->cfg_poll & DISABLE_FCP_RING_INT) { 15219940b97bSJames Smart if (lpfc_readl(phba->HCregaddr, &creg_val)) { 15229940b97bSJames Smart rc = -IOCB_ERROR; 15239940b97bSJames Smart goto issue_ct_rsp_exit; 15249940b97bSJames Smart } 15253b5dd52aSJames Smart creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); 15263b5dd52aSJames Smart writel(creg_val, phba->HCregaddr); 15273b5dd52aSJames Smart readl(phba->HCregaddr); /* flush */ 15283b5dd52aSJames Smart } 15293b5dd52aSJames Smart 15303b5dd52aSJames Smart rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); 15313b5dd52aSJames Smart 15323b5dd52aSJames Smart if (rc == IOCB_SUCCESS) 15333b5dd52aSJames Smart return 0; /* done for now */ 15343b5dd52aSJames Smart 15353b5dd52aSJames Smart issue_ct_rsp_exit: 15363b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, ctiocb); 15373b5dd52aSJames Smart no_ctiocb: 15383b5dd52aSJames Smart kfree(dd_data); 15393b5dd52aSJames Smart no_dd_data: 15403b5dd52aSJames Smart return rc; 15413b5dd52aSJames Smart } 15423b5dd52aSJames Smart 15433b5dd52aSJames Smart /** 15443b5dd52aSJames Smart * lpfc_bsg_send_mgmt_rsp - process a SEND_MGMT_RESP bsg vendor command 15453b5dd52aSJames Smart * @job: SEND_MGMT_RESP fc_bsg_job 15463b5dd52aSJames Smart **/ 15473b5dd52aSJames Smart static int 15483b5dd52aSJames Smart lpfc_bsg_send_mgmt_rsp(struct fc_bsg_job *job) 15493b5dd52aSJames Smart { 15503b5dd52aSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 15513b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 15523b5dd52aSJames Smart struct send_mgmt_resp *mgmt_resp = (struct send_mgmt_resp *) 15533b5dd52aSJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 15543b5dd52aSJames Smart struct ulp_bde64 *bpl; 1555*a33c4f7bSJames Smart struct lpfc_dmabuf *bmp = NULL, *cmp = NULL; 1556*a33c4f7bSJames Smart int bpl_entries; 15573b5dd52aSJames Smart uint32_t tag = mgmt_resp->tag; 15583b5dd52aSJames Smart unsigned long reqbfrcnt = 15593b5dd52aSJames Smart (unsigned long)job->request_payload.payload_len; 15603b5dd52aSJames Smart int rc = 0; 15613b5dd52aSJames Smart 15623b5dd52aSJames Smart /* in case no data is transferred */ 15633b5dd52aSJames Smart job->reply->reply_payload_rcv_len = 0; 15643b5dd52aSJames Smart 15653b5dd52aSJames Smart if (!reqbfrcnt || (reqbfrcnt > (80 * BUF_SZ_4K))) { 15663b5dd52aSJames Smart rc = -ERANGE; 15673b5dd52aSJames Smart goto send_mgmt_rsp_exit; 15683b5dd52aSJames Smart } 15693b5dd52aSJames Smart 15703b5dd52aSJames Smart bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 15713b5dd52aSJames Smart if (!bmp) { 15723b5dd52aSJames Smart rc = -ENOMEM; 15733b5dd52aSJames Smart goto send_mgmt_rsp_exit; 15743b5dd52aSJames Smart } 15753b5dd52aSJames Smart 15763b5dd52aSJames Smart bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); 15773b5dd52aSJames Smart if (!bmp->virt) { 15783b5dd52aSJames Smart rc = -ENOMEM; 15793b5dd52aSJames Smart goto send_mgmt_rsp_free_bmp; 15803b5dd52aSJames Smart } 15813b5dd52aSJames Smart 15823b5dd52aSJames Smart INIT_LIST_HEAD(&bmp->list); 15833b5dd52aSJames Smart bpl = (struct ulp_bde64 *) bmp->virt; 1584*a33c4f7bSJames Smart bpl_entries = (LPFC_BPL_SIZE/sizeof(struct ulp_bde64)); 1585*a33c4f7bSJames Smart cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len, 1586*a33c4f7bSJames Smart 1, bpl, &bpl_entries); 1587*a33c4f7bSJames Smart if (!cmp) { 1588*a33c4f7bSJames Smart rc = -ENOMEM; 1589*a33c4f7bSJames Smart goto send_mgmt_rsp_free_bmp; 15903b5dd52aSJames Smart } 1591*a33c4f7bSJames Smart lpfc_bsg_copy_data(cmp, &job->request_payload, 1592*a33c4f7bSJames Smart job->request_payload.payload_len, 1); 15933b5dd52aSJames Smart 1594*a33c4f7bSJames Smart rc = lpfc_issue_ct_rsp(phba, job, tag, cmp, bmp, bpl_entries); 15953b5dd52aSJames Smart 15963b5dd52aSJames Smart if (rc == IOCB_SUCCESS) 15973b5dd52aSJames Smart return 0; /* done for now */ 15983b5dd52aSJames Smart 15993b5dd52aSJames Smart rc = -EACCES; 1600*a33c4f7bSJames Smart 1601*a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 16023b5dd52aSJames Smart 16033b5dd52aSJames Smart send_mgmt_rsp_free_bmp: 1604*a33c4f7bSJames Smart if (bmp->virt) 1605*a33c4f7bSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 16063b5dd52aSJames Smart kfree(bmp); 16073b5dd52aSJames Smart send_mgmt_rsp_exit: 16083b5dd52aSJames Smart /* make error code available to userspace */ 16093b5dd52aSJames Smart job->reply->result = rc; 16103b5dd52aSJames Smart job->dd_data = NULL; 16113b5dd52aSJames Smart return rc; 16123b5dd52aSJames Smart } 16133b5dd52aSJames Smart 16143b5dd52aSJames Smart /** 16157ad20aa9SJames Smart * lpfc_bsg_diag_mode_enter - process preparing into device diag loopback mode 16167ad20aa9SJames Smart * @phba: Pointer to HBA context object. 16173b5dd52aSJames Smart * 16187ad20aa9SJames Smart * This function is responsible for preparing driver for diag loopback 16197ad20aa9SJames Smart * on device. 16203b5dd52aSJames Smart */ 16213b5dd52aSJames Smart static int 162288a2cfbbSJames Smart lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba) 16233b5dd52aSJames Smart { 16243b5dd52aSJames Smart struct lpfc_vport **vports; 16257ad20aa9SJames Smart struct Scsi_Host *shost; 16267ad20aa9SJames Smart struct lpfc_sli *psli; 16277ad20aa9SJames Smart struct lpfc_sli_ring *pring; 16283b5dd52aSJames Smart int i = 0; 16293b5dd52aSJames Smart 16307ad20aa9SJames Smart psli = &phba->sli; 16317ad20aa9SJames Smart if (!psli) 16327ad20aa9SJames Smart return -ENODEV; 16333b5dd52aSJames Smart 16347ad20aa9SJames Smart pring = &psli->ring[LPFC_FCP_RING]; 16357ad20aa9SJames Smart if (!pring) 16367ad20aa9SJames Smart return -ENODEV; 16373b5dd52aSJames Smart 16383b5dd52aSJames Smart if ((phba->link_state == LPFC_HBA_ERROR) || 16393b5dd52aSJames Smart (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || 16407ad20aa9SJames Smart (!(psli->sli_flag & LPFC_SLI_ACTIVE))) 16417ad20aa9SJames Smart return -EACCES; 16423b5dd52aSJames Smart 16433b5dd52aSJames Smart vports = lpfc_create_vport_work_array(phba); 16443b5dd52aSJames Smart if (vports) { 16453b5dd52aSJames Smart for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { 16463b5dd52aSJames Smart shost = lpfc_shost_from_vport(vports[i]); 16473b5dd52aSJames Smart scsi_block_requests(shost); 16483b5dd52aSJames Smart } 16493b5dd52aSJames Smart lpfc_destroy_vport_work_array(phba, vports); 16503b5dd52aSJames Smart } else { 16513b5dd52aSJames Smart shost = lpfc_shost_from_vport(phba->pport); 16523b5dd52aSJames Smart scsi_block_requests(shost); 16533b5dd52aSJames Smart } 16543b5dd52aSJames Smart 16550e9bb8d7SJames Smart while (!list_empty(&pring->txcmplq)) { 16563b5dd52aSJames Smart if (i++ > 500) /* wait up to 5 seconds */ 16573b5dd52aSJames Smart break; 16583b5dd52aSJames Smart msleep(10); 16593b5dd52aSJames Smart } 16607ad20aa9SJames Smart return 0; 16617ad20aa9SJames Smart } 16623b5dd52aSJames Smart 16637ad20aa9SJames Smart /** 16647ad20aa9SJames Smart * lpfc_bsg_diag_mode_exit - exit process from device diag loopback mode 16657ad20aa9SJames Smart * @phba: Pointer to HBA context object. 16667ad20aa9SJames Smart * 16677ad20aa9SJames Smart * This function is responsible for driver exit processing of setting up 16687ad20aa9SJames Smart * diag loopback mode on device. 16697ad20aa9SJames Smart */ 16707ad20aa9SJames Smart static void 16717ad20aa9SJames Smart lpfc_bsg_diag_mode_exit(struct lpfc_hba *phba) 16727ad20aa9SJames Smart { 16737ad20aa9SJames Smart struct Scsi_Host *shost; 16747ad20aa9SJames Smart struct lpfc_vport **vports; 16757ad20aa9SJames Smart int i; 16767ad20aa9SJames Smart 16777ad20aa9SJames Smart vports = lpfc_create_vport_work_array(phba); 16787ad20aa9SJames Smart if (vports) { 16797ad20aa9SJames Smart for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { 16807ad20aa9SJames Smart shost = lpfc_shost_from_vport(vports[i]); 16817ad20aa9SJames Smart scsi_unblock_requests(shost); 16827ad20aa9SJames Smart } 16837ad20aa9SJames Smart lpfc_destroy_vport_work_array(phba, vports); 16847ad20aa9SJames Smart } else { 16857ad20aa9SJames Smart shost = lpfc_shost_from_vport(phba->pport); 16867ad20aa9SJames Smart scsi_unblock_requests(shost); 16877ad20aa9SJames Smart } 16887ad20aa9SJames Smart return; 16897ad20aa9SJames Smart } 16907ad20aa9SJames Smart 16917ad20aa9SJames Smart /** 16927ad20aa9SJames Smart * lpfc_sli3_bsg_diag_loopback_mode - process an sli3 bsg vendor command 16937ad20aa9SJames Smart * @phba: Pointer to HBA context object. 16947ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_MODE 16957ad20aa9SJames Smart * 16967ad20aa9SJames Smart * This function is responsible for placing an sli3 port into diagnostic 16977ad20aa9SJames Smart * loopback mode in order to perform a diagnostic loopback test. 16987ad20aa9SJames Smart * All new scsi requests are blocked, a small delay is used to allow the 16997ad20aa9SJames Smart * scsi requests to complete then the link is brought down. If the link is 17007ad20aa9SJames Smart * is placed in loopback mode then scsi requests are again allowed 17017ad20aa9SJames Smart * so the scsi mid-layer doesn't give up on the port. 17027ad20aa9SJames Smart * All of this is done in-line. 17037ad20aa9SJames Smart */ 17047ad20aa9SJames Smart static int 17057ad20aa9SJames Smart lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job) 17067ad20aa9SJames Smart { 17077ad20aa9SJames Smart struct diag_mode_set *loopback_mode; 17087ad20aa9SJames Smart uint32_t link_flags; 17097ad20aa9SJames Smart uint32_t timeout; 17101b51197dSJames Smart LPFC_MBOXQ_t *pmboxq = NULL; 1711b76f2dc9SJames Smart int mbxstatus = MBX_SUCCESS; 17127ad20aa9SJames Smart int i = 0; 17137ad20aa9SJames Smart int rc = 0; 17147ad20aa9SJames Smart 17157ad20aa9SJames Smart /* no data to return just the return code */ 17167ad20aa9SJames Smart job->reply->reply_payload_rcv_len = 0; 17177ad20aa9SJames Smart 17187ad20aa9SJames Smart if (job->request_len < sizeof(struct fc_bsg_request) + 17197ad20aa9SJames Smart sizeof(struct diag_mode_set)) { 17207ad20aa9SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 17217ad20aa9SJames Smart "2738 Received DIAG MODE request size:%d " 17227ad20aa9SJames Smart "below the minimum size:%d\n", 17237ad20aa9SJames Smart job->request_len, 17247ad20aa9SJames Smart (int)(sizeof(struct fc_bsg_request) + 17257ad20aa9SJames Smart sizeof(struct diag_mode_set))); 17267ad20aa9SJames Smart rc = -EINVAL; 17277ad20aa9SJames Smart goto job_error; 17287ad20aa9SJames Smart } 17297ad20aa9SJames Smart 173088a2cfbbSJames Smart rc = lpfc_bsg_diag_mode_enter(phba); 17317ad20aa9SJames Smart if (rc) 17327ad20aa9SJames Smart goto job_error; 17337ad20aa9SJames Smart 17347ad20aa9SJames Smart /* bring the link to diagnostic mode */ 17357ad20aa9SJames Smart loopback_mode = (struct diag_mode_set *) 17367ad20aa9SJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 17377ad20aa9SJames Smart link_flags = loopback_mode->type; 17387ad20aa9SJames Smart timeout = loopback_mode->timeout * 100; 17397ad20aa9SJames Smart 17407ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 17417ad20aa9SJames Smart if (!pmboxq) { 17427ad20aa9SJames Smart rc = -ENOMEM; 17437ad20aa9SJames Smart goto loopback_mode_exit; 17447ad20aa9SJames Smart } 17453b5dd52aSJames Smart memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 17463b5dd52aSJames Smart pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK; 17473b5dd52aSJames Smart pmboxq->u.mb.mbxOwner = OWN_HOST; 17483b5dd52aSJames Smart 17493b5dd52aSJames Smart mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); 17503b5dd52aSJames Smart 17513b5dd52aSJames Smart if ((mbxstatus == MBX_SUCCESS) && (pmboxq->u.mb.mbxStatus == 0)) { 17523b5dd52aSJames Smart /* wait for link down before proceeding */ 17533b5dd52aSJames Smart i = 0; 17543b5dd52aSJames Smart while (phba->link_state != LPFC_LINK_DOWN) { 17553b5dd52aSJames Smart if (i++ > timeout) { 17563b5dd52aSJames Smart rc = -ETIMEDOUT; 17573b5dd52aSJames Smart goto loopback_mode_exit; 17583b5dd52aSJames Smart } 17593b5dd52aSJames Smart msleep(10); 17603b5dd52aSJames Smart } 17613b5dd52aSJames Smart 17623b5dd52aSJames Smart memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 17633b5dd52aSJames Smart if (link_flags == INTERNAL_LOOP_BACK) 17643b5dd52aSJames Smart pmboxq->u.mb.un.varInitLnk.link_flags = FLAGS_LOCAL_LB; 17653b5dd52aSJames Smart else 17663b5dd52aSJames Smart pmboxq->u.mb.un.varInitLnk.link_flags = 17673b5dd52aSJames Smart FLAGS_TOPOLOGY_MODE_LOOP; 17683b5dd52aSJames Smart 17693b5dd52aSJames Smart pmboxq->u.mb.mbxCommand = MBX_INIT_LINK; 17703b5dd52aSJames Smart pmboxq->u.mb.mbxOwner = OWN_HOST; 17713b5dd52aSJames Smart 17723b5dd52aSJames Smart mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, 17733b5dd52aSJames Smart LPFC_MBOX_TMO); 17743b5dd52aSJames Smart 17753b5dd52aSJames Smart if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) 17763b5dd52aSJames Smart rc = -ENODEV; 17773b5dd52aSJames Smart else { 17781b51197dSJames Smart spin_lock_irq(&phba->hbalock); 17793b5dd52aSJames Smart phba->link_flag |= LS_LOOPBACK_MODE; 17801b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 17813b5dd52aSJames Smart /* wait for the link attention interrupt */ 17823b5dd52aSJames Smart msleep(100); 17833b5dd52aSJames Smart 17843b5dd52aSJames Smart i = 0; 17853b5dd52aSJames Smart while (phba->link_state != LPFC_HBA_READY) { 17863b5dd52aSJames Smart if (i++ > timeout) { 17873b5dd52aSJames Smart rc = -ETIMEDOUT; 17883b5dd52aSJames Smart break; 17893b5dd52aSJames Smart } 17903b5dd52aSJames Smart 17913b5dd52aSJames Smart msleep(10); 17923b5dd52aSJames Smart } 17933b5dd52aSJames Smart } 17943b5dd52aSJames Smart 17953b5dd52aSJames Smart } else 17963b5dd52aSJames Smart rc = -ENODEV; 17973b5dd52aSJames Smart 17983b5dd52aSJames Smart loopback_mode_exit: 17997ad20aa9SJames Smart lpfc_bsg_diag_mode_exit(phba); 18003b5dd52aSJames Smart 18013b5dd52aSJames Smart /* 18023b5dd52aSJames Smart * Let SLI layer release mboxq if mbox command completed after timeout. 18033b5dd52aSJames Smart */ 18041b51197dSJames Smart if (pmboxq && mbxstatus != MBX_TIMEOUT) 18053b5dd52aSJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 18063b5dd52aSJames Smart 18073b5dd52aSJames Smart job_error: 18083b5dd52aSJames Smart /* make error code available to userspace */ 18093b5dd52aSJames Smart job->reply->result = rc; 18103b5dd52aSJames Smart /* complete the job back to userspace if no error */ 18113b5dd52aSJames Smart if (rc == 0) 18123b5dd52aSJames Smart job->job_done(job); 18133b5dd52aSJames Smart return rc; 18143b5dd52aSJames Smart } 18153b5dd52aSJames Smart 18163b5dd52aSJames Smart /** 18177ad20aa9SJames Smart * lpfc_sli4_bsg_set_link_diag_state - set sli4 link diag state 18187ad20aa9SJames Smart * @phba: Pointer to HBA context object. 18197ad20aa9SJames Smart * @diag: Flag for set link to diag or nomral operation state. 18207ad20aa9SJames Smart * 18217ad20aa9SJames Smart * This function is responsible for issuing a sli4 mailbox command for setting 18227ad20aa9SJames Smart * link to either diag state or normal operation state. 18237ad20aa9SJames Smart */ 18247ad20aa9SJames Smart static int 18257ad20aa9SJames Smart lpfc_sli4_bsg_set_link_diag_state(struct lpfc_hba *phba, uint32_t diag) 18267ad20aa9SJames Smart { 18277ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq; 18287ad20aa9SJames Smart struct lpfc_mbx_set_link_diag_state *link_diag_state; 18297ad20aa9SJames Smart uint32_t req_len, alloc_len; 18307ad20aa9SJames Smart int mbxstatus = MBX_SUCCESS, rc; 18317ad20aa9SJames Smart 18327ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 18337ad20aa9SJames Smart if (!pmboxq) 18347ad20aa9SJames Smart return -ENOMEM; 18357ad20aa9SJames Smart 18367ad20aa9SJames Smart req_len = (sizeof(struct lpfc_mbx_set_link_diag_state) - 18377ad20aa9SJames Smart sizeof(struct lpfc_sli4_cfg_mhdr)); 18387ad20aa9SJames Smart alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, 18397ad20aa9SJames Smart LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE, 18407ad20aa9SJames Smart req_len, LPFC_SLI4_MBX_EMBED); 18417ad20aa9SJames Smart if (alloc_len != req_len) { 18427ad20aa9SJames Smart rc = -ENOMEM; 18437ad20aa9SJames Smart goto link_diag_state_set_out; 18447ad20aa9SJames Smart } 18451b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 18461b51197dSJames Smart "3128 Set link to diagnostic state:x%x (x%x/x%x)\n", 18471b51197dSJames Smart diag, phba->sli4_hba.lnk_info.lnk_tp, 18481b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_no); 18491b51197dSJames Smart 18507ad20aa9SJames Smart link_diag_state = &pmboxq->u.mqe.un.link_diag_state; 18519731592bSJames Smart bf_set(lpfc_mbx_set_diag_state_diag_bit_valid, &link_diag_state->u.req, 18529731592bSJames Smart LPFC_DIAG_STATE_DIAG_BIT_VALID_CHANGE); 18537ad20aa9SJames Smart bf_set(lpfc_mbx_set_diag_state_link_num, &link_diag_state->u.req, 18541b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_no); 18557ad20aa9SJames Smart bf_set(lpfc_mbx_set_diag_state_link_type, &link_diag_state->u.req, 18561b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_tp); 18577ad20aa9SJames Smart if (diag) 18587ad20aa9SJames Smart bf_set(lpfc_mbx_set_diag_state_diag, 18597ad20aa9SJames Smart &link_diag_state->u.req, 1); 18607ad20aa9SJames Smart else 18617ad20aa9SJames Smart bf_set(lpfc_mbx_set_diag_state_diag, 18627ad20aa9SJames Smart &link_diag_state->u.req, 0); 18637ad20aa9SJames Smart 18647ad20aa9SJames Smart mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); 18657ad20aa9SJames Smart 18667ad20aa9SJames Smart if ((mbxstatus == MBX_SUCCESS) && (pmboxq->u.mb.mbxStatus == 0)) 18677ad20aa9SJames Smart rc = 0; 18687ad20aa9SJames Smart else 18697ad20aa9SJames Smart rc = -ENODEV; 18707ad20aa9SJames Smart 18717ad20aa9SJames Smart link_diag_state_set_out: 18727ad20aa9SJames Smart if (pmboxq && (mbxstatus != MBX_TIMEOUT)) 18737ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 18747ad20aa9SJames Smart 18757ad20aa9SJames Smart return rc; 18767ad20aa9SJames Smart } 18777ad20aa9SJames Smart 18787ad20aa9SJames Smart /** 18791b51197dSJames Smart * lpfc_sli4_bsg_set_internal_loopback - set sli4 internal loopback diagnostic 18801b51197dSJames Smart * @phba: Pointer to HBA context object. 18811b51197dSJames Smart * 18821b51197dSJames Smart * This function is responsible for issuing a sli4 mailbox command for setting 18831b51197dSJames Smart * up internal loopback diagnostic. 18841b51197dSJames Smart */ 18851b51197dSJames Smart static int 18861b51197dSJames Smart lpfc_sli4_bsg_set_internal_loopback(struct lpfc_hba *phba) 18871b51197dSJames Smart { 18881b51197dSJames Smart LPFC_MBOXQ_t *pmboxq; 18891b51197dSJames Smart uint32_t req_len, alloc_len; 18901b51197dSJames Smart struct lpfc_mbx_set_link_diag_loopback *link_diag_loopback; 18911b51197dSJames Smart int mbxstatus = MBX_SUCCESS, rc = 0; 18921b51197dSJames Smart 18931b51197dSJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 18941b51197dSJames Smart if (!pmboxq) 18951b51197dSJames Smart return -ENOMEM; 18961b51197dSJames Smart req_len = (sizeof(struct lpfc_mbx_set_link_diag_loopback) - 18971b51197dSJames Smart sizeof(struct lpfc_sli4_cfg_mhdr)); 18981b51197dSJames Smart alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, 18991b51197dSJames Smart LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK, 19001b51197dSJames Smart req_len, LPFC_SLI4_MBX_EMBED); 19011b51197dSJames Smart if (alloc_len != req_len) { 19021b51197dSJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 19031b51197dSJames Smart return -ENOMEM; 19041b51197dSJames Smart } 19051b51197dSJames Smart link_diag_loopback = &pmboxq->u.mqe.un.link_diag_loopback; 19061b51197dSJames Smart bf_set(lpfc_mbx_set_diag_state_link_num, 19071b51197dSJames Smart &link_diag_loopback->u.req, phba->sli4_hba.lnk_info.lnk_no); 19081b51197dSJames Smart bf_set(lpfc_mbx_set_diag_state_link_type, 19091b51197dSJames Smart &link_diag_loopback->u.req, phba->sli4_hba.lnk_info.lnk_tp); 19101b51197dSJames Smart bf_set(lpfc_mbx_set_diag_lpbk_type, &link_diag_loopback->u.req, 19113ef6d24cSJames Smart LPFC_DIAG_LOOPBACK_TYPE_INTERNAL); 19121b51197dSJames Smart 19131b51197dSJames Smart mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); 19141b51197dSJames Smart if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) { 19151b51197dSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 19161b51197dSJames Smart "3127 Failed setup loopback mode mailbox " 19171b51197dSJames Smart "command, rc:x%x, status:x%x\n", mbxstatus, 19181b51197dSJames Smart pmboxq->u.mb.mbxStatus); 19191b51197dSJames Smart rc = -ENODEV; 19201b51197dSJames Smart } 19211b51197dSJames Smart if (pmboxq && (mbxstatus != MBX_TIMEOUT)) 19221b51197dSJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 19231b51197dSJames Smart return rc; 19241b51197dSJames Smart } 19251b51197dSJames Smart 19261b51197dSJames Smart /** 19271b51197dSJames Smart * lpfc_sli4_diag_fcport_reg_setup - setup port registrations for diagnostic 19281b51197dSJames Smart * @phba: Pointer to HBA context object. 19291b51197dSJames Smart * 19301b51197dSJames Smart * This function set up SLI4 FC port registrations for diagnostic run, which 19311b51197dSJames Smart * includes all the rpis, vfi, and also vpi. 19321b51197dSJames Smart */ 19331b51197dSJames Smart static int 19341b51197dSJames Smart lpfc_sli4_diag_fcport_reg_setup(struct lpfc_hba *phba) 19351b51197dSJames Smart { 19361b51197dSJames Smart int rc; 19371b51197dSJames Smart 19381b51197dSJames Smart if (phba->pport->fc_flag & FC_VFI_REGISTERED) { 19391b51197dSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 19401b51197dSJames Smart "3136 Port still had vfi registered: " 19411b51197dSJames Smart "mydid:x%x, fcfi:%d, vfi:%d, vpi:%d\n", 19421b51197dSJames Smart phba->pport->fc_myDID, phba->fcf.fcfi, 19431b51197dSJames Smart phba->sli4_hba.vfi_ids[phba->pport->vfi], 19441b51197dSJames Smart phba->vpi_ids[phba->pport->vpi]); 19451b51197dSJames Smart return -EINVAL; 19461b51197dSJames Smart } 19471b51197dSJames Smart rc = lpfc_issue_reg_vfi(phba->pport); 19481b51197dSJames Smart return rc; 19491b51197dSJames Smart } 19501b51197dSJames Smart 19511b51197dSJames Smart /** 19527ad20aa9SJames Smart * lpfc_sli4_bsg_diag_loopback_mode - process an sli4 bsg vendor command 19537ad20aa9SJames Smart * @phba: Pointer to HBA context object. 19547ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_MODE 19557ad20aa9SJames Smart * 19567ad20aa9SJames Smart * This function is responsible for placing an sli4 port into diagnostic 19577ad20aa9SJames Smart * loopback mode in order to perform a diagnostic loopback test. 19587ad20aa9SJames Smart */ 19597ad20aa9SJames Smart static int 19607ad20aa9SJames Smart lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job) 19617ad20aa9SJames Smart { 19627ad20aa9SJames Smart struct diag_mode_set *loopback_mode; 19631b51197dSJames Smart uint32_t link_flags, timeout; 19641b51197dSJames Smart int i, rc = 0; 19657ad20aa9SJames Smart 19667ad20aa9SJames Smart /* no data to return just the return code */ 19677ad20aa9SJames Smart job->reply->reply_payload_rcv_len = 0; 19687ad20aa9SJames Smart 19697ad20aa9SJames Smart if (job->request_len < sizeof(struct fc_bsg_request) + 19707ad20aa9SJames Smart sizeof(struct diag_mode_set)) { 19717ad20aa9SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 19727ad20aa9SJames Smart "3011 Received DIAG MODE request size:%d " 19737ad20aa9SJames Smart "below the minimum size:%d\n", 19747ad20aa9SJames Smart job->request_len, 19757ad20aa9SJames Smart (int)(sizeof(struct fc_bsg_request) + 19767ad20aa9SJames Smart sizeof(struct diag_mode_set))); 19777ad20aa9SJames Smart rc = -EINVAL; 19787ad20aa9SJames Smart goto job_error; 19797ad20aa9SJames Smart } 19807ad20aa9SJames Smart 198188a2cfbbSJames Smart rc = lpfc_bsg_diag_mode_enter(phba); 19827ad20aa9SJames Smart if (rc) 19837ad20aa9SJames Smart goto job_error; 19847ad20aa9SJames Smart 19851b51197dSJames Smart /* indicate we are in loobpack diagnostic mode */ 19861b51197dSJames Smart spin_lock_irq(&phba->hbalock); 19871b51197dSJames Smart phba->link_flag |= LS_LOOPBACK_MODE; 19881b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 19891b51197dSJames Smart 19901b51197dSJames Smart /* reset port to start frome scratch */ 19911b51197dSJames Smart rc = lpfc_selective_reset(phba); 19921b51197dSJames Smart if (rc) 19931b51197dSJames Smart goto job_error; 19941b51197dSJames Smart 19957ad20aa9SJames Smart /* bring the link to diagnostic mode */ 19961b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 19971b51197dSJames Smart "3129 Bring link to diagnostic state.\n"); 19987ad20aa9SJames Smart loopback_mode = (struct diag_mode_set *) 19997ad20aa9SJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 20007ad20aa9SJames Smart link_flags = loopback_mode->type; 20017ad20aa9SJames Smart timeout = loopback_mode->timeout * 100; 20027ad20aa9SJames Smart 20037ad20aa9SJames Smart rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1); 20041b51197dSJames Smart if (rc) { 20051b51197dSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 20061b51197dSJames Smart "3130 Failed to bring link to diagnostic " 20071b51197dSJames Smart "state, rc:x%x\n", rc); 20087ad20aa9SJames Smart goto loopback_mode_exit; 20091b51197dSJames Smart } 20107ad20aa9SJames Smart 20117ad20aa9SJames Smart /* wait for link down before proceeding */ 20127ad20aa9SJames Smart i = 0; 20137ad20aa9SJames Smart while (phba->link_state != LPFC_LINK_DOWN) { 20147ad20aa9SJames Smart if (i++ > timeout) { 20157ad20aa9SJames Smart rc = -ETIMEDOUT; 20161b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 20171b51197dSJames Smart "3131 Timeout waiting for link to " 20181b51197dSJames Smart "diagnostic mode, timeout:%d ms\n", 20191b51197dSJames Smart timeout * 10); 20207ad20aa9SJames Smart goto loopback_mode_exit; 20217ad20aa9SJames Smart } 20227ad20aa9SJames Smart msleep(10); 20237ad20aa9SJames Smart } 20247ad20aa9SJames Smart 20251b51197dSJames Smart /* set up loopback mode */ 20261b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 20271b51197dSJames Smart "3132 Set up loopback mode:x%x\n", link_flags); 20281b51197dSJames Smart 20291b51197dSJames Smart if (link_flags == INTERNAL_LOOP_BACK) 20301b51197dSJames Smart rc = lpfc_sli4_bsg_set_internal_loopback(phba); 20311b51197dSJames Smart else if (link_flags == EXTERNAL_LOOP_BACK) 20321b51197dSJames Smart rc = lpfc_hba_init_link_fc_topology(phba, 20331b51197dSJames Smart FLAGS_TOPOLOGY_MODE_PT_PT, 20341b51197dSJames Smart MBX_NOWAIT); 20357ad20aa9SJames Smart else { 20361b51197dSJames Smart rc = -EINVAL; 20371b51197dSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 20381b51197dSJames Smart "3141 Loopback mode:x%x not supported\n", 20391b51197dSJames Smart link_flags); 20401b51197dSJames Smart goto loopback_mode_exit; 20411b51197dSJames Smart } 20421b51197dSJames Smart 20431b51197dSJames Smart if (!rc) { 20447ad20aa9SJames Smart /* wait for the link attention interrupt */ 20457ad20aa9SJames Smart msleep(100); 20467ad20aa9SJames Smart i = 0; 20471b51197dSJames Smart while (phba->link_state < LPFC_LINK_UP) { 20481b51197dSJames Smart if (i++ > timeout) { 20491b51197dSJames Smart rc = -ETIMEDOUT; 20501b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 20511b51197dSJames Smart "3137 Timeout waiting for link up " 20521b51197dSJames Smart "in loopback mode, timeout:%d ms\n", 20531b51197dSJames Smart timeout * 10); 20541b51197dSJames Smart break; 20551b51197dSJames Smart } 20561b51197dSJames Smart msleep(10); 20571b51197dSJames Smart } 20581b51197dSJames Smart } 20591b51197dSJames Smart 20601b51197dSJames Smart /* port resource registration setup for loopback diagnostic */ 20611b51197dSJames Smart if (!rc) { 20621b51197dSJames Smart /* set up a none zero myDID for loopback test */ 20631b51197dSJames Smart phba->pport->fc_myDID = 1; 20641b51197dSJames Smart rc = lpfc_sli4_diag_fcport_reg_setup(phba); 20651b51197dSJames Smart } else 20661b51197dSJames Smart goto loopback_mode_exit; 20671b51197dSJames Smart 20681b51197dSJames Smart if (!rc) { 20691b51197dSJames Smart /* wait for the port ready */ 20701b51197dSJames Smart msleep(100); 20711b51197dSJames Smart i = 0; 20727ad20aa9SJames Smart while (phba->link_state != LPFC_HBA_READY) { 20737ad20aa9SJames Smart if (i++ > timeout) { 20747ad20aa9SJames Smart rc = -ETIMEDOUT; 20751b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 20761b51197dSJames Smart "3133 Timeout waiting for port " 20771b51197dSJames Smart "loopback mode ready, timeout:%d ms\n", 20781b51197dSJames Smart timeout * 10); 20797ad20aa9SJames Smart break; 20807ad20aa9SJames Smart } 20817ad20aa9SJames Smart msleep(10); 20827ad20aa9SJames Smart } 20837ad20aa9SJames Smart } 20847ad20aa9SJames Smart 20857ad20aa9SJames Smart loopback_mode_exit: 20861b51197dSJames Smart /* clear loopback diagnostic mode */ 20871b51197dSJames Smart if (rc) { 20881b51197dSJames Smart spin_lock_irq(&phba->hbalock); 20891b51197dSJames Smart phba->link_flag &= ~LS_LOOPBACK_MODE; 20901b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 20911b51197dSJames Smart } 20927ad20aa9SJames Smart lpfc_bsg_diag_mode_exit(phba); 20937ad20aa9SJames Smart 20947ad20aa9SJames Smart job_error: 20957ad20aa9SJames Smart /* make error code available to userspace */ 20967ad20aa9SJames Smart job->reply->result = rc; 20977ad20aa9SJames Smart /* complete the job back to userspace if no error */ 20987ad20aa9SJames Smart if (rc == 0) 20997ad20aa9SJames Smart job->job_done(job); 21007ad20aa9SJames Smart return rc; 21017ad20aa9SJames Smart } 21027ad20aa9SJames Smart 21037ad20aa9SJames Smart /** 21047ad20aa9SJames Smart * lpfc_bsg_diag_loopback_mode - bsg vendor command for diag loopback mode 21057ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_MODE 21067ad20aa9SJames Smart * 21077ad20aa9SJames Smart * This function is responsible for responding to check and dispatch bsg diag 21087ad20aa9SJames Smart * command from the user to proper driver action routines. 21097ad20aa9SJames Smart */ 21107ad20aa9SJames Smart static int 21117ad20aa9SJames Smart lpfc_bsg_diag_loopback_mode(struct fc_bsg_job *job) 21127ad20aa9SJames Smart { 21137ad20aa9SJames Smart struct Scsi_Host *shost; 21147ad20aa9SJames Smart struct lpfc_vport *vport; 21157ad20aa9SJames Smart struct lpfc_hba *phba; 21167ad20aa9SJames Smart int rc; 21177ad20aa9SJames Smart 21187ad20aa9SJames Smart shost = job->shost; 21197ad20aa9SJames Smart if (!shost) 21207ad20aa9SJames Smart return -ENODEV; 21217ad20aa9SJames Smart vport = (struct lpfc_vport *)job->shost->hostdata; 21227ad20aa9SJames Smart if (!vport) 21237ad20aa9SJames Smart return -ENODEV; 21247ad20aa9SJames Smart phba = vport->phba; 21257ad20aa9SJames Smart if (!phba) 21267ad20aa9SJames Smart return -ENODEV; 21277ad20aa9SJames Smart 21287ad20aa9SJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 21297ad20aa9SJames Smart rc = lpfc_sli3_bsg_diag_loopback_mode(phba, job); 21307ad20aa9SJames Smart else if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == 21317ad20aa9SJames Smart LPFC_SLI_INTF_IF_TYPE_2) 21327ad20aa9SJames Smart rc = lpfc_sli4_bsg_diag_loopback_mode(phba, job); 21337ad20aa9SJames Smart else 21347ad20aa9SJames Smart rc = -ENODEV; 21357ad20aa9SJames Smart 21367ad20aa9SJames Smart return rc; 21377ad20aa9SJames Smart } 21387ad20aa9SJames Smart 21397ad20aa9SJames Smart /** 21407ad20aa9SJames Smart * lpfc_sli4_bsg_diag_mode_end - sli4 bsg vendor command for ending diag mode 21417ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_MODE_END 21427ad20aa9SJames Smart * 21437ad20aa9SJames Smart * This function is responsible for responding to check and dispatch bsg diag 21447ad20aa9SJames Smart * command from the user to proper driver action routines. 21457ad20aa9SJames Smart */ 21467ad20aa9SJames Smart static int 21477ad20aa9SJames Smart lpfc_sli4_bsg_diag_mode_end(struct fc_bsg_job *job) 21487ad20aa9SJames Smart { 21497ad20aa9SJames Smart struct Scsi_Host *shost; 21507ad20aa9SJames Smart struct lpfc_vport *vport; 21517ad20aa9SJames Smart struct lpfc_hba *phba; 21521b51197dSJames Smart struct diag_mode_set *loopback_mode_end_cmd; 21531b51197dSJames Smart uint32_t timeout; 21541b51197dSJames Smart int rc, i; 21557ad20aa9SJames Smart 21567ad20aa9SJames Smart shost = job->shost; 21577ad20aa9SJames Smart if (!shost) 21587ad20aa9SJames Smart return -ENODEV; 21597ad20aa9SJames Smart vport = (struct lpfc_vport *)job->shost->hostdata; 21607ad20aa9SJames Smart if (!vport) 21617ad20aa9SJames Smart return -ENODEV; 21627ad20aa9SJames Smart phba = vport->phba; 21637ad20aa9SJames Smart if (!phba) 21647ad20aa9SJames Smart return -ENODEV; 21657ad20aa9SJames Smart 21667ad20aa9SJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 21677ad20aa9SJames Smart return -ENODEV; 21687ad20aa9SJames Smart if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != 21697ad20aa9SJames Smart LPFC_SLI_INTF_IF_TYPE_2) 21707ad20aa9SJames Smart return -ENODEV; 21717ad20aa9SJames Smart 21721b51197dSJames Smart /* clear loopback diagnostic mode */ 21731b51197dSJames Smart spin_lock_irq(&phba->hbalock); 21741b51197dSJames Smart phba->link_flag &= ~LS_LOOPBACK_MODE; 21751b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 21761b51197dSJames Smart loopback_mode_end_cmd = (struct diag_mode_set *) 21771b51197dSJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 21781b51197dSJames Smart timeout = loopback_mode_end_cmd->timeout * 100; 21791b51197dSJames Smart 21807ad20aa9SJames Smart rc = lpfc_sli4_bsg_set_link_diag_state(phba, 0); 21811b51197dSJames Smart if (rc) { 21821b51197dSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 21831b51197dSJames Smart "3139 Failed to bring link to diagnostic " 21841b51197dSJames Smart "state, rc:x%x\n", rc); 21851b51197dSJames Smart goto loopback_mode_end_exit; 21861b51197dSJames Smart } 21877ad20aa9SJames Smart 21881b51197dSJames Smart /* wait for link down before proceeding */ 21891b51197dSJames Smart i = 0; 21901b51197dSJames Smart while (phba->link_state != LPFC_LINK_DOWN) { 21911b51197dSJames Smart if (i++ > timeout) { 21921b51197dSJames Smart rc = -ETIMEDOUT; 21931b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 21941b51197dSJames Smart "3140 Timeout waiting for link to " 21951b51197dSJames Smart "diagnostic mode_end, timeout:%d ms\n", 21961b51197dSJames Smart timeout * 10); 21971b51197dSJames Smart /* there is nothing much we can do here */ 21981b51197dSJames Smart break; 21991b51197dSJames Smart } 22001b51197dSJames Smart msleep(10); 22011b51197dSJames Smart } 22027ad20aa9SJames Smart 22031b51197dSJames Smart /* reset port resource registrations */ 22041b51197dSJames Smart rc = lpfc_selective_reset(phba); 22051b51197dSJames Smart phba->pport->fc_myDID = 0; 22061b51197dSJames Smart 22071b51197dSJames Smart loopback_mode_end_exit: 22081b51197dSJames Smart /* make return code available to userspace */ 22091b51197dSJames Smart job->reply->result = rc; 22101b51197dSJames Smart /* complete the job back to userspace if no error */ 22111b51197dSJames Smart if (rc == 0) 22121b51197dSJames Smart job->job_done(job); 22137ad20aa9SJames Smart return rc; 22147ad20aa9SJames Smart } 22157ad20aa9SJames Smart 22167ad20aa9SJames Smart /** 22177ad20aa9SJames Smart * lpfc_sli4_bsg_link_diag_test - sli4 bsg vendor command for diag link test 22187ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_LINK_TEST 22197ad20aa9SJames Smart * 22207ad20aa9SJames Smart * This function is to perform SLI4 diag link test request from the user 22217ad20aa9SJames Smart * applicaiton. 22227ad20aa9SJames Smart */ 22237ad20aa9SJames Smart static int 22247ad20aa9SJames Smart lpfc_sli4_bsg_link_diag_test(struct fc_bsg_job *job) 22257ad20aa9SJames Smart { 22267ad20aa9SJames Smart struct Scsi_Host *shost; 22277ad20aa9SJames Smart struct lpfc_vport *vport; 22287ad20aa9SJames Smart struct lpfc_hba *phba; 22297ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq; 22307ad20aa9SJames Smart struct sli4_link_diag *link_diag_test_cmd; 22317ad20aa9SJames Smart uint32_t req_len, alloc_len; 22327ad20aa9SJames Smart uint32_t timeout; 22337ad20aa9SJames Smart struct lpfc_mbx_run_link_diag_test *run_link_diag_test; 22347ad20aa9SJames Smart union lpfc_sli4_cfg_shdr *shdr; 22357ad20aa9SJames Smart uint32_t shdr_status, shdr_add_status; 22367ad20aa9SJames Smart struct diag_status *diag_status_reply; 22377ad20aa9SJames Smart int mbxstatus, rc = 0; 22387ad20aa9SJames Smart 22397ad20aa9SJames Smart shost = job->shost; 22407ad20aa9SJames Smart if (!shost) { 22417ad20aa9SJames Smart rc = -ENODEV; 22427ad20aa9SJames Smart goto job_error; 22437ad20aa9SJames Smart } 22447ad20aa9SJames Smart vport = (struct lpfc_vport *)job->shost->hostdata; 22457ad20aa9SJames Smart if (!vport) { 22467ad20aa9SJames Smart rc = -ENODEV; 22477ad20aa9SJames Smart goto job_error; 22487ad20aa9SJames Smart } 22497ad20aa9SJames Smart phba = vport->phba; 22507ad20aa9SJames Smart if (!phba) { 22517ad20aa9SJames Smart rc = -ENODEV; 22527ad20aa9SJames Smart goto job_error; 22537ad20aa9SJames Smart } 22547ad20aa9SJames Smart 22557ad20aa9SJames Smart if (phba->sli_rev < LPFC_SLI_REV4) { 22567ad20aa9SJames Smart rc = -ENODEV; 22577ad20aa9SJames Smart goto job_error; 22587ad20aa9SJames Smart } 22597ad20aa9SJames Smart if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != 22607ad20aa9SJames Smart LPFC_SLI_INTF_IF_TYPE_2) { 22617ad20aa9SJames Smart rc = -ENODEV; 22627ad20aa9SJames Smart goto job_error; 22637ad20aa9SJames Smart } 22647ad20aa9SJames Smart 22657ad20aa9SJames Smart if (job->request_len < sizeof(struct fc_bsg_request) + 22667ad20aa9SJames Smart sizeof(struct sli4_link_diag)) { 22677ad20aa9SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 22687ad20aa9SJames Smart "3013 Received LINK DIAG TEST request " 22697ad20aa9SJames Smart " size:%d below the minimum size:%d\n", 22707ad20aa9SJames Smart job->request_len, 22717ad20aa9SJames Smart (int)(sizeof(struct fc_bsg_request) + 22727ad20aa9SJames Smart sizeof(struct sli4_link_diag))); 22737ad20aa9SJames Smart rc = -EINVAL; 22747ad20aa9SJames Smart goto job_error; 22757ad20aa9SJames Smart } 22767ad20aa9SJames Smart 227788a2cfbbSJames Smart rc = lpfc_bsg_diag_mode_enter(phba); 22787ad20aa9SJames Smart if (rc) 22797ad20aa9SJames Smart goto job_error; 22807ad20aa9SJames Smart 22817ad20aa9SJames Smart link_diag_test_cmd = (struct sli4_link_diag *) 22827ad20aa9SJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 22837ad20aa9SJames Smart timeout = link_diag_test_cmd->timeout * 100; 22847ad20aa9SJames Smart 22857ad20aa9SJames Smart rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1); 22867ad20aa9SJames Smart 22877ad20aa9SJames Smart if (rc) 22887ad20aa9SJames Smart goto job_error; 22897ad20aa9SJames Smart 22907ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 22917ad20aa9SJames Smart if (!pmboxq) { 22927ad20aa9SJames Smart rc = -ENOMEM; 22937ad20aa9SJames Smart goto link_diag_test_exit; 22947ad20aa9SJames Smart } 22957ad20aa9SJames Smart 22967ad20aa9SJames Smart req_len = (sizeof(struct lpfc_mbx_set_link_diag_state) - 22977ad20aa9SJames Smart sizeof(struct lpfc_sli4_cfg_mhdr)); 22987ad20aa9SJames Smart alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, 22997ad20aa9SJames Smart LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE, 23007ad20aa9SJames Smart req_len, LPFC_SLI4_MBX_EMBED); 23017ad20aa9SJames Smart if (alloc_len != req_len) { 23027ad20aa9SJames Smart rc = -ENOMEM; 23037ad20aa9SJames Smart goto link_diag_test_exit; 23047ad20aa9SJames Smart } 23057ad20aa9SJames Smart run_link_diag_test = &pmboxq->u.mqe.un.link_diag_test; 23067ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_link_num, &run_link_diag_test->u.req, 23071b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_no); 23087ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_link_type, &run_link_diag_test->u.req, 23091b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_tp); 23107ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_test_id, &run_link_diag_test->u.req, 23117ad20aa9SJames Smart link_diag_test_cmd->test_id); 23127ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_loops, &run_link_diag_test->u.req, 23137ad20aa9SJames Smart link_diag_test_cmd->loops); 23147ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_test_ver, &run_link_diag_test->u.req, 23157ad20aa9SJames Smart link_diag_test_cmd->test_version); 23167ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_err_act, &run_link_diag_test->u.req, 23177ad20aa9SJames Smart link_diag_test_cmd->error_action); 23187ad20aa9SJames Smart 23197ad20aa9SJames Smart mbxstatus = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); 23207ad20aa9SJames Smart 23217ad20aa9SJames Smart shdr = (union lpfc_sli4_cfg_shdr *) 23227ad20aa9SJames Smart &pmboxq->u.mqe.un.sli4_config.header.cfg_shdr; 23237ad20aa9SJames Smart shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); 23247ad20aa9SJames Smart shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); 23257ad20aa9SJames Smart if (shdr_status || shdr_add_status || mbxstatus) { 23267ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 23277ad20aa9SJames Smart "3010 Run link diag test mailbox failed with " 23287ad20aa9SJames Smart "mbx_status x%x status x%x, add_status x%x\n", 23297ad20aa9SJames Smart mbxstatus, shdr_status, shdr_add_status); 23307ad20aa9SJames Smart } 23317ad20aa9SJames Smart 23327ad20aa9SJames Smart diag_status_reply = (struct diag_status *) 23337ad20aa9SJames Smart job->reply->reply_data.vendor_reply.vendor_rsp; 23347ad20aa9SJames Smart 23357ad20aa9SJames Smart if (job->reply_len < 23367ad20aa9SJames Smart sizeof(struct fc_bsg_request) + sizeof(struct diag_status)) { 23377ad20aa9SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 23387ad20aa9SJames Smart "3012 Received Run link diag test reply " 23397ad20aa9SJames Smart "below minimum size (%d): reply_len:%d\n", 23407ad20aa9SJames Smart (int)(sizeof(struct fc_bsg_request) + 23417ad20aa9SJames Smart sizeof(struct diag_status)), 23427ad20aa9SJames Smart job->reply_len); 23437ad20aa9SJames Smart rc = -EINVAL; 23447ad20aa9SJames Smart goto job_error; 23457ad20aa9SJames Smart } 23467ad20aa9SJames Smart 23477ad20aa9SJames Smart diag_status_reply->mbox_status = mbxstatus; 23487ad20aa9SJames Smart diag_status_reply->shdr_status = shdr_status; 23497ad20aa9SJames Smart diag_status_reply->shdr_add_status = shdr_add_status; 23507ad20aa9SJames Smart 23517ad20aa9SJames Smart link_diag_test_exit: 23527ad20aa9SJames Smart rc = lpfc_sli4_bsg_set_link_diag_state(phba, 0); 23537ad20aa9SJames Smart 23547ad20aa9SJames Smart if (pmboxq) 23557ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 23567ad20aa9SJames Smart 23577ad20aa9SJames Smart lpfc_bsg_diag_mode_exit(phba); 23587ad20aa9SJames Smart 23597ad20aa9SJames Smart job_error: 23607ad20aa9SJames Smart /* make error code available to userspace */ 23617ad20aa9SJames Smart job->reply->result = rc; 23627ad20aa9SJames Smart /* complete the job back to userspace if no error */ 23637ad20aa9SJames Smart if (rc == 0) 23647ad20aa9SJames Smart job->job_done(job); 23657ad20aa9SJames Smart return rc; 23667ad20aa9SJames Smart } 23677ad20aa9SJames Smart 23687ad20aa9SJames Smart /** 23693b5dd52aSJames Smart * lpfcdiag_loop_self_reg - obtains a remote port login id 23703b5dd52aSJames Smart * @phba: Pointer to HBA context object 23713b5dd52aSJames Smart * @rpi: Pointer to a remote port login id 23723b5dd52aSJames Smart * 23733b5dd52aSJames Smart * This function obtains a remote port login id so the diag loopback test 23743b5dd52aSJames Smart * can send and receive its own unsolicited CT command. 23753b5dd52aSJames Smart **/ 23763b5dd52aSJames Smart static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t *rpi) 23773b5dd52aSJames Smart { 23783b5dd52aSJames Smart LPFC_MBOXQ_t *mbox; 23793b5dd52aSJames Smart struct lpfc_dmabuf *dmabuff; 23803b5dd52aSJames Smart int status; 23813b5dd52aSJames Smart 23823b5dd52aSJames Smart mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 23833b5dd52aSJames Smart if (!mbox) 2384d439d286SJames Smart return -ENOMEM; 23853b5dd52aSJames Smart 23861b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 23873b5dd52aSJames Smart status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID, 23881b51197dSJames Smart (uint8_t *)&phba->pport->fc_sparam, 23891b51197dSJames Smart mbox, *rpi); 23901b51197dSJames Smart else { 23911b51197dSJames Smart *rpi = lpfc_sli4_alloc_rpi(phba); 23921b51197dSJames Smart status = lpfc_reg_rpi(phba, phba->pport->vpi, 23931b51197dSJames Smart phba->pport->fc_myDID, 23941b51197dSJames Smart (uint8_t *)&phba->pport->fc_sparam, 23951b51197dSJames Smart mbox, *rpi); 23961b51197dSJames Smart } 23971b51197dSJames Smart 23983b5dd52aSJames Smart if (status) { 23993b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 24004042629eSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 24014042629eSJames Smart lpfc_sli4_free_rpi(phba, *rpi); 2402d439d286SJames Smart return -ENOMEM; 24033b5dd52aSJames Smart } 24043b5dd52aSJames Smart 24053b5dd52aSJames Smart dmabuff = (struct lpfc_dmabuf *) mbox->context1; 24063b5dd52aSJames Smart mbox->context1 = NULL; 2407d439d286SJames Smart mbox->context2 = NULL; 24083b5dd52aSJames Smart status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); 24093b5dd52aSJames Smart 24103b5dd52aSJames Smart if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { 24113b5dd52aSJames Smart lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); 24123b5dd52aSJames Smart kfree(dmabuff); 24133b5dd52aSJames Smart if (status != MBX_TIMEOUT) 24143b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 24154042629eSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 24164042629eSJames Smart lpfc_sli4_free_rpi(phba, *rpi); 2417d439d286SJames Smart return -ENODEV; 24183b5dd52aSJames Smart } 24193b5dd52aSJames Smart 24201b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 24213b5dd52aSJames Smart *rpi = mbox->u.mb.un.varWords[0]; 24223b5dd52aSJames Smart 24233b5dd52aSJames Smart lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); 24243b5dd52aSJames Smart kfree(dmabuff); 24253b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 24263b5dd52aSJames Smart return 0; 24273b5dd52aSJames Smart } 24283b5dd52aSJames Smart 24293b5dd52aSJames Smart /** 24303b5dd52aSJames Smart * lpfcdiag_loop_self_unreg - unregs from the rpi 24313b5dd52aSJames Smart * @phba: Pointer to HBA context object 24323b5dd52aSJames Smart * @rpi: Remote port login id 24333b5dd52aSJames Smart * 24343b5dd52aSJames Smart * This function unregisters the rpi obtained in lpfcdiag_loop_self_reg 24353b5dd52aSJames Smart **/ 24363b5dd52aSJames Smart static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi) 24373b5dd52aSJames Smart { 24383b5dd52aSJames Smart LPFC_MBOXQ_t *mbox; 24393b5dd52aSJames Smart int status; 24403b5dd52aSJames Smart 24413b5dd52aSJames Smart /* Allocate mboxq structure */ 24423b5dd52aSJames Smart mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 24433b5dd52aSJames Smart if (mbox == NULL) 2444d439d286SJames Smart return -ENOMEM; 24453b5dd52aSJames Smart 24461b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 24473b5dd52aSJames Smart lpfc_unreg_login(phba, 0, rpi, mbox); 24481b51197dSJames Smart else 24491b51197dSJames Smart lpfc_unreg_login(phba, phba->pport->vpi, 24501b51197dSJames Smart phba->sli4_hba.rpi_ids[rpi], mbox); 24511b51197dSJames Smart 24523b5dd52aSJames Smart status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); 24533b5dd52aSJames Smart 24543b5dd52aSJames Smart if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { 24553b5dd52aSJames Smart if (status != MBX_TIMEOUT) 24563b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 2457d439d286SJames Smart return -EIO; 24583b5dd52aSJames Smart } 24593b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 24604042629eSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 24614042629eSJames Smart lpfc_sli4_free_rpi(phba, rpi); 24623b5dd52aSJames Smart return 0; 24633b5dd52aSJames Smart } 24643b5dd52aSJames Smart 24653b5dd52aSJames Smart /** 24663b5dd52aSJames Smart * lpfcdiag_loop_get_xri - obtains the transmit and receive ids 24673b5dd52aSJames Smart * @phba: Pointer to HBA context object 24683b5dd52aSJames Smart * @rpi: Remote port login id 24693b5dd52aSJames Smart * @txxri: Pointer to transmit exchange id 24703b5dd52aSJames Smart * @rxxri: Pointer to response exchabge id 24713b5dd52aSJames Smart * 24723b5dd52aSJames Smart * This function obtains the transmit and receive ids required to send 24733b5dd52aSJames Smart * an unsolicited ct command with a payload. A special lpfc FsType and CmdRsp 24743b5dd52aSJames Smart * flags are used to the unsolicted response handler is able to process 24753b5dd52aSJames Smart * the ct command sent on the same port. 24763b5dd52aSJames Smart **/ 24773b5dd52aSJames Smart static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, 24783b5dd52aSJames Smart uint16_t *txxri, uint16_t * rxxri) 24793b5dd52aSJames Smart { 24803b5dd52aSJames Smart struct lpfc_bsg_event *evt; 24813b5dd52aSJames Smart struct lpfc_iocbq *cmdiocbq, *rspiocbq; 24823b5dd52aSJames Smart IOCB_t *cmd, *rsp; 24833b5dd52aSJames Smart struct lpfc_dmabuf *dmabuf; 24843b5dd52aSJames Smart struct ulp_bde64 *bpl = NULL; 24853b5dd52aSJames Smart struct lpfc_sli_ct_request *ctreq = NULL; 24863b5dd52aSJames Smart int ret_val = 0; 2487d439d286SJames Smart int time_left; 2488515e0aa2SJames Smart int iocb_stat = 0; 24893b5dd52aSJames Smart unsigned long flags; 24903b5dd52aSJames Smart 24913b5dd52aSJames Smart *txxri = 0; 24923b5dd52aSJames Smart *rxxri = 0; 24933b5dd52aSJames Smart evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, 24943b5dd52aSJames Smart SLI_CT_ELX_LOOPBACK); 24953b5dd52aSJames Smart if (!evt) 2496d439d286SJames Smart return -ENOMEM; 24973b5dd52aSJames Smart 24983b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 24993b5dd52aSJames Smart list_add(&evt->node, &phba->ct_ev_waiters); 25003b5dd52aSJames Smart lpfc_bsg_event_ref(evt); 25013b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 25023b5dd52aSJames Smart 25033b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 25043b5dd52aSJames Smart rspiocbq = lpfc_sli_get_iocbq(phba); 25053b5dd52aSJames Smart 25063b5dd52aSJames Smart dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 25073b5dd52aSJames Smart if (dmabuf) { 25083b5dd52aSJames Smart dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys); 2509c7495937SJames Smart if (dmabuf->virt) { 25103b5dd52aSJames Smart INIT_LIST_HEAD(&dmabuf->list); 25113b5dd52aSJames Smart bpl = (struct ulp_bde64 *) dmabuf->virt; 25123b5dd52aSJames Smart memset(bpl, 0, sizeof(*bpl)); 25133b5dd52aSJames Smart ctreq = (struct lpfc_sli_ct_request *)(bpl + 1); 25143b5dd52aSJames Smart bpl->addrHigh = 2515c7495937SJames Smart le32_to_cpu(putPaddrHigh(dmabuf->phys + 2516c7495937SJames Smart sizeof(*bpl))); 25173b5dd52aSJames Smart bpl->addrLow = 2518c7495937SJames Smart le32_to_cpu(putPaddrLow(dmabuf->phys + 2519c7495937SJames Smart sizeof(*bpl))); 25203b5dd52aSJames Smart bpl->tus.f.bdeFlags = 0; 25213b5dd52aSJames Smart bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ; 25223b5dd52aSJames Smart bpl->tus.w = le32_to_cpu(bpl->tus.w); 25233b5dd52aSJames Smart } 2524c7495937SJames Smart } 25253b5dd52aSJames Smart 25263b5dd52aSJames Smart if (cmdiocbq == NULL || rspiocbq == NULL || 2527c7495937SJames Smart dmabuf == NULL || bpl == NULL || ctreq == NULL || 2528c7495937SJames Smart dmabuf->virt == NULL) { 2529d439d286SJames Smart ret_val = -ENOMEM; 25303b5dd52aSJames Smart goto err_get_xri_exit; 25313b5dd52aSJames Smart } 25323b5dd52aSJames Smart 25333b5dd52aSJames Smart cmd = &cmdiocbq->iocb; 25343b5dd52aSJames Smart rsp = &rspiocbq->iocb; 25353b5dd52aSJames Smart 25363b5dd52aSJames Smart memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); 25373b5dd52aSJames Smart 25383b5dd52aSJames Smart ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; 25393b5dd52aSJames Smart ctreq->RevisionId.bits.InId = 0; 25403b5dd52aSJames Smart ctreq->FsType = SLI_CT_ELX_LOOPBACK; 25413b5dd52aSJames Smart ctreq->FsSubType = 0; 25423b5dd52aSJames Smart ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_XRI_SETUP; 25433b5dd52aSJames Smart ctreq->CommandResponse.bits.Size = 0; 25443b5dd52aSJames Smart 25453b5dd52aSJames Smart 25463b5dd52aSJames Smart cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(dmabuf->phys); 25473b5dd52aSJames Smart cmd->un.xseq64.bdl.addrLow = putPaddrLow(dmabuf->phys); 25483b5dd52aSJames Smart cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 25493b5dd52aSJames Smart cmd->un.xseq64.bdl.bdeSize = sizeof(*bpl); 25503b5dd52aSJames Smart 25513b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Fctl = LA; 25523b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Dfctl = 0; 25533b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; 25543b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; 25553b5dd52aSJames Smart 25563b5dd52aSJames Smart cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CR; 25573b5dd52aSJames Smart cmd->ulpBdeCount = 1; 25583b5dd52aSJames Smart cmd->ulpLe = 1; 25593b5dd52aSJames Smart cmd->ulpClass = CLASS3; 25603b5dd52aSJames Smart cmd->ulpContext = rpi; 25613b5dd52aSJames Smart 25623b5dd52aSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 25633b5dd52aSJames Smart cmdiocbq->vport = phba->pport; 25643b5dd52aSJames Smart 2565d439d286SJames Smart iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, 25663b5dd52aSJames Smart rspiocbq, 25673b5dd52aSJames Smart (phba->fc_ratov * 2) 25683b5dd52aSJames Smart + LPFC_DRVR_TIMEOUT); 2569d439d286SJames Smart if (iocb_stat) { 2570d439d286SJames Smart ret_val = -EIO; 25713b5dd52aSJames Smart goto err_get_xri_exit; 2572d439d286SJames Smart } 25733b5dd52aSJames Smart *txxri = rsp->ulpContext; 25743b5dd52aSJames Smart 25753b5dd52aSJames Smart evt->waiting = 1; 25763b5dd52aSJames Smart evt->wait_time_stamp = jiffies; 2577d439d286SJames Smart time_left = wait_event_interruptible_timeout( 25783b5dd52aSJames Smart evt->wq, !list_empty(&evt->events_to_see), 25793b5dd52aSJames Smart ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ); 25803b5dd52aSJames Smart if (list_empty(&evt->events_to_see)) 2581d439d286SJames Smart ret_val = (time_left) ? -EINTR : -ETIMEDOUT; 25823b5dd52aSJames Smart else { 25833b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 25843b5dd52aSJames Smart list_move(evt->events_to_see.prev, &evt->events_to_get); 25853b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 25863b5dd52aSJames Smart *rxxri = (list_entry(evt->events_to_get.prev, 25873b5dd52aSJames Smart typeof(struct event_data), 25883b5dd52aSJames Smart node))->immed_dat; 25893b5dd52aSJames Smart } 25903b5dd52aSJames Smart evt->waiting = 0; 25913b5dd52aSJames Smart 25923b5dd52aSJames Smart err_get_xri_exit: 25933b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 25943b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* release ref */ 25953b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* delete */ 25963b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 25973b5dd52aSJames Smart 25983b5dd52aSJames Smart if (dmabuf) { 25993b5dd52aSJames Smart if (dmabuf->virt) 26003b5dd52aSJames Smart lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); 26013b5dd52aSJames Smart kfree(dmabuf); 26023b5dd52aSJames Smart } 26033b5dd52aSJames Smart 2604d439d286SJames Smart if (cmdiocbq && (iocb_stat != IOCB_TIMEDOUT)) 26053b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 26063b5dd52aSJames Smart if (rspiocbq) 26073b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, rspiocbq); 26083b5dd52aSJames Smart return ret_val; 26093b5dd52aSJames Smart } 26103b5dd52aSJames Smart 26113b5dd52aSJames Smart /** 26127ad20aa9SJames Smart * lpfc_bsg_dma_page_alloc - allocate a bsg mbox page sized dma buffers 26137ad20aa9SJames Smart * @phba: Pointer to HBA context object 26147ad20aa9SJames Smart * 26157ad20aa9SJames Smart * This function allocates BSG_MBOX_SIZE (4KB) page size dma buffer and. 26167ad20aa9SJames Smart * retruns the pointer to the buffer. 26177ad20aa9SJames Smart **/ 26187ad20aa9SJames Smart static struct lpfc_dmabuf * 26197ad20aa9SJames Smart lpfc_bsg_dma_page_alloc(struct lpfc_hba *phba) 26207ad20aa9SJames Smart { 26217ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf; 26227ad20aa9SJames Smart struct pci_dev *pcidev = phba->pcidev; 26237ad20aa9SJames Smart 26247ad20aa9SJames Smart /* allocate dma buffer struct */ 26257ad20aa9SJames Smart dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 26267ad20aa9SJames Smart if (!dmabuf) 26277ad20aa9SJames Smart return NULL; 26287ad20aa9SJames Smart 26297ad20aa9SJames Smart INIT_LIST_HEAD(&dmabuf->list); 26307ad20aa9SJames Smart 26317ad20aa9SJames Smart /* now, allocate dma buffer */ 26327ad20aa9SJames Smart dmabuf->virt = dma_alloc_coherent(&pcidev->dev, BSG_MBOX_SIZE, 26337ad20aa9SJames Smart &(dmabuf->phys), GFP_KERNEL); 26347ad20aa9SJames Smart 26357ad20aa9SJames Smart if (!dmabuf->virt) { 26367ad20aa9SJames Smart kfree(dmabuf); 26377ad20aa9SJames Smart return NULL; 26387ad20aa9SJames Smart } 26397ad20aa9SJames Smart memset((uint8_t *)dmabuf->virt, 0, BSG_MBOX_SIZE); 26407ad20aa9SJames Smart 26417ad20aa9SJames Smart return dmabuf; 26427ad20aa9SJames Smart } 26437ad20aa9SJames Smart 26447ad20aa9SJames Smart /** 26457ad20aa9SJames Smart * lpfc_bsg_dma_page_free - free a bsg mbox page sized dma buffer 26467ad20aa9SJames Smart * @phba: Pointer to HBA context object. 26477ad20aa9SJames Smart * @dmabuf: Pointer to the bsg mbox page sized dma buffer descriptor. 26487ad20aa9SJames Smart * 26497ad20aa9SJames Smart * This routine just simply frees a dma buffer and its associated buffer 26507ad20aa9SJames Smart * descriptor referred by @dmabuf. 26517ad20aa9SJames Smart **/ 26527ad20aa9SJames Smart static void 26537ad20aa9SJames Smart lpfc_bsg_dma_page_free(struct lpfc_hba *phba, struct lpfc_dmabuf *dmabuf) 26547ad20aa9SJames Smart { 26557ad20aa9SJames Smart struct pci_dev *pcidev = phba->pcidev; 26567ad20aa9SJames Smart 26577ad20aa9SJames Smart if (!dmabuf) 26587ad20aa9SJames Smart return; 26597ad20aa9SJames Smart 26607ad20aa9SJames Smart if (dmabuf->virt) 26617ad20aa9SJames Smart dma_free_coherent(&pcidev->dev, BSG_MBOX_SIZE, 26627ad20aa9SJames Smart dmabuf->virt, dmabuf->phys); 26637ad20aa9SJames Smart kfree(dmabuf); 26647ad20aa9SJames Smart return; 26657ad20aa9SJames Smart } 26667ad20aa9SJames Smart 26677ad20aa9SJames Smart /** 26687ad20aa9SJames Smart * lpfc_bsg_dma_page_list_free - free a list of bsg mbox page sized dma buffers 26697ad20aa9SJames Smart * @phba: Pointer to HBA context object. 26707ad20aa9SJames Smart * @dmabuf_list: Pointer to a list of bsg mbox page sized dma buffer descs. 26717ad20aa9SJames Smart * 26727ad20aa9SJames Smart * This routine just simply frees all dma buffers and their associated buffer 26737ad20aa9SJames Smart * descriptors referred by @dmabuf_list. 26747ad20aa9SJames Smart **/ 26757ad20aa9SJames Smart static void 26767ad20aa9SJames Smart lpfc_bsg_dma_page_list_free(struct lpfc_hba *phba, 26777ad20aa9SJames Smart struct list_head *dmabuf_list) 26787ad20aa9SJames Smart { 26797ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf, *next_dmabuf; 26807ad20aa9SJames Smart 26817ad20aa9SJames Smart if (list_empty(dmabuf_list)) 26827ad20aa9SJames Smart return; 26837ad20aa9SJames Smart 26847ad20aa9SJames Smart list_for_each_entry_safe(dmabuf, next_dmabuf, dmabuf_list, list) { 26857ad20aa9SJames Smart list_del_init(&dmabuf->list); 26867ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 26877ad20aa9SJames Smart } 26887ad20aa9SJames Smart return; 26897ad20aa9SJames Smart } 26907ad20aa9SJames Smart 26917ad20aa9SJames Smart /** 26923b5dd52aSJames Smart * diag_cmd_data_alloc - fills in a bde struct with dma buffers 26933b5dd52aSJames Smart * @phba: Pointer to HBA context object 26943b5dd52aSJames Smart * @bpl: Pointer to 64 bit bde structure 26953b5dd52aSJames Smart * @size: Number of bytes to process 26963b5dd52aSJames Smart * @nocopydata: Flag to copy user data into the allocated buffer 26973b5dd52aSJames Smart * 26983b5dd52aSJames Smart * This function allocates page size buffers and populates an lpfc_dmabufext. 26993b5dd52aSJames Smart * If allowed the user data pointed to with indataptr is copied into the kernel 27003b5dd52aSJames Smart * memory. The chained list of page size buffers is returned. 27013b5dd52aSJames Smart **/ 27023b5dd52aSJames Smart static struct lpfc_dmabufext * 27033b5dd52aSJames Smart diag_cmd_data_alloc(struct lpfc_hba *phba, 27043b5dd52aSJames Smart struct ulp_bde64 *bpl, uint32_t size, 27053b5dd52aSJames Smart int nocopydata) 27063b5dd52aSJames Smart { 27073b5dd52aSJames Smart struct lpfc_dmabufext *mlist = NULL; 27083b5dd52aSJames Smart struct lpfc_dmabufext *dmp; 27093b5dd52aSJames Smart int cnt, offset = 0, i = 0; 27103b5dd52aSJames Smart struct pci_dev *pcidev; 27113b5dd52aSJames Smart 27123b5dd52aSJames Smart pcidev = phba->pcidev; 27133b5dd52aSJames Smart 27143b5dd52aSJames Smart while (size) { 27153b5dd52aSJames Smart /* We get chunks of 4K */ 27163b5dd52aSJames Smart if (size > BUF_SZ_4K) 27173b5dd52aSJames Smart cnt = BUF_SZ_4K; 27183b5dd52aSJames Smart else 27193b5dd52aSJames Smart cnt = size; 27203b5dd52aSJames Smart 27213b5dd52aSJames Smart /* allocate struct lpfc_dmabufext buffer header */ 27223b5dd52aSJames Smart dmp = kmalloc(sizeof(struct lpfc_dmabufext), GFP_KERNEL); 27233b5dd52aSJames Smart if (!dmp) 27243b5dd52aSJames Smart goto out; 27253b5dd52aSJames Smart 27263b5dd52aSJames Smart INIT_LIST_HEAD(&dmp->dma.list); 27273b5dd52aSJames Smart 27283b5dd52aSJames Smart /* Queue it to a linked list */ 27293b5dd52aSJames Smart if (mlist) 27303b5dd52aSJames Smart list_add_tail(&dmp->dma.list, &mlist->dma.list); 27313b5dd52aSJames Smart else 27323b5dd52aSJames Smart mlist = dmp; 27333b5dd52aSJames Smart 27343b5dd52aSJames Smart /* allocate buffer */ 27353b5dd52aSJames Smart dmp->dma.virt = dma_alloc_coherent(&pcidev->dev, 27363b5dd52aSJames Smart cnt, 27373b5dd52aSJames Smart &(dmp->dma.phys), 27383b5dd52aSJames Smart GFP_KERNEL); 27393b5dd52aSJames Smart 27403b5dd52aSJames Smart if (!dmp->dma.virt) 27413b5dd52aSJames Smart goto out; 27423b5dd52aSJames Smart 27433b5dd52aSJames Smart dmp->size = cnt; 27443b5dd52aSJames Smart 27453b5dd52aSJames Smart if (nocopydata) { 27463b5dd52aSJames Smart bpl->tus.f.bdeFlags = 0; 27473b5dd52aSJames Smart pci_dma_sync_single_for_device(phba->pcidev, 27483b5dd52aSJames Smart dmp->dma.phys, LPFC_BPL_SIZE, PCI_DMA_TODEVICE); 27493b5dd52aSJames Smart 27503b5dd52aSJames Smart } else { 27513b5dd52aSJames Smart memset((uint8_t *)dmp->dma.virt, 0, cnt); 27523b5dd52aSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; 27533b5dd52aSJames Smart } 27543b5dd52aSJames Smart 27553b5dd52aSJames Smart /* build buffer ptr list for IOCB */ 27563b5dd52aSJames Smart bpl->addrLow = le32_to_cpu(putPaddrLow(dmp->dma.phys)); 27573b5dd52aSJames Smart bpl->addrHigh = le32_to_cpu(putPaddrHigh(dmp->dma.phys)); 27583b5dd52aSJames Smart bpl->tus.f.bdeSize = (ushort) cnt; 27593b5dd52aSJames Smart bpl->tus.w = le32_to_cpu(bpl->tus.w); 27603b5dd52aSJames Smart bpl++; 27613b5dd52aSJames Smart 27623b5dd52aSJames Smart i++; 27633b5dd52aSJames Smart offset += cnt; 27643b5dd52aSJames Smart size -= cnt; 27653b5dd52aSJames Smart } 27663b5dd52aSJames Smart 27673b5dd52aSJames Smart mlist->flag = i; 27683b5dd52aSJames Smart return mlist; 27693b5dd52aSJames Smart out: 27703b5dd52aSJames Smart diag_cmd_data_free(phba, mlist); 27713b5dd52aSJames Smart return NULL; 27723b5dd52aSJames Smart } 27733b5dd52aSJames Smart 27743b5dd52aSJames Smart /** 27753b5dd52aSJames Smart * lpfcdiag_loop_post_rxbufs - post the receive buffers for an unsol CT cmd 27763b5dd52aSJames Smart * @phba: Pointer to HBA context object 27773b5dd52aSJames Smart * @rxxri: Receive exchange id 27783b5dd52aSJames Smart * @len: Number of data bytes 27793b5dd52aSJames Smart * 278025985edcSLucas De Marchi * This function allocates and posts a data buffer of sufficient size to receive 27813b5dd52aSJames Smart * an unsolicted CT command. 27823b5dd52aSJames Smart **/ 27833b5dd52aSJames Smart static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, 27843b5dd52aSJames Smart size_t len) 27853b5dd52aSJames Smart { 27863b5dd52aSJames Smart struct lpfc_sli *psli = &phba->sli; 27873b5dd52aSJames Smart struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; 27883b5dd52aSJames Smart struct lpfc_iocbq *cmdiocbq; 27893b5dd52aSJames Smart IOCB_t *cmd = NULL; 27903b5dd52aSJames Smart struct list_head head, *curr, *next; 27913b5dd52aSJames Smart struct lpfc_dmabuf *rxbmp; 27923b5dd52aSJames Smart struct lpfc_dmabuf *dmp; 27933b5dd52aSJames Smart struct lpfc_dmabuf *mp[2] = {NULL, NULL}; 27943b5dd52aSJames Smart struct ulp_bde64 *rxbpl = NULL; 27953b5dd52aSJames Smart uint32_t num_bde; 27963b5dd52aSJames Smart struct lpfc_dmabufext *rxbuffer = NULL; 27973b5dd52aSJames Smart int ret_val = 0; 2798d439d286SJames Smart int iocb_stat; 27993b5dd52aSJames Smart int i = 0; 28003b5dd52aSJames Smart 28013b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 28023b5dd52aSJames Smart rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 28033b5dd52aSJames Smart if (rxbmp != NULL) { 28043b5dd52aSJames Smart rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); 2805c7495937SJames Smart if (rxbmp->virt) { 28063b5dd52aSJames Smart INIT_LIST_HEAD(&rxbmp->list); 28073b5dd52aSJames Smart rxbpl = (struct ulp_bde64 *) rxbmp->virt; 28083b5dd52aSJames Smart rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0); 28093b5dd52aSJames Smart } 2810c7495937SJames Smart } 28113b5dd52aSJames Smart 28123b5dd52aSJames Smart if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer) { 2813d439d286SJames Smart ret_val = -ENOMEM; 28143b5dd52aSJames Smart goto err_post_rxbufs_exit; 28153b5dd52aSJames Smart } 28163b5dd52aSJames Smart 28173b5dd52aSJames Smart /* Queue buffers for the receive exchange */ 28183b5dd52aSJames Smart num_bde = (uint32_t)rxbuffer->flag; 28193b5dd52aSJames Smart dmp = &rxbuffer->dma; 28203b5dd52aSJames Smart 28213b5dd52aSJames Smart cmd = &cmdiocbq->iocb; 28223b5dd52aSJames Smart i = 0; 28233b5dd52aSJames Smart 28243b5dd52aSJames Smart INIT_LIST_HEAD(&head); 28253b5dd52aSJames Smart list_add_tail(&head, &dmp->list); 28263b5dd52aSJames Smart list_for_each_safe(curr, next, &head) { 28273b5dd52aSJames Smart mp[i] = list_entry(curr, struct lpfc_dmabuf, list); 28283b5dd52aSJames Smart list_del(curr); 28293b5dd52aSJames Smart 28303b5dd52aSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 28313b5dd52aSJames Smart mp[i]->buffer_tag = lpfc_sli_get_buffer_tag(phba); 28323b5dd52aSJames Smart cmd->un.quexri64cx.buff.bde.addrHigh = 28333b5dd52aSJames Smart putPaddrHigh(mp[i]->phys); 28343b5dd52aSJames Smart cmd->un.quexri64cx.buff.bde.addrLow = 28353b5dd52aSJames Smart putPaddrLow(mp[i]->phys); 28363b5dd52aSJames Smart cmd->un.quexri64cx.buff.bde.tus.f.bdeSize = 28373b5dd52aSJames Smart ((struct lpfc_dmabufext *)mp[i])->size; 28383b5dd52aSJames Smart cmd->un.quexri64cx.buff.buffer_tag = mp[i]->buffer_tag; 28393b5dd52aSJames Smart cmd->ulpCommand = CMD_QUE_XRI64_CX; 28403b5dd52aSJames Smart cmd->ulpPU = 0; 28413b5dd52aSJames Smart cmd->ulpLe = 1; 28423b5dd52aSJames Smart cmd->ulpBdeCount = 1; 28433b5dd52aSJames Smart cmd->unsli3.que_xri64cx_ext_words.ebde_count = 0; 28443b5dd52aSJames Smart 28453b5dd52aSJames Smart } else { 28463b5dd52aSJames Smart cmd->un.cont64[i].addrHigh = putPaddrHigh(mp[i]->phys); 28473b5dd52aSJames Smart cmd->un.cont64[i].addrLow = putPaddrLow(mp[i]->phys); 28483b5dd52aSJames Smart cmd->un.cont64[i].tus.f.bdeSize = 28493b5dd52aSJames Smart ((struct lpfc_dmabufext *)mp[i])->size; 28503b5dd52aSJames Smart cmd->ulpBdeCount = ++i; 28513b5dd52aSJames Smart 28523b5dd52aSJames Smart if ((--num_bde > 0) && (i < 2)) 28533b5dd52aSJames Smart continue; 28543b5dd52aSJames Smart 28553b5dd52aSJames Smart cmd->ulpCommand = CMD_QUE_XRI_BUF64_CX; 28563b5dd52aSJames Smart cmd->ulpLe = 1; 28573b5dd52aSJames Smart } 28583b5dd52aSJames Smart 28593b5dd52aSJames Smart cmd->ulpClass = CLASS3; 28603b5dd52aSJames Smart cmd->ulpContext = rxxri; 28613b5dd52aSJames Smart 2862d439d286SJames Smart iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 2863d439d286SJames Smart 0); 2864d439d286SJames Smart if (iocb_stat == IOCB_ERROR) { 28653b5dd52aSJames Smart diag_cmd_data_free(phba, 28663b5dd52aSJames Smart (struct lpfc_dmabufext *)mp[0]); 28673b5dd52aSJames Smart if (mp[1]) 28683b5dd52aSJames Smart diag_cmd_data_free(phba, 28693b5dd52aSJames Smart (struct lpfc_dmabufext *)mp[1]); 28703b5dd52aSJames Smart dmp = list_entry(next, struct lpfc_dmabuf, list); 2871d439d286SJames Smart ret_val = -EIO; 28723b5dd52aSJames Smart goto err_post_rxbufs_exit; 28733b5dd52aSJames Smart } 28743b5dd52aSJames Smart 28753b5dd52aSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, mp[0]); 28763b5dd52aSJames Smart if (mp[1]) { 28773b5dd52aSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, mp[1]); 28783b5dd52aSJames Smart mp[1] = NULL; 28793b5dd52aSJames Smart } 28803b5dd52aSJames Smart 28813b5dd52aSJames Smart /* The iocb was freed by lpfc_sli_issue_iocb */ 28823b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 28833b5dd52aSJames Smart if (!cmdiocbq) { 28843b5dd52aSJames Smart dmp = list_entry(next, struct lpfc_dmabuf, list); 2885d439d286SJames Smart ret_val = -EIO; 28863b5dd52aSJames Smart goto err_post_rxbufs_exit; 28873b5dd52aSJames Smart } 28883b5dd52aSJames Smart 28893b5dd52aSJames Smart cmd = &cmdiocbq->iocb; 28903b5dd52aSJames Smart i = 0; 28913b5dd52aSJames Smart } 28923b5dd52aSJames Smart list_del(&head); 28933b5dd52aSJames Smart 28943b5dd52aSJames Smart err_post_rxbufs_exit: 28953b5dd52aSJames Smart 28963b5dd52aSJames Smart if (rxbmp) { 28973b5dd52aSJames Smart if (rxbmp->virt) 28983b5dd52aSJames Smart lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys); 28993b5dd52aSJames Smart kfree(rxbmp); 29003b5dd52aSJames Smart } 29013b5dd52aSJames Smart 29023b5dd52aSJames Smart if (cmdiocbq) 29033b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 29043b5dd52aSJames Smart return ret_val; 29053b5dd52aSJames Smart } 29063b5dd52aSJames Smart 29073b5dd52aSJames Smart /** 29087ad20aa9SJames Smart * lpfc_bsg_diag_loopback_run - run loopback on a port by issue ct cmd to itself 29093b5dd52aSJames Smart * @job: LPFC_BSG_VENDOR_DIAG_TEST fc_bsg_job 29103b5dd52aSJames Smart * 29113b5dd52aSJames Smart * This function receives a user data buffer to be transmitted and received on 29123b5dd52aSJames Smart * the same port, the link must be up and in loopback mode prior 29133b5dd52aSJames Smart * to being called. 29143b5dd52aSJames Smart * 1. A kernel buffer is allocated to copy the user data into. 29153b5dd52aSJames Smart * 2. The port registers with "itself". 29163b5dd52aSJames Smart * 3. The transmit and receive exchange ids are obtained. 29173b5dd52aSJames Smart * 4. The receive exchange id is posted. 29183b5dd52aSJames Smart * 5. A new els loopback event is created. 29193b5dd52aSJames Smart * 6. The command and response iocbs are allocated. 29203b5dd52aSJames Smart * 7. The cmd iocb FsType is set to elx loopback and the CmdRsp to looppback. 29213b5dd52aSJames Smart * 29223b5dd52aSJames Smart * This function is meant to be called n times while the port is in loopback 29233b5dd52aSJames Smart * so it is the apps responsibility to issue a reset to take the port out 29243b5dd52aSJames Smart * of loopback mode. 29253b5dd52aSJames Smart **/ 29263b5dd52aSJames Smart static int 29277ad20aa9SJames Smart lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) 29283b5dd52aSJames Smart { 29293b5dd52aSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 29303b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 29313b5dd52aSJames Smart struct diag_mode_test *diag_mode; 29323b5dd52aSJames Smart struct lpfc_bsg_event *evt; 29333b5dd52aSJames Smart struct event_data *evdat; 29343b5dd52aSJames Smart struct lpfc_sli *psli = &phba->sli; 29353b5dd52aSJames Smart uint32_t size; 29363b5dd52aSJames Smart uint32_t full_size; 29373b5dd52aSJames Smart size_t segment_len = 0, segment_offset = 0, current_offset = 0; 29384042629eSJames Smart uint16_t rpi = 0; 29391b51197dSJames Smart struct lpfc_iocbq *cmdiocbq, *rspiocbq = NULL; 29401b51197dSJames Smart IOCB_t *cmd, *rsp = NULL; 29413b5dd52aSJames Smart struct lpfc_sli_ct_request *ctreq; 29423b5dd52aSJames Smart struct lpfc_dmabuf *txbmp; 29433b5dd52aSJames Smart struct ulp_bde64 *txbpl = NULL; 29443b5dd52aSJames Smart struct lpfc_dmabufext *txbuffer = NULL; 29453b5dd52aSJames Smart struct list_head head; 29463b5dd52aSJames Smart struct lpfc_dmabuf *curr; 29471b51197dSJames Smart uint16_t txxri = 0, rxxri; 29483b5dd52aSJames Smart uint32_t num_bde; 29493b5dd52aSJames Smart uint8_t *ptr = NULL, *rx_databuf = NULL; 29503b5dd52aSJames Smart int rc = 0; 2951d439d286SJames Smart int time_left; 2952d439d286SJames Smart int iocb_stat; 29533b5dd52aSJames Smart unsigned long flags; 29543b5dd52aSJames Smart void *dataout = NULL; 29553b5dd52aSJames Smart uint32_t total_mem; 29563b5dd52aSJames Smart 29573b5dd52aSJames Smart /* in case no data is returned return just the return code */ 29583b5dd52aSJames Smart job->reply->reply_payload_rcv_len = 0; 29593b5dd52aSJames Smart 29603b5dd52aSJames Smart if (job->request_len < 29613b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_test)) { 29623b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 29633b5dd52aSJames Smart "2739 Received DIAG TEST request below minimum " 29643b5dd52aSJames Smart "size\n"); 29653b5dd52aSJames Smart rc = -EINVAL; 29663b5dd52aSJames Smart goto loopback_test_exit; 29673b5dd52aSJames Smart } 29683b5dd52aSJames Smart 29693b5dd52aSJames Smart if (job->request_payload.payload_len != 29703b5dd52aSJames Smart job->reply_payload.payload_len) { 29713b5dd52aSJames Smart rc = -EINVAL; 29723b5dd52aSJames Smart goto loopback_test_exit; 29733b5dd52aSJames Smart } 29743b5dd52aSJames Smart diag_mode = (struct diag_mode_test *) 29753b5dd52aSJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 29763b5dd52aSJames Smart 29773b5dd52aSJames Smart if ((phba->link_state == LPFC_HBA_ERROR) || 29783b5dd52aSJames Smart (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || 29793b5dd52aSJames Smart (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { 29803b5dd52aSJames Smart rc = -EACCES; 29813b5dd52aSJames Smart goto loopback_test_exit; 29823b5dd52aSJames Smart } 29833b5dd52aSJames Smart 29843b5dd52aSJames Smart if (!lpfc_is_link_up(phba) || !(phba->link_flag & LS_LOOPBACK_MODE)) { 29853b5dd52aSJames Smart rc = -EACCES; 29863b5dd52aSJames Smart goto loopback_test_exit; 29873b5dd52aSJames Smart } 29883b5dd52aSJames Smart 29893b5dd52aSJames Smart size = job->request_payload.payload_len; 29903b5dd52aSJames Smart full_size = size + ELX_LOOPBACK_HEADER_SZ; /* plus the header */ 29913b5dd52aSJames Smart 29923b5dd52aSJames Smart if ((size == 0) || (size > 80 * BUF_SZ_4K)) { 29933b5dd52aSJames Smart rc = -ERANGE; 29943b5dd52aSJames Smart goto loopback_test_exit; 29953b5dd52aSJames Smart } 29963b5dd52aSJames Smart 299763e801ceSJames Smart if (full_size >= BUF_SZ_4K) { 29983b5dd52aSJames Smart /* 29993b5dd52aSJames Smart * Allocate memory for ioctl data. If buffer is bigger than 64k, 30003b5dd52aSJames Smart * then we allocate 64k and re-use that buffer over and over to 30013b5dd52aSJames Smart * xfer the whole block. This is because Linux kernel has a 30023b5dd52aSJames Smart * problem allocating more than 120k of kernel space memory. Saw 30033b5dd52aSJames Smart * problem with GET_FCPTARGETMAPPING... 30043b5dd52aSJames Smart */ 30053b5dd52aSJames Smart if (size <= (64 * 1024)) 300663e801ceSJames Smart total_mem = full_size; 30073b5dd52aSJames Smart else 30083b5dd52aSJames Smart total_mem = 64 * 1024; 30093b5dd52aSJames Smart } else 30103b5dd52aSJames Smart /* Allocate memory for ioctl data */ 30113b5dd52aSJames Smart total_mem = BUF_SZ_4K; 30123b5dd52aSJames Smart 30133b5dd52aSJames Smart dataout = kmalloc(total_mem, GFP_KERNEL); 30143b5dd52aSJames Smart if (dataout == NULL) { 30153b5dd52aSJames Smart rc = -ENOMEM; 30163b5dd52aSJames Smart goto loopback_test_exit; 30173b5dd52aSJames Smart } 30183b5dd52aSJames Smart 30193b5dd52aSJames Smart ptr = dataout; 30203b5dd52aSJames Smart ptr += ELX_LOOPBACK_HEADER_SZ; 30213b5dd52aSJames Smart sg_copy_to_buffer(job->request_payload.sg_list, 30223b5dd52aSJames Smart job->request_payload.sg_cnt, 30233b5dd52aSJames Smart ptr, size); 30243b5dd52aSJames Smart rc = lpfcdiag_loop_self_reg(phba, &rpi); 3025d439d286SJames Smart if (rc) 30263b5dd52aSJames Smart goto loopback_test_exit; 30273b5dd52aSJames Smart 30281b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) { 30293b5dd52aSJames Smart rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri); 30303b5dd52aSJames Smart if (rc) { 30313b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 30323b5dd52aSJames Smart goto loopback_test_exit; 30333b5dd52aSJames Smart } 30343b5dd52aSJames Smart 30353b5dd52aSJames Smart rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size); 30363b5dd52aSJames Smart if (rc) { 30373b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 30383b5dd52aSJames Smart goto loopback_test_exit; 30393b5dd52aSJames Smart } 30401b51197dSJames Smart } 30413b5dd52aSJames Smart evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, 30423b5dd52aSJames Smart SLI_CT_ELX_LOOPBACK); 30433b5dd52aSJames Smart if (!evt) { 30443b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 30453b5dd52aSJames Smart rc = -ENOMEM; 30463b5dd52aSJames Smart goto loopback_test_exit; 30473b5dd52aSJames Smart } 30483b5dd52aSJames Smart 30493b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 30503b5dd52aSJames Smart list_add(&evt->node, &phba->ct_ev_waiters); 30513b5dd52aSJames Smart lpfc_bsg_event_ref(evt); 30523b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 30533b5dd52aSJames Smart 30543b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 30551b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 30563b5dd52aSJames Smart rspiocbq = lpfc_sli_get_iocbq(phba); 30573b5dd52aSJames Smart txbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 30583b5dd52aSJames Smart 30593b5dd52aSJames Smart if (txbmp) { 30603b5dd52aSJames Smart txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys); 3061c7495937SJames Smart if (txbmp->virt) { 30623b5dd52aSJames Smart INIT_LIST_HEAD(&txbmp->list); 30633b5dd52aSJames Smart txbpl = (struct ulp_bde64 *) txbmp->virt; 30643b5dd52aSJames Smart txbuffer = diag_cmd_data_alloc(phba, 30653b5dd52aSJames Smart txbpl, full_size, 0); 30663b5dd52aSJames Smart } 3067c7495937SJames Smart } 30683b5dd52aSJames Smart 30691b51197dSJames Smart if (!cmdiocbq || !txbmp || !txbpl || !txbuffer || !txbmp->virt) { 30701b51197dSJames Smart rc = -ENOMEM; 30711b51197dSJames Smart goto err_loopback_test_exit; 30721b51197dSJames Smart } 30731b51197dSJames Smart if ((phba->sli_rev < LPFC_SLI_REV4) && !rspiocbq) { 30743b5dd52aSJames Smart rc = -ENOMEM; 30753b5dd52aSJames Smart goto err_loopback_test_exit; 30763b5dd52aSJames Smart } 30773b5dd52aSJames Smart 30783b5dd52aSJames Smart cmd = &cmdiocbq->iocb; 30791b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 30803b5dd52aSJames Smart rsp = &rspiocbq->iocb; 30813b5dd52aSJames Smart 30823b5dd52aSJames Smart INIT_LIST_HEAD(&head); 30833b5dd52aSJames Smart list_add_tail(&head, &txbuffer->dma.list); 30843b5dd52aSJames Smart list_for_each_entry(curr, &head, list) { 30853b5dd52aSJames Smart segment_len = ((struct lpfc_dmabufext *)curr)->size; 30863b5dd52aSJames Smart if (current_offset == 0) { 30873b5dd52aSJames Smart ctreq = curr->virt; 30883b5dd52aSJames Smart memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); 30893b5dd52aSJames Smart ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; 30903b5dd52aSJames Smart ctreq->RevisionId.bits.InId = 0; 30913b5dd52aSJames Smart ctreq->FsType = SLI_CT_ELX_LOOPBACK; 30923b5dd52aSJames Smart ctreq->FsSubType = 0; 30933b5dd52aSJames Smart ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_DATA; 30943b5dd52aSJames Smart ctreq->CommandResponse.bits.Size = size; 30953b5dd52aSJames Smart segment_offset = ELX_LOOPBACK_HEADER_SZ; 30963b5dd52aSJames Smart } else 30973b5dd52aSJames Smart segment_offset = 0; 30983b5dd52aSJames Smart 30993b5dd52aSJames Smart BUG_ON(segment_offset >= segment_len); 31003b5dd52aSJames Smart memcpy(curr->virt + segment_offset, 31013b5dd52aSJames Smart ptr + current_offset, 31023b5dd52aSJames Smart segment_len - segment_offset); 31033b5dd52aSJames Smart 31043b5dd52aSJames Smart current_offset += segment_len - segment_offset; 31053b5dd52aSJames Smart BUG_ON(current_offset > size); 31063b5dd52aSJames Smart } 31073b5dd52aSJames Smart list_del(&head); 31083b5dd52aSJames Smart 31093b5dd52aSJames Smart /* Build the XMIT_SEQUENCE iocb */ 31103b5dd52aSJames Smart num_bde = (uint32_t)txbuffer->flag; 31113b5dd52aSJames Smart 31123b5dd52aSJames Smart cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(txbmp->phys); 31133b5dd52aSJames Smart cmd->un.xseq64.bdl.addrLow = putPaddrLow(txbmp->phys); 31143b5dd52aSJames Smart cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 31153b5dd52aSJames Smart cmd->un.xseq64.bdl.bdeSize = (num_bde * sizeof(struct ulp_bde64)); 31163b5dd52aSJames Smart 31173b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); 31183b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Dfctl = 0; 31193b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; 31203b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; 31213b5dd52aSJames Smart 31223b5dd52aSJames Smart cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; 31233b5dd52aSJames Smart cmd->ulpBdeCount = 1; 31243b5dd52aSJames Smart cmd->ulpLe = 1; 31253b5dd52aSJames Smart cmd->ulpClass = CLASS3; 31263b5dd52aSJames Smart 31271b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) { 31281b51197dSJames Smart cmd->ulpContext = txxri; 31291b51197dSJames Smart } else { 31301b51197dSJames Smart cmd->un.xseq64.bdl.ulpIoTag32 = 0; 31311b51197dSJames Smart cmd->un.ulpWord[3] = phba->sli4_hba.rpi_ids[rpi]; 31321b51197dSJames Smart cmdiocbq->context3 = txbmp; 31331b51197dSJames Smart cmdiocbq->sli4_xritag = NO_XRI; 31341b51197dSJames Smart cmd->unsli3.rcvsli3.ox_id = 0xffff; 31351b51197dSJames Smart } 31363b5dd52aSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 31373b5dd52aSJames Smart cmdiocbq->vport = phba->pport; 3138d439d286SJames Smart iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, 3139d439d286SJames Smart rspiocbq, (phba->fc_ratov * 2) + 3140d439d286SJames Smart LPFC_DRVR_TIMEOUT); 31413b5dd52aSJames Smart 31421b51197dSJames Smart if ((iocb_stat != IOCB_SUCCESS) || ((phba->sli_rev < LPFC_SLI_REV4) && 31431b51197dSJames Smart (rsp->ulpStatus != IOCB_SUCCESS))) { 31441b51197dSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 31451b51197dSJames Smart "3126 Failed loopback test issue iocb: " 31461b51197dSJames Smart "iocb_stat:x%x\n", iocb_stat); 31473b5dd52aSJames Smart rc = -EIO; 31483b5dd52aSJames Smart goto err_loopback_test_exit; 31493b5dd52aSJames Smart } 31503b5dd52aSJames Smart 31513b5dd52aSJames Smart evt->waiting = 1; 3152d439d286SJames Smart time_left = wait_event_interruptible_timeout( 31533b5dd52aSJames Smart evt->wq, !list_empty(&evt->events_to_see), 31543b5dd52aSJames Smart ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ); 31553b5dd52aSJames Smart evt->waiting = 0; 31561b51197dSJames Smart if (list_empty(&evt->events_to_see)) { 3157d439d286SJames Smart rc = (time_left) ? -EINTR : -ETIMEDOUT; 31581b51197dSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 31591b51197dSJames Smart "3125 Not receiving unsolicited event, " 31601b51197dSJames Smart "rc:x%x\n", rc); 31611b51197dSJames Smart } else { 31623b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 31633b5dd52aSJames Smart list_move(evt->events_to_see.prev, &evt->events_to_get); 31643b5dd52aSJames Smart evdat = list_entry(evt->events_to_get.prev, 31653b5dd52aSJames Smart typeof(*evdat), node); 31663b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 31673b5dd52aSJames Smart rx_databuf = evdat->data; 31683b5dd52aSJames Smart if (evdat->len != full_size) { 31693b5dd52aSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 31703b5dd52aSJames Smart "1603 Loopback test did not receive expected " 31713b5dd52aSJames Smart "data length. actual length 0x%x expected " 31723b5dd52aSJames Smart "length 0x%x\n", 31733b5dd52aSJames Smart evdat->len, full_size); 31743b5dd52aSJames Smart rc = -EIO; 31753b5dd52aSJames Smart } else if (rx_databuf == NULL) 31763b5dd52aSJames Smart rc = -EIO; 31773b5dd52aSJames Smart else { 31783b5dd52aSJames Smart rc = IOCB_SUCCESS; 31793b5dd52aSJames Smart /* skip over elx loopback header */ 31803b5dd52aSJames Smart rx_databuf += ELX_LOOPBACK_HEADER_SZ; 31813b5dd52aSJames Smart job->reply->reply_payload_rcv_len = 31823b5dd52aSJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 31833b5dd52aSJames Smart job->reply_payload.sg_cnt, 31843b5dd52aSJames Smart rx_databuf, size); 31853b5dd52aSJames Smart job->reply->reply_payload_rcv_len = size; 31863b5dd52aSJames Smart } 31873b5dd52aSJames Smart } 31883b5dd52aSJames Smart 31893b5dd52aSJames Smart err_loopback_test_exit: 31903b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 31913b5dd52aSJames Smart 31923b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 31933b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* release ref */ 31943b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* delete */ 31953b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 31963b5dd52aSJames Smart 31973b5dd52aSJames Smart if (cmdiocbq != NULL) 31983b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 31993b5dd52aSJames Smart 32003b5dd52aSJames Smart if (rspiocbq != NULL) 32013b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, rspiocbq); 32023b5dd52aSJames Smart 32033b5dd52aSJames Smart if (txbmp != NULL) { 32043b5dd52aSJames Smart if (txbpl != NULL) { 32053b5dd52aSJames Smart if (txbuffer != NULL) 32063b5dd52aSJames Smart diag_cmd_data_free(phba, txbuffer); 32073b5dd52aSJames Smart lpfc_mbuf_free(phba, txbmp->virt, txbmp->phys); 32083b5dd52aSJames Smart } 32093b5dd52aSJames Smart kfree(txbmp); 32103b5dd52aSJames Smart } 32113b5dd52aSJames Smart 32123b5dd52aSJames Smart loopback_test_exit: 32133b5dd52aSJames Smart kfree(dataout); 32143b5dd52aSJames Smart /* make error code available to userspace */ 32153b5dd52aSJames Smart job->reply->result = rc; 32163b5dd52aSJames Smart job->dd_data = NULL; 32173b5dd52aSJames Smart /* complete the job back to userspace if no error */ 32181b51197dSJames Smart if (rc == IOCB_SUCCESS) 32193b5dd52aSJames Smart job->job_done(job); 32203b5dd52aSJames Smart return rc; 32213b5dd52aSJames Smart } 32223b5dd52aSJames Smart 32233b5dd52aSJames Smart /** 32243b5dd52aSJames Smart * lpfc_bsg_get_dfc_rev - process a GET_DFC_REV bsg vendor command 32253b5dd52aSJames Smart * @job: GET_DFC_REV fc_bsg_job 32263b5dd52aSJames Smart **/ 32273b5dd52aSJames Smart static int 32283b5dd52aSJames Smart lpfc_bsg_get_dfc_rev(struct fc_bsg_job *job) 32293b5dd52aSJames Smart { 32303b5dd52aSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 32313b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 32323b5dd52aSJames Smart struct get_mgmt_rev *event_req; 32333b5dd52aSJames Smart struct get_mgmt_rev_reply *event_reply; 32343b5dd52aSJames Smart int rc = 0; 32353b5dd52aSJames Smart 32363b5dd52aSJames Smart if (job->request_len < 32373b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev)) { 32383b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 32393b5dd52aSJames Smart "2740 Received GET_DFC_REV request below " 32403b5dd52aSJames Smart "minimum size\n"); 32413b5dd52aSJames Smart rc = -EINVAL; 32423b5dd52aSJames Smart goto job_error; 32433b5dd52aSJames Smart } 32443b5dd52aSJames Smart 32453b5dd52aSJames Smart event_req = (struct get_mgmt_rev *) 32463b5dd52aSJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 32473b5dd52aSJames Smart 32483b5dd52aSJames Smart event_reply = (struct get_mgmt_rev_reply *) 32493b5dd52aSJames Smart job->reply->reply_data.vendor_reply.vendor_rsp; 32503b5dd52aSJames Smart 32513b5dd52aSJames Smart if (job->reply_len < 32523b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev_reply)) { 32533b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 32543b5dd52aSJames Smart "2741 Received GET_DFC_REV reply below " 32553b5dd52aSJames Smart "minimum size\n"); 32563b5dd52aSJames Smart rc = -EINVAL; 32573b5dd52aSJames Smart goto job_error; 32583b5dd52aSJames Smart } 32593b5dd52aSJames Smart 32603b5dd52aSJames Smart event_reply->info.a_Major = MANAGEMENT_MAJOR_REV; 32613b5dd52aSJames Smart event_reply->info.a_Minor = MANAGEMENT_MINOR_REV; 32623b5dd52aSJames Smart job_error: 32633b5dd52aSJames Smart job->reply->result = rc; 32643b5dd52aSJames Smart if (rc == 0) 32653b5dd52aSJames Smart job->job_done(job); 32663b5dd52aSJames Smart return rc; 32673b5dd52aSJames Smart } 32683b5dd52aSJames Smart 32693b5dd52aSJames Smart /** 32707ad20aa9SJames Smart * lpfc_bsg_issue_mbox_cmpl - lpfc_bsg_issue_mbox mbox completion handler 32713b5dd52aSJames Smart * @phba: Pointer to HBA context object. 32723b5dd52aSJames Smart * @pmboxq: Pointer to mailbox command. 32733b5dd52aSJames Smart * 32743b5dd52aSJames Smart * This is completion handler function for mailbox commands issued from 32753b5dd52aSJames Smart * lpfc_bsg_issue_mbox function. This function is called by the 32763b5dd52aSJames Smart * mailbox event handler function with no lock held. This function 32773b5dd52aSJames Smart * will wake up thread waiting on the wait queue pointed by context1 32783b5dd52aSJames Smart * of the mailbox. 32793b5dd52aSJames Smart **/ 32803b5dd52aSJames Smart void 32817ad20aa9SJames Smart lpfc_bsg_issue_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) 32823b5dd52aSJames Smart { 32833b5dd52aSJames Smart struct bsg_job_data *dd_data; 32843b5dd52aSJames Smart struct fc_bsg_job *job; 32853b5dd52aSJames Smart uint32_t size; 32863b5dd52aSJames Smart unsigned long flags; 32877ad20aa9SJames Smart uint8_t *pmb, *pmb_buf; 32883b5dd52aSJames Smart 32893b5dd52aSJames Smart dd_data = pmboxq->context1; 32903b5dd52aSJames Smart 32917ad20aa9SJames Smart /* 32927ad20aa9SJames Smart * The outgoing buffer is readily referred from the dma buffer, 32937ad20aa9SJames Smart * just need to get header part from mailboxq structure. 32947a470277SJames Smart */ 32957ad20aa9SJames Smart pmb = (uint8_t *)&pmboxq->u.mb; 32967ad20aa9SJames Smart pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb; 32977ad20aa9SJames Smart memcpy(pmb_buf, pmb, sizeof(MAILBOX_t)); 3298515e0aa2SJames Smart 3299*a33c4f7bSJames Smart /* Determine if job has been aborted */ 3300*a33c4f7bSJames Smart 3301*a33c4f7bSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 3302*a33c4f7bSJames Smart job = dd_data->set_job; 3303*a33c4f7bSJames Smart if (job) { 3304*a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 3305*a33c4f7bSJames Smart job->dd_data = NULL; 3306*a33c4f7bSJames Smart } 3307*a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 3308*a33c4f7bSJames Smart 3309*a33c4f7bSJames Smart /* Copy the mailbox data to the job if it is still active */ 3310*a33c4f7bSJames Smart 33115a6f133eSJames Smart if (job) { 33127a470277SJames Smart size = job->reply_payload.payload_len; 33133b5dd52aSJames Smart job->reply->reply_payload_rcv_len = 33143b5dd52aSJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 33153b5dd52aSJames Smart job->reply_payload.sg_cnt, 33167ad20aa9SJames Smart pmb_buf, size); 3317b6e3b9c6SJames Smart } 33187a470277SJames Smart 3319*a33c4f7bSJames Smart dd_data->set_job = NULL; 33203b5dd52aSJames Smart mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool); 33217ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dd_data->context_un.mbox.dmabuffers); 33223b5dd52aSJames Smart kfree(dd_data); 33237ad20aa9SJames Smart 3324*a33c4f7bSJames Smart /* Complete the job if the job is still active */ 3325*a33c4f7bSJames Smart 33267ad20aa9SJames Smart if (job) { 33277ad20aa9SJames Smart job->reply->result = 0; 33287ad20aa9SJames Smart job->job_done(job); 33297ad20aa9SJames Smart } 33303b5dd52aSJames Smart return; 33313b5dd52aSJames Smart } 33323b5dd52aSJames Smart 33333b5dd52aSJames Smart /** 33343b5dd52aSJames Smart * lpfc_bsg_check_cmd_access - test for a supported mailbox command 33353b5dd52aSJames Smart * @phba: Pointer to HBA context object. 33363b5dd52aSJames Smart * @mb: Pointer to a mailbox object. 33373b5dd52aSJames Smart * @vport: Pointer to a vport object. 33383b5dd52aSJames Smart * 33393b5dd52aSJames Smart * Some commands require the port to be offline, some may not be called from 33403b5dd52aSJames Smart * the application. 33413b5dd52aSJames Smart **/ 33423b5dd52aSJames Smart static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, 33433b5dd52aSJames Smart MAILBOX_t *mb, struct lpfc_vport *vport) 33443b5dd52aSJames Smart { 33453b5dd52aSJames Smart /* return negative error values for bsg job */ 33463b5dd52aSJames Smart switch (mb->mbxCommand) { 33473b5dd52aSJames Smart /* Offline only */ 33483b5dd52aSJames Smart case MBX_INIT_LINK: 33493b5dd52aSJames Smart case MBX_DOWN_LINK: 33503b5dd52aSJames Smart case MBX_CONFIG_LINK: 33513b5dd52aSJames Smart case MBX_CONFIG_RING: 33523b5dd52aSJames Smart case MBX_RESET_RING: 33533b5dd52aSJames Smart case MBX_UNREG_LOGIN: 33543b5dd52aSJames Smart case MBX_CLEAR_LA: 33553b5dd52aSJames Smart case MBX_DUMP_CONTEXT: 33563b5dd52aSJames Smart case MBX_RUN_DIAGS: 33573b5dd52aSJames Smart case MBX_RESTART: 33583b5dd52aSJames Smart case MBX_SET_MASK: 33593b5dd52aSJames Smart if (!(vport->fc_flag & FC_OFFLINE_MODE)) { 33603b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 33613b5dd52aSJames Smart "2743 Command 0x%x is illegal in on-line " 33623b5dd52aSJames Smart "state\n", 33633b5dd52aSJames Smart mb->mbxCommand); 33643b5dd52aSJames Smart return -EPERM; 33653b5dd52aSJames Smart } 33663b5dd52aSJames Smart case MBX_WRITE_NV: 33673b5dd52aSJames Smart case MBX_WRITE_VPARMS: 33683b5dd52aSJames Smart case MBX_LOAD_SM: 33693b5dd52aSJames Smart case MBX_READ_NV: 33703b5dd52aSJames Smart case MBX_READ_CONFIG: 33713b5dd52aSJames Smart case MBX_READ_RCONFIG: 33723b5dd52aSJames Smart case MBX_READ_STATUS: 33733b5dd52aSJames Smart case MBX_READ_XRI: 33743b5dd52aSJames Smart case MBX_READ_REV: 33753b5dd52aSJames Smart case MBX_READ_LNK_STAT: 33763b5dd52aSJames Smart case MBX_DUMP_MEMORY: 33773b5dd52aSJames Smart case MBX_DOWN_LOAD: 33783b5dd52aSJames Smart case MBX_UPDATE_CFG: 33793b5dd52aSJames Smart case MBX_KILL_BOARD: 33803b5dd52aSJames Smart case MBX_LOAD_AREA: 33813b5dd52aSJames Smart case MBX_LOAD_EXP_ROM: 33823b5dd52aSJames Smart case MBX_BEACON: 33833b5dd52aSJames Smart case MBX_DEL_LD_ENTRY: 33843b5dd52aSJames Smart case MBX_SET_DEBUG: 33853b5dd52aSJames Smart case MBX_WRITE_WWN: 33863b5dd52aSJames Smart case MBX_SLI4_CONFIG: 3387c7495937SJames Smart case MBX_READ_EVENT_LOG: 33883b5dd52aSJames Smart case MBX_READ_EVENT_LOG_STATUS: 33893b5dd52aSJames Smart case MBX_WRITE_EVENT_LOG: 33903b5dd52aSJames Smart case MBX_PORT_CAPABILITIES: 33913b5dd52aSJames Smart case MBX_PORT_IOV_CONTROL: 33927a470277SJames Smart case MBX_RUN_BIU_DIAG64: 33933b5dd52aSJames Smart break; 33943b5dd52aSJames Smart case MBX_SET_VARIABLE: 3395e2aed29fSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_INIT, 3396e2aed29fSJames Smart "1226 mbox: set_variable 0x%x, 0x%x\n", 3397e2aed29fSJames Smart mb->un.varWords[0], 3398e2aed29fSJames Smart mb->un.varWords[1]); 3399e2aed29fSJames Smart if ((mb->un.varWords[0] == SETVAR_MLOMNT) 3400e2aed29fSJames Smart && (mb->un.varWords[1] == 1)) { 3401e2aed29fSJames Smart phba->wait_4_mlo_maint_flg = 1; 3402e2aed29fSJames Smart } else if (mb->un.varWords[0] == SETVAR_MLORST) { 34031b51197dSJames Smart spin_lock_irq(&phba->hbalock); 3404e2aed29fSJames Smart phba->link_flag &= ~LS_LOOPBACK_MODE; 34051b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 340676a95d75SJames Smart phba->fc_topology = LPFC_TOPOLOGY_PT_PT; 3407e2aed29fSJames Smart } 3408e2aed29fSJames Smart break; 34093b5dd52aSJames Smart case MBX_READ_SPARM64: 341076a95d75SJames Smart case MBX_READ_TOPOLOGY: 34113b5dd52aSJames Smart case MBX_REG_LOGIN: 34123b5dd52aSJames Smart case MBX_REG_LOGIN64: 34133b5dd52aSJames Smart case MBX_CONFIG_PORT: 34143b5dd52aSJames Smart case MBX_RUN_BIU_DIAG: 34153b5dd52aSJames Smart default: 34163b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 34173b5dd52aSJames Smart "2742 Unknown Command 0x%x\n", 34183b5dd52aSJames Smart mb->mbxCommand); 34193b5dd52aSJames Smart return -EPERM; 34203b5dd52aSJames Smart } 34213b5dd52aSJames Smart 34223b5dd52aSJames Smart return 0; /* ok */ 34233b5dd52aSJames Smart } 34243b5dd52aSJames Smart 34253b5dd52aSJames Smart /** 34267ad20aa9SJames Smart * lpfc_bsg_mbox_ext_cleanup - clean up context of multi-buffer mbox session 34277ad20aa9SJames Smart * @phba: Pointer to HBA context object. 34287ad20aa9SJames Smart * 34297ad20aa9SJames Smart * This is routine clean up and reset BSG handling of multi-buffer mbox 34307ad20aa9SJames Smart * command session. 34317ad20aa9SJames Smart **/ 34327ad20aa9SJames Smart static void 34337ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(struct lpfc_hba *phba) 34347ad20aa9SJames Smart { 34357ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_IDLE) 34367ad20aa9SJames Smart return; 34377ad20aa9SJames Smart 34387ad20aa9SJames Smart /* free all memory, including dma buffers */ 34397ad20aa9SJames Smart lpfc_bsg_dma_page_list_free(phba, 34407ad20aa9SJames Smart &phba->mbox_ext_buf_ctx.ext_dmabuf_list); 34417ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, phba->mbox_ext_buf_ctx.mbx_dmabuf); 34427ad20aa9SJames Smart /* multi-buffer write mailbox command pass-through complete */ 34437ad20aa9SJames Smart memset((char *)&phba->mbox_ext_buf_ctx, 0, 34447ad20aa9SJames Smart sizeof(struct lpfc_mbox_ext_buf_ctx)); 34457ad20aa9SJames Smart INIT_LIST_HEAD(&phba->mbox_ext_buf_ctx.ext_dmabuf_list); 34467ad20aa9SJames Smart 34477ad20aa9SJames Smart return; 34487ad20aa9SJames Smart } 34497ad20aa9SJames Smart 34507ad20aa9SJames Smart /** 34517ad20aa9SJames Smart * lpfc_bsg_issue_mbox_ext_handle_job - job handler for multi-buffer mbox cmpl 34527ad20aa9SJames Smart * @phba: Pointer to HBA context object. 34537ad20aa9SJames Smart * @pmboxq: Pointer to mailbox command. 34547ad20aa9SJames Smart * 34557ad20aa9SJames Smart * This is routine handles BSG job for mailbox commands completions with 34567ad20aa9SJames Smart * multiple external buffers. 34577ad20aa9SJames Smart **/ 34587ad20aa9SJames Smart static struct fc_bsg_job * 34597ad20aa9SJames Smart lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) 34607ad20aa9SJames Smart { 34617ad20aa9SJames Smart struct bsg_job_data *dd_data; 34627ad20aa9SJames Smart struct fc_bsg_job *job; 34637ad20aa9SJames Smart uint8_t *pmb, *pmb_buf; 34647ad20aa9SJames Smart unsigned long flags; 34657ad20aa9SJames Smart uint32_t size; 34667ad20aa9SJames Smart int rc = 0; 3467026abb87SJames Smart struct lpfc_dmabuf *dmabuf; 3468026abb87SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 3469026abb87SJames Smart uint8_t *pmbx; 34707ad20aa9SJames Smart 34717ad20aa9SJames Smart dd_data = pmboxq->context1; 3472*a33c4f7bSJames Smart 3473*a33c4f7bSJames Smart /* Determine if job has been aborted */ 3474*a33c4f7bSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 3475*a33c4f7bSJames Smart job = dd_data->set_job; 3476*a33c4f7bSJames Smart if (job) { 3477*a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 3478*a33c4f7bSJames Smart job->dd_data = NULL; 34797ad20aa9SJames Smart } 3480*a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 34817ad20aa9SJames Smart 34827ad20aa9SJames Smart /* 34837ad20aa9SJames Smart * The outgoing buffer is readily referred from the dma buffer, 34847ad20aa9SJames Smart * just need to get header part from mailboxq structure. 34857ad20aa9SJames Smart */ 3486*a33c4f7bSJames Smart 34877ad20aa9SJames Smart pmb = (uint8_t *)&pmboxq->u.mb; 34887ad20aa9SJames Smart pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb; 3489026abb87SJames Smart /* Copy the byte swapped response mailbox back to the user */ 34907ad20aa9SJames Smart memcpy(pmb_buf, pmb, sizeof(MAILBOX_t)); 3491026abb87SJames Smart /* if there is any non-embedded extended data copy that too */ 3492026abb87SJames Smart dmabuf = phba->mbox_ext_buf_ctx.mbx_dmabuf; 3493026abb87SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; 3494026abb87SJames Smart if (!bsg_bf_get(lpfc_mbox_hdr_emb, 3495026abb87SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) { 3496026abb87SJames Smart pmbx = (uint8_t *)dmabuf->virt; 3497026abb87SJames Smart /* byte swap the extended data following the mailbox command */ 3498026abb87SJames Smart lpfc_sli_pcimem_bcopy(&pmbx[sizeof(MAILBOX_t)], 3499026abb87SJames Smart &pmbx[sizeof(MAILBOX_t)], 3500026abb87SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys.mse[0].buf_len); 3501026abb87SJames Smart } 35027ad20aa9SJames Smart 3503*a33c4f7bSJames Smart /* Complete the job if the job is still active */ 3504*a33c4f7bSJames Smart 35057ad20aa9SJames Smart if (job) { 35067ad20aa9SJames Smart size = job->reply_payload.payload_len; 35077ad20aa9SJames Smart job->reply->reply_payload_rcv_len = 35087ad20aa9SJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 35097ad20aa9SJames Smart job->reply_payload.sg_cnt, 35107ad20aa9SJames Smart pmb_buf, size); 3511*a33c4f7bSJames Smart 35127ad20aa9SJames Smart /* result for successful */ 35137ad20aa9SJames Smart job->reply->result = 0; 3514*a33c4f7bSJames Smart 35157ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 35167ad20aa9SJames Smart "2937 SLI_CONFIG ext-buffer maibox command " 35177ad20aa9SJames Smart "(x%x/x%x) complete bsg job done, bsize:%d\n", 35187ad20aa9SJames Smart phba->mbox_ext_buf_ctx.nembType, 35197ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType, size); 3520b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, 3521b76f2dc9SJames Smart phba->mbox_ext_buf_ctx.nembType, 3522b76f2dc9SJames Smart phba->mbox_ext_buf_ctx.mboxType, 3523b76f2dc9SJames Smart dma_ebuf, sta_pos_addr, 3524b76f2dc9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf, 0); 3525*a33c4f7bSJames Smart } else { 35267ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 35277ad20aa9SJames Smart "2938 SLI_CONFIG ext-buffer maibox " 35287ad20aa9SJames Smart "command (x%x/x%x) failure, rc:x%x\n", 35297ad20aa9SJames Smart phba->mbox_ext_buf_ctx.nembType, 35307ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType, rc); 3531*a33c4f7bSJames Smart } 3532*a33c4f7bSJames Smart 3533*a33c4f7bSJames Smart 35347ad20aa9SJames Smart /* state change */ 35357ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_DONE; 35367ad20aa9SJames Smart kfree(dd_data); 35377ad20aa9SJames Smart return job; 35387ad20aa9SJames Smart } 35397ad20aa9SJames Smart 35407ad20aa9SJames Smart /** 35417ad20aa9SJames Smart * lpfc_bsg_issue_read_mbox_ext_cmpl - compl handler for multi-buffer read mbox 35427ad20aa9SJames Smart * @phba: Pointer to HBA context object. 35437ad20aa9SJames Smart * @pmboxq: Pointer to mailbox command. 35447ad20aa9SJames Smart * 35457ad20aa9SJames Smart * This is completion handler function for mailbox read commands with multiple 35467ad20aa9SJames Smart * external buffers. 35477ad20aa9SJames Smart **/ 35487ad20aa9SJames Smart static void 35497ad20aa9SJames Smart lpfc_bsg_issue_read_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) 35507ad20aa9SJames Smart { 35517ad20aa9SJames Smart struct fc_bsg_job *job; 35527ad20aa9SJames Smart 3553*a33c4f7bSJames Smart job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq); 3554*a33c4f7bSJames Smart 35557ad20aa9SJames Smart /* handle the BSG job with mailbox command */ 3556*a33c4f7bSJames Smart if (!job) 35577ad20aa9SJames Smart pmboxq->u.mb.mbxStatus = MBXERR_ERROR; 35587ad20aa9SJames Smart 35597ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 35607ad20aa9SJames Smart "2939 SLI_CONFIG ext-buffer rd maibox command " 35617ad20aa9SJames Smart "complete, ctxState:x%x, mbxStatus:x%x\n", 35627ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus); 35637ad20aa9SJames Smart 35647ad20aa9SJames Smart if (pmboxq->u.mb.mbxStatus || phba->mbox_ext_buf_ctx.numBuf == 1) 35657ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 35667ad20aa9SJames Smart 35677ad20aa9SJames Smart /* free base driver mailbox structure memory */ 35687ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 35697ad20aa9SJames Smart 3570*a33c4f7bSJames Smart /* if the job is still active, call job done */ 35717ad20aa9SJames Smart if (job) 35727ad20aa9SJames Smart job->job_done(job); 35737ad20aa9SJames Smart 35747ad20aa9SJames Smart return; 35757ad20aa9SJames Smart } 35767ad20aa9SJames Smart 35777ad20aa9SJames Smart /** 35787ad20aa9SJames Smart * lpfc_bsg_issue_write_mbox_ext_cmpl - cmpl handler for multi-buffer write mbox 35797ad20aa9SJames Smart * @phba: Pointer to HBA context object. 35807ad20aa9SJames Smart * @pmboxq: Pointer to mailbox command. 35817ad20aa9SJames Smart * 35827ad20aa9SJames Smart * This is completion handler function for mailbox write commands with multiple 35837ad20aa9SJames Smart * external buffers. 35847ad20aa9SJames Smart **/ 35857ad20aa9SJames Smart static void 35867ad20aa9SJames Smart lpfc_bsg_issue_write_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) 35877ad20aa9SJames Smart { 35887ad20aa9SJames Smart struct fc_bsg_job *job; 35897ad20aa9SJames Smart 3590*a33c4f7bSJames Smart job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq); 3591*a33c4f7bSJames Smart 35927ad20aa9SJames Smart /* handle the BSG job with the mailbox command */ 3593*a33c4f7bSJames Smart if (!job) 35947ad20aa9SJames Smart pmboxq->u.mb.mbxStatus = MBXERR_ERROR; 35957ad20aa9SJames Smart 35967ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 35977ad20aa9SJames Smart "2940 SLI_CONFIG ext-buffer wr maibox command " 35987ad20aa9SJames Smart "complete, ctxState:x%x, mbxStatus:x%x\n", 35997ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus); 36007ad20aa9SJames Smart 36017ad20aa9SJames Smart /* free all memory, including dma buffers */ 36027ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 36037ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 36047ad20aa9SJames Smart 3605*a33c4f7bSJames Smart /* if the job is still active, call job done */ 36067ad20aa9SJames Smart if (job) 36077ad20aa9SJames Smart job->job_done(job); 36087ad20aa9SJames Smart 36097ad20aa9SJames Smart return; 36107ad20aa9SJames Smart } 36117ad20aa9SJames Smart 36127ad20aa9SJames Smart static void 36137ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(struct lpfc_hba *phba, enum nemb_type nemb_tp, 36147ad20aa9SJames Smart uint32_t index, struct lpfc_dmabuf *mbx_dmabuf, 36157ad20aa9SJames Smart struct lpfc_dmabuf *ext_dmabuf) 36167ad20aa9SJames Smart { 36177ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 36187ad20aa9SJames Smart 36197ad20aa9SJames Smart /* pointer to the start of mailbox command */ 36207ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)mbx_dmabuf->virt; 36217ad20aa9SJames Smart 36227ad20aa9SJames Smart if (nemb_tp == nemb_mse) { 36237ad20aa9SJames Smart if (index == 0) { 36247ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 36257ad20aa9SJames Smart mse[index].pa_hi = 36267ad20aa9SJames Smart putPaddrHigh(mbx_dmabuf->phys + 36277ad20aa9SJames Smart sizeof(MAILBOX_t)); 36287ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 36297ad20aa9SJames Smart mse[index].pa_lo = 36307ad20aa9SJames Smart putPaddrLow(mbx_dmabuf->phys + 36317ad20aa9SJames Smart sizeof(MAILBOX_t)); 36327ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 36337ad20aa9SJames Smart "2943 SLI_CONFIG(mse)[%d], " 36347ad20aa9SJames Smart "bufLen:%d, addrHi:x%x, addrLo:x%x\n", 36357ad20aa9SJames Smart index, 36367ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 36377ad20aa9SJames Smart mse[index].buf_len, 36387ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 36397ad20aa9SJames Smart mse[index].pa_hi, 36407ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 36417ad20aa9SJames Smart mse[index].pa_lo); 36427ad20aa9SJames Smart } else { 36437ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 36447ad20aa9SJames Smart mse[index].pa_hi = 36457ad20aa9SJames Smart putPaddrHigh(ext_dmabuf->phys); 36467ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 36477ad20aa9SJames Smart mse[index].pa_lo = 36487ad20aa9SJames Smart putPaddrLow(ext_dmabuf->phys); 36497ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 36507ad20aa9SJames Smart "2944 SLI_CONFIG(mse)[%d], " 36517ad20aa9SJames Smart "bufLen:%d, addrHi:x%x, addrLo:x%x\n", 36527ad20aa9SJames Smart index, 36537ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 36547ad20aa9SJames Smart mse[index].buf_len, 36557ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 36567ad20aa9SJames Smart mse[index].pa_hi, 36577ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 36587ad20aa9SJames Smart mse[index].pa_lo); 36597ad20aa9SJames Smart } 36607ad20aa9SJames Smart } else { 36617ad20aa9SJames Smart if (index == 0) { 36627ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 36637ad20aa9SJames Smart hbd[index].pa_hi = 36647ad20aa9SJames Smart putPaddrHigh(mbx_dmabuf->phys + 36657ad20aa9SJames Smart sizeof(MAILBOX_t)); 36667ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 36677ad20aa9SJames Smart hbd[index].pa_lo = 36687ad20aa9SJames Smart putPaddrLow(mbx_dmabuf->phys + 36697ad20aa9SJames Smart sizeof(MAILBOX_t)); 36707ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 36717ad20aa9SJames Smart "3007 SLI_CONFIG(hbd)[%d], " 36727ad20aa9SJames Smart "bufLen:%d, addrHi:x%x, addrLo:x%x\n", 36737ad20aa9SJames Smart index, 36747ad20aa9SJames Smart bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, 36757ad20aa9SJames Smart &sli_cfg_mbx->un. 36767ad20aa9SJames Smart sli_config_emb1_subsys.hbd[index]), 36777ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 36787ad20aa9SJames Smart hbd[index].pa_hi, 36797ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 36807ad20aa9SJames Smart hbd[index].pa_lo); 36817ad20aa9SJames Smart 36827ad20aa9SJames Smart } else { 36837ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 36847ad20aa9SJames Smart hbd[index].pa_hi = 36857ad20aa9SJames Smart putPaddrHigh(ext_dmabuf->phys); 36867ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 36877ad20aa9SJames Smart hbd[index].pa_lo = 36887ad20aa9SJames Smart putPaddrLow(ext_dmabuf->phys); 36897ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 36907ad20aa9SJames Smart "3008 SLI_CONFIG(hbd)[%d], " 36917ad20aa9SJames Smart "bufLen:%d, addrHi:x%x, addrLo:x%x\n", 36927ad20aa9SJames Smart index, 36937ad20aa9SJames Smart bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, 36947ad20aa9SJames Smart &sli_cfg_mbx->un. 36957ad20aa9SJames Smart sli_config_emb1_subsys.hbd[index]), 36967ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 36977ad20aa9SJames Smart hbd[index].pa_hi, 36987ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 36997ad20aa9SJames Smart hbd[index].pa_lo); 37007ad20aa9SJames Smart } 37017ad20aa9SJames Smart } 37027ad20aa9SJames Smart return; 37037ad20aa9SJames Smart } 37047ad20aa9SJames Smart 37057ad20aa9SJames Smart /** 37067ad20aa9SJames Smart * lpfc_bsg_sli_cfg_mse_read_cmd_ext - sli_config non-embedded mailbox cmd read 37077ad20aa9SJames Smart * @phba: Pointer to HBA context object. 37087ad20aa9SJames Smart * @mb: Pointer to a BSG mailbox object. 37097ad20aa9SJames Smart * @nemb_tp: Enumerate of non-embedded mailbox command type. 37107ad20aa9SJames Smart * @dmabuff: Pointer to a DMA buffer descriptor. 37117ad20aa9SJames Smart * 37127ad20aa9SJames Smart * This routine performs SLI_CONFIG (0x9B) read mailbox command operation with 37137ad20aa9SJames Smart * non-embedded external bufffers. 37147ad20aa9SJames Smart **/ 37157ad20aa9SJames Smart static int 37167ad20aa9SJames Smart lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job, 37177ad20aa9SJames Smart enum nemb_type nemb_tp, 37187ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 37197ad20aa9SJames Smart { 37207ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 37217ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 37227ad20aa9SJames Smart struct lpfc_dmabuf *curr_dmabuf, *next_dmabuf; 37237ad20aa9SJames Smart uint32_t ext_buf_cnt, ext_buf_index; 37247ad20aa9SJames Smart struct lpfc_dmabuf *ext_dmabuf = NULL; 37257ad20aa9SJames Smart struct bsg_job_data *dd_data = NULL; 37267ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq = NULL; 37277ad20aa9SJames Smart MAILBOX_t *pmb; 37287ad20aa9SJames Smart uint8_t *pmbx; 37297ad20aa9SJames Smart int rc, i; 37307ad20aa9SJames Smart 37317ad20aa9SJames Smart mbox_req = 37327ad20aa9SJames Smart (struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd; 37337ad20aa9SJames Smart 37347ad20aa9SJames Smart /* pointer to the start of mailbox command */ 37357ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; 37367ad20aa9SJames Smart 37377ad20aa9SJames Smart if (nemb_tp == nemb_mse) { 37387ad20aa9SJames Smart ext_buf_cnt = bsg_bf_get(lpfc_mbox_hdr_mse_cnt, 37397ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr); 37407ad20aa9SJames Smart if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_MSE) { 37417ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 37427ad20aa9SJames Smart "2945 Handled SLI_CONFIG(mse) rd, " 37437ad20aa9SJames Smart "ext_buf_cnt(%d) out of range(%d)\n", 37447ad20aa9SJames Smart ext_buf_cnt, 37457ad20aa9SJames Smart LPFC_MBX_SLI_CONFIG_MAX_MSE); 37467ad20aa9SJames Smart rc = -ERANGE; 37477ad20aa9SJames Smart goto job_error; 37487ad20aa9SJames Smart } 37497ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 37507ad20aa9SJames Smart "2941 Handled SLI_CONFIG(mse) rd, " 37517ad20aa9SJames Smart "ext_buf_cnt:%d\n", ext_buf_cnt); 37527ad20aa9SJames Smart } else { 37537ad20aa9SJames Smart /* sanity check on interface type for support */ 37547ad20aa9SJames Smart if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != 37557ad20aa9SJames Smart LPFC_SLI_INTF_IF_TYPE_2) { 37567ad20aa9SJames Smart rc = -ENODEV; 37577ad20aa9SJames Smart goto job_error; 37587ad20aa9SJames Smart } 37597ad20aa9SJames Smart /* nemb_tp == nemb_hbd */ 37607ad20aa9SJames Smart ext_buf_cnt = sli_cfg_mbx->un.sli_config_emb1_subsys.hbd_count; 37617ad20aa9SJames Smart if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_HBD) { 37627ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 37637ad20aa9SJames Smart "2946 Handled SLI_CONFIG(hbd) rd, " 37647ad20aa9SJames Smart "ext_buf_cnt(%d) out of range(%d)\n", 37657ad20aa9SJames Smart ext_buf_cnt, 37667ad20aa9SJames Smart LPFC_MBX_SLI_CONFIG_MAX_HBD); 37677ad20aa9SJames Smart rc = -ERANGE; 37687ad20aa9SJames Smart goto job_error; 37697ad20aa9SJames Smart } 37707ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 37717ad20aa9SJames Smart "2942 Handled SLI_CONFIG(hbd) rd, " 37727ad20aa9SJames Smart "ext_buf_cnt:%d\n", ext_buf_cnt); 37737ad20aa9SJames Smart } 37747ad20aa9SJames Smart 3775b76f2dc9SJames Smart /* before dma descriptor setup */ 3776b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_rd, dma_mbox, 3777b76f2dc9SJames Smart sta_pre_addr, dmabuf, ext_buf_cnt); 3778b76f2dc9SJames Smart 37797ad20aa9SJames Smart /* reject non-embedded mailbox command with none external buffer */ 37807ad20aa9SJames Smart if (ext_buf_cnt == 0) { 37817ad20aa9SJames Smart rc = -EPERM; 37827ad20aa9SJames Smart goto job_error; 37837ad20aa9SJames Smart } else if (ext_buf_cnt > 1) { 37847ad20aa9SJames Smart /* additional external read buffers */ 37857ad20aa9SJames Smart for (i = 1; i < ext_buf_cnt; i++) { 37867ad20aa9SJames Smart ext_dmabuf = lpfc_bsg_dma_page_alloc(phba); 37877ad20aa9SJames Smart if (!ext_dmabuf) { 37887ad20aa9SJames Smart rc = -ENOMEM; 37897ad20aa9SJames Smart goto job_error; 37907ad20aa9SJames Smart } 37917ad20aa9SJames Smart list_add_tail(&ext_dmabuf->list, 37927ad20aa9SJames Smart &phba->mbox_ext_buf_ctx.ext_dmabuf_list); 37937ad20aa9SJames Smart } 37947ad20aa9SJames Smart } 37957ad20aa9SJames Smart 37967ad20aa9SJames Smart /* bsg tracking structure */ 37977ad20aa9SJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 37987ad20aa9SJames Smart if (!dd_data) { 37997ad20aa9SJames Smart rc = -ENOMEM; 38007ad20aa9SJames Smart goto job_error; 38017ad20aa9SJames Smart } 38027ad20aa9SJames Smart 38037ad20aa9SJames Smart /* mailbox command structure for base driver */ 38047ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 38057ad20aa9SJames Smart if (!pmboxq) { 38067ad20aa9SJames Smart rc = -ENOMEM; 38077ad20aa9SJames Smart goto job_error; 38087ad20aa9SJames Smart } 38097ad20aa9SJames Smart memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 38107ad20aa9SJames Smart 38117ad20aa9SJames Smart /* for the first external buffer */ 38127ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 0, dmabuf, dmabuf); 38137ad20aa9SJames Smart 38147ad20aa9SJames Smart /* for the rest of external buffer descriptors if any */ 38157ad20aa9SJames Smart if (ext_buf_cnt > 1) { 38167ad20aa9SJames Smart ext_buf_index = 1; 38177ad20aa9SJames Smart list_for_each_entry_safe(curr_dmabuf, next_dmabuf, 38187ad20aa9SJames Smart &phba->mbox_ext_buf_ctx.ext_dmabuf_list, list) { 38197ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 38207ad20aa9SJames Smart ext_buf_index, dmabuf, 38217ad20aa9SJames Smart curr_dmabuf); 38227ad20aa9SJames Smart ext_buf_index++; 38237ad20aa9SJames Smart } 38247ad20aa9SJames Smart } 38257ad20aa9SJames Smart 3826b76f2dc9SJames Smart /* after dma descriptor setup */ 3827b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_rd, dma_mbox, 3828b76f2dc9SJames Smart sta_pos_addr, dmabuf, ext_buf_cnt); 3829b76f2dc9SJames Smart 38307ad20aa9SJames Smart /* construct base driver mbox command */ 38317ad20aa9SJames Smart pmb = &pmboxq->u.mb; 38327ad20aa9SJames Smart pmbx = (uint8_t *)dmabuf->virt; 38337ad20aa9SJames Smart memcpy(pmb, pmbx, sizeof(*pmb)); 38347ad20aa9SJames Smart pmb->mbxOwner = OWN_HOST; 38357ad20aa9SJames Smart pmboxq->vport = phba->pport; 38367ad20aa9SJames Smart 38377ad20aa9SJames Smart /* multi-buffer handling context */ 38387ad20aa9SJames Smart phba->mbox_ext_buf_ctx.nembType = nemb_tp; 38397ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType = mbox_rd; 38407ad20aa9SJames Smart phba->mbox_ext_buf_ctx.numBuf = ext_buf_cnt; 38417ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbxTag = mbox_req->extMboxTag; 38427ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum = mbox_req->extSeqNum; 38437ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf = dmabuf; 38447ad20aa9SJames Smart 38457ad20aa9SJames Smart /* callback for multi-buffer read mailbox command */ 38467ad20aa9SJames Smart pmboxq->mbox_cmpl = lpfc_bsg_issue_read_mbox_ext_cmpl; 38477ad20aa9SJames Smart 38487ad20aa9SJames Smart /* context fields to callback function */ 38497ad20aa9SJames Smart pmboxq->context1 = dd_data; 38507ad20aa9SJames Smart dd_data->type = TYPE_MBOX; 3851*a33c4f7bSJames Smart dd_data->set_job = job; 38527ad20aa9SJames Smart dd_data->context_un.mbox.pmboxq = pmboxq; 38537ad20aa9SJames Smart dd_data->context_un.mbox.mb = (MAILBOX_t *)pmbx; 38547ad20aa9SJames Smart job->dd_data = dd_data; 38557ad20aa9SJames Smart 38567ad20aa9SJames Smart /* state change */ 38577ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT; 38587ad20aa9SJames Smart 3859026abb87SJames Smart /* 3860026abb87SJames Smart * Non-embedded mailbox subcommand data gets byte swapped here because 3861026abb87SJames Smart * the lower level driver code only does the first 64 mailbox words. 3862026abb87SJames Smart */ 3863026abb87SJames Smart if ((!bsg_bf_get(lpfc_mbox_hdr_emb, 3864026abb87SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) && 3865026abb87SJames Smart (nemb_tp == nemb_mse)) 3866026abb87SJames Smart lpfc_sli_pcimem_bcopy(&pmbx[sizeof(MAILBOX_t)], 3867026abb87SJames Smart &pmbx[sizeof(MAILBOX_t)], 3868026abb87SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 3869026abb87SJames Smart mse[0].buf_len); 3870026abb87SJames Smart 38717ad20aa9SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); 38727ad20aa9SJames Smart if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { 38737ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 38747ad20aa9SJames Smart "2947 Issued SLI_CONFIG ext-buffer " 38757ad20aa9SJames Smart "maibox command, rc:x%x\n", rc); 387688a2cfbbSJames Smart return SLI_CONFIG_HANDLED; 38777ad20aa9SJames Smart } 38787ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 38797ad20aa9SJames Smart "2948 Failed to issue SLI_CONFIG ext-buffer " 38807ad20aa9SJames Smart "maibox command, rc:x%x\n", rc); 38817ad20aa9SJames Smart rc = -EPIPE; 38827ad20aa9SJames Smart 38837ad20aa9SJames Smart job_error: 38847ad20aa9SJames Smart if (pmboxq) 38857ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 38867ad20aa9SJames Smart lpfc_bsg_dma_page_list_free(phba, 38877ad20aa9SJames Smart &phba->mbox_ext_buf_ctx.ext_dmabuf_list); 38887ad20aa9SJames Smart kfree(dd_data); 38897ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_IDLE; 38907ad20aa9SJames Smart return rc; 38917ad20aa9SJames Smart } 38927ad20aa9SJames Smart 38937ad20aa9SJames Smart /** 38947ad20aa9SJames Smart * lpfc_bsg_sli_cfg_write_cmd_ext - sli_config non-embedded mailbox cmd write 38957ad20aa9SJames Smart * @phba: Pointer to HBA context object. 38967ad20aa9SJames Smart * @mb: Pointer to a BSG mailbox object. 38977ad20aa9SJames Smart * @dmabuff: Pointer to a DMA buffer descriptor. 38987ad20aa9SJames Smart * 38997ad20aa9SJames Smart * This routine performs SLI_CONFIG (0x9B) write mailbox command operation with 39007ad20aa9SJames Smart * non-embedded external bufffers. 39017ad20aa9SJames Smart **/ 39027ad20aa9SJames Smart static int 39037ad20aa9SJames Smart lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job, 39047ad20aa9SJames Smart enum nemb_type nemb_tp, 39057ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 39067ad20aa9SJames Smart { 39077ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 39087ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 39097ad20aa9SJames Smart uint32_t ext_buf_cnt; 39107ad20aa9SJames Smart struct bsg_job_data *dd_data = NULL; 39117ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq = NULL; 39127ad20aa9SJames Smart MAILBOX_t *pmb; 39137ad20aa9SJames Smart uint8_t *mbx; 391488a2cfbbSJames Smart int rc = SLI_CONFIG_NOT_HANDLED, i; 39157ad20aa9SJames Smart 39167ad20aa9SJames Smart mbox_req = 39177ad20aa9SJames Smart (struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd; 39187ad20aa9SJames Smart 39197ad20aa9SJames Smart /* pointer to the start of mailbox command */ 39207ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; 39217ad20aa9SJames Smart 39227ad20aa9SJames Smart if (nemb_tp == nemb_mse) { 39237ad20aa9SJames Smart ext_buf_cnt = bsg_bf_get(lpfc_mbox_hdr_mse_cnt, 39247ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr); 39257ad20aa9SJames Smart if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_MSE) { 39267ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 3927026abb87SJames Smart "2953 Failed SLI_CONFIG(mse) wr, " 39287ad20aa9SJames Smart "ext_buf_cnt(%d) out of range(%d)\n", 39297ad20aa9SJames Smart ext_buf_cnt, 39307ad20aa9SJames Smart LPFC_MBX_SLI_CONFIG_MAX_MSE); 39317ad20aa9SJames Smart return -ERANGE; 39327ad20aa9SJames Smart } 39337ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 39347ad20aa9SJames Smart "2949 Handled SLI_CONFIG(mse) wr, " 39357ad20aa9SJames Smart "ext_buf_cnt:%d\n", ext_buf_cnt); 39367ad20aa9SJames Smart } else { 39377ad20aa9SJames Smart /* sanity check on interface type for support */ 39387ad20aa9SJames Smart if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != 39397ad20aa9SJames Smart LPFC_SLI_INTF_IF_TYPE_2) 39407ad20aa9SJames Smart return -ENODEV; 39417ad20aa9SJames Smart /* nemb_tp == nemb_hbd */ 39427ad20aa9SJames Smart ext_buf_cnt = sli_cfg_mbx->un.sli_config_emb1_subsys.hbd_count; 39437ad20aa9SJames Smart if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_HBD) { 39447ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 3945026abb87SJames Smart "2954 Failed SLI_CONFIG(hbd) wr, " 39467ad20aa9SJames Smart "ext_buf_cnt(%d) out of range(%d)\n", 39477ad20aa9SJames Smart ext_buf_cnt, 39487ad20aa9SJames Smart LPFC_MBX_SLI_CONFIG_MAX_HBD); 39497ad20aa9SJames Smart return -ERANGE; 39507ad20aa9SJames Smart } 39517ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 39527ad20aa9SJames Smart "2950 Handled SLI_CONFIG(hbd) wr, " 39537ad20aa9SJames Smart "ext_buf_cnt:%d\n", ext_buf_cnt); 39547ad20aa9SJames Smart } 39557ad20aa9SJames Smart 3956b76f2dc9SJames Smart /* before dma buffer descriptor setup */ 3957b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_wr, dma_mbox, 3958b76f2dc9SJames Smart sta_pre_addr, dmabuf, ext_buf_cnt); 3959b76f2dc9SJames Smart 39607ad20aa9SJames Smart if (ext_buf_cnt == 0) 39617ad20aa9SJames Smart return -EPERM; 39627ad20aa9SJames Smart 39637ad20aa9SJames Smart /* for the first external buffer */ 39647ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 0, dmabuf, dmabuf); 39657ad20aa9SJames Smart 3966b76f2dc9SJames Smart /* after dma descriptor setup */ 3967b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_wr, dma_mbox, 3968b76f2dc9SJames Smart sta_pos_addr, dmabuf, ext_buf_cnt); 3969b76f2dc9SJames Smart 39707ad20aa9SJames Smart /* log for looking forward */ 39717ad20aa9SJames Smart for (i = 1; i < ext_buf_cnt; i++) { 39727ad20aa9SJames Smart if (nemb_tp == nemb_mse) 39737ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 39747ad20aa9SJames Smart "2951 SLI_CONFIG(mse), buf[%d]-length:%d\n", 39757ad20aa9SJames Smart i, sli_cfg_mbx->un.sli_config_emb0_subsys. 39767ad20aa9SJames Smart mse[i].buf_len); 39777ad20aa9SJames Smart else 39787ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 39797ad20aa9SJames Smart "2952 SLI_CONFIG(hbd), buf[%d]-length:%d\n", 39807ad20aa9SJames Smart i, bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, 39817ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb1_subsys. 39827ad20aa9SJames Smart hbd[i])); 39837ad20aa9SJames Smart } 39847ad20aa9SJames Smart 39857ad20aa9SJames Smart /* multi-buffer handling context */ 39867ad20aa9SJames Smart phba->mbox_ext_buf_ctx.nembType = nemb_tp; 39877ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType = mbox_wr; 39887ad20aa9SJames Smart phba->mbox_ext_buf_ctx.numBuf = ext_buf_cnt; 39897ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbxTag = mbox_req->extMboxTag; 39907ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum = mbox_req->extSeqNum; 39917ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf = dmabuf; 39927ad20aa9SJames Smart 39937ad20aa9SJames Smart if (ext_buf_cnt == 1) { 39947ad20aa9SJames Smart /* bsg tracking structure */ 39957ad20aa9SJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 39967ad20aa9SJames Smart if (!dd_data) { 39977ad20aa9SJames Smart rc = -ENOMEM; 39987ad20aa9SJames Smart goto job_error; 39997ad20aa9SJames Smart } 40007ad20aa9SJames Smart 40017ad20aa9SJames Smart /* mailbox command structure for base driver */ 40027ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 40037ad20aa9SJames Smart if (!pmboxq) { 40047ad20aa9SJames Smart rc = -ENOMEM; 40057ad20aa9SJames Smart goto job_error; 40067ad20aa9SJames Smart } 40077ad20aa9SJames Smart memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 40087ad20aa9SJames Smart pmb = &pmboxq->u.mb; 40097ad20aa9SJames Smart mbx = (uint8_t *)dmabuf->virt; 40107ad20aa9SJames Smart memcpy(pmb, mbx, sizeof(*pmb)); 40117ad20aa9SJames Smart pmb->mbxOwner = OWN_HOST; 40127ad20aa9SJames Smart pmboxq->vport = phba->pport; 40137ad20aa9SJames Smart 40147ad20aa9SJames Smart /* callback for multi-buffer read mailbox command */ 40157ad20aa9SJames Smart pmboxq->mbox_cmpl = lpfc_bsg_issue_write_mbox_ext_cmpl; 40167ad20aa9SJames Smart 40177ad20aa9SJames Smart /* context fields to callback function */ 40187ad20aa9SJames Smart pmboxq->context1 = dd_data; 40197ad20aa9SJames Smart dd_data->type = TYPE_MBOX; 4020*a33c4f7bSJames Smart dd_data->set_job = job; 40217ad20aa9SJames Smart dd_data->context_un.mbox.pmboxq = pmboxq; 40227ad20aa9SJames Smart dd_data->context_un.mbox.mb = (MAILBOX_t *)mbx; 40237ad20aa9SJames Smart job->dd_data = dd_data; 40247ad20aa9SJames Smart 40257ad20aa9SJames Smart /* state change */ 40267ad20aa9SJames Smart 4027*a33c4f7bSJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT; 40287ad20aa9SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); 40297ad20aa9SJames Smart if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { 40307ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 40317ad20aa9SJames Smart "2955 Issued SLI_CONFIG ext-buffer " 40327ad20aa9SJames Smart "maibox command, rc:x%x\n", rc); 403388a2cfbbSJames Smart return SLI_CONFIG_HANDLED; 40347ad20aa9SJames Smart } 40357ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 40367ad20aa9SJames Smart "2956 Failed to issue SLI_CONFIG ext-buffer " 40377ad20aa9SJames Smart "maibox command, rc:x%x\n", rc); 40387ad20aa9SJames Smart rc = -EPIPE; 4039026abb87SJames Smart goto job_error; 40407ad20aa9SJames Smart } 40417ad20aa9SJames Smart 404288a2cfbbSJames Smart /* wait for additoinal external buffers */ 4043*a33c4f7bSJames Smart 404488a2cfbbSJames Smart job->reply->result = 0; 404588a2cfbbSJames Smart job->job_done(job); 404688a2cfbbSJames Smart return SLI_CONFIG_HANDLED; 404788a2cfbbSJames Smart 40487ad20aa9SJames Smart job_error: 40497ad20aa9SJames Smart if (pmboxq) 40507ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 40517ad20aa9SJames Smart kfree(dd_data); 40527ad20aa9SJames Smart 40537ad20aa9SJames Smart return rc; 40547ad20aa9SJames Smart } 40557ad20aa9SJames Smart 40567ad20aa9SJames Smart /** 40577ad20aa9SJames Smart * lpfc_bsg_handle_sli_cfg_mbox - handle sli-cfg mailbox cmd with ext buffer 40587ad20aa9SJames Smart * @phba: Pointer to HBA context object. 40597ad20aa9SJames Smart * @mb: Pointer to a BSG mailbox object. 40607ad20aa9SJames Smart * @dmabuff: Pointer to a DMA buffer descriptor. 40617ad20aa9SJames Smart * 40627ad20aa9SJames Smart * This routine handles SLI_CONFIG (0x9B) mailbox command with non-embedded 40637ad20aa9SJames Smart * external bufffers, including both 0x9B with non-embedded MSEs and 0x9B 40647ad20aa9SJames Smart * with embedded sussystem 0x1 and opcodes with external HBDs. 40657ad20aa9SJames Smart **/ 40667ad20aa9SJames Smart static int 40677ad20aa9SJames Smart lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, 40687ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 40697ad20aa9SJames Smart { 40707ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 40717ad20aa9SJames Smart uint32_t subsys; 40727ad20aa9SJames Smart uint32_t opcode; 40737ad20aa9SJames Smart int rc = SLI_CONFIG_NOT_HANDLED; 40747ad20aa9SJames Smart 4075026abb87SJames Smart /* state change on new multi-buffer pass-through mailbox command */ 40767ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_HOST; 40777ad20aa9SJames Smart 40787ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; 40797ad20aa9SJames Smart 40807ad20aa9SJames Smart if (!bsg_bf_get(lpfc_mbox_hdr_emb, 40817ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) { 40827ad20aa9SJames Smart subsys = bsg_bf_get(lpfc_emb0_subcmnd_subsys, 40837ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys); 40847ad20aa9SJames Smart opcode = bsg_bf_get(lpfc_emb0_subcmnd_opcode, 40857ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys); 40867ad20aa9SJames Smart if (subsys == SLI_CONFIG_SUBSYS_FCOE) { 40877ad20aa9SJames Smart switch (opcode) { 40887ad20aa9SJames Smart case FCOE_OPCODE_READ_FCF: 40897ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 40907ad20aa9SJames Smart "2957 Handled SLI_CONFIG " 40917ad20aa9SJames Smart "subsys_fcoe, opcode:x%x\n", 40927ad20aa9SJames Smart opcode); 40937ad20aa9SJames Smart rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job, 40947ad20aa9SJames Smart nemb_mse, dmabuf); 40957ad20aa9SJames Smart break; 40967ad20aa9SJames Smart case FCOE_OPCODE_ADD_FCF: 40977ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 40987ad20aa9SJames Smart "2958 Handled SLI_CONFIG " 40997ad20aa9SJames Smart "subsys_fcoe, opcode:x%x\n", 41007ad20aa9SJames Smart opcode); 41017ad20aa9SJames Smart rc = lpfc_bsg_sli_cfg_write_cmd_ext(phba, job, 41027ad20aa9SJames Smart nemb_mse, dmabuf); 41037ad20aa9SJames Smart break; 41047ad20aa9SJames Smart default: 41057ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4106026abb87SJames Smart "2959 Reject SLI_CONFIG " 41077ad20aa9SJames Smart "subsys_fcoe, opcode:x%x\n", 41087ad20aa9SJames Smart opcode); 4109026abb87SJames Smart rc = -EPERM; 4110026abb87SJames Smart break; 4111026abb87SJames Smart } 4112026abb87SJames Smart } else if (subsys == SLI_CONFIG_SUBSYS_COMN) { 4113026abb87SJames Smart switch (opcode) { 4114026abb87SJames Smart case COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES: 4115b99570ddSJames Smart case COMN_OPCODE_GET_CNTL_ATTRIBUTES: 4116026abb87SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4117026abb87SJames Smart "3106 Handled SLI_CONFIG " 41186b5151fdSJames Smart "subsys_comn, opcode:x%x\n", 4119026abb87SJames Smart opcode); 4120026abb87SJames Smart rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job, 4121026abb87SJames Smart nemb_mse, dmabuf); 4122026abb87SJames Smart break; 4123026abb87SJames Smart default: 4124026abb87SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4125026abb87SJames Smart "3107 Reject SLI_CONFIG " 41266b5151fdSJames Smart "subsys_comn, opcode:x%x\n", 4127026abb87SJames Smart opcode); 4128026abb87SJames Smart rc = -EPERM; 41297ad20aa9SJames Smart break; 41307ad20aa9SJames Smart } 41317ad20aa9SJames Smart } else { 41327ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4133026abb87SJames Smart "2977 Reject SLI_CONFIG " 41347ad20aa9SJames Smart "subsys:x%d, opcode:x%x\n", 41357ad20aa9SJames Smart subsys, opcode); 4136026abb87SJames Smart rc = -EPERM; 41377ad20aa9SJames Smart } 41387ad20aa9SJames Smart } else { 41397ad20aa9SJames Smart subsys = bsg_bf_get(lpfc_emb1_subcmnd_subsys, 41407ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb1_subsys); 41417ad20aa9SJames Smart opcode = bsg_bf_get(lpfc_emb1_subcmnd_opcode, 41427ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb1_subsys); 41437ad20aa9SJames Smart if (subsys == SLI_CONFIG_SUBSYS_COMN) { 41447ad20aa9SJames Smart switch (opcode) { 41457ad20aa9SJames Smart case COMN_OPCODE_READ_OBJECT: 41467ad20aa9SJames Smart case COMN_OPCODE_READ_OBJECT_LIST: 41477ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 41487ad20aa9SJames Smart "2960 Handled SLI_CONFIG " 41497ad20aa9SJames Smart "subsys_comn, opcode:x%x\n", 41507ad20aa9SJames Smart opcode); 41517ad20aa9SJames Smart rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job, 41527ad20aa9SJames Smart nemb_hbd, dmabuf); 41537ad20aa9SJames Smart break; 41547ad20aa9SJames Smart case COMN_OPCODE_WRITE_OBJECT: 41557ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 41567ad20aa9SJames Smart "2961 Handled SLI_CONFIG " 41577ad20aa9SJames Smart "subsys_comn, opcode:x%x\n", 41587ad20aa9SJames Smart opcode); 41597ad20aa9SJames Smart rc = lpfc_bsg_sli_cfg_write_cmd_ext(phba, job, 41607ad20aa9SJames Smart nemb_hbd, dmabuf); 41617ad20aa9SJames Smart break; 41627ad20aa9SJames Smart default: 41637ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 41647ad20aa9SJames Smart "2962 Not handled SLI_CONFIG " 41657ad20aa9SJames Smart "subsys_comn, opcode:x%x\n", 41667ad20aa9SJames Smart opcode); 41677ad20aa9SJames Smart rc = SLI_CONFIG_NOT_HANDLED; 41687ad20aa9SJames Smart break; 41697ad20aa9SJames Smart } 41707ad20aa9SJames Smart } else { 41717ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4172026abb87SJames Smart "2978 Not handled SLI_CONFIG " 41737ad20aa9SJames Smart "subsys:x%d, opcode:x%x\n", 41747ad20aa9SJames Smart subsys, opcode); 41757ad20aa9SJames Smart rc = SLI_CONFIG_NOT_HANDLED; 41767ad20aa9SJames Smart } 41777ad20aa9SJames Smart } 4178026abb87SJames Smart 4179026abb87SJames Smart /* state reset on not handled new multi-buffer mailbox command */ 4180026abb87SJames Smart if (rc != SLI_CONFIG_HANDLED) 4181026abb87SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_IDLE; 4182026abb87SJames Smart 41837ad20aa9SJames Smart return rc; 41847ad20aa9SJames Smart } 41857ad20aa9SJames Smart 41867ad20aa9SJames Smart /** 41877ad20aa9SJames Smart * lpfc_bsg_mbox_ext_abort_req - request to abort mbox command with ext buffers 41887ad20aa9SJames Smart * @phba: Pointer to HBA context object. 41897ad20aa9SJames Smart * 41907ad20aa9SJames Smart * This routine is for requesting to abort a pass-through mailbox command with 41917ad20aa9SJames Smart * multiple external buffers due to error condition. 41927ad20aa9SJames Smart **/ 41937ad20aa9SJames Smart static void 41947ad20aa9SJames Smart lpfc_bsg_mbox_ext_abort(struct lpfc_hba *phba) 41957ad20aa9SJames Smart { 41967ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_PORT) 41977ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_ABTS; 41987ad20aa9SJames Smart else 41997ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 42007ad20aa9SJames Smart return; 42017ad20aa9SJames Smart } 42027ad20aa9SJames Smart 42037ad20aa9SJames Smart /** 42047ad20aa9SJames Smart * lpfc_bsg_read_ebuf_get - get the next mailbox read external buffer 42057ad20aa9SJames Smart * @phba: Pointer to HBA context object. 42067ad20aa9SJames Smart * @dmabuf: Pointer to a DMA buffer descriptor. 42077ad20aa9SJames Smart * 42087ad20aa9SJames Smart * This routine extracts the next mailbox read external buffer back to 42097ad20aa9SJames Smart * user space through BSG. 42107ad20aa9SJames Smart **/ 42117ad20aa9SJames Smart static int 42127ad20aa9SJames Smart lpfc_bsg_read_ebuf_get(struct lpfc_hba *phba, struct fc_bsg_job *job) 42137ad20aa9SJames Smart { 42147ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 42157ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf; 42167ad20aa9SJames Smart uint8_t *pbuf; 42177ad20aa9SJames Smart uint32_t size; 42187ad20aa9SJames Smart uint32_t index; 42197ad20aa9SJames Smart 42207ad20aa9SJames Smart index = phba->mbox_ext_buf_ctx.seqNum; 42217ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum++; 42227ad20aa9SJames Smart 42237ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *) 42247ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf->virt; 42257ad20aa9SJames Smart 42267ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.nembType == nemb_mse) { 42277ad20aa9SJames Smart size = bsg_bf_get(lpfc_mbox_sli_config_mse_len, 42287ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.mse[index]); 42297ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 42307ad20aa9SJames Smart "2963 SLI_CONFIG (mse) ext-buffer rd get " 42317ad20aa9SJames Smart "buffer[%d], size:%d\n", index, size); 42327ad20aa9SJames Smart } else { 42337ad20aa9SJames Smart size = bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, 42347ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb1_subsys.hbd[index]); 42357ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 42367ad20aa9SJames Smart "2964 SLI_CONFIG (hbd) ext-buffer rd get " 42377ad20aa9SJames Smart "buffer[%d], size:%d\n", index, size); 42387ad20aa9SJames Smart } 42397ad20aa9SJames Smart if (list_empty(&phba->mbox_ext_buf_ctx.ext_dmabuf_list)) 42407ad20aa9SJames Smart return -EPIPE; 42417ad20aa9SJames Smart dmabuf = list_first_entry(&phba->mbox_ext_buf_ctx.ext_dmabuf_list, 42427ad20aa9SJames Smart struct lpfc_dmabuf, list); 42437ad20aa9SJames Smart list_del_init(&dmabuf->list); 4244b76f2dc9SJames Smart 4245b76f2dc9SJames Smart /* after dma buffer descriptor setup */ 4246b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, phba->mbox_ext_buf_ctx.nembType, 4247b76f2dc9SJames Smart mbox_rd, dma_ebuf, sta_pos_addr, 4248b76f2dc9SJames Smart dmabuf, index); 4249b76f2dc9SJames Smart 42507ad20aa9SJames Smart pbuf = (uint8_t *)dmabuf->virt; 42517ad20aa9SJames Smart job->reply->reply_payload_rcv_len = 42527ad20aa9SJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 42537ad20aa9SJames Smart job->reply_payload.sg_cnt, 42547ad20aa9SJames Smart pbuf, size); 42557ad20aa9SJames Smart 42567ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 42577ad20aa9SJames Smart 42587ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.seqNum == phba->mbox_ext_buf_ctx.numBuf) { 42597ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 42607ad20aa9SJames Smart "2965 SLI_CONFIG (hbd) ext-buffer rd mbox " 42617ad20aa9SJames Smart "command session done\n"); 42627ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 42637ad20aa9SJames Smart } 42647ad20aa9SJames Smart 42657ad20aa9SJames Smart job->reply->result = 0; 42667ad20aa9SJames Smart job->job_done(job); 42677ad20aa9SJames Smart 42687ad20aa9SJames Smart return SLI_CONFIG_HANDLED; 42697ad20aa9SJames Smart } 42707ad20aa9SJames Smart 42717ad20aa9SJames Smart /** 42727ad20aa9SJames Smart * lpfc_bsg_write_ebuf_set - set the next mailbox write external buffer 42737ad20aa9SJames Smart * @phba: Pointer to HBA context object. 42747ad20aa9SJames Smart * @dmabuf: Pointer to a DMA buffer descriptor. 42757ad20aa9SJames Smart * 42767ad20aa9SJames Smart * This routine sets up the next mailbox read external buffer obtained 42777ad20aa9SJames Smart * from user space through BSG. 42787ad20aa9SJames Smart **/ 42797ad20aa9SJames Smart static int 42807ad20aa9SJames Smart lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct fc_bsg_job *job, 42817ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 42827ad20aa9SJames Smart { 42837ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 42847ad20aa9SJames Smart struct bsg_job_data *dd_data = NULL; 42857ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq = NULL; 42867ad20aa9SJames Smart MAILBOX_t *pmb; 42877ad20aa9SJames Smart enum nemb_type nemb_tp; 42887ad20aa9SJames Smart uint8_t *pbuf; 42897ad20aa9SJames Smart uint32_t size; 42907ad20aa9SJames Smart uint32_t index; 42917ad20aa9SJames Smart int rc; 42927ad20aa9SJames Smart 42937ad20aa9SJames Smart index = phba->mbox_ext_buf_ctx.seqNum; 42947ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum++; 42957ad20aa9SJames Smart nemb_tp = phba->mbox_ext_buf_ctx.nembType; 42967ad20aa9SJames Smart 42977ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *) 42987ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf->virt; 42997ad20aa9SJames Smart 43007ad20aa9SJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 43017ad20aa9SJames Smart if (!dd_data) { 43027ad20aa9SJames Smart rc = -ENOMEM; 43037ad20aa9SJames Smart goto job_error; 43047ad20aa9SJames Smart } 43057ad20aa9SJames Smart 43067ad20aa9SJames Smart pbuf = (uint8_t *)dmabuf->virt; 43077ad20aa9SJames Smart size = job->request_payload.payload_len; 43087ad20aa9SJames Smart sg_copy_to_buffer(job->request_payload.sg_list, 43097ad20aa9SJames Smart job->request_payload.sg_cnt, 43107ad20aa9SJames Smart pbuf, size); 43117ad20aa9SJames Smart 43127ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.nembType == nemb_mse) { 43137ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 43147ad20aa9SJames Smart "2966 SLI_CONFIG (mse) ext-buffer wr set " 43157ad20aa9SJames Smart "buffer[%d], size:%d\n", 43167ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum, size); 43177ad20aa9SJames Smart 43187ad20aa9SJames Smart } else { 43197ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 43207ad20aa9SJames Smart "2967 SLI_CONFIG (hbd) ext-buffer wr set " 43217ad20aa9SJames Smart "buffer[%d], size:%d\n", 43227ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum, size); 43237ad20aa9SJames Smart 43247ad20aa9SJames Smart } 43257ad20aa9SJames Smart 43267ad20aa9SJames Smart /* set up external buffer descriptor and add to external buffer list */ 43277ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, index, 43287ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf, 43297ad20aa9SJames Smart dmabuf); 43307ad20aa9SJames Smart list_add_tail(&dmabuf->list, &phba->mbox_ext_buf_ctx.ext_dmabuf_list); 43317ad20aa9SJames Smart 4332b76f2dc9SJames Smart /* after write dma buffer */ 4333b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, phba->mbox_ext_buf_ctx.nembType, 4334b76f2dc9SJames Smart mbox_wr, dma_ebuf, sta_pos_addr, 4335b76f2dc9SJames Smart dmabuf, index); 4336b76f2dc9SJames Smart 43377ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.seqNum == phba->mbox_ext_buf_ctx.numBuf) { 43387ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 43397ad20aa9SJames Smart "2968 SLI_CONFIG ext-buffer wr all %d " 43407ad20aa9SJames Smart "ebuffers received\n", 43417ad20aa9SJames Smart phba->mbox_ext_buf_ctx.numBuf); 43427ad20aa9SJames Smart /* mailbox command structure for base driver */ 43437ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 43447ad20aa9SJames Smart if (!pmboxq) { 43457ad20aa9SJames Smart rc = -ENOMEM; 43467ad20aa9SJames Smart goto job_error; 43477ad20aa9SJames Smart } 43487ad20aa9SJames Smart memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 43497ad20aa9SJames Smart pbuf = (uint8_t *)phba->mbox_ext_buf_ctx.mbx_dmabuf->virt; 43507ad20aa9SJames Smart pmb = &pmboxq->u.mb; 43517ad20aa9SJames Smart memcpy(pmb, pbuf, sizeof(*pmb)); 43527ad20aa9SJames Smart pmb->mbxOwner = OWN_HOST; 43537ad20aa9SJames Smart pmboxq->vport = phba->pport; 43547ad20aa9SJames Smart 43557ad20aa9SJames Smart /* callback for multi-buffer write mailbox command */ 43567ad20aa9SJames Smart pmboxq->mbox_cmpl = lpfc_bsg_issue_write_mbox_ext_cmpl; 43577ad20aa9SJames Smart 43587ad20aa9SJames Smart /* context fields to callback function */ 43597ad20aa9SJames Smart pmboxq->context1 = dd_data; 43607ad20aa9SJames Smart dd_data->type = TYPE_MBOX; 4361*a33c4f7bSJames Smart dd_data->set_job = job; 43627ad20aa9SJames Smart dd_data->context_un.mbox.pmboxq = pmboxq; 43637ad20aa9SJames Smart dd_data->context_un.mbox.mb = (MAILBOX_t *)pbuf; 43647ad20aa9SJames Smart job->dd_data = dd_data; 43657ad20aa9SJames Smart 43667ad20aa9SJames Smart /* state change */ 43677ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT; 43687ad20aa9SJames Smart 43697ad20aa9SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); 43707ad20aa9SJames Smart if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { 43717ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 43727ad20aa9SJames Smart "2969 Issued SLI_CONFIG ext-buffer " 43737ad20aa9SJames Smart "maibox command, rc:x%x\n", rc); 437488a2cfbbSJames Smart return SLI_CONFIG_HANDLED; 43757ad20aa9SJames Smart } 43767ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 43777ad20aa9SJames Smart "2970 Failed to issue SLI_CONFIG ext-buffer " 43787ad20aa9SJames Smart "maibox command, rc:x%x\n", rc); 43797ad20aa9SJames Smart rc = -EPIPE; 43807ad20aa9SJames Smart goto job_error; 43817ad20aa9SJames Smart } 43827ad20aa9SJames Smart 43837ad20aa9SJames Smart /* wait for additoinal external buffers */ 43847ad20aa9SJames Smart job->reply->result = 0; 43857ad20aa9SJames Smart job->job_done(job); 43867ad20aa9SJames Smart return SLI_CONFIG_HANDLED; 43877ad20aa9SJames Smart 43887ad20aa9SJames Smart job_error: 43897ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 43907ad20aa9SJames Smart kfree(dd_data); 43917ad20aa9SJames Smart 43927ad20aa9SJames Smart return rc; 43937ad20aa9SJames Smart } 43947ad20aa9SJames Smart 43957ad20aa9SJames Smart /** 43967ad20aa9SJames Smart * lpfc_bsg_handle_sli_cfg_ebuf - handle ext buffer with sli-cfg mailbox cmd 43977ad20aa9SJames Smart * @phba: Pointer to HBA context object. 43987ad20aa9SJames Smart * @mb: Pointer to a BSG mailbox object. 43997ad20aa9SJames Smart * @dmabuff: Pointer to a DMA buffer descriptor. 44007ad20aa9SJames Smart * 44017ad20aa9SJames Smart * This routine handles the external buffer with SLI_CONFIG (0x9B) mailbox 44027ad20aa9SJames Smart * command with multiple non-embedded external buffers. 44037ad20aa9SJames Smart **/ 44047ad20aa9SJames Smart static int 44057ad20aa9SJames Smart lpfc_bsg_handle_sli_cfg_ebuf(struct lpfc_hba *phba, struct fc_bsg_job *job, 44067ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 44077ad20aa9SJames Smart { 44087ad20aa9SJames Smart int rc; 44097ad20aa9SJames Smart 44107ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 44117ad20aa9SJames Smart "2971 SLI_CONFIG buffer (type:x%x)\n", 44127ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType); 44137ad20aa9SJames Smart 44147ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.mboxType == mbox_rd) { 44157ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state != LPFC_BSG_MBOX_DONE) { 44167ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 44177ad20aa9SJames Smart "2972 SLI_CONFIG rd buffer state " 44187ad20aa9SJames Smart "mismatch:x%x\n", 44197ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state); 44207ad20aa9SJames Smart lpfc_bsg_mbox_ext_abort(phba); 44217ad20aa9SJames Smart return -EPIPE; 44227ad20aa9SJames Smart } 44237ad20aa9SJames Smart rc = lpfc_bsg_read_ebuf_get(phba, job); 44247ad20aa9SJames Smart if (rc == SLI_CONFIG_HANDLED) 44257ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 44267ad20aa9SJames Smart } else { /* phba->mbox_ext_buf_ctx.mboxType == mbox_wr */ 44277ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state != LPFC_BSG_MBOX_HOST) { 44287ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 44297ad20aa9SJames Smart "2973 SLI_CONFIG wr buffer state " 44307ad20aa9SJames Smart "mismatch:x%x\n", 44317ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state); 44327ad20aa9SJames Smart lpfc_bsg_mbox_ext_abort(phba); 44337ad20aa9SJames Smart return -EPIPE; 44347ad20aa9SJames Smart } 44357ad20aa9SJames Smart rc = lpfc_bsg_write_ebuf_set(phba, job, dmabuf); 44367ad20aa9SJames Smart } 44377ad20aa9SJames Smart return rc; 44387ad20aa9SJames Smart } 44397ad20aa9SJames Smart 44407ad20aa9SJames Smart /** 44417ad20aa9SJames Smart * lpfc_bsg_handle_sli_cfg_ext - handle sli-cfg mailbox with external buffer 44427ad20aa9SJames Smart * @phba: Pointer to HBA context object. 44437ad20aa9SJames Smart * @mb: Pointer to a BSG mailbox object. 44447ad20aa9SJames Smart * @dmabuff: Pointer to a DMA buffer descriptor. 44457ad20aa9SJames Smart * 44467ad20aa9SJames Smart * This routine checkes and handles non-embedded multi-buffer SLI_CONFIG 44477ad20aa9SJames Smart * (0x9B) mailbox commands and external buffers. 44487ad20aa9SJames Smart **/ 44497ad20aa9SJames Smart static int 44507ad20aa9SJames Smart lpfc_bsg_handle_sli_cfg_ext(struct lpfc_hba *phba, struct fc_bsg_job *job, 44517ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 44527ad20aa9SJames Smart { 44537ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 445488a2cfbbSJames Smart int rc = SLI_CONFIG_NOT_HANDLED; 44557ad20aa9SJames Smart 44567ad20aa9SJames Smart mbox_req = 44577ad20aa9SJames Smart (struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd; 44587ad20aa9SJames Smart 44597ad20aa9SJames Smart /* mbox command with/without single external buffer */ 44607ad20aa9SJames Smart if (mbox_req->extMboxTag == 0 && mbox_req->extSeqNum == 0) 446188a2cfbbSJames Smart return rc; 44627ad20aa9SJames Smart 44637ad20aa9SJames Smart /* mbox command and first external buffer */ 44647ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_IDLE) { 44657ad20aa9SJames Smart if (mbox_req->extSeqNum == 1) { 44667ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 44677ad20aa9SJames Smart "2974 SLI_CONFIG mailbox: tag:%d, " 44687ad20aa9SJames Smart "seq:%d\n", mbox_req->extMboxTag, 44697ad20aa9SJames Smart mbox_req->extSeqNum); 44707ad20aa9SJames Smart rc = lpfc_bsg_handle_sli_cfg_mbox(phba, job, dmabuf); 44717ad20aa9SJames Smart return rc; 44727ad20aa9SJames Smart } else 44737ad20aa9SJames Smart goto sli_cfg_ext_error; 44747ad20aa9SJames Smart } 44757ad20aa9SJames Smart 44767ad20aa9SJames Smart /* 44777ad20aa9SJames Smart * handle additional external buffers 44787ad20aa9SJames Smart */ 44797ad20aa9SJames Smart 44807ad20aa9SJames Smart /* check broken pipe conditions */ 44817ad20aa9SJames Smart if (mbox_req->extMboxTag != phba->mbox_ext_buf_ctx.mbxTag) 44827ad20aa9SJames Smart goto sli_cfg_ext_error; 44837ad20aa9SJames Smart if (mbox_req->extSeqNum > phba->mbox_ext_buf_ctx.numBuf) 44847ad20aa9SJames Smart goto sli_cfg_ext_error; 44857ad20aa9SJames Smart if (mbox_req->extSeqNum != phba->mbox_ext_buf_ctx.seqNum + 1) 44867ad20aa9SJames Smart goto sli_cfg_ext_error; 44877ad20aa9SJames Smart 44887ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 44897ad20aa9SJames Smart "2975 SLI_CONFIG mailbox external buffer: " 44907ad20aa9SJames Smart "extSta:x%x, tag:%d, seq:%d\n", 44917ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state, mbox_req->extMboxTag, 44927ad20aa9SJames Smart mbox_req->extSeqNum); 44937ad20aa9SJames Smart rc = lpfc_bsg_handle_sli_cfg_ebuf(phba, job, dmabuf); 44947ad20aa9SJames Smart return rc; 44957ad20aa9SJames Smart 44967ad20aa9SJames Smart sli_cfg_ext_error: 44977ad20aa9SJames Smart /* all other cases, broken pipe */ 44987ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 44997ad20aa9SJames Smart "2976 SLI_CONFIG mailbox broken pipe: " 45007ad20aa9SJames Smart "ctxSta:x%x, ctxNumBuf:%d " 45017ad20aa9SJames Smart "ctxTag:%d, ctxSeq:%d, tag:%d, seq:%d\n", 45027ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state, 45037ad20aa9SJames Smart phba->mbox_ext_buf_ctx.numBuf, 45047ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbxTag, 45057ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum, 45067ad20aa9SJames Smart mbox_req->extMboxTag, mbox_req->extSeqNum); 45077ad20aa9SJames Smart 45087ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 45097ad20aa9SJames Smart 45107ad20aa9SJames Smart return -EPIPE; 45117ad20aa9SJames Smart } 45127ad20aa9SJames Smart 45137ad20aa9SJames Smart /** 45143b5dd52aSJames Smart * lpfc_bsg_issue_mbox - issues a mailbox command on behalf of an app 45153b5dd52aSJames Smart * @phba: Pointer to HBA context object. 45163b5dd52aSJames Smart * @mb: Pointer to a mailbox object. 45173b5dd52aSJames Smart * @vport: Pointer to a vport object. 45183b5dd52aSJames Smart * 45193b5dd52aSJames Smart * Allocate a tracking object, mailbox command memory, get a mailbox 45203b5dd52aSJames Smart * from the mailbox pool, copy the caller mailbox command. 45213b5dd52aSJames Smart * 45223b5dd52aSJames Smart * If offline and the sli is active we need to poll for the command (port is 45233b5dd52aSJames Smart * being reset) and com-plete the job, otherwise issue the mailbox command and 45243b5dd52aSJames Smart * let our completion handler finish the command. 45253b5dd52aSJames Smart **/ 45263b5dd52aSJames Smart static uint32_t 45273b5dd52aSJames Smart lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, 45283b5dd52aSJames Smart struct lpfc_vport *vport) 45293b5dd52aSJames Smart { 45307a470277SJames Smart LPFC_MBOXQ_t *pmboxq = NULL; /* internal mailbox queue */ 45317a470277SJames Smart MAILBOX_t *pmb; /* shortcut to the pmboxq mailbox */ 45327a470277SJames Smart /* a 4k buffer to hold the mb and extended data from/to the bsg */ 45337ad20aa9SJames Smart uint8_t *pmbx = NULL; 45347a470277SJames Smart struct bsg_job_data *dd_data = NULL; /* bsg data tracking structure */ 45357ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf = NULL; 45367ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 4537b6e3b9c6SJames Smart struct READ_EVENT_LOG_VAR *rdEventLog; 4538b6e3b9c6SJames Smart uint32_t transmit_length, receive_length, mode; 45397ad20aa9SJames Smart struct lpfc_mbx_sli4_config *sli4_config; 4540b6e3b9c6SJames Smart struct lpfc_mbx_nembed_cmd *nembed_sge; 4541b6e3b9c6SJames Smart struct mbox_header *header; 4542b6e3b9c6SJames Smart struct ulp_bde64 *bde; 45437a470277SJames Smart uint8_t *ext = NULL; 45443b5dd52aSJames Smart int rc = 0; 45457a470277SJames Smart uint8_t *from; 45467ad20aa9SJames Smart uint32_t size; 45477ad20aa9SJames Smart 45487a470277SJames Smart /* in case no data is transferred */ 45497a470277SJames Smart job->reply->reply_payload_rcv_len = 0; 45507a470277SJames Smart 4551b6e3b9c6SJames Smart /* sanity check to protect driver */ 4552b6e3b9c6SJames Smart if (job->reply_payload.payload_len > BSG_MBOX_SIZE || 4553b6e3b9c6SJames Smart job->request_payload.payload_len > BSG_MBOX_SIZE) { 4554b6e3b9c6SJames Smart rc = -ERANGE; 4555b6e3b9c6SJames Smart goto job_done; 4556b6e3b9c6SJames Smart } 4557b6e3b9c6SJames Smart 45587ad20aa9SJames Smart /* 45597ad20aa9SJames Smart * Don't allow mailbox commands to be sent when blocked or when in 45607ad20aa9SJames Smart * the middle of discovery 45617ad20aa9SJames Smart */ 45627ad20aa9SJames Smart if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { 45637ad20aa9SJames Smart rc = -EAGAIN; 45647ad20aa9SJames Smart goto job_done; 45657ad20aa9SJames Smart } 45667ad20aa9SJames Smart 45677ad20aa9SJames Smart mbox_req = 45687ad20aa9SJames Smart (struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd; 45697ad20aa9SJames Smart 45707a470277SJames Smart /* check if requested extended data lengths are valid */ 4571b6e3b9c6SJames Smart if ((mbox_req->inExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t)) || 4572b6e3b9c6SJames Smart (mbox_req->outExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t))) { 45737a470277SJames Smart rc = -ERANGE; 45747a470277SJames Smart goto job_done; 45757a470277SJames Smart } 45763b5dd52aSJames Smart 45777ad20aa9SJames Smart dmabuf = lpfc_bsg_dma_page_alloc(phba); 45787ad20aa9SJames Smart if (!dmabuf || !dmabuf->virt) { 45797ad20aa9SJames Smart rc = -ENOMEM; 45807ad20aa9SJames Smart goto job_done; 45817ad20aa9SJames Smart } 45827ad20aa9SJames Smart 45837ad20aa9SJames Smart /* Get the mailbox command or external buffer from BSG */ 45847ad20aa9SJames Smart pmbx = (uint8_t *)dmabuf->virt; 45857ad20aa9SJames Smart size = job->request_payload.payload_len; 45867ad20aa9SJames Smart sg_copy_to_buffer(job->request_payload.sg_list, 45877ad20aa9SJames Smart job->request_payload.sg_cnt, pmbx, size); 45887ad20aa9SJames Smart 45897ad20aa9SJames Smart /* Handle possible SLI_CONFIG with non-embedded payloads */ 45907ad20aa9SJames Smart if (phba->sli_rev == LPFC_SLI_REV4) { 45917ad20aa9SJames Smart rc = lpfc_bsg_handle_sli_cfg_ext(phba, job, dmabuf); 45927ad20aa9SJames Smart if (rc == SLI_CONFIG_HANDLED) 45937ad20aa9SJames Smart goto job_cont; 45947ad20aa9SJames Smart if (rc) 45957ad20aa9SJames Smart goto job_done; 45967ad20aa9SJames Smart /* SLI_CONFIG_NOT_HANDLED for other mailbox commands */ 45977ad20aa9SJames Smart } 45987ad20aa9SJames Smart 45997ad20aa9SJames Smart rc = lpfc_bsg_check_cmd_access(phba, (MAILBOX_t *)pmbx, vport); 46007ad20aa9SJames Smart if (rc != 0) 46017ad20aa9SJames Smart goto job_done; /* must be negative */ 46027ad20aa9SJames Smart 46033b5dd52aSJames Smart /* allocate our bsg tracking structure */ 46043b5dd52aSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 46053b5dd52aSJames Smart if (!dd_data) { 46063b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 46073b5dd52aSJames Smart "2727 Failed allocation of dd_data\n"); 46087a470277SJames Smart rc = -ENOMEM; 46097a470277SJames Smart goto job_done; 46103b5dd52aSJames Smart } 46113b5dd52aSJames Smart 46123b5dd52aSJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 46133b5dd52aSJames Smart if (!pmboxq) { 46147a470277SJames Smart rc = -ENOMEM; 46157a470277SJames Smart goto job_done; 46163b5dd52aSJames Smart } 46177a470277SJames Smart memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 46183b5dd52aSJames Smart 46193b5dd52aSJames Smart pmb = &pmboxq->u.mb; 46207ad20aa9SJames Smart memcpy(pmb, pmbx, sizeof(*pmb)); 46213b5dd52aSJames Smart pmb->mbxOwner = OWN_HOST; 46223b5dd52aSJames Smart pmboxq->vport = vport; 46233b5dd52aSJames Smart 4624c7495937SJames Smart /* If HBA encountered an error attention, allow only DUMP 4625c7495937SJames Smart * or RESTART mailbox commands until the HBA is restarted. 4626c7495937SJames Smart */ 4627c7495937SJames Smart if (phba->pport->stopped && 4628c7495937SJames Smart pmb->mbxCommand != MBX_DUMP_MEMORY && 4629c7495937SJames Smart pmb->mbxCommand != MBX_RESTART && 4630c7495937SJames Smart pmb->mbxCommand != MBX_WRITE_VPARMS && 4631c7495937SJames Smart pmb->mbxCommand != MBX_WRITE_WWN) 4632c7495937SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, 4633c7495937SJames Smart "2797 mbox: Issued mailbox cmd " 4634c7495937SJames Smart "0x%x while in stopped state.\n", 4635c7495937SJames Smart pmb->mbxCommand); 4636c7495937SJames Smart 46377a470277SJames Smart /* extended mailbox commands will need an extended buffer */ 4638c7495937SJames Smart if (mbox_req->inExtWLen || mbox_req->outExtWLen) { 46397ad20aa9SJames Smart from = pmbx; 46407ad20aa9SJames Smart ext = from + sizeof(MAILBOX_t); 46417a470277SJames Smart pmboxq->context2 = ext; 46427a470277SJames Smart pmboxq->in_ext_byte_len = 46437a470277SJames Smart mbox_req->inExtWLen * sizeof(uint32_t); 46447a470277SJames Smart pmboxq->out_ext_byte_len = 4645c7495937SJames Smart mbox_req->outExtWLen * sizeof(uint32_t); 46467a470277SJames Smart pmboxq->mbox_offset_word = mbox_req->mbOffset; 46477a470277SJames Smart } 46487a470277SJames Smart 46497a470277SJames Smart /* biu diag will need a kernel buffer to transfer the data 46507a470277SJames Smart * allocate our own buffer and setup the mailbox command to 46517a470277SJames Smart * use ours 46527a470277SJames Smart */ 46537a470277SJames Smart if (pmb->mbxCommand == MBX_RUN_BIU_DIAG64) { 4654b6e3b9c6SJames Smart transmit_length = pmb->un.varWords[1]; 4655b6e3b9c6SJames Smart receive_length = pmb->un.varWords[4]; 4656c7495937SJames Smart /* transmit length cannot be greater than receive length or 4657c7495937SJames Smart * mailbox extension size 4658c7495937SJames Smart */ 4659c7495937SJames Smart if ((transmit_length > receive_length) || 466088a2cfbbSJames Smart (transmit_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t))) { 4661c7495937SJames Smart rc = -ERANGE; 4662c7495937SJames Smart goto job_done; 4663c7495937SJames Smart } 46647a470277SJames Smart pmb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh = 46657ad20aa9SJames Smart putPaddrHigh(dmabuf->phys + sizeof(MAILBOX_t)); 46667a470277SJames Smart pmb->un.varBIUdiag.un.s2.xmit_bde64.addrLow = 46677ad20aa9SJames Smart putPaddrLow(dmabuf->phys + sizeof(MAILBOX_t)); 46687a470277SJames Smart 46697a470277SJames Smart pmb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh = 46707ad20aa9SJames Smart putPaddrHigh(dmabuf->phys + sizeof(MAILBOX_t) 46717ad20aa9SJames Smart + pmb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize); 46727a470277SJames Smart pmb->un.varBIUdiag.un.s2.rcv_bde64.addrLow = 46737ad20aa9SJames Smart putPaddrLow(dmabuf->phys + sizeof(MAILBOX_t) 46747ad20aa9SJames Smart + pmb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize); 4675c7495937SJames Smart } else if (pmb->mbxCommand == MBX_READ_EVENT_LOG) { 4676b6e3b9c6SJames Smart rdEventLog = &pmb->un.varRdEventLog; 4677b6e3b9c6SJames Smart receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize; 4678b6e3b9c6SJames Smart mode = bf_get(lpfc_event_log, rdEventLog); 4679c7495937SJames Smart 4680c7495937SJames Smart /* receive length cannot be greater than mailbox 4681c7495937SJames Smart * extension size 4682c7495937SJames Smart */ 468388a2cfbbSJames Smart if (receive_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t)) { 4684c7495937SJames Smart rc = -ERANGE; 4685c7495937SJames Smart goto job_done; 4686c7495937SJames Smart } 4687c7495937SJames Smart 4688c7495937SJames Smart /* mode zero uses a bde like biu diags command */ 4689c7495937SJames Smart if (mode == 0) { 46907ad20aa9SJames Smart pmb->un.varWords[3] = putPaddrLow(dmabuf->phys 46917ad20aa9SJames Smart + sizeof(MAILBOX_t)); 46927ad20aa9SJames Smart pmb->un.varWords[4] = putPaddrHigh(dmabuf->phys 46937ad20aa9SJames Smart + sizeof(MAILBOX_t)); 4694c7495937SJames Smart } 4695c7495937SJames Smart } else if (phba->sli_rev == LPFC_SLI_REV4) { 46963ef6d24cSJames Smart /* Let type 4 (well known data) through because the data is 46973ef6d24cSJames Smart * returned in varwords[4-8] 46983ef6d24cSJames Smart * otherwise check the recieve length and fetch the buffer addr 46993ef6d24cSJames Smart */ 47003ef6d24cSJames Smart if ((pmb->mbxCommand == MBX_DUMP_MEMORY) && 47013ef6d24cSJames Smart (pmb->un.varDmp.type != DMP_WELL_KNOWN)) { 4702c7495937SJames Smart /* rebuild the command for sli4 using our own buffers 4703c7495937SJames Smart * like we do for biu diags 4704c7495937SJames Smart */ 4705b6e3b9c6SJames Smart receive_length = pmb->un.varWords[2]; 4706c7495937SJames Smart /* receive length cannot be greater than mailbox 4707c7495937SJames Smart * extension size 4708c7495937SJames Smart */ 47097ad20aa9SJames Smart if (receive_length == 0) { 4710c7495937SJames Smart rc = -ERANGE; 4711c7495937SJames Smart goto job_done; 4712c7495937SJames Smart } 47137ad20aa9SJames Smart pmb->un.varWords[3] = putPaddrLow(dmabuf->phys 47147ad20aa9SJames Smart + sizeof(MAILBOX_t)); 47157ad20aa9SJames Smart pmb->un.varWords[4] = putPaddrHigh(dmabuf->phys 47167ad20aa9SJames Smart + sizeof(MAILBOX_t)); 4717c7495937SJames Smart } else if ((pmb->mbxCommand == MBX_UPDATE_CFG) && 4718c7495937SJames Smart pmb->un.varUpdateCfg.co) { 4719b6e3b9c6SJames Smart bde = (struct ulp_bde64 *)&pmb->un.varWords[4]; 4720c7495937SJames Smart 4721c7495937SJames Smart /* bde size cannot be greater than mailbox ext size */ 472288a2cfbbSJames Smart if (bde->tus.f.bdeSize > 472388a2cfbbSJames Smart BSG_MBOX_SIZE - sizeof(MAILBOX_t)) { 4724c7495937SJames Smart rc = -ERANGE; 4725c7495937SJames Smart goto job_done; 4726c7495937SJames Smart } 47277ad20aa9SJames Smart bde->addrHigh = putPaddrHigh(dmabuf->phys 47287ad20aa9SJames Smart + sizeof(MAILBOX_t)); 47297ad20aa9SJames Smart bde->addrLow = putPaddrLow(dmabuf->phys 47307ad20aa9SJames Smart + sizeof(MAILBOX_t)); 4731515e0aa2SJames Smart } else if (pmb->mbxCommand == MBX_SLI4_CONFIG) { 47327ad20aa9SJames Smart /* Handling non-embedded SLI_CONFIG mailbox command */ 47337ad20aa9SJames Smart sli4_config = &pmboxq->u.mqe.un.sli4_config; 47347ad20aa9SJames Smart if (!bf_get(lpfc_mbox_hdr_emb, 47357ad20aa9SJames Smart &sli4_config->header.cfg_mhdr)) { 47367ad20aa9SJames Smart /* rebuild the command for sli4 using our 47377ad20aa9SJames Smart * own buffers like we do for biu diags 4738515e0aa2SJames Smart */ 47397ad20aa9SJames Smart header = (struct mbox_header *) 47407ad20aa9SJames Smart &pmb->un.varWords[0]; 4741515e0aa2SJames Smart nembed_sge = (struct lpfc_mbx_nembed_cmd *) 4742515e0aa2SJames Smart &pmb->un.varWords[0]; 4743515e0aa2SJames Smart receive_length = nembed_sge->sge[0].length; 4744515e0aa2SJames Smart 47457ad20aa9SJames Smart /* receive length cannot be greater than 47467ad20aa9SJames Smart * mailbox extension size 4747515e0aa2SJames Smart */ 4748515e0aa2SJames Smart if ((receive_length == 0) || 474988a2cfbbSJames Smart (receive_length > 475088a2cfbbSJames Smart BSG_MBOX_SIZE - sizeof(MAILBOX_t))) { 4751515e0aa2SJames Smart rc = -ERANGE; 4752515e0aa2SJames Smart goto job_done; 4753515e0aa2SJames Smart } 4754515e0aa2SJames Smart 47557ad20aa9SJames Smart nembed_sge->sge[0].pa_hi = 47567ad20aa9SJames Smart putPaddrHigh(dmabuf->phys 47577ad20aa9SJames Smart + sizeof(MAILBOX_t)); 47587ad20aa9SJames Smart nembed_sge->sge[0].pa_lo = 47597ad20aa9SJames Smart putPaddrLow(dmabuf->phys 47607ad20aa9SJames Smart + sizeof(MAILBOX_t)); 4761515e0aa2SJames Smart } 4762c7495937SJames Smart } 4763c7495937SJames Smart } 4764c7495937SJames Smart 47657ad20aa9SJames Smart dd_data->context_un.mbox.dmabuffers = dmabuf; 47663b5dd52aSJames Smart 47673b5dd52aSJames Smart /* setup wake call as IOCB callback */ 47687ad20aa9SJames Smart pmboxq->mbox_cmpl = lpfc_bsg_issue_mbox_cmpl; 47697a470277SJames Smart 47703b5dd52aSJames Smart /* setup context field to pass wait_queue pointer to wake function */ 47713b5dd52aSJames Smart pmboxq->context1 = dd_data; 47723b5dd52aSJames Smart dd_data->type = TYPE_MBOX; 4773*a33c4f7bSJames Smart dd_data->set_job = job; 47743b5dd52aSJames Smart dd_data->context_un.mbox.pmboxq = pmboxq; 47757ad20aa9SJames Smart dd_data->context_un.mbox.mb = (MAILBOX_t *)pmbx; 47767a470277SJames Smart dd_data->context_un.mbox.ext = ext; 47777a470277SJames Smart dd_data->context_un.mbox.mbOffset = mbox_req->mbOffset; 47787a470277SJames Smart dd_data->context_un.mbox.inExtWLen = mbox_req->inExtWLen; 4779c7495937SJames Smart dd_data->context_un.mbox.outExtWLen = mbox_req->outExtWLen; 47803b5dd52aSJames Smart job->dd_data = dd_data; 47817a470277SJames Smart 47827a470277SJames Smart if ((vport->fc_flag & FC_OFFLINE_MODE) || 47837a470277SJames Smart (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { 47847a470277SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); 47857a470277SJames Smart if (rc != MBX_SUCCESS) { 47867a470277SJames Smart rc = (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; 47877a470277SJames Smart goto job_done; 47883b5dd52aSJames Smart } 47893b5dd52aSJames Smart 47907a470277SJames Smart /* job finished, copy the data */ 47917ad20aa9SJames Smart memcpy(pmbx, pmb, sizeof(*pmb)); 47927a470277SJames Smart job->reply->reply_payload_rcv_len = 47937a470277SJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 47947a470277SJames Smart job->reply_payload.sg_cnt, 47957ad20aa9SJames Smart pmbx, size); 47967a470277SJames Smart /* not waiting mbox already done */ 47977a470277SJames Smart rc = 0; 47987a470277SJames Smart goto job_done; 47997a470277SJames Smart } 48007a470277SJames Smart 48017a470277SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); 48027a470277SJames Smart if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) 48037a470277SJames Smart return 1; /* job started */ 48047a470277SJames Smart 48057a470277SJames Smart job_done: 48067a470277SJames Smart /* common exit for error or job completed inline */ 48077a470277SJames Smart if (pmboxq) 48087a470277SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 48097ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 48107a470277SJames Smart kfree(dd_data); 48117a470277SJames Smart 48127ad20aa9SJames Smart job_cont: 48137a470277SJames Smart return rc; 48143b5dd52aSJames Smart } 48153b5dd52aSJames Smart 48163b5dd52aSJames Smart /** 48173b5dd52aSJames Smart * lpfc_bsg_mbox_cmd - process an fc bsg LPFC_BSG_VENDOR_MBOX command 48183b5dd52aSJames Smart * @job: MBOX fc_bsg_job for LPFC_BSG_VENDOR_MBOX. 48193b5dd52aSJames Smart **/ 48203b5dd52aSJames Smart static int 48213b5dd52aSJames Smart lpfc_bsg_mbox_cmd(struct fc_bsg_job *job) 48223b5dd52aSJames Smart { 48233b5dd52aSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 48243b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 48257ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 48263b5dd52aSJames Smart int rc = 0; 48273b5dd52aSJames Smart 48287ad20aa9SJames Smart /* mix-and-match backward compatibility */ 48293b5dd52aSJames Smart job->reply->reply_payload_rcv_len = 0; 48303b5dd52aSJames Smart if (job->request_len < 48313b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct dfc_mbox_req)) { 48327ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 48337ad20aa9SJames Smart "2737 Mix-and-match backward compability " 48347ad20aa9SJames Smart "between MBOX_REQ old size:%d and " 48357ad20aa9SJames Smart "new request size:%d\n", 48367ad20aa9SJames Smart (int)(job->request_len - 48377ad20aa9SJames Smart sizeof(struct fc_bsg_request)), 48387ad20aa9SJames Smart (int)sizeof(struct dfc_mbox_req)); 48397ad20aa9SJames Smart mbox_req = (struct dfc_mbox_req *) 48407ad20aa9SJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 48417ad20aa9SJames Smart mbox_req->extMboxTag = 0; 48427ad20aa9SJames Smart mbox_req->extSeqNum = 0; 48433b5dd52aSJames Smart } 48443b5dd52aSJames Smart 48453b5dd52aSJames Smart rc = lpfc_bsg_issue_mbox(phba, job, vport); 48463b5dd52aSJames Smart 48473b5dd52aSJames Smart if (rc == 0) { 48483b5dd52aSJames Smart /* job done */ 48493b5dd52aSJames Smart job->reply->result = 0; 48503b5dd52aSJames Smart job->dd_data = NULL; 48513b5dd52aSJames Smart job->job_done(job); 48523b5dd52aSJames Smart } else if (rc == 1) 48533b5dd52aSJames Smart /* job submitted, will complete later*/ 48543b5dd52aSJames Smart rc = 0; /* return zero, no error */ 48553b5dd52aSJames Smart else { 48563b5dd52aSJames Smart /* some error occurred */ 48573b5dd52aSJames Smart job->reply->result = rc; 48583b5dd52aSJames Smart job->dd_data = NULL; 48593b5dd52aSJames Smart } 48603b5dd52aSJames Smart 48613b5dd52aSJames Smart return rc; 48623b5dd52aSJames Smart } 48633b5dd52aSJames Smart 48643b5dd52aSJames Smart /** 4865e2aed29fSJames Smart * lpfc_bsg_menlo_cmd_cmp - lpfc_menlo_cmd completion handler 4866e2aed29fSJames Smart * @phba: Pointer to HBA context object. 4867e2aed29fSJames Smart * @cmdiocbq: Pointer to command iocb. 4868e2aed29fSJames Smart * @rspiocbq: Pointer to response iocb. 4869e2aed29fSJames Smart * 4870e2aed29fSJames Smart * This function is the completion handler for iocbs issued using 4871e2aed29fSJames Smart * lpfc_menlo_cmd function. This function is called by the 4872e2aed29fSJames Smart * ring event handler function without any lock held. This function 4873e2aed29fSJames Smart * can be called from both worker thread context and interrupt 4874e2aed29fSJames Smart * context. This function also can be called from another thread which 4875e2aed29fSJames Smart * cleans up the SLI layer objects. 4876e2aed29fSJames Smart * This function copies the contents of the response iocb to the 4877e2aed29fSJames Smart * response iocb memory object provided by the caller of 4878e2aed29fSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 4879e2aed29fSJames Smart * sleeps for the iocb completion. 4880e2aed29fSJames Smart **/ 4881e2aed29fSJames Smart static void 4882e2aed29fSJames Smart lpfc_bsg_menlo_cmd_cmp(struct lpfc_hba *phba, 4883e2aed29fSJames Smart struct lpfc_iocbq *cmdiocbq, 4884e2aed29fSJames Smart struct lpfc_iocbq *rspiocbq) 4885e2aed29fSJames Smart { 4886e2aed29fSJames Smart struct bsg_job_data *dd_data; 4887e2aed29fSJames Smart struct fc_bsg_job *job; 4888e2aed29fSJames Smart IOCB_t *rsp; 4889*a33c4f7bSJames Smart struct lpfc_dmabuf *bmp, *cmp, *rmp; 4890e2aed29fSJames Smart struct lpfc_bsg_menlo *menlo; 4891e2aed29fSJames Smart unsigned long flags; 4892e2aed29fSJames Smart struct menlo_response *menlo_resp; 4893*a33c4f7bSJames Smart unsigned int rsp_size; 4894e2aed29fSJames Smart int rc = 0; 4895e2aed29fSJames Smart 4896e2aed29fSJames Smart dd_data = cmdiocbq->context1; 4897*a33c4f7bSJames Smart cmp = cmdiocbq->context2; 4898*a33c4f7bSJames Smart bmp = cmdiocbq->context3; 4899e2aed29fSJames Smart menlo = &dd_data->context_un.menlo; 4900*a33c4f7bSJames Smart rmp = menlo->rmp; 4901e2aed29fSJames Smart rsp = &rspiocbq->iocb; 4902e2aed29fSJames Smart 4903*a33c4f7bSJames Smart /* Determine if job has been aborted */ 4904*a33c4f7bSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 4905*a33c4f7bSJames Smart job = dd_data->set_job; 4906*a33c4f7bSJames Smart if (job) { 4907*a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 4908*a33c4f7bSJames Smart job->dd_data = NULL; 4909*a33c4f7bSJames Smart } 4910*a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 4911e2aed29fSJames Smart 4912*a33c4f7bSJames Smart /* Copy the job data or set the failing status for the job */ 4913*a33c4f7bSJames Smart 4914*a33c4f7bSJames Smart if (job) { 4915e2aed29fSJames Smart /* always return the xri, this would be used in the case 4916*a33c4f7bSJames Smart * of a menlo download to allow the data to be sent as a 4917*a33c4f7bSJames Smart * continuation of the exchange. 4918e2aed29fSJames Smart */ 4919*a33c4f7bSJames Smart 4920e2aed29fSJames Smart menlo_resp = (struct menlo_response *) 4921e2aed29fSJames Smart job->reply->reply_data.vendor_reply.vendor_rsp; 4922e2aed29fSJames Smart menlo_resp->xri = rsp->ulpContext; 4923e2aed29fSJames Smart if (rsp->ulpStatus) { 4924e2aed29fSJames Smart if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { 4925e3d2b802SJames Smart switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) { 4926e2aed29fSJames Smart case IOERR_SEQUENCE_TIMEOUT: 4927e2aed29fSJames Smart rc = -ETIMEDOUT; 4928e2aed29fSJames Smart break; 4929e2aed29fSJames Smart case IOERR_INVALID_RPI: 4930e2aed29fSJames Smart rc = -EFAULT; 4931e2aed29fSJames Smart break; 4932e2aed29fSJames Smart default: 4933e2aed29fSJames Smart rc = -EACCES; 4934e2aed29fSJames Smart break; 4935e2aed29fSJames Smart } 4936*a33c4f7bSJames Smart } else { 4937e2aed29fSJames Smart rc = -EACCES; 4938*a33c4f7bSJames Smart } 4939*a33c4f7bSJames Smart } else { 4940*a33c4f7bSJames Smart rsp_size = rsp->un.genreq64.bdl.bdeSize; 4941e2aed29fSJames Smart job->reply->reply_payload_rcv_len = 4942*a33c4f7bSJames Smart lpfc_bsg_copy_data(rmp, &job->reply_payload, 4943*a33c4f7bSJames Smart rsp_size, 0); 4944*a33c4f7bSJames Smart } 4945e2aed29fSJames Smart 4946*a33c4f7bSJames Smart } 4947*a33c4f7bSJames Smart 4948e2aed29fSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 4949*a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 4950*a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, rmp); 4951*a33c4f7bSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 4952e2aed29fSJames Smart kfree(bmp); 4953e2aed29fSJames Smart kfree(dd_data); 4954*a33c4f7bSJames Smart 4955*a33c4f7bSJames Smart /* Complete the job if active */ 4956*a33c4f7bSJames Smart 4957*a33c4f7bSJames Smart if (job) { 4958e2aed29fSJames Smart job->reply->result = rc; 4959e2aed29fSJames Smart job->job_done(job); 4960*a33c4f7bSJames Smart } 4961*a33c4f7bSJames Smart 4962e2aed29fSJames Smart return; 4963e2aed29fSJames Smart } 4964e2aed29fSJames Smart 4965e2aed29fSJames Smart /** 4966e2aed29fSJames Smart * lpfc_menlo_cmd - send an ioctl for menlo hardware 4967e2aed29fSJames Smart * @job: fc_bsg_job to handle 4968e2aed29fSJames Smart * 4969e2aed29fSJames Smart * This function issues a gen request 64 CR ioctl for all menlo cmd requests, 4970e2aed29fSJames Smart * all the command completions will return the xri for the command. 4971e2aed29fSJames Smart * For menlo data requests a gen request 64 CX is used to continue the exchange 4972e2aed29fSJames Smart * supplied in the menlo request header xri field. 4973e2aed29fSJames Smart **/ 4974e2aed29fSJames Smart static int 4975e2aed29fSJames Smart lpfc_menlo_cmd(struct fc_bsg_job *job) 4976e2aed29fSJames Smart { 4977e2aed29fSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 4978e2aed29fSJames Smart struct lpfc_hba *phba = vport->phba; 4979*a33c4f7bSJames Smart struct lpfc_iocbq *cmdiocbq; 4980*a33c4f7bSJames Smart IOCB_t *cmd; 4981e2aed29fSJames Smart int rc = 0; 4982e2aed29fSJames Smart struct menlo_command *menlo_cmd; 4983e2aed29fSJames Smart struct menlo_response *menlo_resp; 4984*a33c4f7bSJames Smart struct lpfc_dmabuf *bmp = NULL, *cmp = NULL, *rmp = NULL; 4985e2aed29fSJames Smart int request_nseg; 4986e2aed29fSJames Smart int reply_nseg; 4987e2aed29fSJames Smart struct bsg_job_data *dd_data; 4988e2aed29fSJames Smart struct ulp_bde64 *bpl = NULL; 4989e2aed29fSJames Smart 4990e2aed29fSJames Smart /* in case no data is returned return just the return code */ 4991e2aed29fSJames Smart job->reply->reply_payload_rcv_len = 0; 4992e2aed29fSJames Smart 4993e2aed29fSJames Smart if (job->request_len < 4994e2aed29fSJames Smart sizeof(struct fc_bsg_request) + 4995e2aed29fSJames Smart sizeof(struct menlo_command)) { 4996e2aed29fSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 4997e2aed29fSJames Smart "2784 Received MENLO_CMD request below " 4998e2aed29fSJames Smart "minimum size\n"); 4999e2aed29fSJames Smart rc = -ERANGE; 5000e2aed29fSJames Smart goto no_dd_data; 5001e2aed29fSJames Smart } 5002e2aed29fSJames Smart 5003e2aed29fSJames Smart if (job->reply_len < 5004e2aed29fSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct menlo_response)) { 5005e2aed29fSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 5006e2aed29fSJames Smart "2785 Received MENLO_CMD reply below " 5007e2aed29fSJames Smart "minimum size\n"); 5008e2aed29fSJames Smart rc = -ERANGE; 5009e2aed29fSJames Smart goto no_dd_data; 5010e2aed29fSJames Smart } 5011e2aed29fSJames Smart 5012e2aed29fSJames Smart if (!(phba->menlo_flag & HBA_MENLO_SUPPORT)) { 5013e2aed29fSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 5014e2aed29fSJames Smart "2786 Adapter does not support menlo " 5015e2aed29fSJames Smart "commands\n"); 5016e2aed29fSJames Smart rc = -EPERM; 5017e2aed29fSJames Smart goto no_dd_data; 5018e2aed29fSJames Smart } 5019e2aed29fSJames Smart 5020e2aed29fSJames Smart menlo_cmd = (struct menlo_command *) 5021e2aed29fSJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 5022e2aed29fSJames Smart 5023e2aed29fSJames Smart menlo_resp = (struct menlo_response *) 5024e2aed29fSJames Smart job->reply->reply_data.vendor_reply.vendor_rsp; 5025e2aed29fSJames Smart 5026e2aed29fSJames Smart /* allocate our bsg tracking structure */ 5027e2aed29fSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 5028e2aed29fSJames Smart if (!dd_data) { 5029e2aed29fSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 5030e2aed29fSJames Smart "2787 Failed allocation of dd_data\n"); 5031e2aed29fSJames Smart rc = -ENOMEM; 5032e2aed29fSJames Smart goto no_dd_data; 5033e2aed29fSJames Smart } 5034e2aed29fSJames Smart 5035e2aed29fSJames Smart bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 5036e2aed29fSJames Smart if (!bmp) { 5037e2aed29fSJames Smart rc = -ENOMEM; 5038e2aed29fSJames Smart goto free_dd; 5039e2aed29fSJames Smart } 5040e2aed29fSJames Smart 5041*a33c4f7bSJames Smart bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); 5042*a33c4f7bSJames Smart if (!bmp->virt) { 5043e2aed29fSJames Smart rc = -ENOMEM; 5044e2aed29fSJames Smart goto free_bmp; 5045e2aed29fSJames Smart } 5046e2aed29fSJames Smart 5047e2aed29fSJames Smart INIT_LIST_HEAD(&bmp->list); 5048*a33c4f7bSJames Smart 5049e2aed29fSJames Smart bpl = (struct ulp_bde64 *)bmp->virt; 5050*a33c4f7bSJames Smart request_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64); 5051*a33c4f7bSJames Smart cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len, 5052*a33c4f7bSJames Smart 1, bpl, &request_nseg); 5053*a33c4f7bSJames Smart if (!cmp) { 5054*a33c4f7bSJames Smart rc = -ENOMEM; 5055*a33c4f7bSJames Smart goto free_bmp; 5056*a33c4f7bSJames Smart } 5057*a33c4f7bSJames Smart lpfc_bsg_copy_data(cmp, &job->request_payload, 5058*a33c4f7bSJames Smart job->request_payload.payload_len, 1); 5059*a33c4f7bSJames Smart 5060*a33c4f7bSJames Smart bpl += request_nseg; 5061*a33c4f7bSJames Smart reply_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64) - request_nseg; 5062*a33c4f7bSJames Smart rmp = lpfc_alloc_bsg_buffers(phba, job->reply_payload.payload_len, 0, 5063*a33c4f7bSJames Smart bpl, &reply_nseg); 5064*a33c4f7bSJames Smart if (!rmp) { 5065*a33c4f7bSJames Smart rc = -ENOMEM; 5066*a33c4f7bSJames Smart goto free_cmp; 5067e2aed29fSJames Smart } 5068e2aed29fSJames Smart 5069*a33c4f7bSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 5070*a33c4f7bSJames Smart if (!cmdiocbq) { 5071*a33c4f7bSJames Smart rc = -ENOMEM; 5072*a33c4f7bSJames Smart goto free_rmp; 5073e2aed29fSJames Smart } 5074e2aed29fSJames Smart 5075e2aed29fSJames Smart cmd = &cmdiocbq->iocb; 5076e2aed29fSJames Smart cmd->un.genreq64.bdl.ulpIoTag32 = 0; 5077e2aed29fSJames Smart cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); 5078e2aed29fSJames Smart cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); 5079e2aed29fSJames Smart cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 5080e2aed29fSJames Smart cmd->un.genreq64.bdl.bdeSize = 5081e2aed29fSJames Smart (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); 5082e2aed29fSJames Smart cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); 5083e2aed29fSJames Smart cmd->un.genreq64.w5.hcsw.Dfctl = 0; 5084e2aed29fSJames Smart cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CMD; 5085e2aed29fSJames Smart cmd->un.genreq64.w5.hcsw.Type = MENLO_TRANSPORT_TYPE; /* 0xfe */ 5086e2aed29fSJames Smart cmd->ulpBdeCount = 1; 5087e2aed29fSJames Smart cmd->ulpClass = CLASS3; 5088e2aed29fSJames Smart cmd->ulpOwner = OWN_CHIP; 5089e2aed29fSJames Smart cmd->ulpLe = 1; /* Limited Edition */ 5090e2aed29fSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 5091e2aed29fSJames Smart cmdiocbq->vport = phba->pport; 5092e2aed29fSJames Smart /* We want the firmware to timeout before we do */ 5093e2aed29fSJames Smart cmd->ulpTimeout = MENLO_TIMEOUT - 5; 5094e2aed29fSJames Smart cmdiocbq->iocb_cmpl = lpfc_bsg_menlo_cmd_cmp; 5095e2aed29fSJames Smart cmdiocbq->context1 = dd_data; 5096*a33c4f7bSJames Smart cmdiocbq->context2 = cmp; 5097*a33c4f7bSJames Smart cmdiocbq->context3 = bmp; 5098e2aed29fSJames Smart if (menlo_cmd->cmd == LPFC_BSG_VENDOR_MENLO_CMD) { 5099e2aed29fSJames Smart cmd->ulpCommand = CMD_GEN_REQUEST64_CR; 5100e2aed29fSJames Smart cmd->ulpPU = MENLO_PU; /* 3 */ 5101e2aed29fSJames Smart cmd->un.ulpWord[4] = MENLO_DID; /* 0x0000FC0E */ 5102e2aed29fSJames Smart cmd->ulpContext = MENLO_CONTEXT; /* 0 */ 5103e2aed29fSJames Smart } else { 5104e2aed29fSJames Smart cmd->ulpCommand = CMD_GEN_REQUEST64_CX; 5105e2aed29fSJames Smart cmd->ulpPU = 1; 5106e2aed29fSJames Smart cmd->un.ulpWord[4] = 0; 5107e2aed29fSJames Smart cmd->ulpContext = menlo_cmd->xri; 5108e2aed29fSJames Smart } 5109e2aed29fSJames Smart 5110e2aed29fSJames Smart dd_data->type = TYPE_MENLO; 5111*a33c4f7bSJames Smart dd_data->set_job = job; 5112e2aed29fSJames Smart dd_data->context_un.menlo.cmdiocbq = cmdiocbq; 5113*a33c4f7bSJames Smart dd_data->context_un.menlo.rmp = rmp; 5114*a33c4f7bSJames Smart job->dd_data = dd_data; 5115e2aed29fSJames Smart 5116e2aed29fSJames Smart rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 5117e2aed29fSJames Smart MENLO_TIMEOUT - 5); 5118e2aed29fSJames Smart if (rc == IOCB_SUCCESS) 5119e2aed29fSJames Smart return 0; /* done for now */ 5120e2aed29fSJames Smart 5121e2aed29fSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 5122*a33c4f7bSJames Smart 5123*a33c4f7bSJames Smart free_rmp: 5124*a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, rmp); 5125*a33c4f7bSJames Smart free_cmp: 5126*a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 5127e2aed29fSJames Smart free_bmp: 5128*a33c4f7bSJames Smart if (bmp->virt) 5129*a33c4f7bSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 5130e2aed29fSJames Smart kfree(bmp); 5131e2aed29fSJames Smart free_dd: 5132e2aed29fSJames Smart kfree(dd_data); 5133e2aed29fSJames Smart no_dd_data: 5134e2aed29fSJames Smart /* make error code available to userspace */ 5135e2aed29fSJames Smart job->reply->result = rc; 5136e2aed29fSJames Smart job->dd_data = NULL; 5137e2aed29fSJames Smart return rc; 5138e2aed29fSJames Smart } 5139b6e3b9c6SJames Smart 5140e2aed29fSJames Smart /** 5141f1c3b0fcSJames Smart * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job 5142f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 51433b5dd52aSJames Smart **/ 5144f1c3b0fcSJames Smart static int 5145f1c3b0fcSJames Smart lpfc_bsg_hst_vendor(struct fc_bsg_job *job) 5146f1c3b0fcSJames Smart { 5147f1c3b0fcSJames Smart int command = job->request->rqst_data.h_vendor.vendor_cmd[0]; 51484cc0e56eSJames Smart int rc; 5149f1c3b0fcSJames Smart 5150f1c3b0fcSJames Smart switch (command) { 5151f1c3b0fcSJames Smart case LPFC_BSG_VENDOR_SET_CT_EVENT: 51524cc0e56eSJames Smart rc = lpfc_bsg_hba_set_event(job); 5153f1c3b0fcSJames Smart break; 5154f1c3b0fcSJames Smart case LPFC_BSG_VENDOR_GET_CT_EVENT: 51554cc0e56eSJames Smart rc = lpfc_bsg_hba_get_event(job); 5156f1c3b0fcSJames Smart break; 51573b5dd52aSJames Smart case LPFC_BSG_VENDOR_SEND_MGMT_RESP: 51583b5dd52aSJames Smart rc = lpfc_bsg_send_mgmt_rsp(job); 51593b5dd52aSJames Smart break; 51603b5dd52aSJames Smart case LPFC_BSG_VENDOR_DIAG_MODE: 51617ad20aa9SJames Smart rc = lpfc_bsg_diag_loopback_mode(job); 51623b5dd52aSJames Smart break; 51637ad20aa9SJames Smart case LPFC_BSG_VENDOR_DIAG_MODE_END: 51647ad20aa9SJames Smart rc = lpfc_sli4_bsg_diag_mode_end(job); 51657ad20aa9SJames Smart break; 51667ad20aa9SJames Smart case LPFC_BSG_VENDOR_DIAG_RUN_LOOPBACK: 51677ad20aa9SJames Smart rc = lpfc_bsg_diag_loopback_run(job); 51687ad20aa9SJames Smart break; 51697ad20aa9SJames Smart case LPFC_BSG_VENDOR_LINK_DIAG_TEST: 51707ad20aa9SJames Smart rc = lpfc_sli4_bsg_link_diag_test(job); 51713b5dd52aSJames Smart break; 51723b5dd52aSJames Smart case LPFC_BSG_VENDOR_GET_MGMT_REV: 51733b5dd52aSJames Smart rc = lpfc_bsg_get_dfc_rev(job); 51743b5dd52aSJames Smart break; 51753b5dd52aSJames Smart case LPFC_BSG_VENDOR_MBOX: 51763b5dd52aSJames Smart rc = lpfc_bsg_mbox_cmd(job); 51773b5dd52aSJames Smart break; 5178e2aed29fSJames Smart case LPFC_BSG_VENDOR_MENLO_CMD: 5179e2aed29fSJames Smart case LPFC_BSG_VENDOR_MENLO_DATA: 5180e2aed29fSJames Smart rc = lpfc_menlo_cmd(job); 5181e2aed29fSJames Smart break; 5182f1c3b0fcSJames Smart default: 51834cc0e56eSJames Smart rc = -EINVAL; 51844cc0e56eSJames Smart job->reply->reply_payload_rcv_len = 0; 51854cc0e56eSJames Smart /* make error code available to userspace */ 51864cc0e56eSJames Smart job->reply->result = rc; 51874cc0e56eSJames Smart break; 5188f1c3b0fcSJames Smart } 51894cc0e56eSJames Smart 51904cc0e56eSJames Smart return rc; 5191f1c3b0fcSJames Smart } 5192f1c3b0fcSJames Smart 5193f1c3b0fcSJames Smart /** 5194f1c3b0fcSJames Smart * lpfc_bsg_request - handle a bsg request from the FC transport 5195f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 51963b5dd52aSJames Smart **/ 5197f1c3b0fcSJames Smart int 5198f1c3b0fcSJames Smart lpfc_bsg_request(struct fc_bsg_job *job) 5199f1c3b0fcSJames Smart { 5200f1c3b0fcSJames Smart uint32_t msgcode; 52014cc0e56eSJames Smart int rc; 5202f1c3b0fcSJames Smart 5203f1c3b0fcSJames Smart msgcode = job->request->msgcode; 5204f1c3b0fcSJames Smart switch (msgcode) { 5205f1c3b0fcSJames Smart case FC_BSG_HST_VENDOR: 5206f1c3b0fcSJames Smart rc = lpfc_bsg_hst_vendor(job); 5207f1c3b0fcSJames Smart break; 5208f1c3b0fcSJames Smart case FC_BSG_RPT_ELS: 5209f1c3b0fcSJames Smart rc = lpfc_bsg_rport_els(job); 5210f1c3b0fcSJames Smart break; 5211f1c3b0fcSJames Smart case FC_BSG_RPT_CT: 52124cc0e56eSJames Smart rc = lpfc_bsg_send_mgmt_cmd(job); 5213f1c3b0fcSJames Smart break; 5214f1c3b0fcSJames Smart default: 52154cc0e56eSJames Smart rc = -EINVAL; 52164cc0e56eSJames Smart job->reply->reply_payload_rcv_len = 0; 52174cc0e56eSJames Smart /* make error code available to userspace */ 52184cc0e56eSJames Smart job->reply->result = rc; 5219f1c3b0fcSJames Smart break; 5220f1c3b0fcSJames Smart } 5221f1c3b0fcSJames Smart 5222f1c3b0fcSJames Smart return rc; 5223f1c3b0fcSJames Smart } 5224f1c3b0fcSJames Smart 5225f1c3b0fcSJames Smart /** 5226f1c3b0fcSJames Smart * lpfc_bsg_timeout - handle timeout of a bsg request from the FC transport 5227f1c3b0fcSJames Smart * @job: fc_bsg_job that has timed out 5228f1c3b0fcSJames Smart * 5229f1c3b0fcSJames Smart * This function just aborts the job's IOCB. The aborted IOCB will return to 5230f1c3b0fcSJames Smart * the waiting function which will handle passing the error back to userspace 52313b5dd52aSJames Smart **/ 5232f1c3b0fcSJames Smart int 5233f1c3b0fcSJames Smart lpfc_bsg_timeout(struct fc_bsg_job *job) 5234f1c3b0fcSJames Smart { 5235f1c3b0fcSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 5236f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 52374cc0e56eSJames Smart struct lpfc_iocbq *cmdiocb; 5238f1c3b0fcSJames Smart struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; 52394cc0e56eSJames Smart struct bsg_job_data *dd_data; 52404cc0e56eSJames Smart unsigned long flags; 5241*a33c4f7bSJames Smart int rc = 0; 5242*a33c4f7bSJames Smart LIST_HEAD(completions); 5243*a33c4f7bSJames Smart struct lpfc_iocbq *check_iocb, *next_iocb; 5244*a33c4f7bSJames Smart 5245*a33c4f7bSJames Smart /* if job's driver data is NULL, the command completed or is in the 5246*a33c4f7bSJames Smart * the process of completing. In this case, return status to request 5247*a33c4f7bSJames Smart * so the timeout is retried. This avoids double completion issues 5248*a33c4f7bSJames Smart * and the request will be pulled off the timer queue when the 5249*a33c4f7bSJames Smart * command's completion handler executes. Otherwise, prevent the 5250*a33c4f7bSJames Smart * command's completion handler from executing the job done callback 5251*a33c4f7bSJames Smart * and continue processing to abort the outstanding the command. 5252*a33c4f7bSJames Smart */ 5253f1c3b0fcSJames Smart 52544cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 52554cc0e56eSJames Smart dd_data = (struct bsg_job_data *)job->dd_data; 5256*a33c4f7bSJames Smart if (dd_data) { 5257*a33c4f7bSJames Smart dd_data->set_job = NULL; 5258*a33c4f7bSJames Smart job->dd_data = NULL; 5259*a33c4f7bSJames Smart } else { 52604cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 5261*a33c4f7bSJames Smart return -EAGAIN; 52624cc0e56eSJames Smart } 52634cc0e56eSJames Smart 52644cc0e56eSJames Smart switch (dd_data->type) { 52654cc0e56eSJames Smart case TYPE_IOCB: 5266*a33c4f7bSJames Smart /* Check to see if IOCB was issued to the port or not. If not, 5267*a33c4f7bSJames Smart * remove it from the txq queue and call cancel iocbs. 5268*a33c4f7bSJames Smart * Otherwise, call abort iotag 5269*a33c4f7bSJames Smart */ 5270*a33c4f7bSJames Smart 5271*a33c4f7bSJames Smart cmdiocb = dd_data->context_un.iocb.cmdiocbq; 52724cc0e56eSJames Smart spin_lock_irq(&phba->hbalock); 5273*a33c4f7bSJames Smart list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq, 5274*a33c4f7bSJames Smart list) { 5275*a33c4f7bSJames Smart if (check_iocb == cmdiocb) { 5276*a33c4f7bSJames Smart list_move_tail(&check_iocb->list, &completions); 5277*a33c4f7bSJames Smart break; 5278*a33c4f7bSJames Smart } 5279*a33c4f7bSJames Smart } 5280*a33c4f7bSJames Smart if (list_empty(&completions)) 5281f1c3b0fcSJames Smart lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); 52824cc0e56eSJames Smart spin_unlock_irq(&phba->hbalock); 5283*a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 5284*a33c4f7bSJames Smart if (!list_empty(&completions)) { 5285*a33c4f7bSJames Smart lpfc_sli_cancel_iocbs(phba, &completions, 5286*a33c4f7bSJames Smart IOSTAT_LOCAL_REJECT, 5287*a33c4f7bSJames Smart IOERR_SLI_ABORTED); 5288*a33c4f7bSJames Smart } 52894cc0e56eSJames Smart break; 5290*a33c4f7bSJames Smart 52914cc0e56eSJames Smart case TYPE_EVT: 52924cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 52934cc0e56eSJames Smart break; 5294*a33c4f7bSJames Smart 52953b5dd52aSJames Smart case TYPE_MBOX: 5296*a33c4f7bSJames Smart /* Update the ext buf ctx state if needed */ 5297*a33c4f7bSJames Smart 52987ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_PORT) 52997ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_ABTS; 5300*a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 53013b5dd52aSJames Smart break; 5302e2aed29fSJames Smart case TYPE_MENLO: 5303*a33c4f7bSJames Smart /* Check to see if IOCB was issued to the port or not. If not, 5304*a33c4f7bSJames Smart * remove it from the txq queue and call cancel iocbs. 5305*a33c4f7bSJames Smart * Otherwise, call abort iotag. 5306*a33c4f7bSJames Smart */ 5307*a33c4f7bSJames Smart 5308*a33c4f7bSJames Smart cmdiocb = dd_data->context_un.menlo.cmdiocbq; 5309e2aed29fSJames Smart spin_lock_irq(&phba->hbalock); 5310*a33c4f7bSJames Smart list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq, 5311*a33c4f7bSJames Smart list) { 5312*a33c4f7bSJames Smart if (check_iocb == cmdiocb) { 5313*a33c4f7bSJames Smart list_move_tail(&check_iocb->list, &completions); 5314*a33c4f7bSJames Smart break; 5315*a33c4f7bSJames Smart } 5316*a33c4f7bSJames Smart } 5317*a33c4f7bSJames Smart if (list_empty(&completions)) 5318e2aed29fSJames Smart lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); 5319e2aed29fSJames Smart spin_unlock_irq(&phba->hbalock); 5320*a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 5321*a33c4f7bSJames Smart if (!list_empty(&completions)) { 5322*a33c4f7bSJames Smart lpfc_sli_cancel_iocbs(phba, &completions, 5323*a33c4f7bSJames Smart IOSTAT_LOCAL_REJECT, 5324*a33c4f7bSJames Smart IOERR_SLI_ABORTED); 5325*a33c4f7bSJames Smart } 5326e2aed29fSJames Smart break; 53274cc0e56eSJames Smart default: 53284cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 53294cc0e56eSJames Smart break; 53304cc0e56eSJames Smart } 5331f1c3b0fcSJames Smart 53324cc0e56eSJames Smart /* scsi transport fc fc_bsg_job_timeout expects a zero return code, 53334cc0e56eSJames Smart * otherwise an error message will be displayed on the console 53344cc0e56eSJames Smart * so always return success (zero) 53354cc0e56eSJames Smart */ 5336*a33c4f7bSJames Smart return rc; 5337f1c3b0fcSJames Smart } 5338