1f1c3b0fcSJames Smart /******************************************************************* 2f1c3b0fcSJames Smart * This file is part of the Emulex Linux Device Driver for * 3f1c3b0fcSJames Smart * Fibre Channel Host Bus Adapters. * 4d080abe0SJames Smart * Copyright (C) 2017 Broadcom. All Rights Reserved. The term * 5d080abe0SJames Smart * “Broadcom” refers to Broadcom Limited and/or its subsidiaries. * 6f25e8e79SJames Smart * Copyright (C) 2009-2015 Emulex. All rights reserved. * 7f1c3b0fcSJames Smart * EMULEX and SLI are trademarks of Emulex. * 8d080abe0SJames Smart * www.broadcom.com * 9f1c3b0fcSJames Smart * * 10f1c3b0fcSJames Smart * This program is free software; you can redistribute it and/or * 11f1c3b0fcSJames Smart * modify it under the terms of version 2 of the GNU General * 12f1c3b0fcSJames Smart * Public License as published by the Free Software Foundation. * 13f1c3b0fcSJames Smart * This program is distributed in the hope that it will be useful. * 14f1c3b0fcSJames Smart * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * 15f1c3b0fcSJames Smart * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * 16f1c3b0fcSJames Smart * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * 17f1c3b0fcSJames Smart * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * 18f1c3b0fcSJames Smart * TO BE LEGALLY INVALID. See the GNU General Public License for * 19f1c3b0fcSJames Smart * more details, a copy of which can be found in the file COPYING * 20f1c3b0fcSJames Smart * included with this package. * 21f1c3b0fcSJames Smart *******************************************************************/ 22f1c3b0fcSJames Smart 23f1c3b0fcSJames Smart #include <linux/interrupt.h> 24f1c3b0fcSJames Smart #include <linux/mempool.h> 25f1c3b0fcSJames Smart #include <linux/pci.h> 265a0e3ad6STejun Heo #include <linux/slab.h> 27277e76f1SJames Smart #include <linux/delay.h> 287ad20aa9SJames Smart #include <linux/list.h> 29eb340948SJohannes Thumshirn #include <linux/bsg-lib.h> 30f1c3b0fcSJames Smart 31f1c3b0fcSJames Smart #include <scsi/scsi.h> 32f1c3b0fcSJames Smart #include <scsi/scsi_host.h> 33f1c3b0fcSJames Smart #include <scsi/scsi_transport_fc.h> 34f1c3b0fcSJames Smart #include <scsi/scsi_bsg_fc.h> 356a9c52cfSJames Smart #include <scsi/fc/fc_fs.h> 36f1c3b0fcSJames Smart 37f1c3b0fcSJames Smart #include "lpfc_hw4.h" 38f1c3b0fcSJames Smart #include "lpfc_hw.h" 39f1c3b0fcSJames Smart #include "lpfc_sli.h" 40f1c3b0fcSJames Smart #include "lpfc_sli4.h" 41f1c3b0fcSJames Smart #include "lpfc_nl.h" 424fede78fSJames Smart #include "lpfc_bsg.h" 43f1c3b0fcSJames Smart #include "lpfc_disc.h" 44f1c3b0fcSJames Smart #include "lpfc_scsi.h" 45f1c3b0fcSJames Smart #include "lpfc.h" 46f1c3b0fcSJames Smart #include "lpfc_logmsg.h" 47f1c3b0fcSJames Smart #include "lpfc_crtn.h" 48b76f2dc9SJames Smart #include "lpfc_debugfs.h" 49f1c3b0fcSJames Smart #include "lpfc_vport.h" 50f1c3b0fcSJames Smart #include "lpfc_version.h" 51f1c3b0fcSJames Smart 524cc0e56eSJames Smart struct lpfc_bsg_event { 534cc0e56eSJames Smart struct list_head node; 544cc0e56eSJames Smart struct kref kref; 554cc0e56eSJames Smart wait_queue_head_t wq; 564cc0e56eSJames Smart 574cc0e56eSJames Smart /* Event type and waiter identifiers */ 584cc0e56eSJames Smart uint32_t type_mask; 594cc0e56eSJames Smart uint32_t req_id; 604cc0e56eSJames Smart uint32_t reg_id; 614cc0e56eSJames Smart 624cc0e56eSJames Smart /* next two flags are here for the auto-delete logic */ 634cc0e56eSJames Smart unsigned long wait_time_stamp; 644cc0e56eSJames Smart int waiting; 654cc0e56eSJames Smart 664cc0e56eSJames Smart /* seen and not seen events */ 674cc0e56eSJames Smart struct list_head events_to_get; 684cc0e56eSJames Smart struct list_head events_to_see; 694cc0e56eSJames Smart 70a33c4f7bSJames Smart /* driver data associated with the job */ 71a33c4f7bSJames Smart void *dd_data; 724cc0e56eSJames Smart }; 734cc0e56eSJames Smart 744cc0e56eSJames Smart struct lpfc_bsg_iocb { 754cc0e56eSJames Smart struct lpfc_iocbq *cmdiocbq; 76a33c4f7bSJames Smart struct lpfc_dmabuf *rmp; 774cc0e56eSJames Smart struct lpfc_nodelist *ndlp; 784cc0e56eSJames Smart }; 794cc0e56eSJames Smart 803b5dd52aSJames Smart struct lpfc_bsg_mbox { 813b5dd52aSJames Smart LPFC_MBOXQ_t *pmboxq; 823b5dd52aSJames Smart MAILBOX_t *mb; 837ad20aa9SJames Smart struct lpfc_dmabuf *dmabuffers; /* for BIU diags */ 847a470277SJames Smart uint8_t *ext; /* extended mailbox data */ 857a470277SJames Smart uint32_t mbOffset; /* from app */ 867a470277SJames Smart uint32_t inExtWLen; /* from app */ 87c7495937SJames Smart uint32_t outExtWLen; /* from app */ 883b5dd52aSJames Smart }; 893b5dd52aSJames Smart 90e2aed29fSJames Smart #define MENLO_DID 0x0000FC0E 91e2aed29fSJames Smart 92e2aed29fSJames Smart struct lpfc_bsg_menlo { 93e2aed29fSJames Smart struct lpfc_iocbq *cmdiocbq; 94a33c4f7bSJames Smart struct lpfc_dmabuf *rmp; 95e2aed29fSJames Smart }; 96e2aed29fSJames Smart 974cc0e56eSJames Smart #define TYPE_EVT 1 984cc0e56eSJames Smart #define TYPE_IOCB 2 993b5dd52aSJames Smart #define TYPE_MBOX 3 100e2aed29fSJames Smart #define TYPE_MENLO 4 1014cc0e56eSJames Smart struct bsg_job_data { 1024cc0e56eSJames Smart uint32_t type; 10375cc8cfcSJohannes Thumshirn struct bsg_job *set_job; /* job waiting for this iocb to finish */ 1044cc0e56eSJames Smart union { 1054cc0e56eSJames Smart struct lpfc_bsg_event *evt; 1064cc0e56eSJames Smart struct lpfc_bsg_iocb iocb; 1073b5dd52aSJames Smart struct lpfc_bsg_mbox mbox; 108e2aed29fSJames Smart struct lpfc_bsg_menlo menlo; 1094cc0e56eSJames Smart } context_un; 1104cc0e56eSJames Smart }; 1114cc0e56eSJames Smart 1124cc0e56eSJames Smart struct event_data { 1134cc0e56eSJames Smart struct list_head node; 1144cc0e56eSJames Smart uint32_t type; 1154cc0e56eSJames Smart uint32_t immed_dat; 1164cc0e56eSJames Smart void *data; 1174cc0e56eSJames Smart uint32_t len; 1184cc0e56eSJames Smart }; 1194cc0e56eSJames Smart 1203b5dd52aSJames Smart #define BUF_SZ_4K 4096 1214cc0e56eSJames Smart #define SLI_CT_ELX_LOOPBACK 0x10 1224cc0e56eSJames Smart 1234cc0e56eSJames Smart enum ELX_LOOPBACK_CMD { 1244cc0e56eSJames Smart ELX_LOOPBACK_XRI_SETUP, 1254cc0e56eSJames Smart ELX_LOOPBACK_DATA, 1264cc0e56eSJames Smart }; 1274cc0e56eSJames Smart 1283b5dd52aSJames Smart #define ELX_LOOPBACK_HEADER_SZ \ 1293b5dd52aSJames Smart (size_t)(&((struct lpfc_sli_ct_request *)NULL)->un) 1303b5dd52aSJames Smart 1314cc0e56eSJames Smart struct lpfc_dmabufext { 1324cc0e56eSJames Smart struct lpfc_dmabuf dma; 1334cc0e56eSJames Smart uint32_t size; 1344cc0e56eSJames Smart uint32_t flag; 1354cc0e56eSJames Smart }; 1364cc0e56eSJames Smart 137a33c4f7bSJames Smart static void 138a33c4f7bSJames Smart lpfc_free_bsg_buffers(struct lpfc_hba *phba, struct lpfc_dmabuf *mlist) 139a33c4f7bSJames Smart { 140a33c4f7bSJames Smart struct lpfc_dmabuf *mlast, *next_mlast; 141a33c4f7bSJames Smart 142a33c4f7bSJames Smart if (mlist) { 143a33c4f7bSJames Smart list_for_each_entry_safe(mlast, next_mlast, &mlist->list, 144a33c4f7bSJames Smart list) { 145a33c4f7bSJames Smart lpfc_mbuf_free(phba, mlast->virt, mlast->phys); 146a33c4f7bSJames Smart list_del(&mlast->list); 147a33c4f7bSJames Smart kfree(mlast); 148a33c4f7bSJames Smart } 149a33c4f7bSJames Smart lpfc_mbuf_free(phba, mlist->virt, mlist->phys); 150a33c4f7bSJames Smart kfree(mlist); 151a33c4f7bSJames Smart } 152a33c4f7bSJames Smart return; 153a33c4f7bSJames Smart } 154a33c4f7bSJames Smart 155a33c4f7bSJames Smart static struct lpfc_dmabuf * 156a33c4f7bSJames Smart lpfc_alloc_bsg_buffers(struct lpfc_hba *phba, unsigned int size, 157a33c4f7bSJames Smart int outbound_buffers, struct ulp_bde64 *bpl, 158a33c4f7bSJames Smart int *bpl_entries) 159a33c4f7bSJames Smart { 160a33c4f7bSJames Smart struct lpfc_dmabuf *mlist = NULL; 161a33c4f7bSJames Smart struct lpfc_dmabuf *mp; 162a33c4f7bSJames Smart unsigned int bytes_left = size; 163a33c4f7bSJames Smart 164a33c4f7bSJames Smart /* Verify we can support the size specified */ 165a33c4f7bSJames Smart if (!size || (size > (*bpl_entries * LPFC_BPL_SIZE))) 166a33c4f7bSJames Smart return NULL; 167a33c4f7bSJames Smart 168a33c4f7bSJames Smart /* Determine the number of dma buffers to allocate */ 169a33c4f7bSJames Smart *bpl_entries = (size % LPFC_BPL_SIZE ? size/LPFC_BPL_SIZE + 1 : 170a33c4f7bSJames Smart size/LPFC_BPL_SIZE); 171a33c4f7bSJames Smart 172a33c4f7bSJames Smart /* Allocate dma buffer and place in BPL passed */ 173a33c4f7bSJames Smart while (bytes_left) { 174a33c4f7bSJames Smart /* Allocate dma buffer */ 175a33c4f7bSJames Smart mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 176a33c4f7bSJames Smart if (!mp) { 177a33c4f7bSJames Smart if (mlist) 178a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, mlist); 179a33c4f7bSJames Smart return NULL; 180a33c4f7bSJames Smart } 181a33c4f7bSJames Smart 182a33c4f7bSJames Smart INIT_LIST_HEAD(&mp->list); 183a33c4f7bSJames Smart mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys)); 184a33c4f7bSJames Smart 185a33c4f7bSJames Smart if (!mp->virt) { 186a33c4f7bSJames Smart kfree(mp); 187a33c4f7bSJames Smart if (mlist) 188a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, mlist); 189a33c4f7bSJames Smart return NULL; 190a33c4f7bSJames Smart } 191a33c4f7bSJames Smart 192a33c4f7bSJames Smart /* Queue it to a linked list */ 193a33c4f7bSJames Smart if (!mlist) 194a33c4f7bSJames Smart mlist = mp; 195a33c4f7bSJames Smart else 196a33c4f7bSJames Smart list_add_tail(&mp->list, &mlist->list); 197a33c4f7bSJames Smart 198a33c4f7bSJames Smart /* Add buffer to buffer pointer list */ 199a33c4f7bSJames Smart if (outbound_buffers) 200a33c4f7bSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; 201a33c4f7bSJames Smart else 202a33c4f7bSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; 203a33c4f7bSJames Smart bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys)); 204a33c4f7bSJames Smart bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys)); 205a33c4f7bSJames Smart bpl->tus.f.bdeSize = (uint16_t) 206a33c4f7bSJames Smart (bytes_left >= LPFC_BPL_SIZE ? LPFC_BPL_SIZE : 207a33c4f7bSJames Smart bytes_left); 208a33c4f7bSJames Smart bytes_left -= bpl->tus.f.bdeSize; 209a33c4f7bSJames Smart bpl->tus.w = le32_to_cpu(bpl->tus.w); 210a33c4f7bSJames Smart bpl++; 211a33c4f7bSJames Smart } 212a33c4f7bSJames Smart return mlist; 213a33c4f7bSJames Smart } 214a33c4f7bSJames Smart 215a33c4f7bSJames Smart static unsigned int 216a33c4f7bSJames Smart lpfc_bsg_copy_data(struct lpfc_dmabuf *dma_buffers, 217eb340948SJohannes Thumshirn struct bsg_buffer *bsg_buffers, 218a33c4f7bSJames Smart unsigned int bytes_to_transfer, int to_buffers) 219a33c4f7bSJames Smart { 220a33c4f7bSJames Smart 221a33c4f7bSJames Smart struct lpfc_dmabuf *mp; 222a33c4f7bSJames Smart unsigned int transfer_bytes, bytes_copied = 0; 223a33c4f7bSJames Smart unsigned int sg_offset, dma_offset; 224a33c4f7bSJames Smart unsigned char *dma_address, *sg_address; 225a33c4f7bSJames Smart LIST_HEAD(temp_list); 226d5ce53b7SJames Smart struct sg_mapping_iter miter; 227d5ce53b7SJames Smart unsigned long flags; 228d5ce53b7SJames Smart unsigned int sg_flags = SG_MITER_ATOMIC; 229d5ce53b7SJames Smart bool sg_valid; 230a33c4f7bSJames Smart 231a33c4f7bSJames Smart list_splice_init(&dma_buffers->list, &temp_list); 232a33c4f7bSJames Smart list_add(&dma_buffers->list, &temp_list); 233a33c4f7bSJames Smart sg_offset = 0; 234d5ce53b7SJames Smart if (to_buffers) 235d5ce53b7SJames Smart sg_flags |= SG_MITER_FROM_SG; 236d5ce53b7SJames Smart else 237d5ce53b7SJames Smart sg_flags |= SG_MITER_TO_SG; 238d5ce53b7SJames Smart sg_miter_start(&miter, bsg_buffers->sg_list, bsg_buffers->sg_cnt, 239d5ce53b7SJames Smart sg_flags); 240d5ce53b7SJames Smart local_irq_save(flags); 241d5ce53b7SJames Smart sg_valid = sg_miter_next(&miter); 242a33c4f7bSJames Smart list_for_each_entry(mp, &temp_list, list) { 243a33c4f7bSJames Smart dma_offset = 0; 244d5ce53b7SJames Smart while (bytes_to_transfer && sg_valid && 245a33c4f7bSJames Smart (dma_offset < LPFC_BPL_SIZE)) { 246a33c4f7bSJames Smart dma_address = mp->virt + dma_offset; 247a33c4f7bSJames Smart if (sg_offset) { 248a33c4f7bSJames Smart /* Continue previous partial transfer of sg */ 249d5ce53b7SJames Smart sg_address = miter.addr + sg_offset; 250d5ce53b7SJames Smart transfer_bytes = miter.length - sg_offset; 251a33c4f7bSJames Smart } else { 252d5ce53b7SJames Smart sg_address = miter.addr; 253d5ce53b7SJames Smart transfer_bytes = miter.length; 254a33c4f7bSJames Smart } 255a33c4f7bSJames Smart if (bytes_to_transfer < transfer_bytes) 256a33c4f7bSJames Smart transfer_bytes = bytes_to_transfer; 257a33c4f7bSJames Smart if (transfer_bytes > (LPFC_BPL_SIZE - dma_offset)) 258a33c4f7bSJames Smart transfer_bytes = LPFC_BPL_SIZE - dma_offset; 259a33c4f7bSJames Smart if (to_buffers) 260a33c4f7bSJames Smart memcpy(dma_address, sg_address, transfer_bytes); 261a33c4f7bSJames Smart else 262a33c4f7bSJames Smart memcpy(sg_address, dma_address, transfer_bytes); 263a33c4f7bSJames Smart dma_offset += transfer_bytes; 264a33c4f7bSJames Smart sg_offset += transfer_bytes; 265a33c4f7bSJames Smart bytes_to_transfer -= transfer_bytes; 266a33c4f7bSJames Smart bytes_copied += transfer_bytes; 267d5ce53b7SJames Smart if (sg_offset >= miter.length) { 268a33c4f7bSJames Smart sg_offset = 0; 269d5ce53b7SJames Smart sg_valid = sg_miter_next(&miter); 270a33c4f7bSJames Smart } 271a33c4f7bSJames Smart } 272a33c4f7bSJames Smart } 273d5ce53b7SJames Smart sg_miter_stop(&miter); 274d5ce53b7SJames Smart local_irq_restore(flags); 275a33c4f7bSJames Smart list_del_init(&dma_buffers->list); 276a33c4f7bSJames Smart list_splice(&temp_list, &dma_buffers->list); 277a33c4f7bSJames Smart return bytes_copied; 278a33c4f7bSJames Smart } 279a33c4f7bSJames Smart 280f1c3b0fcSJames Smart /** 2814cc0e56eSJames Smart * lpfc_bsg_send_mgmt_cmd_cmp - lpfc_bsg_send_mgmt_cmd's completion handler 2824cc0e56eSJames Smart * @phba: Pointer to HBA context object. 2834cc0e56eSJames Smart * @cmdiocbq: Pointer to command iocb. 2844cc0e56eSJames Smart * @rspiocbq: Pointer to response iocb. 2854cc0e56eSJames Smart * 2864cc0e56eSJames Smart * This function is the completion handler for iocbs issued using 2874cc0e56eSJames Smart * lpfc_bsg_send_mgmt_cmd function. This function is called by the 2884cc0e56eSJames Smart * ring event handler function without any lock held. This function 2894cc0e56eSJames Smart * can be called from both worker thread context and interrupt 2904cc0e56eSJames Smart * context. This function also can be called from another thread which 2914cc0e56eSJames Smart * cleans up the SLI layer objects. 2924cc0e56eSJames Smart * This function copies the contents of the response iocb to the 2934cc0e56eSJames Smart * response iocb memory object provided by the caller of 2944cc0e56eSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 2954cc0e56eSJames Smart * sleeps for the iocb completion. 2964cc0e56eSJames Smart **/ 2974cc0e56eSJames Smart static void 2984cc0e56eSJames Smart lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, 2994cc0e56eSJames Smart struct lpfc_iocbq *cmdiocbq, 3004cc0e56eSJames Smart struct lpfc_iocbq *rspiocbq) 3014cc0e56eSJames Smart { 3024cc0e56eSJames Smart struct bsg_job_data *dd_data; 30375cc8cfcSJohannes Thumshirn struct bsg_job *job; 30401e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 3054cc0e56eSJames Smart IOCB_t *rsp; 306a33c4f7bSJames Smart struct lpfc_dmabuf *bmp, *cmp, *rmp; 3074cc0e56eSJames Smart struct lpfc_nodelist *ndlp; 3084cc0e56eSJames Smart struct lpfc_bsg_iocb *iocb; 3094cc0e56eSJames Smart unsigned long flags; 310a33c4f7bSJames Smart unsigned int rsp_size; 3114cc0e56eSJames Smart int rc = 0; 3124cc0e56eSJames Smart 313a33c4f7bSJames Smart dd_data = cmdiocbq->context1; 314a33c4f7bSJames Smart 315a33c4f7bSJames Smart /* Determine if job has been aborted */ 3164cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 317a33c4f7bSJames Smart job = dd_data->set_job; 318a33c4f7bSJames Smart if (job) { 31901e0e15cSJohannes Thumshirn bsg_reply = job->reply; 320a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 321a33c4f7bSJames Smart job->dd_data = NULL; 3224cc0e56eSJames Smart } 323a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 3244cc0e56eSJames Smart 325b5a9b2dfSJames Smart /* Close the timeout handler abort window */ 326b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 3271b8d11abSJames Smart cmdiocbq->iocb_flag &= ~LPFC_IO_CMD_OUTSTANDING; 328b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 329b5a9b2dfSJames Smart 3304cc0e56eSJames Smart iocb = &dd_data->context_un.iocb; 331a33c4f7bSJames Smart ndlp = iocb->ndlp; 332a33c4f7bSJames Smart rmp = iocb->rmp; 333a33c4f7bSJames Smart cmp = cmdiocbq->context2; 334a33c4f7bSJames Smart bmp = cmdiocbq->context3; 3354cc0e56eSJames Smart rsp = &rspiocbq->iocb; 3364cc0e56eSJames Smart 337a33c4f7bSJames Smart /* Copy the completed data or set the error status */ 3384cc0e56eSJames Smart 339a33c4f7bSJames Smart if (job) { 3404cc0e56eSJames Smart if (rsp->ulpStatus) { 3414cc0e56eSJames Smart if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { 342e3d2b802SJames Smart switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) { 3434cc0e56eSJames Smart case IOERR_SEQUENCE_TIMEOUT: 3444cc0e56eSJames Smart rc = -ETIMEDOUT; 3454cc0e56eSJames Smart break; 3464cc0e56eSJames Smart case IOERR_INVALID_RPI: 3474cc0e56eSJames Smart rc = -EFAULT; 3484cc0e56eSJames Smart break; 3494cc0e56eSJames Smart default: 3504cc0e56eSJames Smart rc = -EACCES; 3514cc0e56eSJames Smart break; 3524cc0e56eSJames Smart } 353a33c4f7bSJames Smart } else { 3544cc0e56eSJames Smart rc = -EACCES; 355a33c4f7bSJames Smart } 356a33c4f7bSJames Smart } else { 357a33c4f7bSJames Smart rsp_size = rsp->un.genreq64.bdl.bdeSize; 35801e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 359a33c4f7bSJames Smart lpfc_bsg_copy_data(rmp, &job->reply_payload, 360a33c4f7bSJames Smart rsp_size, 0); 361a33c4f7bSJames Smart } 362a33c4f7bSJames Smart } 3634cc0e56eSJames Smart 364a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 365a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, rmp); 3664cc0e56eSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 367a33c4f7bSJames Smart kfree(bmp); 3684cc0e56eSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 3694cc0e56eSJames Smart lpfc_nlp_put(ndlp); 3704cc0e56eSJames Smart kfree(dd_data); 371a33c4f7bSJames Smart 372a33c4f7bSJames Smart /* Complete the job if the job is still active */ 373a33c4f7bSJames Smart 374a33c4f7bSJames Smart if (job) { 37501e0e15cSJohannes Thumshirn bsg_reply->result = rc; 37606548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 3771abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 378a33c4f7bSJames Smart } 3794cc0e56eSJames Smart return; 3804cc0e56eSJames Smart } 3814cc0e56eSJames Smart 3824cc0e56eSJames Smart /** 3834cc0e56eSJames Smart * lpfc_bsg_send_mgmt_cmd - send a CT command from a bsg request 384f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 3853b5dd52aSJames Smart **/ 386f1c3b0fcSJames Smart static int 38775cc8cfcSJohannes Thumshirn lpfc_bsg_send_mgmt_cmd(struct bsg_job *job) 388f1c3b0fcSJames Smart { 389cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 390f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 3911d69b122SJohannes Thumshirn struct lpfc_rport_data *rdata = fc_bsg_to_rport(job)->dd_data; 392f1c3b0fcSJames Smart struct lpfc_nodelist *ndlp = rdata->pnode; 39301e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 394f1c3b0fcSJames Smart struct ulp_bde64 *bpl = NULL; 395f1c3b0fcSJames Smart uint32_t timeout; 396f1c3b0fcSJames Smart struct lpfc_iocbq *cmdiocbq = NULL; 397f1c3b0fcSJames Smart IOCB_t *cmd; 398a33c4f7bSJames Smart struct lpfc_dmabuf *bmp = NULL, *cmp = NULL, *rmp = NULL; 399f1c3b0fcSJames Smart int request_nseg; 400f1c3b0fcSJames Smart int reply_nseg; 4014cc0e56eSJames Smart struct bsg_job_data *dd_data; 402b5a9b2dfSJames Smart unsigned long flags; 4034cc0e56eSJames Smart uint32_t creg_val; 404f1c3b0fcSJames Smart int rc = 0; 405d439d286SJames Smart int iocb_stat; 406f1c3b0fcSJames Smart 407f1c3b0fcSJames Smart /* in case no data is transferred */ 40801e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 409f1c3b0fcSJames Smart 4104cc0e56eSJames Smart /* allocate our bsg tracking structure */ 4114cc0e56eSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 4124cc0e56eSJames Smart if (!dd_data) { 4134cc0e56eSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 4144cc0e56eSJames Smart "2733 Failed allocation of dd_data\n"); 4154cc0e56eSJames Smart rc = -ENOMEM; 4164cc0e56eSJames Smart goto no_dd_data; 4174cc0e56eSJames Smart } 4184cc0e56eSJames Smart 419f1c3b0fcSJames Smart if (!lpfc_nlp_get(ndlp)) { 4204cc0e56eSJames Smart rc = -ENODEV; 4214cc0e56eSJames Smart goto no_ndlp; 4224cc0e56eSJames Smart } 4234cc0e56eSJames Smart 424f1c3b0fcSJames Smart if (ndlp->nlp_flag & NLP_ELS_SND_MASK) { 425f1c3b0fcSJames Smart rc = -ENODEV; 426a33c4f7bSJames Smart goto free_ndlp; 427f1c3b0fcSJames Smart } 428f1c3b0fcSJames Smart 429f1c3b0fcSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 430f1c3b0fcSJames Smart if (!cmdiocbq) { 431f1c3b0fcSJames Smart rc = -ENOMEM; 432a33c4f7bSJames Smart goto free_ndlp; 433f1c3b0fcSJames Smart } 434f1c3b0fcSJames Smart 4354cc0e56eSJames Smart cmd = &cmdiocbq->iocb; 436a33c4f7bSJames Smart 437a33c4f7bSJames Smart bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 438a33c4f7bSJames Smart if (!bmp) { 439f1c3b0fcSJames Smart rc = -ENOMEM; 440be858b65SJames Smart goto free_cmdiocbq; 441f1c3b0fcSJames Smart } 442a33c4f7bSJames Smart bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); 443a33c4f7bSJames Smart if (!bmp->virt) { 444a33c4f7bSJames Smart rc = -ENOMEM; 445a33c4f7bSJames Smart goto free_bmp; 446f1c3b0fcSJames Smart } 447f1c3b0fcSJames Smart 448a33c4f7bSJames Smart INIT_LIST_HEAD(&bmp->list); 449a33c4f7bSJames Smart 450a33c4f7bSJames Smart bpl = (struct ulp_bde64 *) bmp->virt; 451a33c4f7bSJames Smart request_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64); 452a33c4f7bSJames Smart cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len, 453a33c4f7bSJames Smart 1, bpl, &request_nseg); 454a33c4f7bSJames Smart if (!cmp) { 455a33c4f7bSJames Smart rc = -ENOMEM; 456a33c4f7bSJames Smart goto free_bmp; 457a33c4f7bSJames Smart } 458a33c4f7bSJames Smart lpfc_bsg_copy_data(cmp, &job->request_payload, 459a33c4f7bSJames Smart job->request_payload.payload_len, 1); 460a33c4f7bSJames Smart 461a33c4f7bSJames Smart bpl += request_nseg; 462a33c4f7bSJames Smart reply_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64) - request_nseg; 463a33c4f7bSJames Smart rmp = lpfc_alloc_bsg_buffers(phba, job->reply_payload.payload_len, 0, 464a33c4f7bSJames Smart bpl, &reply_nseg); 465a33c4f7bSJames Smart if (!rmp) { 466a33c4f7bSJames Smart rc = -ENOMEM; 467a33c4f7bSJames Smart goto free_cmp; 468f1c3b0fcSJames Smart } 469f1c3b0fcSJames Smart 470f1c3b0fcSJames Smart cmd->un.genreq64.bdl.ulpIoTag32 = 0; 471f1c3b0fcSJames Smart cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); 472f1c3b0fcSJames Smart cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); 473f1c3b0fcSJames Smart cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 474f1c3b0fcSJames Smart cmd->un.genreq64.bdl.bdeSize = 475f1c3b0fcSJames Smart (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); 476f1c3b0fcSJames Smart cmd->ulpCommand = CMD_GEN_REQUEST64_CR; 477f1c3b0fcSJames Smart cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); 478f1c3b0fcSJames Smart cmd->un.genreq64.w5.hcsw.Dfctl = 0; 4796a9c52cfSJames Smart cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; 4806a9c52cfSJames Smart cmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT; 481f1c3b0fcSJames Smart cmd->ulpBdeCount = 1; 482f1c3b0fcSJames Smart cmd->ulpLe = 1; 483f1c3b0fcSJames Smart cmd->ulpClass = CLASS3; 484f1c3b0fcSJames Smart cmd->ulpContext = ndlp->nlp_rpi; 4856d368e53SJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 4866d368e53SJames Smart cmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; 487f1c3b0fcSJames Smart cmd->ulpOwner = OWN_CHIP; 488f1c3b0fcSJames Smart cmdiocbq->vport = phba->pport; 4894cc0e56eSJames Smart cmdiocbq->context3 = bmp; 490f1c3b0fcSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 491f1c3b0fcSJames Smart timeout = phba->fc_ratov * 2; 4924cc0e56eSJames Smart cmd->ulpTimeout = timeout; 493f1c3b0fcSJames Smart 4944cc0e56eSJames Smart cmdiocbq->iocb_cmpl = lpfc_bsg_send_mgmt_cmd_cmp; 495a33c4f7bSJames Smart cmdiocbq->context1 = dd_data; 496a33c4f7bSJames Smart cmdiocbq->context2 = cmp; 497a33c4f7bSJames Smart cmdiocbq->context3 = bmp; 498d5ce53b7SJames Smart cmdiocbq->context_un.ndlp = ndlp; 4994cc0e56eSJames Smart dd_data->type = TYPE_IOCB; 500a33c4f7bSJames Smart dd_data->set_job = job; 5014cc0e56eSJames Smart dd_data->context_un.iocb.cmdiocbq = cmdiocbq; 502a33c4f7bSJames Smart dd_data->context_un.iocb.ndlp = ndlp; 503a33c4f7bSJames Smart dd_data->context_un.iocb.rmp = rmp; 504a33c4f7bSJames Smart job->dd_data = dd_data; 505f1c3b0fcSJames Smart 5064cc0e56eSJames Smart if (phba->cfg_poll & DISABLE_FCP_RING_INT) { 5079940b97bSJames Smart if (lpfc_readl(phba->HCregaddr, &creg_val)) { 5089940b97bSJames Smart rc = -EIO ; 509a33c4f7bSJames Smart goto free_rmp; 5109940b97bSJames Smart } 5114cc0e56eSJames Smart creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); 5124cc0e56eSJames Smart writel(creg_val, phba->HCregaddr); 5134cc0e56eSJames Smart readl(phba->HCregaddr); /* flush */ 5144cc0e56eSJames Smart } 5154cc0e56eSJames Smart 516d439d286SJames Smart iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); 517b5a9b2dfSJames Smart 518b5a9b2dfSJames Smart if (iocb_stat == IOCB_SUCCESS) { 519b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 520b5a9b2dfSJames Smart /* make sure the I/O had not been completed yet */ 521b5a9b2dfSJames Smart if (cmdiocbq->iocb_flag & LPFC_IO_LIBDFC) { 522b5a9b2dfSJames Smart /* open up abort window to timeout handler */ 5231b8d11abSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_CMD_OUTSTANDING; 524b5a9b2dfSJames Smart } 525b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 5264cc0e56eSJames Smart return 0; /* done for now */ 527b5a9b2dfSJames Smart } else if (iocb_stat == IOCB_BUSY) { 528d439d286SJames Smart rc = -EAGAIN; 529b5a9b2dfSJames Smart } else { 530d439d286SJames Smart rc = -EIO; 531b5a9b2dfSJames Smart } 5322a9bf3d0SJames Smart 5334cc0e56eSJames Smart /* iocb failed so cleanup */ 534b5a9b2dfSJames Smart job->dd_data = NULL; 535f1c3b0fcSJames Smart 536a33c4f7bSJames Smart free_rmp: 537a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, rmp); 538a33c4f7bSJames Smart free_cmp: 539a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 540a33c4f7bSJames Smart free_bmp: 541a33c4f7bSJames Smart if (bmp->virt) 542f1c3b0fcSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 543a33c4f7bSJames Smart kfree(bmp); 544f1c3b0fcSJames Smart free_cmdiocbq: 545f1c3b0fcSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 5464cc0e56eSJames Smart free_ndlp: 547f1c3b0fcSJames Smart lpfc_nlp_put(ndlp); 5484cc0e56eSJames Smart no_ndlp: 5494cc0e56eSJames Smart kfree(dd_data); 5504cc0e56eSJames Smart no_dd_data: 551f1c3b0fcSJames Smart /* make error code available to userspace */ 55201e0e15cSJohannes Thumshirn bsg_reply->result = rc; 5534cc0e56eSJames Smart job->dd_data = NULL; 5544cc0e56eSJames Smart return rc; 5554cc0e56eSJames Smart } 5564cc0e56eSJames Smart 5574cc0e56eSJames Smart /** 5584cc0e56eSJames Smart * lpfc_bsg_rport_els_cmp - lpfc_bsg_rport_els's completion handler 5594cc0e56eSJames Smart * @phba: Pointer to HBA context object. 5604cc0e56eSJames Smart * @cmdiocbq: Pointer to command iocb. 5614cc0e56eSJames Smart * @rspiocbq: Pointer to response iocb. 5624cc0e56eSJames Smart * 5634cc0e56eSJames Smart * This function is the completion handler for iocbs issued using 5644cc0e56eSJames Smart * lpfc_bsg_rport_els_cmp function. This function is called by the 5654cc0e56eSJames Smart * ring event handler function without any lock held. This function 5664cc0e56eSJames Smart * can be called from both worker thread context and interrupt 5674cc0e56eSJames Smart * context. This function also can be called from other thread which 5684cc0e56eSJames Smart * cleans up the SLI layer objects. 5693b5dd52aSJames Smart * This function copies the contents of the response iocb to the 5704cc0e56eSJames Smart * response iocb memory object provided by the caller of 5714cc0e56eSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 5724cc0e56eSJames Smart * sleeps for the iocb completion. 5734cc0e56eSJames Smart **/ 5744cc0e56eSJames Smart static void 5754cc0e56eSJames Smart lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba, 5764cc0e56eSJames Smart struct lpfc_iocbq *cmdiocbq, 5774cc0e56eSJames Smart struct lpfc_iocbq *rspiocbq) 5784cc0e56eSJames Smart { 5794cc0e56eSJames Smart struct bsg_job_data *dd_data; 58075cc8cfcSJohannes Thumshirn struct bsg_job *job; 58101e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 5824cc0e56eSJames Smart IOCB_t *rsp; 5834cc0e56eSJames Smart struct lpfc_nodelist *ndlp; 584a33c4f7bSJames Smart struct lpfc_dmabuf *pcmd = NULL, *prsp = NULL; 5854cc0e56eSJames Smart struct fc_bsg_ctels_reply *els_reply; 5864cc0e56eSJames Smart uint8_t *rjt_data; 5874cc0e56eSJames Smart unsigned long flags; 588a33c4f7bSJames Smart unsigned int rsp_size; 5894cc0e56eSJames Smart int rc = 0; 5904cc0e56eSJames Smart 5914cc0e56eSJames Smart dd_data = cmdiocbq->context1; 5924cc0e56eSJames Smart ndlp = dd_data->context_un.iocb.ndlp; 593a33c4f7bSJames Smart cmdiocbq->context1 = ndlp; 5944cc0e56eSJames Smart 595a33c4f7bSJames Smart /* Determine if job has been aborted */ 596a33c4f7bSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 597a33c4f7bSJames Smart job = dd_data->set_job; 598a33c4f7bSJames Smart if (job) { 59901e0e15cSJohannes Thumshirn bsg_reply = job->reply; 600a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 601a33c4f7bSJames Smart job->dd_data = NULL; 602a33c4f7bSJames Smart } 603a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 6044cc0e56eSJames Smart 605b5a9b2dfSJames Smart /* Close the timeout handler abort window */ 606b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 6071b8d11abSJames Smart cmdiocbq->iocb_flag &= ~LPFC_IO_CMD_OUTSTANDING; 608b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 609b5a9b2dfSJames Smart 610a33c4f7bSJames Smart rsp = &rspiocbq->iocb; 611a33c4f7bSJames Smart pcmd = (struct lpfc_dmabuf *)cmdiocbq->context2; 612a33c4f7bSJames Smart prsp = (struct lpfc_dmabuf *)pcmd->list.next; 613a33c4f7bSJames Smart 614a33c4f7bSJames Smart /* Copy the completed job data or determine the job status if job is 615a33c4f7bSJames Smart * still active 616a33c4f7bSJames Smart */ 617a33c4f7bSJames Smart 618a33c4f7bSJames Smart if (job) { 619a33c4f7bSJames Smart if (rsp->ulpStatus == IOSTAT_SUCCESS) { 620a33c4f7bSJames Smart rsp_size = rsp->un.elsreq64.bdl.bdeSize; 62101e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 622a33c4f7bSJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 623a33c4f7bSJames Smart job->reply_payload.sg_cnt, 624a33c4f7bSJames Smart prsp->virt, 625a33c4f7bSJames Smart rsp_size); 626a33c4f7bSJames Smart } else if (rsp->ulpStatus == IOSTAT_LS_RJT) { 62701e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 6284cc0e56eSJames Smart sizeof(struct fc_bsg_ctels_reply); 6294cc0e56eSJames Smart /* LS_RJT data returned in word 4 */ 6304cc0e56eSJames Smart rjt_data = (uint8_t *)&rsp->un.ulpWord[4]; 63101e0e15cSJohannes Thumshirn els_reply = &bsg_reply->reply_data.ctels_reply; 6324cc0e56eSJames Smart els_reply->status = FC_CTELS_STATUS_REJECT; 6334cc0e56eSJames Smart els_reply->rjt_data.action = rjt_data[3]; 6344cc0e56eSJames Smart els_reply->rjt_data.reason_code = rjt_data[2]; 6354cc0e56eSJames Smart els_reply->rjt_data.reason_explanation = rjt_data[1]; 6364cc0e56eSJames Smart els_reply->rjt_data.vendor_unique = rjt_data[0]; 637a33c4f7bSJames Smart } else { 6384cc0e56eSJames Smart rc = -EIO; 639a33c4f7bSJames Smart } 640a33c4f7bSJames Smart } 6414cc0e56eSJames Smart 6424cc0e56eSJames Smart lpfc_nlp_put(ndlp); 643a33c4f7bSJames Smart lpfc_els_free_iocb(phba, cmdiocbq); 6444cc0e56eSJames Smart kfree(dd_data); 645a33c4f7bSJames Smart 646a33c4f7bSJames Smart /* Complete the job if the job is still active */ 647a33c4f7bSJames Smart 648a33c4f7bSJames Smart if (job) { 64901e0e15cSJohannes Thumshirn bsg_reply->result = rc; 65006548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 6511abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 652a33c4f7bSJames Smart } 6534cc0e56eSJames Smart return; 654f1c3b0fcSJames Smart } 655f1c3b0fcSJames Smart 656f1c3b0fcSJames Smart /** 657f1c3b0fcSJames Smart * lpfc_bsg_rport_els - send an ELS command from a bsg request 658f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 6593b5dd52aSJames Smart **/ 660f1c3b0fcSJames Smart static int 66175cc8cfcSJohannes Thumshirn lpfc_bsg_rport_els(struct bsg_job *job) 662f1c3b0fcSJames Smart { 663cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 664f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 6651d69b122SJohannes Thumshirn struct lpfc_rport_data *rdata = fc_bsg_to_rport(job)->dd_data; 666f1c3b0fcSJames Smart struct lpfc_nodelist *ndlp = rdata->pnode; 66701e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 66801e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 669f1c3b0fcSJames Smart uint32_t elscmd; 670f1c3b0fcSJames Smart uint32_t cmdsize; 671f1c3b0fcSJames Smart struct lpfc_iocbq *cmdiocbq; 672f1c3b0fcSJames Smart uint16_t rpi = 0; 6734cc0e56eSJames Smart struct bsg_job_data *dd_data; 674b5a9b2dfSJames Smart unsigned long flags; 6754cc0e56eSJames Smart uint32_t creg_val; 676f1c3b0fcSJames Smart int rc = 0; 677f1c3b0fcSJames Smart 678f1c3b0fcSJames Smart /* in case no data is transferred */ 67901e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 680f1c3b0fcSJames Smart 681a33c4f7bSJames Smart /* verify the els command is not greater than the 682a33c4f7bSJames Smart * maximum ELS transfer size. 683a33c4f7bSJames Smart */ 684a33c4f7bSJames Smart 685a33c4f7bSJames Smart if (job->request_payload.payload_len > FCELSSIZE) { 686a33c4f7bSJames Smart rc = -EINVAL; 687a33c4f7bSJames Smart goto no_dd_data; 688a33c4f7bSJames Smart } 689a33c4f7bSJames Smart 6904cc0e56eSJames Smart /* allocate our bsg tracking structure */ 6914cc0e56eSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 6924cc0e56eSJames Smart if (!dd_data) { 6934cc0e56eSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 6944cc0e56eSJames Smart "2735 Failed allocation of dd_data\n"); 6954cc0e56eSJames Smart rc = -ENOMEM; 6964cc0e56eSJames Smart goto no_dd_data; 6974cc0e56eSJames Smart } 6984cc0e56eSJames Smart 69901e0e15cSJohannes Thumshirn elscmd = bsg_request->rqst_data.r_els.els_code; 700a33c4f7bSJames Smart cmdsize = job->request_payload.payload_len; 701a33c4f7bSJames Smart 702f1c3b0fcSJames Smart if (!lpfc_nlp_get(ndlp)) { 703f1c3b0fcSJames Smart rc = -ENODEV; 7044cc0e56eSJames Smart goto free_dd_data; 705f1c3b0fcSJames Smart } 706f1c3b0fcSJames Smart 707a33c4f7bSJames Smart /* We will use the allocated dma buffers by prep els iocb for command 708a33c4f7bSJames Smart * and response to ensure if the job times out and the request is freed, 709a33c4f7bSJames Smart * we won't be dma into memory that is no longer allocated to for the 710a33c4f7bSJames Smart * request. 711a33c4f7bSJames Smart */ 712f1c3b0fcSJames Smart 7134cc0e56eSJames Smart cmdiocbq = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, 714f1c3b0fcSJames Smart ndlp->nlp_DID, elscmd); 715f1c3b0fcSJames Smart if (!cmdiocbq) { 7164cc0e56eSJames Smart rc = -EIO; 717a33c4f7bSJames Smart goto release_ndlp; 718f1c3b0fcSJames Smart } 719f1c3b0fcSJames Smart 720a33c4f7bSJames Smart rpi = ndlp->nlp_rpi; 721f1c3b0fcSJames Smart 722a33c4f7bSJames Smart /* Transfer the request payload to allocated command dma buffer */ 723f1c3b0fcSJames Smart 724a33c4f7bSJames Smart sg_copy_to_buffer(job->request_payload.sg_list, 725a33c4f7bSJames Smart job->request_payload.sg_cnt, 726a33c4f7bSJames Smart ((struct lpfc_dmabuf *)cmdiocbq->context2)->virt, 727a33c4f7bSJames Smart cmdsize); 728f1c3b0fcSJames Smart 7293ef6d24cSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 7303ef6d24cSJames Smart cmdiocbq->iocb.ulpContext = phba->sli4_hba.rpi_ids[rpi]; 7313ef6d24cSJames Smart else 732f1c3b0fcSJames Smart cmdiocbq->iocb.ulpContext = rpi; 733f1c3b0fcSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 7344cc0e56eSJames Smart cmdiocbq->context1 = dd_data; 73593d1379eSJames Smart cmdiocbq->context_un.ndlp = ndlp; 736a33c4f7bSJames Smart cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp; 7374cc0e56eSJames Smart dd_data->type = TYPE_IOCB; 738a33c4f7bSJames Smart dd_data->set_job = job; 7394cc0e56eSJames Smart dd_data->context_un.iocb.cmdiocbq = cmdiocbq; 7404cc0e56eSJames Smart dd_data->context_un.iocb.ndlp = ndlp; 741a33c4f7bSJames Smart dd_data->context_un.iocb.rmp = NULL; 742a33c4f7bSJames Smart job->dd_data = dd_data; 743f1c3b0fcSJames Smart 7444cc0e56eSJames Smart if (phba->cfg_poll & DISABLE_FCP_RING_INT) { 7459940b97bSJames Smart if (lpfc_readl(phba->HCregaddr, &creg_val)) { 7469940b97bSJames Smart rc = -EIO; 7479940b97bSJames Smart goto linkdown_err; 7489940b97bSJames Smart } 7494cc0e56eSJames Smart creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); 7504cc0e56eSJames Smart writel(creg_val, phba->HCregaddr); 7514cc0e56eSJames Smart readl(phba->HCregaddr); /* flush */ 7524cc0e56eSJames Smart } 753a33c4f7bSJames Smart 7544cc0e56eSJames Smart rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); 755a33c4f7bSJames Smart 756b5a9b2dfSJames Smart if (rc == IOCB_SUCCESS) { 757b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 758b5a9b2dfSJames Smart /* make sure the I/O had not been completed/released */ 759b5a9b2dfSJames Smart if (cmdiocbq->iocb_flag & LPFC_IO_LIBDFC) { 760b5a9b2dfSJames Smart /* open up abort window to timeout handler */ 7611b8d11abSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_CMD_OUTSTANDING; 762b5a9b2dfSJames Smart } 763b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 7644cc0e56eSJames Smart return 0; /* done for now */ 765b5a9b2dfSJames Smart } else if (rc == IOCB_BUSY) { 766d439d286SJames Smart rc = -EAGAIN; 767b5a9b2dfSJames Smart } else { 768d439d286SJames Smart rc = -EIO; 769b5a9b2dfSJames Smart } 770b5a9b2dfSJames Smart 771b5a9b2dfSJames Smart /* iocb failed so cleanup */ 772b5a9b2dfSJames Smart job->dd_data = NULL; 7734cc0e56eSJames Smart 7749940b97bSJames Smart linkdown_err: 775a33c4f7bSJames Smart cmdiocbq->context1 = ndlp; 776a33c4f7bSJames Smart lpfc_els_free_iocb(phba, cmdiocbq); 777f1c3b0fcSJames Smart 778a33c4f7bSJames Smart release_ndlp: 779a33c4f7bSJames Smart lpfc_nlp_put(ndlp); 780f1c3b0fcSJames Smart 7814cc0e56eSJames Smart free_dd_data: 7824cc0e56eSJames Smart kfree(dd_data); 7834cc0e56eSJames Smart 7844cc0e56eSJames Smart no_dd_data: 785f1c3b0fcSJames Smart /* make error code available to userspace */ 78601e0e15cSJohannes Thumshirn bsg_reply->result = rc; 7874cc0e56eSJames Smart job->dd_data = NULL; 7884cc0e56eSJames Smart return rc; 789f1c3b0fcSJames Smart } 790f1c3b0fcSJames Smart 7913b5dd52aSJames Smart /** 7923b5dd52aSJames Smart * lpfc_bsg_event_free - frees an allocated event structure 7933b5dd52aSJames Smart * @kref: Pointer to a kref. 7943b5dd52aSJames Smart * 7953b5dd52aSJames Smart * Called from kref_put. Back cast the kref into an event structure address. 7963b5dd52aSJames Smart * Free any events to get, delete associated nodes, free any events to see, 7973b5dd52aSJames Smart * free any data then free the event itself. 7983b5dd52aSJames Smart **/ 799f1c3b0fcSJames Smart static void 8004cc0e56eSJames Smart lpfc_bsg_event_free(struct kref *kref) 801f1c3b0fcSJames Smart { 8024cc0e56eSJames Smart struct lpfc_bsg_event *evt = container_of(kref, struct lpfc_bsg_event, 8034cc0e56eSJames Smart kref); 804f1c3b0fcSJames Smart struct event_data *ed; 805f1c3b0fcSJames Smart 806f1c3b0fcSJames Smart list_del(&evt->node); 807f1c3b0fcSJames Smart 808f1c3b0fcSJames Smart while (!list_empty(&evt->events_to_get)) { 809f1c3b0fcSJames Smart ed = list_entry(evt->events_to_get.next, typeof(*ed), node); 810f1c3b0fcSJames Smart list_del(&ed->node); 811f1c3b0fcSJames Smart kfree(ed->data); 812f1c3b0fcSJames Smart kfree(ed); 813f1c3b0fcSJames Smart } 814f1c3b0fcSJames Smart 815f1c3b0fcSJames Smart while (!list_empty(&evt->events_to_see)) { 816f1c3b0fcSJames Smart ed = list_entry(evt->events_to_see.next, typeof(*ed), node); 817f1c3b0fcSJames Smart list_del(&ed->node); 818f1c3b0fcSJames Smart kfree(ed->data); 819f1c3b0fcSJames Smart kfree(ed); 820f1c3b0fcSJames Smart } 821f1c3b0fcSJames Smart 822a33c4f7bSJames Smart kfree(evt->dd_data); 823f1c3b0fcSJames Smart kfree(evt); 824f1c3b0fcSJames Smart } 825f1c3b0fcSJames Smart 8263b5dd52aSJames Smart /** 8273b5dd52aSJames Smart * lpfc_bsg_event_ref - increments the kref for an event 8283b5dd52aSJames Smart * @evt: Pointer to an event structure. 8293b5dd52aSJames Smart **/ 830f1c3b0fcSJames Smart static inline void 8314cc0e56eSJames Smart lpfc_bsg_event_ref(struct lpfc_bsg_event *evt) 832f1c3b0fcSJames Smart { 8334cc0e56eSJames Smart kref_get(&evt->kref); 834f1c3b0fcSJames Smart } 835f1c3b0fcSJames Smart 8363b5dd52aSJames Smart /** 8373b5dd52aSJames Smart * lpfc_bsg_event_unref - Uses kref_put to free an event structure 8383b5dd52aSJames Smart * @evt: Pointer to an event structure. 8393b5dd52aSJames Smart **/ 840f1c3b0fcSJames Smart static inline void 8414cc0e56eSJames Smart lpfc_bsg_event_unref(struct lpfc_bsg_event *evt) 842f1c3b0fcSJames Smart { 8434cc0e56eSJames Smart kref_put(&evt->kref, lpfc_bsg_event_free); 844f1c3b0fcSJames Smart } 845f1c3b0fcSJames Smart 8463b5dd52aSJames Smart /** 8473b5dd52aSJames Smart * lpfc_bsg_event_new - allocate and initialize a event structure 8483b5dd52aSJames Smart * @ev_mask: Mask of events. 8493b5dd52aSJames Smart * @ev_reg_id: Event reg id. 8503b5dd52aSJames Smart * @ev_req_id: Event request id. 8513b5dd52aSJames Smart **/ 8524cc0e56eSJames Smart static struct lpfc_bsg_event * 8534cc0e56eSJames Smart lpfc_bsg_event_new(uint32_t ev_mask, int ev_reg_id, uint32_t ev_req_id) 8544cc0e56eSJames Smart { 8554cc0e56eSJames Smart struct lpfc_bsg_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL); 856f1c3b0fcSJames Smart 8574cc0e56eSJames Smart if (!evt) 8584cc0e56eSJames Smart return NULL; 8594cc0e56eSJames Smart 8604cc0e56eSJames Smart INIT_LIST_HEAD(&evt->events_to_get); 8614cc0e56eSJames Smart INIT_LIST_HEAD(&evt->events_to_see); 8624cc0e56eSJames Smart evt->type_mask = ev_mask; 8634cc0e56eSJames Smart evt->req_id = ev_req_id; 8644cc0e56eSJames Smart evt->reg_id = ev_reg_id; 8654cc0e56eSJames Smart evt->wait_time_stamp = jiffies; 866a33c4f7bSJames Smart evt->dd_data = NULL; 8674cc0e56eSJames Smart init_waitqueue_head(&evt->wq); 8684cc0e56eSJames Smart kref_init(&evt->kref); 8694cc0e56eSJames Smart return evt; 8704cc0e56eSJames Smart } 8714cc0e56eSJames Smart 8723b5dd52aSJames Smart /** 8733b5dd52aSJames Smart * diag_cmd_data_free - Frees an lpfc dma buffer extension 8743b5dd52aSJames Smart * @phba: Pointer to HBA context object. 8753b5dd52aSJames Smart * @mlist: Pointer to an lpfc dma buffer extension. 8763b5dd52aSJames Smart **/ 8774cc0e56eSJames Smart static int 8783b5dd52aSJames Smart diag_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist) 8794cc0e56eSJames Smart { 8804cc0e56eSJames Smart struct lpfc_dmabufext *mlast; 8814cc0e56eSJames Smart struct pci_dev *pcidev; 8824cc0e56eSJames Smart struct list_head head, *curr, *next; 8834cc0e56eSJames Smart 8844cc0e56eSJames Smart if ((!mlist) || (!lpfc_is_link_up(phba) && 8854cc0e56eSJames Smart (phba->link_flag & LS_LOOPBACK_MODE))) { 8864cc0e56eSJames Smart return 0; 8874cc0e56eSJames Smart } 8884cc0e56eSJames Smart 8894cc0e56eSJames Smart pcidev = phba->pcidev; 8904cc0e56eSJames Smart list_add_tail(&head, &mlist->dma.list); 8914cc0e56eSJames Smart 8924cc0e56eSJames Smart list_for_each_safe(curr, next, &head) { 8934cc0e56eSJames Smart mlast = list_entry(curr, struct lpfc_dmabufext , dma.list); 8944cc0e56eSJames Smart if (mlast->dma.virt) 8954cc0e56eSJames Smart dma_free_coherent(&pcidev->dev, 8964cc0e56eSJames Smart mlast->size, 8974cc0e56eSJames Smart mlast->dma.virt, 8984cc0e56eSJames Smart mlast->dma.phys); 8994cc0e56eSJames Smart kfree(mlast); 9004cc0e56eSJames Smart } 9014cc0e56eSJames Smart return 0; 9024cc0e56eSJames Smart } 903f1c3b0fcSJames Smart 904f1c3b0fcSJames Smart /** 905f1c3b0fcSJames Smart * lpfc_bsg_ct_unsol_event - process an unsolicited CT command 906f1c3b0fcSJames Smart * @phba: 907f1c3b0fcSJames Smart * @pring: 908f1c3b0fcSJames Smart * @piocbq: 909f1c3b0fcSJames Smart * 910f1c3b0fcSJames Smart * This function is called when an unsolicited CT command is received. It 9114cc0e56eSJames Smart * forwards the event to any processes registered to receive CT events. 9123b5dd52aSJames Smart **/ 9134fede78fSJames Smart int 914f1c3b0fcSJames Smart lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, 915f1c3b0fcSJames Smart struct lpfc_iocbq *piocbq) 916f1c3b0fcSJames Smart { 917f1c3b0fcSJames Smart uint32_t evt_req_id = 0; 918f1c3b0fcSJames Smart uint32_t cmd; 919f1c3b0fcSJames Smart struct lpfc_dmabuf *dmabuf = NULL; 9204cc0e56eSJames Smart struct lpfc_bsg_event *evt; 921f1c3b0fcSJames Smart struct event_data *evt_dat = NULL; 922f1c3b0fcSJames Smart struct lpfc_iocbq *iocbq; 923f1c3b0fcSJames Smart size_t offset = 0; 924f1c3b0fcSJames Smart struct list_head head; 925f1c3b0fcSJames Smart struct ulp_bde64 *bde; 926f1c3b0fcSJames Smart dma_addr_t dma_addr; 927f1c3b0fcSJames Smart int i; 928f1c3b0fcSJames Smart struct lpfc_dmabuf *bdeBuf1 = piocbq->context2; 929f1c3b0fcSJames Smart struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; 930f1c3b0fcSJames Smart struct lpfc_hbq_entry *hbqe; 931f1c3b0fcSJames Smart struct lpfc_sli_ct_request *ct_req; 93275cc8cfcSJohannes Thumshirn struct bsg_job *job = NULL; 93301e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 934a33c4f7bSJames Smart struct bsg_job_data *dd_data = NULL; 9354fede78fSJames Smart unsigned long flags; 9364cc0e56eSJames Smart int size = 0; 937f1c3b0fcSJames Smart 938f1c3b0fcSJames Smart INIT_LIST_HEAD(&head); 939f1c3b0fcSJames Smart list_add_tail(&head, &piocbq->list); 940f1c3b0fcSJames Smart 941f1c3b0fcSJames Smart if (piocbq->iocb.ulpBdeCount == 0 || 942f1c3b0fcSJames Smart piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0) 943f1c3b0fcSJames Smart goto error_ct_unsol_exit; 944f1c3b0fcSJames Smart 9454cc0e56eSJames Smart if (phba->link_state == LPFC_HBA_ERROR || 9464cc0e56eSJames Smart (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) 9474cc0e56eSJames Smart goto error_ct_unsol_exit; 9484cc0e56eSJames Smart 949f1c3b0fcSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) 950f1c3b0fcSJames Smart dmabuf = bdeBuf1; 951f1c3b0fcSJames Smart else { 952f1c3b0fcSJames Smart dma_addr = getPaddr(piocbq->iocb.un.cont64[0].addrHigh, 953f1c3b0fcSJames Smart piocbq->iocb.un.cont64[0].addrLow); 954f1c3b0fcSJames Smart dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr); 955f1c3b0fcSJames Smart } 9564cc0e56eSJames Smart if (dmabuf == NULL) 9574cc0e56eSJames Smart goto error_ct_unsol_exit; 958f1c3b0fcSJames Smart ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt; 959f1c3b0fcSJames Smart evt_req_id = ct_req->FsType; 960f1c3b0fcSJames Smart cmd = ct_req->CommandResponse.bits.CmdRsp; 961f1c3b0fcSJames Smart if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) 962f1c3b0fcSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, dmabuf); 963f1c3b0fcSJames Smart 9644fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 965f1c3b0fcSJames Smart list_for_each_entry(evt, &phba->ct_ev_waiters, node) { 9664cc0e56eSJames Smart if (!(evt->type_mask & FC_REG_CT_EVENT) || 9674cc0e56eSJames Smart evt->req_id != evt_req_id) 968f1c3b0fcSJames Smart continue; 969f1c3b0fcSJames Smart 9704cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 9714cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 972f1c3b0fcSJames Smart evt_dat = kzalloc(sizeof(*evt_dat), GFP_KERNEL); 9734cc0e56eSJames Smart if (evt_dat == NULL) { 9744cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 9754cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 976f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 977f1c3b0fcSJames Smart "2614 Memory allocation failed for " 978f1c3b0fcSJames Smart "CT event\n"); 979f1c3b0fcSJames Smart break; 980f1c3b0fcSJames Smart } 981f1c3b0fcSJames Smart 982f1c3b0fcSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 983f1c3b0fcSJames Smart /* take accumulated byte count from the last iocbq */ 984f1c3b0fcSJames Smart iocbq = list_entry(head.prev, typeof(*iocbq), list); 985f1c3b0fcSJames Smart evt_dat->len = iocbq->iocb.unsli3.rcvsli3.acc_len; 986f1c3b0fcSJames Smart } else { 987f1c3b0fcSJames Smart list_for_each_entry(iocbq, &head, list) { 988f1c3b0fcSJames Smart for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) 989f1c3b0fcSJames Smart evt_dat->len += 990f1c3b0fcSJames Smart iocbq->iocb.un.cont64[i].tus.f.bdeSize; 991f1c3b0fcSJames Smart } 992f1c3b0fcSJames Smart } 993f1c3b0fcSJames Smart 994f1c3b0fcSJames Smart evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL); 9954cc0e56eSJames Smart if (evt_dat->data == NULL) { 996f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 997f1c3b0fcSJames Smart "2615 Memory allocation failed for " 998f1c3b0fcSJames Smart "CT event data, size %d\n", 999f1c3b0fcSJames Smart evt_dat->len); 1000f1c3b0fcSJames Smart kfree(evt_dat); 10014fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 10024cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 10034fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 1004f1c3b0fcSJames Smart goto error_ct_unsol_exit; 1005f1c3b0fcSJames Smart } 1006f1c3b0fcSJames Smart 1007f1c3b0fcSJames Smart list_for_each_entry(iocbq, &head, list) { 10084cc0e56eSJames Smart size = 0; 1009f1c3b0fcSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 1010f1c3b0fcSJames Smart bdeBuf1 = iocbq->context2; 1011f1c3b0fcSJames Smart bdeBuf2 = iocbq->context3; 1012f1c3b0fcSJames Smart } 1013f1c3b0fcSJames Smart for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) { 1014f1c3b0fcSJames Smart if (phba->sli3_options & 1015f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED) { 1016f1c3b0fcSJames Smart if (i == 0) { 1017f1c3b0fcSJames Smart hbqe = (struct lpfc_hbq_entry *) 1018f1c3b0fcSJames Smart &iocbq->iocb.un.ulpWord[0]; 1019f1c3b0fcSJames Smart size = hbqe->bde.tus.f.bdeSize; 1020f1c3b0fcSJames Smart dmabuf = bdeBuf1; 1021f1c3b0fcSJames Smart } else if (i == 1) { 1022f1c3b0fcSJames Smart hbqe = (struct lpfc_hbq_entry *) 1023f1c3b0fcSJames Smart &iocbq->iocb.unsli3. 1024f1c3b0fcSJames Smart sli3Words[4]; 1025f1c3b0fcSJames Smart size = hbqe->bde.tus.f.bdeSize; 1026f1c3b0fcSJames Smart dmabuf = bdeBuf2; 1027f1c3b0fcSJames Smart } 1028f1c3b0fcSJames Smart if ((offset + size) > evt_dat->len) 1029f1c3b0fcSJames Smart size = evt_dat->len - offset; 1030f1c3b0fcSJames Smart } else { 1031f1c3b0fcSJames Smart size = iocbq->iocb.un.cont64[i]. 1032f1c3b0fcSJames Smart tus.f.bdeSize; 1033f1c3b0fcSJames Smart bde = &iocbq->iocb.un.cont64[i]; 1034f1c3b0fcSJames Smart dma_addr = getPaddr(bde->addrHigh, 1035f1c3b0fcSJames Smart bde->addrLow); 1036f1c3b0fcSJames Smart dmabuf = lpfc_sli_ringpostbuf_get(phba, 1037f1c3b0fcSJames Smart pring, dma_addr); 1038f1c3b0fcSJames Smart } 1039f1c3b0fcSJames Smart if (!dmabuf) { 1040f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_ERR, 1041f1c3b0fcSJames Smart LOG_LIBDFC, "2616 No dmabuf " 1042f1c3b0fcSJames Smart "found for iocbq 0x%p\n", 1043f1c3b0fcSJames Smart iocbq); 1044f1c3b0fcSJames Smart kfree(evt_dat->data); 1045f1c3b0fcSJames Smart kfree(evt_dat); 10464fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, 10474fede78fSJames Smart flags); 10484cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 10494fede78fSJames Smart spin_unlock_irqrestore( 10504fede78fSJames Smart &phba->ct_ev_lock, flags); 1051f1c3b0fcSJames Smart goto error_ct_unsol_exit; 1052f1c3b0fcSJames Smart } 1053f1c3b0fcSJames Smart memcpy((char *)(evt_dat->data) + offset, 1054f1c3b0fcSJames Smart dmabuf->virt, size); 1055f1c3b0fcSJames Smart offset += size; 1056f1c3b0fcSJames Smart if (evt_req_id != SLI_CT_ELX_LOOPBACK && 1057f1c3b0fcSJames Smart !(phba->sli3_options & 1058f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED)) { 1059f1c3b0fcSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, 1060f1c3b0fcSJames Smart dmabuf); 1061f1c3b0fcSJames Smart } else { 1062f1c3b0fcSJames Smart switch (cmd) { 10634cc0e56eSJames Smart case ELX_LOOPBACK_DATA: 10641b51197dSJames Smart if (phba->sli_rev < 10651b51197dSJames Smart LPFC_SLI_REV4) 10663b5dd52aSJames Smart diag_cmd_data_free(phba, 10671b51197dSJames Smart (struct lpfc_dmabufext 10681b51197dSJames Smart *)dmabuf); 10694cc0e56eSJames Smart break; 1070f1c3b0fcSJames Smart case ELX_LOOPBACK_XRI_SETUP: 10714cc0e56eSJames Smart if ((phba->sli_rev == 10724cc0e56eSJames Smart LPFC_SLI_REV2) || 10734cc0e56eSJames Smart (phba->sli3_options & 10744cc0e56eSJames Smart LPFC_SLI3_HBQ_ENABLED 10754cc0e56eSJames Smart )) { 10764cc0e56eSJames Smart lpfc_in_buf_free(phba, 10774cc0e56eSJames Smart dmabuf); 10784cc0e56eSJames Smart } else { 1079f1c3b0fcSJames Smart lpfc_post_buffer(phba, 1080f1c3b0fcSJames Smart pring, 1081f1c3b0fcSJames Smart 1); 10824cc0e56eSJames Smart } 1083f1c3b0fcSJames Smart break; 1084f1c3b0fcSJames Smart default: 1085f1c3b0fcSJames Smart if (!(phba->sli3_options & 1086f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED)) 1087f1c3b0fcSJames Smart lpfc_post_buffer(phba, 1088f1c3b0fcSJames Smart pring, 1089f1c3b0fcSJames Smart 1); 1090f1c3b0fcSJames Smart break; 1091f1c3b0fcSJames Smart } 1092f1c3b0fcSJames Smart } 1093f1c3b0fcSJames Smart } 1094f1c3b0fcSJames Smart } 1095f1c3b0fcSJames Smart 10964fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1097f1c3b0fcSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) { 1098f1c3b0fcSJames Smart evt_dat->immed_dat = phba->ctx_idx; 10996dd9e31cSJames Smart phba->ctx_idx = (phba->ctx_idx + 1) % LPFC_CT_CTX_MAX; 1100589a52d6SJames Smart /* Provide warning for over-run of the ct_ctx array */ 11016dd9e31cSJames Smart if (phba->ct_ctx[evt_dat->immed_dat].valid == 1102589a52d6SJames Smart UNSOL_VALID) 1103589a52d6SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, 1104589a52d6SJames Smart "2717 CT context array entry " 1105589a52d6SJames Smart "[%d] over-run: oxid:x%x, " 1106589a52d6SJames Smart "sid:x%x\n", phba->ctx_idx, 1107589a52d6SJames Smart phba->ct_ctx[ 1108589a52d6SJames Smart evt_dat->immed_dat].oxid, 1109589a52d6SJames Smart phba->ct_ctx[ 1110589a52d6SJames Smart evt_dat->immed_dat].SID); 11117851fe2cSJames Smart phba->ct_ctx[evt_dat->immed_dat].rxid = 1112f1c3b0fcSJames Smart piocbq->iocb.ulpContext; 11137851fe2cSJames Smart phba->ct_ctx[evt_dat->immed_dat].oxid = 11147851fe2cSJames Smart piocbq->iocb.unsli3.rcvsli3.ox_id; 1115f1c3b0fcSJames Smart phba->ct_ctx[evt_dat->immed_dat].SID = 1116f1c3b0fcSJames Smart piocbq->iocb.un.rcvels.remoteID; 11176dd9e31cSJames Smart phba->ct_ctx[evt_dat->immed_dat].valid = UNSOL_VALID; 1118f1c3b0fcSJames Smart } else 1119f1c3b0fcSJames Smart evt_dat->immed_dat = piocbq->iocb.ulpContext; 1120f1c3b0fcSJames Smart 1121f1c3b0fcSJames Smart evt_dat->type = FC_REG_CT_EVENT; 1122f1c3b0fcSJames Smart list_add(&evt_dat->node, &evt->events_to_see); 11234cc0e56eSJames Smart if (evt_req_id == SLI_CT_ELX_LOOPBACK) { 1124f1c3b0fcSJames Smart wake_up_interruptible(&evt->wq); 11254cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 1126f1c3b0fcSJames Smart break; 1127f1c3b0fcSJames Smart } 11284cc0e56eSJames Smart 11294cc0e56eSJames Smart list_move(evt->events_to_see.prev, &evt->events_to_get); 11304cc0e56eSJames Smart 1131a33c4f7bSJames Smart dd_data = (struct bsg_job_data *)evt->dd_data; 1132a33c4f7bSJames Smart job = dd_data->set_job; 1133a33c4f7bSJames Smart dd_data->set_job = NULL; 1134a33c4f7bSJames Smart lpfc_bsg_event_unref(evt); 11354cc0e56eSJames Smart if (job) { 113601e0e15cSJohannes Thumshirn bsg_reply = job->reply; 113701e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = size; 11384cc0e56eSJames Smart /* make error code available to userspace */ 113901e0e15cSJohannes Thumshirn bsg_reply->result = 0; 11404cc0e56eSJames Smart job->dd_data = NULL; 11414cc0e56eSJames Smart /* complete the job back to userspace */ 11424cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 114306548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 11441abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 11454cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 11464cc0e56eSJames Smart } 11474cc0e56eSJames Smart } 11484fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 1149f1c3b0fcSJames Smart 1150f1c3b0fcSJames Smart error_ct_unsol_exit: 1151f1c3b0fcSJames Smart if (!list_empty(&head)) 1152f1c3b0fcSJames Smart list_del(&head); 11531b51197dSJames Smart if ((phba->sli_rev < LPFC_SLI_REV4) && 11541b51197dSJames Smart (evt_req_id == SLI_CT_ELX_LOOPBACK)) 11554cc0e56eSJames Smart return 0; 11564fede78fSJames Smart return 1; 1157f1c3b0fcSJames Smart } 1158f1c3b0fcSJames Smart 1159f1c3b0fcSJames Smart /** 11606dd9e31cSJames Smart * lpfc_bsg_ct_unsol_abort - handler ct abort to management plane 11616dd9e31cSJames Smart * @phba: Pointer to HBA context object. 11626dd9e31cSJames Smart * @dmabuf: pointer to a dmabuf that describes the FC sequence 11636dd9e31cSJames Smart * 11646dd9e31cSJames Smart * This function handles abort to the CT command toward management plane 11656dd9e31cSJames Smart * for SLI4 port. 11666dd9e31cSJames Smart * 11676dd9e31cSJames Smart * If the pending context of a CT command to management plane present, clears 11686dd9e31cSJames Smart * such context and returns 1 for handled; otherwise, it returns 0 indicating 11696dd9e31cSJames Smart * no context exists. 11706dd9e31cSJames Smart **/ 11716dd9e31cSJames Smart int 11726dd9e31cSJames Smart lpfc_bsg_ct_unsol_abort(struct lpfc_hba *phba, struct hbq_dmabuf *dmabuf) 11736dd9e31cSJames Smart { 11746dd9e31cSJames Smart struct fc_frame_header fc_hdr; 11756dd9e31cSJames Smart struct fc_frame_header *fc_hdr_ptr = &fc_hdr; 11766dd9e31cSJames Smart int ctx_idx, handled = 0; 11776dd9e31cSJames Smart uint16_t oxid, rxid; 11786dd9e31cSJames Smart uint32_t sid; 11796dd9e31cSJames Smart 11806dd9e31cSJames Smart memcpy(fc_hdr_ptr, dmabuf->hbuf.virt, sizeof(struct fc_frame_header)); 11816dd9e31cSJames Smart sid = sli4_sid_from_fc_hdr(fc_hdr_ptr); 11826dd9e31cSJames Smart oxid = be16_to_cpu(fc_hdr_ptr->fh_ox_id); 11836dd9e31cSJames Smart rxid = be16_to_cpu(fc_hdr_ptr->fh_rx_id); 11846dd9e31cSJames Smart 11856dd9e31cSJames Smart for (ctx_idx = 0; ctx_idx < LPFC_CT_CTX_MAX; ctx_idx++) { 11866dd9e31cSJames Smart if (phba->ct_ctx[ctx_idx].valid != UNSOL_VALID) 11876dd9e31cSJames Smart continue; 11886dd9e31cSJames Smart if (phba->ct_ctx[ctx_idx].rxid != rxid) 11896dd9e31cSJames Smart continue; 11906dd9e31cSJames Smart if (phba->ct_ctx[ctx_idx].oxid != oxid) 11916dd9e31cSJames Smart continue; 11926dd9e31cSJames Smart if (phba->ct_ctx[ctx_idx].SID != sid) 11936dd9e31cSJames Smart continue; 11946dd9e31cSJames Smart phba->ct_ctx[ctx_idx].valid = UNSOL_INVALID; 11956dd9e31cSJames Smart handled = 1; 11966dd9e31cSJames Smart } 11976dd9e31cSJames Smart return handled; 11986dd9e31cSJames Smart } 11996dd9e31cSJames Smart 12006dd9e31cSJames Smart /** 12014cc0e56eSJames Smart * lpfc_bsg_hba_set_event - process a SET_EVENT bsg vendor command 1202f1c3b0fcSJames Smart * @job: SET_EVENT fc_bsg_job 12033b5dd52aSJames Smart **/ 1204f1c3b0fcSJames Smart static int 120575cc8cfcSJohannes Thumshirn lpfc_bsg_hba_set_event(struct bsg_job *job) 1206f1c3b0fcSJames Smart { 1207cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 1208f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 120901e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 1210f1c3b0fcSJames Smart struct set_ct_event *event_req; 12114cc0e56eSJames Smart struct lpfc_bsg_event *evt; 1212f1c3b0fcSJames Smart int rc = 0; 12134cc0e56eSJames Smart struct bsg_job_data *dd_data = NULL; 12144cc0e56eSJames Smart uint32_t ev_mask; 12154cc0e56eSJames Smart unsigned long flags; 1216f1c3b0fcSJames Smart 1217f1c3b0fcSJames Smart if (job->request_len < 1218f1c3b0fcSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct set_ct_event)) { 1219f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1220f1c3b0fcSJames Smart "2612 Received SET_CT_EVENT below minimum " 1221f1c3b0fcSJames Smart "size\n"); 12224cc0e56eSJames Smart rc = -EINVAL; 12234cc0e56eSJames Smart goto job_error; 12244cc0e56eSJames Smart } 12254cc0e56eSJames Smart 1226f1c3b0fcSJames Smart event_req = (struct set_ct_event *) 122701e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 12284cc0e56eSJames Smart ev_mask = ((uint32_t)(unsigned long)event_req->type_mask & 12294cc0e56eSJames Smart FC_REG_EVENT_MASK); 12304fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1231f1c3b0fcSJames Smart list_for_each_entry(evt, &phba->ct_ev_waiters, node) { 1232f1c3b0fcSJames Smart if (evt->reg_id == event_req->ev_reg_id) { 12334cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 1234f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 1235a33c4f7bSJames Smart dd_data = (struct bsg_job_data *)evt->dd_data; 1236f1c3b0fcSJames Smart break; 1237f1c3b0fcSJames Smart } 1238f1c3b0fcSJames Smart } 12394fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 1240f1c3b0fcSJames Smart 1241f1c3b0fcSJames Smart if (&evt->node == &phba->ct_ev_waiters) { 1242f1c3b0fcSJames Smart /* no event waiting struct yet - first call */ 1243a33c4f7bSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 1244a33c4f7bSJames Smart if (dd_data == NULL) { 1245a33c4f7bSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1246a33c4f7bSJames Smart "2734 Failed allocation of dd_data\n"); 1247a33c4f7bSJames Smart rc = -ENOMEM; 1248a33c4f7bSJames Smart goto job_error; 1249a33c4f7bSJames Smart } 12504cc0e56eSJames Smart evt = lpfc_bsg_event_new(ev_mask, event_req->ev_reg_id, 1251f1c3b0fcSJames Smart event_req->ev_req_id); 1252f1c3b0fcSJames Smart if (!evt) { 1253f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1254f1c3b0fcSJames Smart "2617 Failed allocation of event " 1255f1c3b0fcSJames Smart "waiter\n"); 12564cc0e56eSJames Smart rc = -ENOMEM; 12574cc0e56eSJames Smart goto job_error; 1258f1c3b0fcSJames Smart } 1259a33c4f7bSJames Smart dd_data->type = TYPE_EVT; 1260a33c4f7bSJames Smart dd_data->set_job = NULL; 1261a33c4f7bSJames Smart dd_data->context_un.evt = evt; 1262a33c4f7bSJames Smart evt->dd_data = (void *)dd_data; 12634fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1264f1c3b0fcSJames Smart list_add(&evt->node, &phba->ct_ev_waiters); 12654cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 1266f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 12674cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 12684cc0e56eSJames Smart } 1269f1c3b0fcSJames Smart 12704fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 12714cc0e56eSJames Smart evt->waiting = 1; 1272a33c4f7bSJames Smart dd_data->set_job = job; /* for unsolicited command */ 12734cc0e56eSJames Smart job->dd_data = dd_data; /* for fc transport timeout callback*/ 12744fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 12754cc0e56eSJames Smart return 0; /* call job done later */ 1276f1c3b0fcSJames Smart 12774cc0e56eSJames Smart job_error: 12784cc0e56eSJames Smart if (dd_data != NULL) 12794cc0e56eSJames Smart kfree(dd_data); 1280f1c3b0fcSJames Smart 12814cc0e56eSJames Smart job->dd_data = NULL; 12824cc0e56eSJames Smart return rc; 1283f1c3b0fcSJames Smart } 1284f1c3b0fcSJames Smart 1285f1c3b0fcSJames Smart /** 12864cc0e56eSJames Smart * lpfc_bsg_hba_get_event - process a GET_EVENT bsg vendor command 1287f1c3b0fcSJames Smart * @job: GET_EVENT fc_bsg_job 12883b5dd52aSJames Smart **/ 1289f1c3b0fcSJames Smart static int 129075cc8cfcSJohannes Thumshirn lpfc_bsg_hba_get_event(struct bsg_job *job) 1291f1c3b0fcSJames Smart { 1292cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 1293f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 129401e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 129501e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 1296f1c3b0fcSJames Smart struct get_ct_event *event_req; 1297f1c3b0fcSJames Smart struct get_ct_event_reply *event_reply; 12989a803a74SJames Smart struct lpfc_bsg_event *evt, *evt_next; 1299f1c3b0fcSJames Smart struct event_data *evt_dat = NULL; 13004fede78fSJames Smart unsigned long flags; 13014cc0e56eSJames Smart uint32_t rc = 0; 1302f1c3b0fcSJames Smart 1303f1c3b0fcSJames Smart if (job->request_len < 1304f1c3b0fcSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct get_ct_event)) { 1305f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1306f1c3b0fcSJames Smart "2613 Received GET_CT_EVENT request below " 1307f1c3b0fcSJames Smart "minimum size\n"); 13084cc0e56eSJames Smart rc = -EINVAL; 13094cc0e56eSJames Smart goto job_error; 1310f1c3b0fcSJames Smart } 1311f1c3b0fcSJames Smart 1312f1c3b0fcSJames Smart event_req = (struct get_ct_event *) 131301e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 1314f1c3b0fcSJames Smart 1315f1c3b0fcSJames Smart event_reply = (struct get_ct_event_reply *) 131601e0e15cSJohannes Thumshirn bsg_reply->reply_data.vendor_reply.vendor_rsp; 13174fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 13189a803a74SJames Smart list_for_each_entry_safe(evt, evt_next, &phba->ct_ev_waiters, node) { 1319f1c3b0fcSJames Smart if (evt->reg_id == event_req->ev_reg_id) { 1320f1c3b0fcSJames Smart if (list_empty(&evt->events_to_get)) 1321f1c3b0fcSJames Smart break; 13224cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 1323f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 1324f1c3b0fcSJames Smart evt_dat = list_entry(evt->events_to_get.prev, 1325f1c3b0fcSJames Smart struct event_data, node); 1326f1c3b0fcSJames Smart list_del(&evt_dat->node); 1327f1c3b0fcSJames Smart break; 1328f1c3b0fcSJames Smart } 1329f1c3b0fcSJames Smart } 13304fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 1331f1c3b0fcSJames Smart 13324cc0e56eSJames Smart /* The app may continue to ask for event data until it gets 13334cc0e56eSJames Smart * an error indicating that there isn't anymore 13344cc0e56eSJames Smart */ 13354cc0e56eSJames Smart if (evt_dat == NULL) { 133601e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 1337f1c3b0fcSJames Smart rc = -ENOENT; 13384cc0e56eSJames Smart goto job_error; 1339f1c3b0fcSJames Smart } 1340f1c3b0fcSJames Smart 13414cc0e56eSJames Smart if (evt_dat->len > job->request_payload.payload_len) { 13424cc0e56eSJames Smart evt_dat->len = job->request_payload.payload_len; 1343f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1344f1c3b0fcSJames Smart "2618 Truncated event data at %d " 1345f1c3b0fcSJames Smart "bytes\n", 13464cc0e56eSJames Smart job->request_payload.payload_len); 1347f1c3b0fcSJames Smart } 1348f1c3b0fcSJames Smart 13494cc0e56eSJames Smart event_reply->type = evt_dat->type; 1350f1c3b0fcSJames Smart event_reply->immed_data = evt_dat->immed_dat; 1351f1c3b0fcSJames Smart if (evt_dat->len > 0) 135201e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 13534cc0e56eSJames Smart sg_copy_from_buffer(job->request_payload.sg_list, 13544cc0e56eSJames Smart job->request_payload.sg_cnt, 1355f1c3b0fcSJames Smart evt_dat->data, evt_dat->len); 1356f1c3b0fcSJames Smart else 135701e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 1358f1c3b0fcSJames Smart 13594cc0e56eSJames Smart if (evt_dat) { 1360f1c3b0fcSJames Smart kfree(evt_dat->data); 1361f1c3b0fcSJames Smart kfree(evt_dat); 13624cc0e56eSJames Smart } 13634cc0e56eSJames Smart 13644fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 13654cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 13664fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 13674cc0e56eSJames Smart job->dd_data = NULL; 136801e0e15cSJohannes Thumshirn bsg_reply->result = 0; 136906548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 13701abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 13714cc0e56eSJames Smart return 0; 1372f1c3b0fcSJames Smart 13734cc0e56eSJames Smart job_error: 13744cc0e56eSJames Smart job->dd_data = NULL; 137501e0e15cSJohannes Thumshirn bsg_reply->result = rc; 1376f1c3b0fcSJames Smart return rc; 1377f1c3b0fcSJames Smart } 1378f1c3b0fcSJames Smart 1379f1c3b0fcSJames Smart /** 13803b5dd52aSJames Smart * lpfc_issue_ct_rsp_cmp - lpfc_issue_ct_rsp's completion handler 13813b5dd52aSJames Smart * @phba: Pointer to HBA context object. 13823b5dd52aSJames Smart * @cmdiocbq: Pointer to command iocb. 13833b5dd52aSJames Smart * @rspiocbq: Pointer to response iocb. 13843b5dd52aSJames Smart * 13853b5dd52aSJames Smart * This function is the completion handler for iocbs issued using 13863b5dd52aSJames Smart * lpfc_issue_ct_rsp_cmp function. This function is called by the 13873b5dd52aSJames Smart * ring event handler function without any lock held. This function 13883b5dd52aSJames Smart * can be called from both worker thread context and interrupt 13893b5dd52aSJames Smart * context. This function also can be called from other thread which 13903b5dd52aSJames Smart * cleans up the SLI layer objects. 13913b5dd52aSJames Smart * This function copy the contents of the response iocb to the 13923b5dd52aSJames Smart * response iocb memory object provided by the caller of 13933b5dd52aSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 13943b5dd52aSJames Smart * sleeps for the iocb completion. 13953b5dd52aSJames Smart **/ 13963b5dd52aSJames Smart static void 13973b5dd52aSJames Smart lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba, 13983b5dd52aSJames Smart struct lpfc_iocbq *cmdiocbq, 13993b5dd52aSJames Smart struct lpfc_iocbq *rspiocbq) 14003b5dd52aSJames Smart { 14013b5dd52aSJames Smart struct bsg_job_data *dd_data; 140275cc8cfcSJohannes Thumshirn struct bsg_job *job; 140301e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 14043b5dd52aSJames Smart IOCB_t *rsp; 1405a33c4f7bSJames Smart struct lpfc_dmabuf *bmp, *cmp; 14063b5dd52aSJames Smart struct lpfc_nodelist *ndlp; 14073b5dd52aSJames Smart unsigned long flags; 14083b5dd52aSJames Smart int rc = 0; 14093b5dd52aSJames Smart 1410a33c4f7bSJames Smart dd_data = cmdiocbq->context1; 1411a33c4f7bSJames Smart 1412a33c4f7bSJames Smart /* Determine if job has been aborted */ 14133b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1414a33c4f7bSJames Smart job = dd_data->set_job; 1415a33c4f7bSJames Smart if (job) { 1416a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 1417a33c4f7bSJames Smart job->dd_data = NULL; 14183b5dd52aSJames Smart } 1419a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 14203b5dd52aSJames Smart 1421b5a9b2dfSJames Smart /* Close the timeout handler abort window */ 1422b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 14231b8d11abSJames Smart cmdiocbq->iocb_flag &= ~LPFC_IO_CMD_OUTSTANDING; 1424b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 1425b5a9b2dfSJames Smart 14263b5dd52aSJames Smart ndlp = dd_data->context_un.iocb.ndlp; 1427a33c4f7bSJames Smart cmp = cmdiocbq->context2; 1428a33c4f7bSJames Smart bmp = cmdiocbq->context3; 1429a33c4f7bSJames Smart rsp = &rspiocbq->iocb; 14303b5dd52aSJames Smart 1431a33c4f7bSJames Smart /* Copy the completed job data or set the error status */ 14323b5dd52aSJames Smart 1433a33c4f7bSJames Smart if (job) { 143401e0e15cSJohannes Thumshirn bsg_reply = job->reply; 14353b5dd52aSJames Smart if (rsp->ulpStatus) { 14363b5dd52aSJames Smart if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { 1437e3d2b802SJames Smart switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) { 14383b5dd52aSJames Smart case IOERR_SEQUENCE_TIMEOUT: 14393b5dd52aSJames Smart rc = -ETIMEDOUT; 14403b5dd52aSJames Smart break; 14413b5dd52aSJames Smart case IOERR_INVALID_RPI: 14423b5dd52aSJames Smart rc = -EFAULT; 14433b5dd52aSJames Smart break; 14443b5dd52aSJames Smart default: 14453b5dd52aSJames Smart rc = -EACCES; 14463b5dd52aSJames Smart break; 14473b5dd52aSJames Smart } 1448a33c4f7bSJames Smart } else { 14493b5dd52aSJames Smart rc = -EACCES; 1450a33c4f7bSJames Smart } 1451a33c4f7bSJames Smart } else { 145201e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 1453a33c4f7bSJames Smart } 1454a33c4f7bSJames Smart } 14553b5dd52aSJames Smart 1456a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 14573b5dd52aSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 1458a33c4f7bSJames Smart kfree(bmp); 14593b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 14603b5dd52aSJames Smart lpfc_nlp_put(ndlp); 14613b5dd52aSJames Smart kfree(dd_data); 1462a33c4f7bSJames Smart 1463a33c4f7bSJames Smart /* Complete the job if the job is still active */ 1464a33c4f7bSJames Smart 1465a33c4f7bSJames Smart if (job) { 146601e0e15cSJohannes Thumshirn bsg_reply->result = rc; 146706548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 14681abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 1469a33c4f7bSJames Smart } 14703b5dd52aSJames Smart return; 14713b5dd52aSJames Smart } 14723b5dd52aSJames Smart 14733b5dd52aSJames Smart /** 14743b5dd52aSJames Smart * lpfc_issue_ct_rsp - issue a ct response 14753b5dd52aSJames Smart * @phba: Pointer to HBA context object. 14763b5dd52aSJames Smart * @job: Pointer to the job object. 14773b5dd52aSJames Smart * @tag: tag index value into the ports context exchange array. 14783b5dd52aSJames Smart * @bmp: Pointer to a dma buffer descriptor. 14793b5dd52aSJames Smart * @num_entry: Number of enties in the bde. 14803b5dd52aSJames Smart **/ 14813b5dd52aSJames Smart static int 148275cc8cfcSJohannes Thumshirn lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct bsg_job *job, uint32_t tag, 1483a33c4f7bSJames Smart struct lpfc_dmabuf *cmp, struct lpfc_dmabuf *bmp, 1484a33c4f7bSJames Smart int num_entry) 14853b5dd52aSJames Smart { 14863b5dd52aSJames Smart IOCB_t *icmd; 14873b5dd52aSJames Smart struct lpfc_iocbq *ctiocb = NULL; 14883b5dd52aSJames Smart int rc = 0; 14893b5dd52aSJames Smart struct lpfc_nodelist *ndlp = NULL; 14903b5dd52aSJames Smart struct bsg_job_data *dd_data; 1491b5a9b2dfSJames Smart unsigned long flags; 14923b5dd52aSJames Smart uint32_t creg_val; 14933b5dd52aSJames Smart 14943b5dd52aSJames Smart /* allocate our bsg tracking structure */ 14953b5dd52aSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 14963b5dd52aSJames Smart if (!dd_data) { 14973b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 14983b5dd52aSJames Smart "2736 Failed allocation of dd_data\n"); 14993b5dd52aSJames Smart rc = -ENOMEM; 15003b5dd52aSJames Smart goto no_dd_data; 15013b5dd52aSJames Smart } 15023b5dd52aSJames Smart 15033b5dd52aSJames Smart /* Allocate buffer for command iocb */ 15043b5dd52aSJames Smart ctiocb = lpfc_sli_get_iocbq(phba); 15053b5dd52aSJames Smart if (!ctiocb) { 1506d439d286SJames Smart rc = -ENOMEM; 15073b5dd52aSJames Smart goto no_ctiocb; 15083b5dd52aSJames Smart } 15093b5dd52aSJames Smart 15103b5dd52aSJames Smart icmd = &ctiocb->iocb; 15113b5dd52aSJames Smart icmd->un.xseq64.bdl.ulpIoTag32 = 0; 15123b5dd52aSJames Smart icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(bmp->phys); 15133b5dd52aSJames Smart icmd->un.xseq64.bdl.addrLow = putPaddrLow(bmp->phys); 15143b5dd52aSJames Smart icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 15153b5dd52aSJames Smart icmd->un.xseq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64)); 15163b5dd52aSJames Smart icmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); 15173b5dd52aSJames Smart icmd->un.xseq64.w5.hcsw.Dfctl = 0; 15183b5dd52aSJames Smart icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_SOL_CTL; 15193b5dd52aSJames Smart icmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; 15203b5dd52aSJames Smart 15213b5dd52aSJames Smart /* Fill in rest of iocb */ 15223b5dd52aSJames Smart icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; 15233b5dd52aSJames Smart icmd->ulpBdeCount = 1; 15243b5dd52aSJames Smart icmd->ulpLe = 1; 15253b5dd52aSJames Smart icmd->ulpClass = CLASS3; 15263b5dd52aSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) { 15273b5dd52aSJames Smart /* Do not issue unsol response if oxid not marked as valid */ 15286dd9e31cSJames Smart if (phba->ct_ctx[tag].valid != UNSOL_VALID) { 15293b5dd52aSJames Smart rc = IOCB_ERROR; 15303b5dd52aSJames Smart goto issue_ct_rsp_exit; 15313b5dd52aSJames Smart } 15327851fe2cSJames Smart icmd->ulpContext = phba->ct_ctx[tag].rxid; 15337851fe2cSJames Smart icmd->unsli3.rcvsli3.ox_id = phba->ct_ctx[tag].oxid; 15343b5dd52aSJames Smart ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID); 15353b5dd52aSJames Smart if (!ndlp) { 15363b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, 15373b5dd52aSJames Smart "2721 ndlp null for oxid %x SID %x\n", 15383b5dd52aSJames Smart icmd->ulpContext, 15393b5dd52aSJames Smart phba->ct_ctx[tag].SID); 15403b5dd52aSJames Smart rc = IOCB_ERROR; 15413b5dd52aSJames Smart goto issue_ct_rsp_exit; 15423b5dd52aSJames Smart } 1543589a52d6SJames Smart 1544589a52d6SJames Smart /* Check if the ndlp is active */ 1545589a52d6SJames Smart if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { 1546a33c4f7bSJames Smart rc = IOCB_ERROR; 1547589a52d6SJames Smart goto issue_ct_rsp_exit; 1548589a52d6SJames Smart } 1549589a52d6SJames Smart 1550589a52d6SJames Smart /* get a refernece count so the ndlp doesn't go away while 1551589a52d6SJames Smart * we respond 1552589a52d6SJames Smart */ 1553589a52d6SJames Smart if (!lpfc_nlp_get(ndlp)) { 1554a33c4f7bSJames Smart rc = IOCB_ERROR; 1555589a52d6SJames Smart goto issue_ct_rsp_exit; 1556589a52d6SJames Smart } 1557589a52d6SJames Smart 15587851fe2cSJames Smart icmd->un.ulpWord[3] = 15596d368e53SJames Smart phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; 15606d368e53SJames Smart 15613b5dd52aSJames Smart /* The exchange is done, mark the entry as invalid */ 15626dd9e31cSJames Smart phba->ct_ctx[tag].valid = UNSOL_INVALID; 15633b5dd52aSJames Smart } else 15643b5dd52aSJames Smart icmd->ulpContext = (ushort) tag; 15653b5dd52aSJames Smart 15663b5dd52aSJames Smart icmd->ulpTimeout = phba->fc_ratov * 2; 15673b5dd52aSJames Smart 15683b5dd52aSJames Smart /* Xmit CT response on exchange <xid> */ 15693b5dd52aSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_ELS, 15707851fe2cSJames Smart "2722 Xmit CT response on exchange x%x Data: x%x x%x x%x\n", 15717851fe2cSJames Smart icmd->ulpContext, icmd->ulpIoTag, tag, phba->link_state); 15723b5dd52aSJames Smart 15733b5dd52aSJames Smart ctiocb->iocb_cmpl = NULL; 15743b5dd52aSJames Smart ctiocb->iocb_flag |= LPFC_IO_LIBDFC; 15753b5dd52aSJames Smart ctiocb->vport = phba->pport; 1576a33c4f7bSJames Smart ctiocb->context1 = dd_data; 1577a33c4f7bSJames Smart ctiocb->context2 = cmp; 15783b5dd52aSJames Smart ctiocb->context3 = bmp; 1579d5ce53b7SJames Smart ctiocb->context_un.ndlp = ndlp; 15803b5dd52aSJames Smart ctiocb->iocb_cmpl = lpfc_issue_ct_rsp_cmp; 1581a33c4f7bSJames Smart 15823b5dd52aSJames Smart dd_data->type = TYPE_IOCB; 1583a33c4f7bSJames Smart dd_data->set_job = job; 15843b5dd52aSJames Smart dd_data->context_un.iocb.cmdiocbq = ctiocb; 15853b5dd52aSJames Smart dd_data->context_un.iocb.ndlp = ndlp; 1586a33c4f7bSJames Smart dd_data->context_un.iocb.rmp = NULL; 1587a33c4f7bSJames Smart job->dd_data = dd_data; 15883b5dd52aSJames Smart 15893b5dd52aSJames Smart if (phba->cfg_poll & DISABLE_FCP_RING_INT) { 15909940b97bSJames Smart if (lpfc_readl(phba->HCregaddr, &creg_val)) { 15919940b97bSJames Smart rc = -IOCB_ERROR; 15929940b97bSJames Smart goto issue_ct_rsp_exit; 15939940b97bSJames Smart } 15943b5dd52aSJames Smart creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); 15953b5dd52aSJames Smart writel(creg_val, phba->HCregaddr); 15963b5dd52aSJames Smart readl(phba->HCregaddr); /* flush */ 15973b5dd52aSJames Smart } 15983b5dd52aSJames Smart 15993b5dd52aSJames Smart rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); 16003b5dd52aSJames Smart 1601b5a9b2dfSJames Smart if (rc == IOCB_SUCCESS) { 1602b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 1603b5a9b2dfSJames Smart /* make sure the I/O had not been completed/released */ 1604b5a9b2dfSJames Smart if (ctiocb->iocb_flag & LPFC_IO_LIBDFC) { 1605b5a9b2dfSJames Smart /* open up abort window to timeout handler */ 16061b8d11abSJames Smart ctiocb->iocb_flag |= LPFC_IO_CMD_OUTSTANDING; 1607b5a9b2dfSJames Smart } 1608b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 16093b5dd52aSJames Smart return 0; /* done for now */ 1610b5a9b2dfSJames Smart } 1611b5a9b2dfSJames Smart 1612b5a9b2dfSJames Smart /* iocb failed so cleanup */ 1613b5a9b2dfSJames Smart job->dd_data = NULL; 16143b5dd52aSJames Smart 16153b5dd52aSJames Smart issue_ct_rsp_exit: 16163b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, ctiocb); 16173b5dd52aSJames Smart no_ctiocb: 16183b5dd52aSJames Smart kfree(dd_data); 16193b5dd52aSJames Smart no_dd_data: 16203b5dd52aSJames Smart return rc; 16213b5dd52aSJames Smart } 16223b5dd52aSJames Smart 16233b5dd52aSJames Smart /** 16243b5dd52aSJames Smart * lpfc_bsg_send_mgmt_rsp - process a SEND_MGMT_RESP bsg vendor command 16253b5dd52aSJames Smart * @job: SEND_MGMT_RESP fc_bsg_job 16263b5dd52aSJames Smart **/ 16273b5dd52aSJames Smart static int 162875cc8cfcSJohannes Thumshirn lpfc_bsg_send_mgmt_rsp(struct bsg_job *job) 16293b5dd52aSJames Smart { 1630cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 16313b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 163201e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 163301e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 16343b5dd52aSJames Smart struct send_mgmt_resp *mgmt_resp = (struct send_mgmt_resp *) 163501e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 16363b5dd52aSJames Smart struct ulp_bde64 *bpl; 1637a33c4f7bSJames Smart struct lpfc_dmabuf *bmp = NULL, *cmp = NULL; 1638a33c4f7bSJames Smart int bpl_entries; 16393b5dd52aSJames Smart uint32_t tag = mgmt_resp->tag; 16403b5dd52aSJames Smart unsigned long reqbfrcnt = 16413b5dd52aSJames Smart (unsigned long)job->request_payload.payload_len; 16423b5dd52aSJames Smart int rc = 0; 16433b5dd52aSJames Smart 16443b5dd52aSJames Smart /* in case no data is transferred */ 164501e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 16463b5dd52aSJames Smart 16473b5dd52aSJames Smart if (!reqbfrcnt || (reqbfrcnt > (80 * BUF_SZ_4K))) { 16483b5dd52aSJames Smart rc = -ERANGE; 16493b5dd52aSJames Smart goto send_mgmt_rsp_exit; 16503b5dd52aSJames Smart } 16513b5dd52aSJames Smart 16523b5dd52aSJames Smart bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 16533b5dd52aSJames Smart if (!bmp) { 16543b5dd52aSJames Smart rc = -ENOMEM; 16553b5dd52aSJames Smart goto send_mgmt_rsp_exit; 16563b5dd52aSJames Smart } 16573b5dd52aSJames Smart 16583b5dd52aSJames Smart bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); 16593b5dd52aSJames Smart if (!bmp->virt) { 16603b5dd52aSJames Smart rc = -ENOMEM; 16613b5dd52aSJames Smart goto send_mgmt_rsp_free_bmp; 16623b5dd52aSJames Smart } 16633b5dd52aSJames Smart 16643b5dd52aSJames Smart INIT_LIST_HEAD(&bmp->list); 16653b5dd52aSJames Smart bpl = (struct ulp_bde64 *) bmp->virt; 1666a33c4f7bSJames Smart bpl_entries = (LPFC_BPL_SIZE/sizeof(struct ulp_bde64)); 1667a33c4f7bSJames Smart cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len, 1668a33c4f7bSJames Smart 1, bpl, &bpl_entries); 1669a33c4f7bSJames Smart if (!cmp) { 1670a33c4f7bSJames Smart rc = -ENOMEM; 1671a33c4f7bSJames Smart goto send_mgmt_rsp_free_bmp; 16723b5dd52aSJames Smart } 1673a33c4f7bSJames Smart lpfc_bsg_copy_data(cmp, &job->request_payload, 1674a33c4f7bSJames Smart job->request_payload.payload_len, 1); 16753b5dd52aSJames Smart 1676a33c4f7bSJames Smart rc = lpfc_issue_ct_rsp(phba, job, tag, cmp, bmp, bpl_entries); 16773b5dd52aSJames Smart 16783b5dd52aSJames Smart if (rc == IOCB_SUCCESS) 16793b5dd52aSJames Smart return 0; /* done for now */ 16803b5dd52aSJames Smart 16813b5dd52aSJames Smart rc = -EACCES; 1682a33c4f7bSJames Smart 1683a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 16843b5dd52aSJames Smart 16853b5dd52aSJames Smart send_mgmt_rsp_free_bmp: 1686a33c4f7bSJames Smart if (bmp->virt) 1687a33c4f7bSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 16883b5dd52aSJames Smart kfree(bmp); 16893b5dd52aSJames Smart send_mgmt_rsp_exit: 16903b5dd52aSJames Smart /* make error code available to userspace */ 169101e0e15cSJohannes Thumshirn bsg_reply->result = rc; 16923b5dd52aSJames Smart job->dd_data = NULL; 16933b5dd52aSJames Smart return rc; 16943b5dd52aSJames Smart } 16953b5dd52aSJames Smart 16963b5dd52aSJames Smart /** 16977ad20aa9SJames Smart * lpfc_bsg_diag_mode_enter - process preparing into device diag loopback mode 16987ad20aa9SJames Smart * @phba: Pointer to HBA context object. 16993b5dd52aSJames Smart * 17007ad20aa9SJames Smart * This function is responsible for preparing driver for diag loopback 17017ad20aa9SJames Smart * on device. 17023b5dd52aSJames Smart */ 17033b5dd52aSJames Smart static int 170488a2cfbbSJames Smart lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba) 17053b5dd52aSJames Smart { 17063b5dd52aSJames Smart struct lpfc_vport **vports; 17077ad20aa9SJames Smart struct Scsi_Host *shost; 17087ad20aa9SJames Smart struct lpfc_sli *psli; 1709895427bdSJames Smart struct lpfc_queue *qp = NULL; 17107ad20aa9SJames Smart struct lpfc_sli_ring *pring; 17113b5dd52aSJames Smart int i = 0; 17123b5dd52aSJames Smart 17137ad20aa9SJames Smart psli = &phba->sli; 17147ad20aa9SJames Smart if (!psli) 17157ad20aa9SJames Smart return -ENODEV; 17163b5dd52aSJames Smart 17173b5dd52aSJames Smart 17183b5dd52aSJames Smart if ((phba->link_state == LPFC_HBA_ERROR) || 17193b5dd52aSJames Smart (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || 17207ad20aa9SJames Smart (!(psli->sli_flag & LPFC_SLI_ACTIVE))) 17217ad20aa9SJames Smart return -EACCES; 17223b5dd52aSJames Smart 17233b5dd52aSJames Smart vports = lpfc_create_vport_work_array(phba); 17243b5dd52aSJames Smart if (vports) { 17253b5dd52aSJames Smart for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { 17263b5dd52aSJames Smart shost = lpfc_shost_from_vport(vports[i]); 17273b5dd52aSJames Smart scsi_block_requests(shost); 17283b5dd52aSJames Smart } 17293b5dd52aSJames Smart lpfc_destroy_vport_work_array(phba, vports); 17303b5dd52aSJames Smart } else { 17313b5dd52aSJames Smart shost = lpfc_shost_from_vport(phba->pport); 17323b5dd52aSJames Smart scsi_block_requests(shost); 17333b5dd52aSJames Smart } 17343b5dd52aSJames Smart 1735895427bdSJames Smart if (phba->sli_rev != LPFC_SLI_REV4) { 1736895427bdSJames Smart pring = &psli->sli3_ring[LPFC_FCP_RING]; 1737895427bdSJames Smart lpfc_emptyq_wait(phba, &pring->txcmplq, &phba->hbalock); 1738895427bdSJames Smart return 0; 1739895427bdSJames Smart } 1740895427bdSJames Smart list_for_each_entry(qp, &phba->sli4_hba.lpfc_wq_list, wq_list) { 1741895427bdSJames Smart pring = qp->pring; 1742895427bdSJames Smart if (!pring || (pring->ringno != LPFC_FCP_RING)) 1743895427bdSJames Smart continue; 1744895427bdSJames Smart if (!lpfc_emptyq_wait(phba, &pring->txcmplq, 1745895427bdSJames Smart &pring->ring_lock)) 17463b5dd52aSJames Smart break; 17473b5dd52aSJames Smart } 17487ad20aa9SJames Smart return 0; 17497ad20aa9SJames Smart } 17503b5dd52aSJames Smart 17517ad20aa9SJames Smart /** 17527ad20aa9SJames Smart * lpfc_bsg_diag_mode_exit - exit process from device diag loopback mode 17537ad20aa9SJames Smart * @phba: Pointer to HBA context object. 17547ad20aa9SJames Smart * 17557ad20aa9SJames Smart * This function is responsible for driver exit processing of setting up 17567ad20aa9SJames Smart * diag loopback mode on device. 17577ad20aa9SJames Smart */ 17587ad20aa9SJames Smart static void 17597ad20aa9SJames Smart lpfc_bsg_diag_mode_exit(struct lpfc_hba *phba) 17607ad20aa9SJames Smart { 17617ad20aa9SJames Smart struct Scsi_Host *shost; 17627ad20aa9SJames Smart struct lpfc_vport **vports; 17637ad20aa9SJames Smart int i; 17647ad20aa9SJames Smart 17657ad20aa9SJames Smart vports = lpfc_create_vport_work_array(phba); 17667ad20aa9SJames Smart if (vports) { 17677ad20aa9SJames Smart for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { 17687ad20aa9SJames Smart shost = lpfc_shost_from_vport(vports[i]); 17697ad20aa9SJames Smart scsi_unblock_requests(shost); 17707ad20aa9SJames Smart } 17717ad20aa9SJames Smart lpfc_destroy_vport_work_array(phba, vports); 17727ad20aa9SJames Smart } else { 17737ad20aa9SJames Smart shost = lpfc_shost_from_vport(phba->pport); 17747ad20aa9SJames Smart scsi_unblock_requests(shost); 17757ad20aa9SJames Smart } 17767ad20aa9SJames Smart return; 17777ad20aa9SJames Smart } 17787ad20aa9SJames Smart 17797ad20aa9SJames Smart /** 17807ad20aa9SJames Smart * lpfc_sli3_bsg_diag_loopback_mode - process an sli3 bsg vendor command 17817ad20aa9SJames Smart * @phba: Pointer to HBA context object. 17827ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_MODE 17837ad20aa9SJames Smart * 17847ad20aa9SJames Smart * This function is responsible for placing an sli3 port into diagnostic 17857ad20aa9SJames Smart * loopback mode in order to perform a diagnostic loopback test. 17867ad20aa9SJames Smart * All new scsi requests are blocked, a small delay is used to allow the 17877ad20aa9SJames Smart * scsi requests to complete then the link is brought down. If the link is 17887ad20aa9SJames Smart * is placed in loopback mode then scsi requests are again allowed 17897ad20aa9SJames Smart * so the scsi mid-layer doesn't give up on the port. 17907ad20aa9SJames Smart * All of this is done in-line. 17917ad20aa9SJames Smart */ 17927ad20aa9SJames Smart static int 179375cc8cfcSJohannes Thumshirn lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job) 17947ad20aa9SJames Smart { 179501e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 179601e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 17977ad20aa9SJames Smart struct diag_mode_set *loopback_mode; 17987ad20aa9SJames Smart uint32_t link_flags; 17997ad20aa9SJames Smart uint32_t timeout; 18001b51197dSJames Smart LPFC_MBOXQ_t *pmboxq = NULL; 1801b76f2dc9SJames Smart int mbxstatus = MBX_SUCCESS; 18027ad20aa9SJames Smart int i = 0; 18037ad20aa9SJames Smart int rc = 0; 18047ad20aa9SJames Smart 18057ad20aa9SJames Smart /* no data to return just the return code */ 180601e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 18077ad20aa9SJames Smart 18087ad20aa9SJames Smart if (job->request_len < sizeof(struct fc_bsg_request) + 18097ad20aa9SJames Smart sizeof(struct diag_mode_set)) { 18107ad20aa9SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 18117ad20aa9SJames Smart "2738 Received DIAG MODE request size:%d " 18127ad20aa9SJames Smart "below the minimum size:%d\n", 18137ad20aa9SJames Smart job->request_len, 18147ad20aa9SJames Smart (int)(sizeof(struct fc_bsg_request) + 18157ad20aa9SJames Smart sizeof(struct diag_mode_set))); 18167ad20aa9SJames Smart rc = -EINVAL; 18177ad20aa9SJames Smart goto job_error; 18187ad20aa9SJames Smart } 18197ad20aa9SJames Smart 182088a2cfbbSJames Smart rc = lpfc_bsg_diag_mode_enter(phba); 18217ad20aa9SJames Smart if (rc) 18227ad20aa9SJames Smart goto job_error; 18237ad20aa9SJames Smart 18247ad20aa9SJames Smart /* bring the link to diagnostic mode */ 18257ad20aa9SJames Smart loopback_mode = (struct diag_mode_set *) 182601e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 18277ad20aa9SJames Smart link_flags = loopback_mode->type; 18287ad20aa9SJames Smart timeout = loopback_mode->timeout * 100; 18297ad20aa9SJames Smart 18307ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 18317ad20aa9SJames Smart if (!pmboxq) { 18327ad20aa9SJames Smart rc = -ENOMEM; 18337ad20aa9SJames Smart goto loopback_mode_exit; 18347ad20aa9SJames Smart } 18353b5dd52aSJames Smart memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 18363b5dd52aSJames Smart pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK; 18373b5dd52aSJames Smart pmboxq->u.mb.mbxOwner = OWN_HOST; 18383b5dd52aSJames Smart 18393b5dd52aSJames Smart mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); 18403b5dd52aSJames Smart 18413b5dd52aSJames Smart if ((mbxstatus == MBX_SUCCESS) && (pmboxq->u.mb.mbxStatus == 0)) { 18423b5dd52aSJames Smart /* wait for link down before proceeding */ 18433b5dd52aSJames Smart i = 0; 18443b5dd52aSJames Smart while (phba->link_state != LPFC_LINK_DOWN) { 18453b5dd52aSJames Smart if (i++ > timeout) { 18463b5dd52aSJames Smart rc = -ETIMEDOUT; 18473b5dd52aSJames Smart goto loopback_mode_exit; 18483b5dd52aSJames Smart } 18493b5dd52aSJames Smart msleep(10); 18503b5dd52aSJames Smart } 18513b5dd52aSJames Smart 18523b5dd52aSJames Smart memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 18533b5dd52aSJames Smart if (link_flags == INTERNAL_LOOP_BACK) 18543b5dd52aSJames Smart pmboxq->u.mb.un.varInitLnk.link_flags = FLAGS_LOCAL_LB; 18553b5dd52aSJames Smart else 18563b5dd52aSJames Smart pmboxq->u.mb.un.varInitLnk.link_flags = 18573b5dd52aSJames Smart FLAGS_TOPOLOGY_MODE_LOOP; 18583b5dd52aSJames Smart 18593b5dd52aSJames Smart pmboxq->u.mb.mbxCommand = MBX_INIT_LINK; 18603b5dd52aSJames Smart pmboxq->u.mb.mbxOwner = OWN_HOST; 18613b5dd52aSJames Smart 18623b5dd52aSJames Smart mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, 18633b5dd52aSJames Smart LPFC_MBOX_TMO); 18643b5dd52aSJames Smart 18653b5dd52aSJames Smart if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) 18663b5dd52aSJames Smart rc = -ENODEV; 18673b5dd52aSJames Smart else { 18681b51197dSJames Smart spin_lock_irq(&phba->hbalock); 18693b5dd52aSJames Smart phba->link_flag |= LS_LOOPBACK_MODE; 18701b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 18713b5dd52aSJames Smart /* wait for the link attention interrupt */ 18723b5dd52aSJames Smart msleep(100); 18733b5dd52aSJames Smart 18743b5dd52aSJames Smart i = 0; 18753b5dd52aSJames Smart while (phba->link_state != LPFC_HBA_READY) { 18763b5dd52aSJames Smart if (i++ > timeout) { 18773b5dd52aSJames Smart rc = -ETIMEDOUT; 18783b5dd52aSJames Smart break; 18793b5dd52aSJames Smart } 18803b5dd52aSJames Smart 18813b5dd52aSJames Smart msleep(10); 18823b5dd52aSJames Smart } 18833b5dd52aSJames Smart } 18843b5dd52aSJames Smart 18853b5dd52aSJames Smart } else 18863b5dd52aSJames Smart rc = -ENODEV; 18873b5dd52aSJames Smart 18883b5dd52aSJames Smart loopback_mode_exit: 18897ad20aa9SJames Smart lpfc_bsg_diag_mode_exit(phba); 18903b5dd52aSJames Smart 18913b5dd52aSJames Smart /* 18923b5dd52aSJames Smart * Let SLI layer release mboxq if mbox command completed after timeout. 18933b5dd52aSJames Smart */ 18941b51197dSJames Smart if (pmboxq && mbxstatus != MBX_TIMEOUT) 18953b5dd52aSJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 18963b5dd52aSJames Smart 18973b5dd52aSJames Smart job_error: 18983b5dd52aSJames Smart /* make error code available to userspace */ 189901e0e15cSJohannes Thumshirn bsg_reply->result = rc; 19003b5dd52aSJames Smart /* complete the job back to userspace if no error */ 19013b5dd52aSJames Smart if (rc == 0) 190206548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 19031abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 19043b5dd52aSJames Smart return rc; 19053b5dd52aSJames Smart } 19063b5dd52aSJames Smart 19073b5dd52aSJames Smart /** 19087ad20aa9SJames Smart * lpfc_sli4_bsg_set_link_diag_state - set sli4 link diag state 19097ad20aa9SJames Smart * @phba: Pointer to HBA context object. 19107ad20aa9SJames Smart * @diag: Flag for set link to diag or nomral operation state. 19117ad20aa9SJames Smart * 19127ad20aa9SJames Smart * This function is responsible for issuing a sli4 mailbox command for setting 19137ad20aa9SJames Smart * link to either diag state or normal operation state. 19147ad20aa9SJames Smart */ 19157ad20aa9SJames Smart static int 19167ad20aa9SJames Smart lpfc_sli4_bsg_set_link_diag_state(struct lpfc_hba *phba, uint32_t diag) 19177ad20aa9SJames Smart { 19187ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq; 19197ad20aa9SJames Smart struct lpfc_mbx_set_link_diag_state *link_diag_state; 19207ad20aa9SJames Smart uint32_t req_len, alloc_len; 19217ad20aa9SJames Smart int mbxstatus = MBX_SUCCESS, rc; 19227ad20aa9SJames Smart 19237ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 19247ad20aa9SJames Smart if (!pmboxq) 19257ad20aa9SJames Smart return -ENOMEM; 19267ad20aa9SJames Smart 19277ad20aa9SJames Smart req_len = (sizeof(struct lpfc_mbx_set_link_diag_state) - 19287ad20aa9SJames Smart sizeof(struct lpfc_sli4_cfg_mhdr)); 19297ad20aa9SJames Smart alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, 19307ad20aa9SJames Smart LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE, 19317ad20aa9SJames Smart req_len, LPFC_SLI4_MBX_EMBED); 19327ad20aa9SJames Smart if (alloc_len != req_len) { 19337ad20aa9SJames Smart rc = -ENOMEM; 19347ad20aa9SJames Smart goto link_diag_state_set_out; 19357ad20aa9SJames Smart } 19361b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 19371b51197dSJames Smart "3128 Set link to diagnostic state:x%x (x%x/x%x)\n", 19381b51197dSJames Smart diag, phba->sli4_hba.lnk_info.lnk_tp, 19391b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_no); 19401b51197dSJames Smart 19417ad20aa9SJames Smart link_diag_state = &pmboxq->u.mqe.un.link_diag_state; 19429731592bSJames Smart bf_set(lpfc_mbx_set_diag_state_diag_bit_valid, &link_diag_state->u.req, 19439731592bSJames Smart LPFC_DIAG_STATE_DIAG_BIT_VALID_CHANGE); 19447ad20aa9SJames Smart bf_set(lpfc_mbx_set_diag_state_link_num, &link_diag_state->u.req, 19451b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_no); 19467ad20aa9SJames Smart bf_set(lpfc_mbx_set_diag_state_link_type, &link_diag_state->u.req, 19471b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_tp); 19487ad20aa9SJames Smart if (diag) 19497ad20aa9SJames Smart bf_set(lpfc_mbx_set_diag_state_diag, 19507ad20aa9SJames Smart &link_diag_state->u.req, 1); 19517ad20aa9SJames Smart else 19527ad20aa9SJames Smart bf_set(lpfc_mbx_set_diag_state_diag, 19537ad20aa9SJames Smart &link_diag_state->u.req, 0); 19547ad20aa9SJames Smart 19557ad20aa9SJames Smart mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); 19567ad20aa9SJames Smart 19577ad20aa9SJames Smart if ((mbxstatus == MBX_SUCCESS) && (pmboxq->u.mb.mbxStatus == 0)) 19587ad20aa9SJames Smart rc = 0; 19597ad20aa9SJames Smart else 19607ad20aa9SJames Smart rc = -ENODEV; 19617ad20aa9SJames Smart 19627ad20aa9SJames Smart link_diag_state_set_out: 19637ad20aa9SJames Smart if (pmboxq && (mbxstatus != MBX_TIMEOUT)) 19647ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 19657ad20aa9SJames Smart 19667ad20aa9SJames Smart return rc; 19677ad20aa9SJames Smart } 19687ad20aa9SJames Smart 19697ad20aa9SJames Smart /** 19701b51197dSJames Smart * lpfc_sli4_bsg_set_internal_loopback - set sli4 internal loopback diagnostic 19711b51197dSJames Smart * @phba: Pointer to HBA context object. 19721b51197dSJames Smart * 19731b51197dSJames Smart * This function is responsible for issuing a sli4 mailbox command for setting 19741b51197dSJames Smart * up internal loopback diagnostic. 19751b51197dSJames Smart */ 19761b51197dSJames Smart static int 19771b51197dSJames Smart lpfc_sli4_bsg_set_internal_loopback(struct lpfc_hba *phba) 19781b51197dSJames Smart { 19791b51197dSJames Smart LPFC_MBOXQ_t *pmboxq; 19801b51197dSJames Smart uint32_t req_len, alloc_len; 19811b51197dSJames Smart struct lpfc_mbx_set_link_diag_loopback *link_diag_loopback; 19821b51197dSJames Smart int mbxstatus = MBX_SUCCESS, rc = 0; 19831b51197dSJames Smart 19841b51197dSJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 19851b51197dSJames Smart if (!pmboxq) 19861b51197dSJames Smart return -ENOMEM; 19871b51197dSJames Smart req_len = (sizeof(struct lpfc_mbx_set_link_diag_loopback) - 19881b51197dSJames Smart sizeof(struct lpfc_sli4_cfg_mhdr)); 19891b51197dSJames Smart alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, 19901b51197dSJames Smart LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK, 19911b51197dSJames Smart req_len, LPFC_SLI4_MBX_EMBED); 19921b51197dSJames Smart if (alloc_len != req_len) { 19931b51197dSJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 19941b51197dSJames Smart return -ENOMEM; 19951b51197dSJames Smart } 19961b51197dSJames Smart link_diag_loopback = &pmboxq->u.mqe.un.link_diag_loopback; 19971b51197dSJames Smart bf_set(lpfc_mbx_set_diag_state_link_num, 19981b51197dSJames Smart &link_diag_loopback->u.req, phba->sli4_hba.lnk_info.lnk_no); 19991b51197dSJames Smart bf_set(lpfc_mbx_set_diag_state_link_type, 20001b51197dSJames Smart &link_diag_loopback->u.req, phba->sli4_hba.lnk_info.lnk_tp); 20011b51197dSJames Smart bf_set(lpfc_mbx_set_diag_lpbk_type, &link_diag_loopback->u.req, 20023ef6d24cSJames Smart LPFC_DIAG_LOOPBACK_TYPE_INTERNAL); 20031b51197dSJames Smart 20041b51197dSJames Smart mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); 20051b51197dSJames Smart if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) { 20061b51197dSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 20071b51197dSJames Smart "3127 Failed setup loopback mode mailbox " 20081b51197dSJames Smart "command, rc:x%x, status:x%x\n", mbxstatus, 20091b51197dSJames Smart pmboxq->u.mb.mbxStatus); 20101b51197dSJames Smart rc = -ENODEV; 20111b51197dSJames Smart } 20121b51197dSJames Smart if (pmboxq && (mbxstatus != MBX_TIMEOUT)) 20131b51197dSJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 20141b51197dSJames Smart return rc; 20151b51197dSJames Smart } 20161b51197dSJames Smart 20171b51197dSJames Smart /** 20181b51197dSJames Smart * lpfc_sli4_diag_fcport_reg_setup - setup port registrations for diagnostic 20191b51197dSJames Smart * @phba: Pointer to HBA context object. 20201b51197dSJames Smart * 20211b51197dSJames Smart * This function set up SLI4 FC port registrations for diagnostic run, which 20221b51197dSJames Smart * includes all the rpis, vfi, and also vpi. 20231b51197dSJames Smart */ 20241b51197dSJames Smart static int 20251b51197dSJames Smart lpfc_sli4_diag_fcport_reg_setup(struct lpfc_hba *phba) 20261b51197dSJames Smart { 20271b51197dSJames Smart int rc; 20281b51197dSJames Smart 20291b51197dSJames Smart if (phba->pport->fc_flag & FC_VFI_REGISTERED) { 20301b51197dSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 20311b51197dSJames Smart "3136 Port still had vfi registered: " 20321b51197dSJames Smart "mydid:x%x, fcfi:%d, vfi:%d, vpi:%d\n", 20331b51197dSJames Smart phba->pport->fc_myDID, phba->fcf.fcfi, 20341b51197dSJames Smart phba->sli4_hba.vfi_ids[phba->pport->vfi], 20351b51197dSJames Smart phba->vpi_ids[phba->pport->vpi]); 20361b51197dSJames Smart return -EINVAL; 20371b51197dSJames Smart } 20381b51197dSJames Smart rc = lpfc_issue_reg_vfi(phba->pport); 20391b51197dSJames Smart return rc; 20401b51197dSJames Smart } 20411b51197dSJames Smart 20421b51197dSJames Smart /** 20437ad20aa9SJames Smart * lpfc_sli4_bsg_diag_loopback_mode - process an sli4 bsg vendor command 20447ad20aa9SJames Smart * @phba: Pointer to HBA context object. 20457ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_MODE 20467ad20aa9SJames Smart * 20477ad20aa9SJames Smart * This function is responsible for placing an sli4 port into diagnostic 20487ad20aa9SJames Smart * loopback mode in order to perform a diagnostic loopback test. 20497ad20aa9SJames Smart */ 20507ad20aa9SJames Smart static int 205175cc8cfcSJohannes Thumshirn lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job) 20527ad20aa9SJames Smart { 205301e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 205401e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 20557ad20aa9SJames Smart struct diag_mode_set *loopback_mode; 20561b51197dSJames Smart uint32_t link_flags, timeout; 20571b51197dSJames Smart int i, rc = 0; 20587ad20aa9SJames Smart 20597ad20aa9SJames Smart /* no data to return just the return code */ 206001e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 20617ad20aa9SJames Smart 20627ad20aa9SJames Smart if (job->request_len < sizeof(struct fc_bsg_request) + 20637ad20aa9SJames Smart sizeof(struct diag_mode_set)) { 20647ad20aa9SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 20657ad20aa9SJames Smart "3011 Received DIAG MODE request size:%d " 20667ad20aa9SJames Smart "below the minimum size:%d\n", 20677ad20aa9SJames Smart job->request_len, 20687ad20aa9SJames Smart (int)(sizeof(struct fc_bsg_request) + 20697ad20aa9SJames Smart sizeof(struct diag_mode_set))); 20707ad20aa9SJames Smart rc = -EINVAL; 20717ad20aa9SJames Smart goto job_error; 20727ad20aa9SJames Smart } 20737ad20aa9SJames Smart 207488a2cfbbSJames Smart rc = lpfc_bsg_diag_mode_enter(phba); 20757ad20aa9SJames Smart if (rc) 20767ad20aa9SJames Smart goto job_error; 20777ad20aa9SJames Smart 20781b51197dSJames Smart /* indicate we are in loobpack diagnostic mode */ 20791b51197dSJames Smart spin_lock_irq(&phba->hbalock); 20801b51197dSJames Smart phba->link_flag |= LS_LOOPBACK_MODE; 20811b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 20821b51197dSJames Smart 20831b51197dSJames Smart /* reset port to start frome scratch */ 20841b51197dSJames Smart rc = lpfc_selective_reset(phba); 20851b51197dSJames Smart if (rc) 20861b51197dSJames Smart goto job_error; 20871b51197dSJames Smart 20887ad20aa9SJames Smart /* bring the link to diagnostic mode */ 20891b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 20901b51197dSJames Smart "3129 Bring link to diagnostic state.\n"); 20917ad20aa9SJames Smart loopback_mode = (struct diag_mode_set *) 209201e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 20937ad20aa9SJames Smart link_flags = loopback_mode->type; 20947ad20aa9SJames Smart timeout = loopback_mode->timeout * 100; 20957ad20aa9SJames Smart 20967ad20aa9SJames Smart rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1); 20971b51197dSJames Smart if (rc) { 20981b51197dSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 20991b51197dSJames Smart "3130 Failed to bring link to diagnostic " 21001b51197dSJames Smart "state, rc:x%x\n", rc); 21017ad20aa9SJames Smart goto loopback_mode_exit; 21021b51197dSJames Smart } 21037ad20aa9SJames Smart 21047ad20aa9SJames Smart /* wait for link down before proceeding */ 21057ad20aa9SJames Smart i = 0; 21067ad20aa9SJames Smart while (phba->link_state != LPFC_LINK_DOWN) { 21077ad20aa9SJames Smart if (i++ > timeout) { 21087ad20aa9SJames Smart rc = -ETIMEDOUT; 21091b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 21101b51197dSJames Smart "3131 Timeout waiting for link to " 21111b51197dSJames Smart "diagnostic mode, timeout:%d ms\n", 21121b51197dSJames Smart timeout * 10); 21137ad20aa9SJames Smart goto loopback_mode_exit; 21147ad20aa9SJames Smart } 21157ad20aa9SJames Smart msleep(10); 21167ad20aa9SJames Smart } 21177ad20aa9SJames Smart 21181b51197dSJames Smart /* set up loopback mode */ 21191b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 21201b51197dSJames Smart "3132 Set up loopback mode:x%x\n", link_flags); 21211b51197dSJames Smart 21221b51197dSJames Smart if (link_flags == INTERNAL_LOOP_BACK) 21231b51197dSJames Smart rc = lpfc_sli4_bsg_set_internal_loopback(phba); 21241b51197dSJames Smart else if (link_flags == EXTERNAL_LOOP_BACK) 21251b51197dSJames Smart rc = lpfc_hba_init_link_fc_topology(phba, 21261b51197dSJames Smart FLAGS_TOPOLOGY_MODE_PT_PT, 21271b51197dSJames Smart MBX_NOWAIT); 21287ad20aa9SJames Smart else { 21291b51197dSJames Smart rc = -EINVAL; 21301b51197dSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 21311b51197dSJames Smart "3141 Loopback mode:x%x not supported\n", 21321b51197dSJames Smart link_flags); 21331b51197dSJames Smart goto loopback_mode_exit; 21341b51197dSJames Smart } 21351b51197dSJames Smart 21361b51197dSJames Smart if (!rc) { 21377ad20aa9SJames Smart /* wait for the link attention interrupt */ 21387ad20aa9SJames Smart msleep(100); 21397ad20aa9SJames Smart i = 0; 21401b51197dSJames Smart while (phba->link_state < LPFC_LINK_UP) { 21411b51197dSJames Smart if (i++ > timeout) { 21421b51197dSJames Smart rc = -ETIMEDOUT; 21431b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 21441b51197dSJames Smart "3137 Timeout waiting for link up " 21451b51197dSJames Smart "in loopback mode, timeout:%d ms\n", 21461b51197dSJames Smart timeout * 10); 21471b51197dSJames Smart break; 21481b51197dSJames Smart } 21491b51197dSJames Smart msleep(10); 21501b51197dSJames Smart } 21511b51197dSJames Smart } 21521b51197dSJames Smart 21531b51197dSJames Smart /* port resource registration setup for loopback diagnostic */ 21541b51197dSJames Smart if (!rc) { 21551b51197dSJames Smart /* set up a none zero myDID for loopback test */ 21561b51197dSJames Smart phba->pport->fc_myDID = 1; 21571b51197dSJames Smart rc = lpfc_sli4_diag_fcport_reg_setup(phba); 21581b51197dSJames Smart } else 21591b51197dSJames Smart goto loopback_mode_exit; 21601b51197dSJames Smart 21611b51197dSJames Smart if (!rc) { 21621b51197dSJames Smart /* wait for the port ready */ 21631b51197dSJames Smart msleep(100); 21641b51197dSJames Smart i = 0; 21657ad20aa9SJames Smart while (phba->link_state != LPFC_HBA_READY) { 21667ad20aa9SJames Smart if (i++ > timeout) { 21677ad20aa9SJames Smart rc = -ETIMEDOUT; 21681b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 21691b51197dSJames Smart "3133 Timeout waiting for port " 21701b51197dSJames Smart "loopback mode ready, timeout:%d ms\n", 21711b51197dSJames Smart timeout * 10); 21727ad20aa9SJames Smart break; 21737ad20aa9SJames Smart } 21747ad20aa9SJames Smart msleep(10); 21757ad20aa9SJames Smart } 21767ad20aa9SJames Smart } 21777ad20aa9SJames Smart 21787ad20aa9SJames Smart loopback_mode_exit: 21791b51197dSJames Smart /* clear loopback diagnostic mode */ 21801b51197dSJames Smart if (rc) { 21811b51197dSJames Smart spin_lock_irq(&phba->hbalock); 21821b51197dSJames Smart phba->link_flag &= ~LS_LOOPBACK_MODE; 21831b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 21841b51197dSJames Smart } 21857ad20aa9SJames Smart lpfc_bsg_diag_mode_exit(phba); 21867ad20aa9SJames Smart 21877ad20aa9SJames Smart job_error: 21887ad20aa9SJames Smart /* make error code available to userspace */ 218901e0e15cSJohannes Thumshirn bsg_reply->result = rc; 21907ad20aa9SJames Smart /* complete the job back to userspace if no error */ 21917ad20aa9SJames Smart if (rc == 0) 219206548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 21931abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 21947ad20aa9SJames Smart return rc; 21957ad20aa9SJames Smart } 21967ad20aa9SJames Smart 21977ad20aa9SJames Smart /** 21987ad20aa9SJames Smart * lpfc_bsg_diag_loopback_mode - bsg vendor command for diag loopback mode 21997ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_MODE 22007ad20aa9SJames Smart * 22017ad20aa9SJames Smart * This function is responsible for responding to check and dispatch bsg diag 22027ad20aa9SJames Smart * command from the user to proper driver action routines. 22037ad20aa9SJames Smart */ 22047ad20aa9SJames Smart static int 220575cc8cfcSJohannes Thumshirn lpfc_bsg_diag_loopback_mode(struct bsg_job *job) 22067ad20aa9SJames Smart { 22077ad20aa9SJames Smart struct Scsi_Host *shost; 22087ad20aa9SJames Smart struct lpfc_vport *vport; 22097ad20aa9SJames Smart struct lpfc_hba *phba; 22107ad20aa9SJames Smart int rc; 22117ad20aa9SJames Smart 2212cd21c605SJohannes Thumshirn shost = fc_bsg_to_shost(job); 22137ad20aa9SJames Smart if (!shost) 22147ad20aa9SJames Smart return -ENODEV; 2215cd21c605SJohannes Thumshirn vport = shost_priv(shost); 22167ad20aa9SJames Smart if (!vport) 22177ad20aa9SJames Smart return -ENODEV; 22187ad20aa9SJames Smart phba = vport->phba; 22197ad20aa9SJames Smart if (!phba) 22207ad20aa9SJames Smart return -ENODEV; 22217ad20aa9SJames Smart 22227ad20aa9SJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 22237ad20aa9SJames Smart rc = lpfc_sli3_bsg_diag_loopback_mode(phba, job); 22247ad20aa9SJames Smart else if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == 22257ad20aa9SJames Smart LPFC_SLI_INTF_IF_TYPE_2) 22267ad20aa9SJames Smart rc = lpfc_sli4_bsg_diag_loopback_mode(phba, job); 22277ad20aa9SJames Smart else 22287ad20aa9SJames Smart rc = -ENODEV; 22297ad20aa9SJames Smart 22307ad20aa9SJames Smart return rc; 22317ad20aa9SJames Smart } 22327ad20aa9SJames Smart 22337ad20aa9SJames Smart /** 22347ad20aa9SJames Smart * lpfc_sli4_bsg_diag_mode_end - sli4 bsg vendor command for ending diag mode 22357ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_MODE_END 22367ad20aa9SJames Smart * 22377ad20aa9SJames Smart * This function is responsible for responding to check and dispatch bsg diag 22387ad20aa9SJames Smart * command from the user to proper driver action routines. 22397ad20aa9SJames Smart */ 22407ad20aa9SJames Smart static int 224175cc8cfcSJohannes Thumshirn lpfc_sli4_bsg_diag_mode_end(struct bsg_job *job) 22427ad20aa9SJames Smart { 224301e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 224401e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 22457ad20aa9SJames Smart struct Scsi_Host *shost; 22467ad20aa9SJames Smart struct lpfc_vport *vport; 22477ad20aa9SJames Smart struct lpfc_hba *phba; 22481b51197dSJames Smart struct diag_mode_set *loopback_mode_end_cmd; 22491b51197dSJames Smart uint32_t timeout; 22501b51197dSJames Smart int rc, i; 22517ad20aa9SJames Smart 2252cd21c605SJohannes Thumshirn shost = fc_bsg_to_shost(job); 22537ad20aa9SJames Smart if (!shost) 22547ad20aa9SJames Smart return -ENODEV; 2255cd21c605SJohannes Thumshirn vport = shost_priv(shost); 22567ad20aa9SJames Smart if (!vport) 22577ad20aa9SJames Smart return -ENODEV; 22587ad20aa9SJames Smart phba = vport->phba; 22597ad20aa9SJames Smart if (!phba) 22607ad20aa9SJames Smart return -ENODEV; 22617ad20aa9SJames Smart 22627ad20aa9SJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 22637ad20aa9SJames Smart return -ENODEV; 22647ad20aa9SJames Smart if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != 22657ad20aa9SJames Smart LPFC_SLI_INTF_IF_TYPE_2) 22667ad20aa9SJames Smart return -ENODEV; 22677ad20aa9SJames Smart 22681b51197dSJames Smart /* clear loopback diagnostic mode */ 22691b51197dSJames Smart spin_lock_irq(&phba->hbalock); 22701b51197dSJames Smart phba->link_flag &= ~LS_LOOPBACK_MODE; 22711b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 22721b51197dSJames Smart loopback_mode_end_cmd = (struct diag_mode_set *) 227301e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 22741b51197dSJames Smart timeout = loopback_mode_end_cmd->timeout * 100; 22751b51197dSJames Smart 22767ad20aa9SJames Smart rc = lpfc_sli4_bsg_set_link_diag_state(phba, 0); 22771b51197dSJames Smart if (rc) { 22781b51197dSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 22791b51197dSJames Smart "3139 Failed to bring link to diagnostic " 22801b51197dSJames Smart "state, rc:x%x\n", rc); 22811b51197dSJames Smart goto loopback_mode_end_exit; 22821b51197dSJames Smart } 22837ad20aa9SJames Smart 22841b51197dSJames Smart /* wait for link down before proceeding */ 22851b51197dSJames Smart i = 0; 22861b51197dSJames Smart while (phba->link_state != LPFC_LINK_DOWN) { 22871b51197dSJames Smart if (i++ > timeout) { 22881b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 22891b51197dSJames Smart "3140 Timeout waiting for link to " 22901b51197dSJames Smart "diagnostic mode_end, timeout:%d ms\n", 22911b51197dSJames Smart timeout * 10); 22921b51197dSJames Smart /* there is nothing much we can do here */ 22931b51197dSJames Smart break; 22941b51197dSJames Smart } 22951b51197dSJames Smart msleep(10); 22961b51197dSJames Smart } 22977ad20aa9SJames Smart 22981b51197dSJames Smart /* reset port resource registrations */ 22991b51197dSJames Smart rc = lpfc_selective_reset(phba); 23001b51197dSJames Smart phba->pport->fc_myDID = 0; 23011b51197dSJames Smart 23021b51197dSJames Smart loopback_mode_end_exit: 23031b51197dSJames Smart /* make return code available to userspace */ 230401e0e15cSJohannes Thumshirn bsg_reply->result = rc; 23051b51197dSJames Smart /* complete the job back to userspace if no error */ 23061b51197dSJames Smart if (rc == 0) 230706548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 23081abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 23097ad20aa9SJames Smart return rc; 23107ad20aa9SJames Smart } 23117ad20aa9SJames Smart 23127ad20aa9SJames Smart /** 23137ad20aa9SJames Smart * lpfc_sli4_bsg_link_diag_test - sli4 bsg vendor command for diag link test 23147ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_LINK_TEST 23157ad20aa9SJames Smart * 23167ad20aa9SJames Smart * This function is to perform SLI4 diag link test request from the user 23177ad20aa9SJames Smart * applicaiton. 23187ad20aa9SJames Smart */ 23197ad20aa9SJames Smart static int 232075cc8cfcSJohannes Thumshirn lpfc_sli4_bsg_link_diag_test(struct bsg_job *job) 23217ad20aa9SJames Smart { 232201e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 232301e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 23247ad20aa9SJames Smart struct Scsi_Host *shost; 23257ad20aa9SJames Smart struct lpfc_vport *vport; 23267ad20aa9SJames Smart struct lpfc_hba *phba; 23277ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq; 23287ad20aa9SJames Smart struct sli4_link_diag *link_diag_test_cmd; 23297ad20aa9SJames Smart uint32_t req_len, alloc_len; 23307ad20aa9SJames Smart struct lpfc_mbx_run_link_diag_test *run_link_diag_test; 23317ad20aa9SJames Smart union lpfc_sli4_cfg_shdr *shdr; 23327ad20aa9SJames Smart uint32_t shdr_status, shdr_add_status; 23337ad20aa9SJames Smart struct diag_status *diag_status_reply; 23347ad20aa9SJames Smart int mbxstatus, rc = 0; 23357ad20aa9SJames Smart 2336cd21c605SJohannes Thumshirn shost = fc_bsg_to_shost(job); 23377ad20aa9SJames Smart if (!shost) { 23387ad20aa9SJames Smart rc = -ENODEV; 23397ad20aa9SJames Smart goto job_error; 23407ad20aa9SJames Smart } 2341cd21c605SJohannes Thumshirn vport = shost_priv(shost); 23427ad20aa9SJames Smart if (!vport) { 23437ad20aa9SJames Smart rc = -ENODEV; 23447ad20aa9SJames Smart goto job_error; 23457ad20aa9SJames Smart } 23467ad20aa9SJames Smart phba = vport->phba; 23477ad20aa9SJames Smart if (!phba) { 23487ad20aa9SJames Smart rc = -ENODEV; 23497ad20aa9SJames Smart goto job_error; 23507ad20aa9SJames Smart } 23517ad20aa9SJames Smart 23527ad20aa9SJames Smart if (phba->sli_rev < LPFC_SLI_REV4) { 23537ad20aa9SJames Smart rc = -ENODEV; 23547ad20aa9SJames Smart goto job_error; 23557ad20aa9SJames Smart } 23567ad20aa9SJames Smart if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != 23577ad20aa9SJames Smart LPFC_SLI_INTF_IF_TYPE_2) { 23587ad20aa9SJames Smart rc = -ENODEV; 23597ad20aa9SJames Smart goto job_error; 23607ad20aa9SJames Smart } 23617ad20aa9SJames Smart 23627ad20aa9SJames Smart if (job->request_len < sizeof(struct fc_bsg_request) + 23637ad20aa9SJames Smart sizeof(struct sli4_link_diag)) { 23647ad20aa9SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 23657ad20aa9SJames Smart "3013 Received LINK DIAG TEST request " 23667ad20aa9SJames Smart " size:%d below the minimum size:%d\n", 23677ad20aa9SJames Smart job->request_len, 23687ad20aa9SJames Smart (int)(sizeof(struct fc_bsg_request) + 23697ad20aa9SJames Smart sizeof(struct sli4_link_diag))); 23707ad20aa9SJames Smart rc = -EINVAL; 23717ad20aa9SJames Smart goto job_error; 23727ad20aa9SJames Smart } 23737ad20aa9SJames Smart 237488a2cfbbSJames Smart rc = lpfc_bsg_diag_mode_enter(phba); 23757ad20aa9SJames Smart if (rc) 23767ad20aa9SJames Smart goto job_error; 23777ad20aa9SJames Smart 23787ad20aa9SJames Smart link_diag_test_cmd = (struct sli4_link_diag *) 237901e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 23807ad20aa9SJames Smart 23817ad20aa9SJames Smart rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1); 23827ad20aa9SJames Smart 23837ad20aa9SJames Smart if (rc) 23847ad20aa9SJames Smart goto job_error; 23857ad20aa9SJames Smart 23867ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 238744ed33e6SGustavo A. R. Silva if (!pmboxq) 23887ad20aa9SJames Smart goto link_diag_test_exit; 23897ad20aa9SJames Smart 23907ad20aa9SJames Smart req_len = (sizeof(struct lpfc_mbx_set_link_diag_state) - 23917ad20aa9SJames Smart sizeof(struct lpfc_sli4_cfg_mhdr)); 23927ad20aa9SJames Smart alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, 23937ad20aa9SJames Smart LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE, 23947ad20aa9SJames Smart req_len, LPFC_SLI4_MBX_EMBED); 239544ed33e6SGustavo A. R. Silva if (alloc_len != req_len) 23967ad20aa9SJames Smart goto link_diag_test_exit; 239744ed33e6SGustavo A. R. Silva 23987ad20aa9SJames Smart run_link_diag_test = &pmboxq->u.mqe.un.link_diag_test; 23997ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_link_num, &run_link_diag_test->u.req, 24001b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_no); 24017ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_link_type, &run_link_diag_test->u.req, 24021b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_tp); 24037ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_test_id, &run_link_diag_test->u.req, 24047ad20aa9SJames Smart link_diag_test_cmd->test_id); 24057ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_loops, &run_link_diag_test->u.req, 24067ad20aa9SJames Smart link_diag_test_cmd->loops); 24077ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_test_ver, &run_link_diag_test->u.req, 24087ad20aa9SJames Smart link_diag_test_cmd->test_version); 24097ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_err_act, &run_link_diag_test->u.req, 24107ad20aa9SJames Smart link_diag_test_cmd->error_action); 24117ad20aa9SJames Smart 24127ad20aa9SJames Smart mbxstatus = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); 24137ad20aa9SJames Smart 24147ad20aa9SJames Smart shdr = (union lpfc_sli4_cfg_shdr *) 24157ad20aa9SJames Smart &pmboxq->u.mqe.un.sli4_config.header.cfg_shdr; 24167ad20aa9SJames Smart shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); 24177ad20aa9SJames Smart shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); 24187ad20aa9SJames Smart if (shdr_status || shdr_add_status || mbxstatus) { 24197ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 24207ad20aa9SJames Smart "3010 Run link diag test mailbox failed with " 24217ad20aa9SJames Smart "mbx_status x%x status x%x, add_status x%x\n", 24227ad20aa9SJames Smart mbxstatus, shdr_status, shdr_add_status); 24237ad20aa9SJames Smart } 24247ad20aa9SJames Smart 24257ad20aa9SJames Smart diag_status_reply = (struct diag_status *) 242601e0e15cSJohannes Thumshirn bsg_reply->reply_data.vendor_reply.vendor_rsp; 24277ad20aa9SJames Smart 24287ad20aa9SJames Smart if (job->reply_len < 24297ad20aa9SJames Smart sizeof(struct fc_bsg_request) + sizeof(struct diag_status)) { 24307ad20aa9SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 24317ad20aa9SJames Smart "3012 Received Run link diag test reply " 24327ad20aa9SJames Smart "below minimum size (%d): reply_len:%d\n", 24337ad20aa9SJames Smart (int)(sizeof(struct fc_bsg_request) + 24347ad20aa9SJames Smart sizeof(struct diag_status)), 24357ad20aa9SJames Smart job->reply_len); 24367ad20aa9SJames Smart rc = -EINVAL; 24377ad20aa9SJames Smart goto job_error; 24387ad20aa9SJames Smart } 24397ad20aa9SJames Smart 24407ad20aa9SJames Smart diag_status_reply->mbox_status = mbxstatus; 24417ad20aa9SJames Smart diag_status_reply->shdr_status = shdr_status; 24427ad20aa9SJames Smart diag_status_reply->shdr_add_status = shdr_add_status; 24437ad20aa9SJames Smart 24447ad20aa9SJames Smart link_diag_test_exit: 24457ad20aa9SJames Smart rc = lpfc_sli4_bsg_set_link_diag_state(phba, 0); 24467ad20aa9SJames Smart 24477ad20aa9SJames Smart if (pmboxq) 24487ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 24497ad20aa9SJames Smart 24507ad20aa9SJames Smart lpfc_bsg_diag_mode_exit(phba); 24517ad20aa9SJames Smart 24527ad20aa9SJames Smart job_error: 24537ad20aa9SJames Smart /* make error code available to userspace */ 245401e0e15cSJohannes Thumshirn bsg_reply->result = rc; 24557ad20aa9SJames Smart /* complete the job back to userspace if no error */ 24567ad20aa9SJames Smart if (rc == 0) 245706548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 24581abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 24597ad20aa9SJames Smart return rc; 24607ad20aa9SJames Smart } 24617ad20aa9SJames Smart 24627ad20aa9SJames Smart /** 24633b5dd52aSJames Smart * lpfcdiag_loop_self_reg - obtains a remote port login id 24643b5dd52aSJames Smart * @phba: Pointer to HBA context object 24653b5dd52aSJames Smart * @rpi: Pointer to a remote port login id 24663b5dd52aSJames Smart * 24673b5dd52aSJames Smart * This function obtains a remote port login id so the diag loopback test 24683b5dd52aSJames Smart * can send and receive its own unsolicited CT command. 24693b5dd52aSJames Smart **/ 24703b5dd52aSJames Smart static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t *rpi) 24713b5dd52aSJames Smart { 24723b5dd52aSJames Smart LPFC_MBOXQ_t *mbox; 24733b5dd52aSJames Smart struct lpfc_dmabuf *dmabuff; 24743b5dd52aSJames Smart int status; 24753b5dd52aSJames Smart 24763b5dd52aSJames Smart mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 24773b5dd52aSJames Smart if (!mbox) 2478d439d286SJames Smart return -ENOMEM; 24793b5dd52aSJames Smart 24801b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 24813b5dd52aSJames Smart status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID, 24821b51197dSJames Smart (uint8_t *)&phba->pport->fc_sparam, 24831b51197dSJames Smart mbox, *rpi); 24841b51197dSJames Smart else { 24851b51197dSJames Smart *rpi = lpfc_sli4_alloc_rpi(phba); 24869d3d340dSJames Smart if (*rpi == LPFC_RPI_ALLOC_ERROR) { 24879d3d340dSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 24889d3d340dSJames Smart return -EBUSY; 24899d3d340dSJames Smart } 24901b51197dSJames Smart status = lpfc_reg_rpi(phba, phba->pport->vpi, 24911b51197dSJames Smart phba->pport->fc_myDID, 24921b51197dSJames Smart (uint8_t *)&phba->pport->fc_sparam, 24931b51197dSJames Smart mbox, *rpi); 24941b51197dSJames Smart } 24951b51197dSJames Smart 24963b5dd52aSJames Smart if (status) { 24973b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 24984042629eSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 24994042629eSJames Smart lpfc_sli4_free_rpi(phba, *rpi); 2500d439d286SJames Smart return -ENOMEM; 25013b5dd52aSJames Smart } 25023b5dd52aSJames Smart 25033b5dd52aSJames Smart dmabuff = (struct lpfc_dmabuf *) mbox->context1; 25043b5dd52aSJames Smart mbox->context1 = NULL; 2505d439d286SJames Smart mbox->context2 = NULL; 25063b5dd52aSJames Smart status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); 25073b5dd52aSJames Smart 25083b5dd52aSJames Smart if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { 25093b5dd52aSJames Smart lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); 25103b5dd52aSJames Smart kfree(dmabuff); 25113b5dd52aSJames Smart if (status != MBX_TIMEOUT) 25123b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 25134042629eSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 25144042629eSJames Smart lpfc_sli4_free_rpi(phba, *rpi); 2515d439d286SJames Smart return -ENODEV; 25163b5dd52aSJames Smart } 25173b5dd52aSJames Smart 25181b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 25193b5dd52aSJames Smart *rpi = mbox->u.mb.un.varWords[0]; 25203b5dd52aSJames Smart 25213b5dd52aSJames Smart lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); 25223b5dd52aSJames Smart kfree(dmabuff); 25233b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 25243b5dd52aSJames Smart return 0; 25253b5dd52aSJames Smart } 25263b5dd52aSJames Smart 25273b5dd52aSJames Smart /** 25283b5dd52aSJames Smart * lpfcdiag_loop_self_unreg - unregs from the rpi 25293b5dd52aSJames Smart * @phba: Pointer to HBA context object 25303b5dd52aSJames Smart * @rpi: Remote port login id 25313b5dd52aSJames Smart * 25323b5dd52aSJames Smart * This function unregisters the rpi obtained in lpfcdiag_loop_self_reg 25333b5dd52aSJames Smart **/ 25343b5dd52aSJames Smart static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi) 25353b5dd52aSJames Smart { 25363b5dd52aSJames Smart LPFC_MBOXQ_t *mbox; 25373b5dd52aSJames Smart int status; 25383b5dd52aSJames Smart 25393b5dd52aSJames Smart /* Allocate mboxq structure */ 25403b5dd52aSJames Smart mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 25413b5dd52aSJames Smart if (mbox == NULL) 2542d439d286SJames Smart return -ENOMEM; 25433b5dd52aSJames Smart 25441b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 25453b5dd52aSJames Smart lpfc_unreg_login(phba, 0, rpi, mbox); 25461b51197dSJames Smart else 25471b51197dSJames Smart lpfc_unreg_login(phba, phba->pport->vpi, 25481b51197dSJames Smart phba->sli4_hba.rpi_ids[rpi], mbox); 25491b51197dSJames Smart 25503b5dd52aSJames Smart status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); 25513b5dd52aSJames Smart 25523b5dd52aSJames Smart if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { 25533b5dd52aSJames Smart if (status != MBX_TIMEOUT) 25543b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 2555d439d286SJames Smart return -EIO; 25563b5dd52aSJames Smart } 25573b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 25584042629eSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 25594042629eSJames Smart lpfc_sli4_free_rpi(phba, rpi); 25603b5dd52aSJames Smart return 0; 25613b5dd52aSJames Smart } 25623b5dd52aSJames Smart 25633b5dd52aSJames Smart /** 25643b5dd52aSJames Smart * lpfcdiag_loop_get_xri - obtains the transmit and receive ids 25653b5dd52aSJames Smart * @phba: Pointer to HBA context object 25663b5dd52aSJames Smart * @rpi: Remote port login id 25673b5dd52aSJames Smart * @txxri: Pointer to transmit exchange id 25683b5dd52aSJames Smart * @rxxri: Pointer to response exchabge id 25693b5dd52aSJames Smart * 25703b5dd52aSJames Smart * This function obtains the transmit and receive ids required to send 25713b5dd52aSJames Smart * an unsolicited ct command with a payload. A special lpfc FsType and CmdRsp 25723b5dd52aSJames Smart * flags are used to the unsolicted response handler is able to process 25733b5dd52aSJames Smart * the ct command sent on the same port. 25743b5dd52aSJames Smart **/ 25753b5dd52aSJames Smart static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, 25763b5dd52aSJames Smart uint16_t *txxri, uint16_t * rxxri) 25773b5dd52aSJames Smart { 25783b5dd52aSJames Smart struct lpfc_bsg_event *evt; 25793b5dd52aSJames Smart struct lpfc_iocbq *cmdiocbq, *rspiocbq; 25803b5dd52aSJames Smart IOCB_t *cmd, *rsp; 25813b5dd52aSJames Smart struct lpfc_dmabuf *dmabuf; 25823b5dd52aSJames Smart struct ulp_bde64 *bpl = NULL; 25833b5dd52aSJames Smart struct lpfc_sli_ct_request *ctreq = NULL; 25843b5dd52aSJames Smart int ret_val = 0; 2585d439d286SJames Smart int time_left; 25865a0916b4SJames Smart int iocb_stat = IOCB_SUCCESS; 25873b5dd52aSJames Smart unsigned long flags; 25883b5dd52aSJames Smart 25893b5dd52aSJames Smart *txxri = 0; 25903b5dd52aSJames Smart *rxxri = 0; 25913b5dd52aSJames Smart evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, 25923b5dd52aSJames Smart SLI_CT_ELX_LOOPBACK); 25933b5dd52aSJames Smart if (!evt) 2594d439d286SJames Smart return -ENOMEM; 25953b5dd52aSJames Smart 25963b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 25973b5dd52aSJames Smart list_add(&evt->node, &phba->ct_ev_waiters); 25983b5dd52aSJames Smart lpfc_bsg_event_ref(evt); 25993b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 26003b5dd52aSJames Smart 26013b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 26023b5dd52aSJames Smart rspiocbq = lpfc_sli_get_iocbq(phba); 26033b5dd52aSJames Smart 26043b5dd52aSJames Smart dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 26053b5dd52aSJames Smart if (dmabuf) { 26063b5dd52aSJames Smart dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys); 2607c7495937SJames Smart if (dmabuf->virt) { 26083b5dd52aSJames Smart INIT_LIST_HEAD(&dmabuf->list); 26093b5dd52aSJames Smart bpl = (struct ulp_bde64 *) dmabuf->virt; 26103b5dd52aSJames Smart memset(bpl, 0, sizeof(*bpl)); 26113b5dd52aSJames Smart ctreq = (struct lpfc_sli_ct_request *)(bpl + 1); 26123b5dd52aSJames Smart bpl->addrHigh = 2613c7495937SJames Smart le32_to_cpu(putPaddrHigh(dmabuf->phys + 2614c7495937SJames Smart sizeof(*bpl))); 26153b5dd52aSJames Smart bpl->addrLow = 2616c7495937SJames Smart le32_to_cpu(putPaddrLow(dmabuf->phys + 2617c7495937SJames Smart sizeof(*bpl))); 26183b5dd52aSJames Smart bpl->tus.f.bdeFlags = 0; 26193b5dd52aSJames Smart bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ; 26203b5dd52aSJames Smart bpl->tus.w = le32_to_cpu(bpl->tus.w); 26213b5dd52aSJames Smart } 2622c7495937SJames Smart } 26233b5dd52aSJames Smart 26243b5dd52aSJames Smart if (cmdiocbq == NULL || rspiocbq == NULL || 2625c7495937SJames Smart dmabuf == NULL || bpl == NULL || ctreq == NULL || 2626c7495937SJames Smart dmabuf->virt == NULL) { 2627d439d286SJames Smart ret_val = -ENOMEM; 26283b5dd52aSJames Smart goto err_get_xri_exit; 26293b5dd52aSJames Smart } 26303b5dd52aSJames Smart 26313b5dd52aSJames Smart cmd = &cmdiocbq->iocb; 26323b5dd52aSJames Smart rsp = &rspiocbq->iocb; 26333b5dd52aSJames Smart 26343b5dd52aSJames Smart memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); 26353b5dd52aSJames Smart 26363b5dd52aSJames Smart ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; 26373b5dd52aSJames Smart ctreq->RevisionId.bits.InId = 0; 26383b5dd52aSJames Smart ctreq->FsType = SLI_CT_ELX_LOOPBACK; 26393b5dd52aSJames Smart ctreq->FsSubType = 0; 26403b5dd52aSJames Smart ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_XRI_SETUP; 26413b5dd52aSJames Smart ctreq->CommandResponse.bits.Size = 0; 26423b5dd52aSJames Smart 26433b5dd52aSJames Smart 26443b5dd52aSJames Smart cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(dmabuf->phys); 26453b5dd52aSJames Smart cmd->un.xseq64.bdl.addrLow = putPaddrLow(dmabuf->phys); 26463b5dd52aSJames Smart cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 26473b5dd52aSJames Smart cmd->un.xseq64.bdl.bdeSize = sizeof(*bpl); 26483b5dd52aSJames Smart 26493b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Fctl = LA; 26503b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Dfctl = 0; 26513b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; 26523b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; 26533b5dd52aSJames Smart 26543b5dd52aSJames Smart cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CR; 26553b5dd52aSJames Smart cmd->ulpBdeCount = 1; 26563b5dd52aSJames Smart cmd->ulpLe = 1; 26573b5dd52aSJames Smart cmd->ulpClass = CLASS3; 26583b5dd52aSJames Smart cmd->ulpContext = rpi; 26593b5dd52aSJames Smart 26603b5dd52aSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 26613b5dd52aSJames Smart cmdiocbq->vport = phba->pport; 26625a0916b4SJames Smart cmdiocbq->iocb_cmpl = NULL; 26633b5dd52aSJames Smart 2664d439d286SJames Smart iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, 26653b5dd52aSJames Smart rspiocbq, 26663b5dd52aSJames Smart (phba->fc_ratov * 2) 26673b5dd52aSJames Smart + LPFC_DRVR_TIMEOUT); 266853151bbbSJames Smart if ((iocb_stat != IOCB_SUCCESS) || (rsp->ulpStatus != IOSTAT_SUCCESS)) { 2669d439d286SJames Smart ret_val = -EIO; 26703b5dd52aSJames Smart goto err_get_xri_exit; 2671d439d286SJames Smart } 26723b5dd52aSJames Smart *txxri = rsp->ulpContext; 26733b5dd52aSJames Smart 26743b5dd52aSJames Smart evt->waiting = 1; 26753b5dd52aSJames Smart evt->wait_time_stamp = jiffies; 2676d439d286SJames Smart time_left = wait_event_interruptible_timeout( 26773b5dd52aSJames Smart evt->wq, !list_empty(&evt->events_to_see), 2678256ec0d0SJames Smart msecs_to_jiffies(1000 * 2679256ec0d0SJames Smart ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT))); 26803b5dd52aSJames Smart if (list_empty(&evt->events_to_see)) 2681d439d286SJames Smart ret_val = (time_left) ? -EINTR : -ETIMEDOUT; 26823b5dd52aSJames Smart else { 26833b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 26843b5dd52aSJames Smart list_move(evt->events_to_see.prev, &evt->events_to_get); 26853b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 26863b5dd52aSJames Smart *rxxri = (list_entry(evt->events_to_get.prev, 26873b5dd52aSJames Smart typeof(struct event_data), 26883b5dd52aSJames Smart node))->immed_dat; 26893b5dd52aSJames Smart } 26903b5dd52aSJames Smart evt->waiting = 0; 26913b5dd52aSJames Smart 26923b5dd52aSJames Smart err_get_xri_exit: 26933b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 26943b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* release ref */ 26953b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* delete */ 26963b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 26973b5dd52aSJames Smart 26983b5dd52aSJames Smart if (dmabuf) { 26993b5dd52aSJames Smart if (dmabuf->virt) 27003b5dd52aSJames Smart lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); 27013b5dd52aSJames Smart kfree(dmabuf); 27023b5dd52aSJames Smart } 27033b5dd52aSJames Smart 2704d439d286SJames Smart if (cmdiocbq && (iocb_stat != IOCB_TIMEDOUT)) 27053b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 27063b5dd52aSJames Smart if (rspiocbq) 27073b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, rspiocbq); 27083b5dd52aSJames Smart return ret_val; 27093b5dd52aSJames Smart } 27103b5dd52aSJames Smart 27113b5dd52aSJames Smart /** 27127ad20aa9SJames Smart * lpfc_bsg_dma_page_alloc - allocate a bsg mbox page sized dma buffers 27137ad20aa9SJames Smart * @phba: Pointer to HBA context object 27147ad20aa9SJames Smart * 27152ea259eeSJames Smart * This function allocates BSG_MBOX_SIZE (4KB) page size dma buffer and 27169e03aa2fSJoe Perches * returns the pointer to the buffer. 27177ad20aa9SJames Smart **/ 27187ad20aa9SJames Smart static struct lpfc_dmabuf * 27197ad20aa9SJames Smart lpfc_bsg_dma_page_alloc(struct lpfc_hba *phba) 27207ad20aa9SJames Smart { 27217ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf; 27227ad20aa9SJames Smart struct pci_dev *pcidev = phba->pcidev; 27237ad20aa9SJames Smart 27247ad20aa9SJames Smart /* allocate dma buffer struct */ 27257ad20aa9SJames Smart dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 27267ad20aa9SJames Smart if (!dmabuf) 27277ad20aa9SJames Smart return NULL; 27287ad20aa9SJames Smart 27297ad20aa9SJames Smart INIT_LIST_HEAD(&dmabuf->list); 27307ad20aa9SJames Smart 27317ad20aa9SJames Smart /* now, allocate dma buffer */ 27321aee383dSJoe Perches dmabuf->virt = dma_zalloc_coherent(&pcidev->dev, BSG_MBOX_SIZE, 27337ad20aa9SJames Smart &(dmabuf->phys), GFP_KERNEL); 27347ad20aa9SJames Smart 27357ad20aa9SJames Smart if (!dmabuf->virt) { 27367ad20aa9SJames Smart kfree(dmabuf); 27377ad20aa9SJames Smart return NULL; 27387ad20aa9SJames Smart } 27397ad20aa9SJames Smart 27407ad20aa9SJames Smart return dmabuf; 27417ad20aa9SJames Smart } 27427ad20aa9SJames Smart 27437ad20aa9SJames Smart /** 27447ad20aa9SJames Smart * lpfc_bsg_dma_page_free - free a bsg mbox page sized dma buffer 27457ad20aa9SJames Smart * @phba: Pointer to HBA context object. 27467ad20aa9SJames Smart * @dmabuf: Pointer to the bsg mbox page sized dma buffer descriptor. 27477ad20aa9SJames Smart * 27487ad20aa9SJames Smart * This routine just simply frees a dma buffer and its associated buffer 27497ad20aa9SJames Smart * descriptor referred by @dmabuf. 27507ad20aa9SJames Smart **/ 27517ad20aa9SJames Smart static void 27527ad20aa9SJames Smart lpfc_bsg_dma_page_free(struct lpfc_hba *phba, struct lpfc_dmabuf *dmabuf) 27537ad20aa9SJames Smart { 27547ad20aa9SJames Smart struct pci_dev *pcidev = phba->pcidev; 27557ad20aa9SJames Smart 27567ad20aa9SJames Smart if (!dmabuf) 27577ad20aa9SJames Smart return; 27587ad20aa9SJames Smart 27597ad20aa9SJames Smart if (dmabuf->virt) 27607ad20aa9SJames Smart dma_free_coherent(&pcidev->dev, BSG_MBOX_SIZE, 27617ad20aa9SJames Smart dmabuf->virt, dmabuf->phys); 27627ad20aa9SJames Smart kfree(dmabuf); 27637ad20aa9SJames Smart return; 27647ad20aa9SJames Smart } 27657ad20aa9SJames Smart 27667ad20aa9SJames Smart /** 27677ad20aa9SJames Smart * lpfc_bsg_dma_page_list_free - free a list of bsg mbox page sized dma buffers 27687ad20aa9SJames Smart * @phba: Pointer to HBA context object. 27697ad20aa9SJames Smart * @dmabuf_list: Pointer to a list of bsg mbox page sized dma buffer descs. 27707ad20aa9SJames Smart * 27717ad20aa9SJames Smart * This routine just simply frees all dma buffers and their associated buffer 27727ad20aa9SJames Smart * descriptors referred by @dmabuf_list. 27737ad20aa9SJames Smart **/ 27747ad20aa9SJames Smart static void 27757ad20aa9SJames Smart lpfc_bsg_dma_page_list_free(struct lpfc_hba *phba, 27767ad20aa9SJames Smart struct list_head *dmabuf_list) 27777ad20aa9SJames Smart { 27787ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf, *next_dmabuf; 27797ad20aa9SJames Smart 27807ad20aa9SJames Smart if (list_empty(dmabuf_list)) 27817ad20aa9SJames Smart return; 27827ad20aa9SJames Smart 27837ad20aa9SJames Smart list_for_each_entry_safe(dmabuf, next_dmabuf, dmabuf_list, list) { 27847ad20aa9SJames Smart list_del_init(&dmabuf->list); 27857ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 27867ad20aa9SJames Smart } 27877ad20aa9SJames Smart return; 27887ad20aa9SJames Smart } 27897ad20aa9SJames Smart 27907ad20aa9SJames Smart /** 27913b5dd52aSJames Smart * diag_cmd_data_alloc - fills in a bde struct with dma buffers 27923b5dd52aSJames Smart * @phba: Pointer to HBA context object 27933b5dd52aSJames Smart * @bpl: Pointer to 64 bit bde structure 27943b5dd52aSJames Smart * @size: Number of bytes to process 27953b5dd52aSJames Smart * @nocopydata: Flag to copy user data into the allocated buffer 27963b5dd52aSJames Smart * 27973b5dd52aSJames Smart * This function allocates page size buffers and populates an lpfc_dmabufext. 27983b5dd52aSJames Smart * If allowed the user data pointed to with indataptr is copied into the kernel 27993b5dd52aSJames Smart * memory. The chained list of page size buffers is returned. 28003b5dd52aSJames Smart **/ 28013b5dd52aSJames Smart static struct lpfc_dmabufext * 28023b5dd52aSJames Smart diag_cmd_data_alloc(struct lpfc_hba *phba, 28033b5dd52aSJames Smart struct ulp_bde64 *bpl, uint32_t size, 28043b5dd52aSJames Smart int nocopydata) 28053b5dd52aSJames Smart { 28063b5dd52aSJames Smart struct lpfc_dmabufext *mlist = NULL; 28073b5dd52aSJames Smart struct lpfc_dmabufext *dmp; 28083b5dd52aSJames Smart int cnt, offset = 0, i = 0; 28093b5dd52aSJames Smart struct pci_dev *pcidev; 28103b5dd52aSJames Smart 28113b5dd52aSJames Smart pcidev = phba->pcidev; 28123b5dd52aSJames Smart 28133b5dd52aSJames Smart while (size) { 28143b5dd52aSJames Smart /* We get chunks of 4K */ 28153b5dd52aSJames Smart if (size > BUF_SZ_4K) 28163b5dd52aSJames Smart cnt = BUF_SZ_4K; 28173b5dd52aSJames Smart else 28183b5dd52aSJames Smart cnt = size; 28193b5dd52aSJames Smart 28203b5dd52aSJames Smart /* allocate struct lpfc_dmabufext buffer header */ 28213b5dd52aSJames Smart dmp = kmalloc(sizeof(struct lpfc_dmabufext), GFP_KERNEL); 28223b5dd52aSJames Smart if (!dmp) 28233b5dd52aSJames Smart goto out; 28243b5dd52aSJames Smart 28253b5dd52aSJames Smart INIT_LIST_HEAD(&dmp->dma.list); 28263b5dd52aSJames Smart 28273b5dd52aSJames Smart /* Queue it to a linked list */ 28283b5dd52aSJames Smart if (mlist) 28293b5dd52aSJames Smart list_add_tail(&dmp->dma.list, &mlist->dma.list); 28303b5dd52aSJames Smart else 28313b5dd52aSJames Smart mlist = dmp; 28323b5dd52aSJames Smart 28333b5dd52aSJames Smart /* allocate buffer */ 28343b5dd52aSJames Smart dmp->dma.virt = dma_alloc_coherent(&pcidev->dev, 28353b5dd52aSJames Smart cnt, 28363b5dd52aSJames Smart &(dmp->dma.phys), 28373b5dd52aSJames Smart GFP_KERNEL); 28383b5dd52aSJames Smart 28393b5dd52aSJames Smart if (!dmp->dma.virt) 28403b5dd52aSJames Smart goto out; 28413b5dd52aSJames Smart 28423b5dd52aSJames Smart dmp->size = cnt; 28433b5dd52aSJames Smart 28443b5dd52aSJames Smart if (nocopydata) { 28453b5dd52aSJames Smart bpl->tus.f.bdeFlags = 0; 28463b5dd52aSJames Smart pci_dma_sync_single_for_device(phba->pcidev, 28473b5dd52aSJames Smart dmp->dma.phys, LPFC_BPL_SIZE, PCI_DMA_TODEVICE); 28483b5dd52aSJames Smart 28493b5dd52aSJames Smart } else { 28503b5dd52aSJames Smart memset((uint8_t *)dmp->dma.virt, 0, cnt); 28513b5dd52aSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; 28523b5dd52aSJames Smart } 28533b5dd52aSJames Smart 28543b5dd52aSJames Smart /* build buffer ptr list for IOCB */ 28553b5dd52aSJames Smart bpl->addrLow = le32_to_cpu(putPaddrLow(dmp->dma.phys)); 28563b5dd52aSJames Smart bpl->addrHigh = le32_to_cpu(putPaddrHigh(dmp->dma.phys)); 28573b5dd52aSJames Smart bpl->tus.f.bdeSize = (ushort) cnt; 28583b5dd52aSJames Smart bpl->tus.w = le32_to_cpu(bpl->tus.w); 28593b5dd52aSJames Smart bpl++; 28603b5dd52aSJames Smart 28613b5dd52aSJames Smart i++; 28623b5dd52aSJames Smart offset += cnt; 28633b5dd52aSJames Smart size -= cnt; 28643b5dd52aSJames Smart } 28653b5dd52aSJames Smart 2866a2fc4aefSJames Smart if (mlist) { 28673b5dd52aSJames Smart mlist->flag = i; 28683b5dd52aSJames Smart return mlist; 2869a2fc4aefSJames Smart } 28703b5dd52aSJames Smart out: 28713b5dd52aSJames Smart diag_cmd_data_free(phba, mlist); 28723b5dd52aSJames Smart return NULL; 28733b5dd52aSJames Smart } 28743b5dd52aSJames Smart 28753b5dd52aSJames Smart /** 28763b5dd52aSJames Smart * lpfcdiag_loop_post_rxbufs - post the receive buffers for an unsol CT cmd 28773b5dd52aSJames Smart * @phba: Pointer to HBA context object 28783b5dd52aSJames Smart * @rxxri: Receive exchange id 28793b5dd52aSJames Smart * @len: Number of data bytes 28803b5dd52aSJames Smart * 288125985edcSLucas De Marchi * This function allocates and posts a data buffer of sufficient size to receive 28823b5dd52aSJames Smart * an unsolicted CT command. 28833b5dd52aSJames Smart **/ 28843b5dd52aSJames Smart static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, 28853b5dd52aSJames Smart size_t len) 28863b5dd52aSJames Smart { 2887895427bdSJames Smart struct lpfc_sli_ring *pring; 28883b5dd52aSJames Smart struct lpfc_iocbq *cmdiocbq; 28893b5dd52aSJames Smart IOCB_t *cmd = NULL; 28903b5dd52aSJames Smart struct list_head head, *curr, *next; 28913b5dd52aSJames Smart struct lpfc_dmabuf *rxbmp; 28923b5dd52aSJames Smart struct lpfc_dmabuf *dmp; 28933b5dd52aSJames Smart struct lpfc_dmabuf *mp[2] = {NULL, NULL}; 28943b5dd52aSJames Smart struct ulp_bde64 *rxbpl = NULL; 28953b5dd52aSJames Smart uint32_t num_bde; 28963b5dd52aSJames Smart struct lpfc_dmabufext *rxbuffer = NULL; 28973b5dd52aSJames Smart int ret_val = 0; 2898d439d286SJames Smart int iocb_stat; 28993b5dd52aSJames Smart int i = 0; 29003b5dd52aSJames Smart 2901895427bdSJames Smart pring = lpfc_phba_elsring(phba); 2902895427bdSJames Smart 29033b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 29043b5dd52aSJames Smart rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 29053b5dd52aSJames Smart if (rxbmp != NULL) { 29063b5dd52aSJames Smart rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); 2907c7495937SJames Smart if (rxbmp->virt) { 29083b5dd52aSJames Smart INIT_LIST_HEAD(&rxbmp->list); 29093b5dd52aSJames Smart rxbpl = (struct ulp_bde64 *) rxbmp->virt; 29103b5dd52aSJames Smart rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0); 29113b5dd52aSJames Smart } 2912c7495937SJames Smart } 29133b5dd52aSJames Smart 2914*1234a6d5SDick Kennedy if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer || !pring) { 2915d439d286SJames Smart ret_val = -ENOMEM; 29163b5dd52aSJames Smart goto err_post_rxbufs_exit; 29173b5dd52aSJames Smart } 29183b5dd52aSJames Smart 29193b5dd52aSJames Smart /* Queue buffers for the receive exchange */ 29203b5dd52aSJames Smart num_bde = (uint32_t)rxbuffer->flag; 29213b5dd52aSJames Smart dmp = &rxbuffer->dma; 29223b5dd52aSJames Smart 29233b5dd52aSJames Smart cmd = &cmdiocbq->iocb; 29243b5dd52aSJames Smart i = 0; 29253b5dd52aSJames Smart 29263b5dd52aSJames Smart INIT_LIST_HEAD(&head); 29273b5dd52aSJames Smart list_add_tail(&head, &dmp->list); 29283b5dd52aSJames Smart list_for_each_safe(curr, next, &head) { 29293b5dd52aSJames Smart mp[i] = list_entry(curr, struct lpfc_dmabuf, list); 29303b5dd52aSJames Smart list_del(curr); 29313b5dd52aSJames Smart 29323b5dd52aSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 29333b5dd52aSJames Smart mp[i]->buffer_tag = lpfc_sli_get_buffer_tag(phba); 29343b5dd52aSJames Smart cmd->un.quexri64cx.buff.bde.addrHigh = 29353b5dd52aSJames Smart putPaddrHigh(mp[i]->phys); 29363b5dd52aSJames Smart cmd->un.quexri64cx.buff.bde.addrLow = 29373b5dd52aSJames Smart putPaddrLow(mp[i]->phys); 29383b5dd52aSJames Smart cmd->un.quexri64cx.buff.bde.tus.f.bdeSize = 29393b5dd52aSJames Smart ((struct lpfc_dmabufext *)mp[i])->size; 29403b5dd52aSJames Smart cmd->un.quexri64cx.buff.buffer_tag = mp[i]->buffer_tag; 29413b5dd52aSJames Smart cmd->ulpCommand = CMD_QUE_XRI64_CX; 29423b5dd52aSJames Smart cmd->ulpPU = 0; 29433b5dd52aSJames Smart cmd->ulpLe = 1; 29443b5dd52aSJames Smart cmd->ulpBdeCount = 1; 29453b5dd52aSJames Smart cmd->unsli3.que_xri64cx_ext_words.ebde_count = 0; 29463b5dd52aSJames Smart 29473b5dd52aSJames Smart } else { 29483b5dd52aSJames Smart cmd->un.cont64[i].addrHigh = putPaddrHigh(mp[i]->phys); 29493b5dd52aSJames Smart cmd->un.cont64[i].addrLow = putPaddrLow(mp[i]->phys); 29503b5dd52aSJames Smart cmd->un.cont64[i].tus.f.bdeSize = 29513b5dd52aSJames Smart ((struct lpfc_dmabufext *)mp[i])->size; 29523b5dd52aSJames Smart cmd->ulpBdeCount = ++i; 29533b5dd52aSJames Smart 29543b5dd52aSJames Smart if ((--num_bde > 0) && (i < 2)) 29553b5dd52aSJames Smart continue; 29563b5dd52aSJames Smart 29573b5dd52aSJames Smart cmd->ulpCommand = CMD_QUE_XRI_BUF64_CX; 29583b5dd52aSJames Smart cmd->ulpLe = 1; 29593b5dd52aSJames Smart } 29603b5dd52aSJames Smart 29613b5dd52aSJames Smart cmd->ulpClass = CLASS3; 29623b5dd52aSJames Smart cmd->ulpContext = rxxri; 29633b5dd52aSJames Smart 2964d439d286SJames Smart iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 2965d439d286SJames Smart 0); 2966d439d286SJames Smart if (iocb_stat == IOCB_ERROR) { 29673b5dd52aSJames Smart diag_cmd_data_free(phba, 29683b5dd52aSJames Smart (struct lpfc_dmabufext *)mp[0]); 29693b5dd52aSJames Smart if (mp[1]) 29703b5dd52aSJames Smart diag_cmd_data_free(phba, 29713b5dd52aSJames Smart (struct lpfc_dmabufext *)mp[1]); 29723b5dd52aSJames Smart dmp = list_entry(next, struct lpfc_dmabuf, list); 2973d439d286SJames Smart ret_val = -EIO; 29743b5dd52aSJames Smart goto err_post_rxbufs_exit; 29753b5dd52aSJames Smart } 29763b5dd52aSJames Smart 29773b5dd52aSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, mp[0]); 29783b5dd52aSJames Smart if (mp[1]) { 29793b5dd52aSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, mp[1]); 29803b5dd52aSJames Smart mp[1] = NULL; 29813b5dd52aSJames Smart } 29823b5dd52aSJames Smart 29833b5dd52aSJames Smart /* The iocb was freed by lpfc_sli_issue_iocb */ 29843b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 29853b5dd52aSJames Smart if (!cmdiocbq) { 29863b5dd52aSJames Smart dmp = list_entry(next, struct lpfc_dmabuf, list); 2987d439d286SJames Smart ret_val = -EIO; 29883b5dd52aSJames Smart goto err_post_rxbufs_exit; 29893b5dd52aSJames Smart } 29903b5dd52aSJames Smart 29913b5dd52aSJames Smart cmd = &cmdiocbq->iocb; 29923b5dd52aSJames Smart i = 0; 29933b5dd52aSJames Smart } 29943b5dd52aSJames Smart list_del(&head); 29953b5dd52aSJames Smart 29963b5dd52aSJames Smart err_post_rxbufs_exit: 29973b5dd52aSJames Smart 29983b5dd52aSJames Smart if (rxbmp) { 29993b5dd52aSJames Smart if (rxbmp->virt) 30003b5dd52aSJames Smart lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys); 30013b5dd52aSJames Smart kfree(rxbmp); 30023b5dd52aSJames Smart } 30033b5dd52aSJames Smart 30043b5dd52aSJames Smart if (cmdiocbq) 30053b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 30063b5dd52aSJames Smart return ret_val; 30073b5dd52aSJames Smart } 30083b5dd52aSJames Smart 30093b5dd52aSJames Smart /** 30107ad20aa9SJames Smart * lpfc_bsg_diag_loopback_run - run loopback on a port by issue ct cmd to itself 30113b5dd52aSJames Smart * @job: LPFC_BSG_VENDOR_DIAG_TEST fc_bsg_job 30123b5dd52aSJames Smart * 30133b5dd52aSJames Smart * This function receives a user data buffer to be transmitted and received on 30143b5dd52aSJames Smart * the same port, the link must be up and in loopback mode prior 30153b5dd52aSJames Smart * to being called. 30163b5dd52aSJames Smart * 1. A kernel buffer is allocated to copy the user data into. 30173b5dd52aSJames Smart * 2. The port registers with "itself". 30183b5dd52aSJames Smart * 3. The transmit and receive exchange ids are obtained. 30193b5dd52aSJames Smart * 4. The receive exchange id is posted. 30203b5dd52aSJames Smart * 5. A new els loopback event is created. 30213b5dd52aSJames Smart * 6. The command and response iocbs are allocated. 30223b5dd52aSJames Smart * 7. The cmd iocb FsType is set to elx loopback and the CmdRsp to looppback. 30233b5dd52aSJames Smart * 30243b5dd52aSJames Smart * This function is meant to be called n times while the port is in loopback 30253b5dd52aSJames Smart * so it is the apps responsibility to issue a reset to take the port out 30263b5dd52aSJames Smart * of loopback mode. 30273b5dd52aSJames Smart **/ 30283b5dd52aSJames Smart static int 302975cc8cfcSJohannes Thumshirn lpfc_bsg_diag_loopback_run(struct bsg_job *job) 30303b5dd52aSJames Smart { 3031cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 303201e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 30333b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 30343b5dd52aSJames Smart struct lpfc_bsg_event *evt; 30353b5dd52aSJames Smart struct event_data *evdat; 30363b5dd52aSJames Smart struct lpfc_sli *psli = &phba->sli; 30373b5dd52aSJames Smart uint32_t size; 30383b5dd52aSJames Smart uint32_t full_size; 30393b5dd52aSJames Smart size_t segment_len = 0, segment_offset = 0, current_offset = 0; 30404042629eSJames Smart uint16_t rpi = 0; 30411b51197dSJames Smart struct lpfc_iocbq *cmdiocbq, *rspiocbq = NULL; 30421b51197dSJames Smart IOCB_t *cmd, *rsp = NULL; 30433b5dd52aSJames Smart struct lpfc_sli_ct_request *ctreq; 30443b5dd52aSJames Smart struct lpfc_dmabuf *txbmp; 30453b5dd52aSJames Smart struct ulp_bde64 *txbpl = NULL; 30463b5dd52aSJames Smart struct lpfc_dmabufext *txbuffer = NULL; 30473b5dd52aSJames Smart struct list_head head; 30483b5dd52aSJames Smart struct lpfc_dmabuf *curr; 30491b51197dSJames Smart uint16_t txxri = 0, rxxri; 30503b5dd52aSJames Smart uint32_t num_bde; 30513b5dd52aSJames Smart uint8_t *ptr = NULL, *rx_databuf = NULL; 30523b5dd52aSJames Smart int rc = 0; 3053d439d286SJames Smart int time_left; 30545a0916b4SJames Smart int iocb_stat = IOCB_SUCCESS; 30553b5dd52aSJames Smart unsigned long flags; 30563b5dd52aSJames Smart void *dataout = NULL; 30573b5dd52aSJames Smart uint32_t total_mem; 30583b5dd52aSJames Smart 30593b5dd52aSJames Smart /* in case no data is returned return just the return code */ 306001e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 30613b5dd52aSJames Smart 30623b5dd52aSJames Smart if (job->request_len < 30633b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_test)) { 30643b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 30653b5dd52aSJames Smart "2739 Received DIAG TEST request below minimum " 30663b5dd52aSJames Smart "size\n"); 30673b5dd52aSJames Smart rc = -EINVAL; 30683b5dd52aSJames Smart goto loopback_test_exit; 30693b5dd52aSJames Smart } 30703b5dd52aSJames Smart 30713b5dd52aSJames Smart if (job->request_payload.payload_len != 30723b5dd52aSJames Smart job->reply_payload.payload_len) { 30733b5dd52aSJames Smart rc = -EINVAL; 30743b5dd52aSJames Smart goto loopback_test_exit; 30753b5dd52aSJames Smart } 30763b5dd52aSJames Smart 30773b5dd52aSJames Smart if ((phba->link_state == LPFC_HBA_ERROR) || 30783b5dd52aSJames Smart (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || 30793b5dd52aSJames Smart (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { 30803b5dd52aSJames Smart rc = -EACCES; 30813b5dd52aSJames Smart goto loopback_test_exit; 30823b5dd52aSJames Smart } 30833b5dd52aSJames Smart 30843b5dd52aSJames Smart if (!lpfc_is_link_up(phba) || !(phba->link_flag & LS_LOOPBACK_MODE)) { 30853b5dd52aSJames Smart rc = -EACCES; 30863b5dd52aSJames Smart goto loopback_test_exit; 30873b5dd52aSJames Smart } 30883b5dd52aSJames Smart 30893b5dd52aSJames Smart size = job->request_payload.payload_len; 30903b5dd52aSJames Smart full_size = size + ELX_LOOPBACK_HEADER_SZ; /* plus the header */ 30913b5dd52aSJames Smart 30923b5dd52aSJames Smart if ((size == 0) || (size > 80 * BUF_SZ_4K)) { 30933b5dd52aSJames Smart rc = -ERANGE; 30943b5dd52aSJames Smart goto loopback_test_exit; 30953b5dd52aSJames Smart } 30963b5dd52aSJames Smart 309763e801ceSJames Smart if (full_size >= BUF_SZ_4K) { 30983b5dd52aSJames Smart /* 30993b5dd52aSJames Smart * Allocate memory for ioctl data. If buffer is bigger than 64k, 31003b5dd52aSJames Smart * then we allocate 64k and re-use that buffer over and over to 31013b5dd52aSJames Smart * xfer the whole block. This is because Linux kernel has a 31023b5dd52aSJames Smart * problem allocating more than 120k of kernel space memory. Saw 31033b5dd52aSJames Smart * problem with GET_FCPTARGETMAPPING... 31043b5dd52aSJames Smart */ 31053b5dd52aSJames Smart if (size <= (64 * 1024)) 310663e801ceSJames Smart total_mem = full_size; 31073b5dd52aSJames Smart else 31083b5dd52aSJames Smart total_mem = 64 * 1024; 31093b5dd52aSJames Smart } else 31103b5dd52aSJames Smart /* Allocate memory for ioctl data */ 31113b5dd52aSJames Smart total_mem = BUF_SZ_4K; 31123b5dd52aSJames Smart 31133b5dd52aSJames Smart dataout = kmalloc(total_mem, GFP_KERNEL); 31143b5dd52aSJames Smart if (dataout == NULL) { 31153b5dd52aSJames Smart rc = -ENOMEM; 31163b5dd52aSJames Smart goto loopback_test_exit; 31173b5dd52aSJames Smart } 31183b5dd52aSJames Smart 31193b5dd52aSJames Smart ptr = dataout; 31203b5dd52aSJames Smart ptr += ELX_LOOPBACK_HEADER_SZ; 31213b5dd52aSJames Smart sg_copy_to_buffer(job->request_payload.sg_list, 31223b5dd52aSJames Smart job->request_payload.sg_cnt, 31233b5dd52aSJames Smart ptr, size); 31243b5dd52aSJames Smart rc = lpfcdiag_loop_self_reg(phba, &rpi); 3125d439d286SJames Smart if (rc) 31263b5dd52aSJames Smart goto loopback_test_exit; 31273b5dd52aSJames Smart 31281b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) { 31293b5dd52aSJames Smart rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri); 31303b5dd52aSJames Smart if (rc) { 31313b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 31323b5dd52aSJames Smart goto loopback_test_exit; 31333b5dd52aSJames Smart } 31343b5dd52aSJames Smart 31353b5dd52aSJames Smart rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size); 31363b5dd52aSJames Smart if (rc) { 31373b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 31383b5dd52aSJames Smart goto loopback_test_exit; 31393b5dd52aSJames Smart } 31401b51197dSJames Smart } 31413b5dd52aSJames Smart evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, 31423b5dd52aSJames Smart SLI_CT_ELX_LOOPBACK); 31433b5dd52aSJames Smart if (!evt) { 31443b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 31453b5dd52aSJames Smart rc = -ENOMEM; 31463b5dd52aSJames Smart goto loopback_test_exit; 31473b5dd52aSJames Smart } 31483b5dd52aSJames Smart 31493b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 31503b5dd52aSJames Smart list_add(&evt->node, &phba->ct_ev_waiters); 31513b5dd52aSJames Smart lpfc_bsg_event_ref(evt); 31523b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 31533b5dd52aSJames Smart 31543b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 31551b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 31563b5dd52aSJames Smart rspiocbq = lpfc_sli_get_iocbq(phba); 31573b5dd52aSJames Smart txbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 31583b5dd52aSJames Smart 31593b5dd52aSJames Smart if (txbmp) { 31603b5dd52aSJames Smart txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys); 3161c7495937SJames Smart if (txbmp->virt) { 31623b5dd52aSJames Smart INIT_LIST_HEAD(&txbmp->list); 31633b5dd52aSJames Smart txbpl = (struct ulp_bde64 *) txbmp->virt; 31643b5dd52aSJames Smart txbuffer = diag_cmd_data_alloc(phba, 31653b5dd52aSJames Smart txbpl, full_size, 0); 31663b5dd52aSJames Smart } 3167c7495937SJames Smart } 31683b5dd52aSJames Smart 31691b51197dSJames Smart if (!cmdiocbq || !txbmp || !txbpl || !txbuffer || !txbmp->virt) { 31701b51197dSJames Smart rc = -ENOMEM; 31711b51197dSJames Smart goto err_loopback_test_exit; 31721b51197dSJames Smart } 31731b51197dSJames Smart if ((phba->sli_rev < LPFC_SLI_REV4) && !rspiocbq) { 31743b5dd52aSJames Smart rc = -ENOMEM; 31753b5dd52aSJames Smart goto err_loopback_test_exit; 31763b5dd52aSJames Smart } 31773b5dd52aSJames Smart 31783b5dd52aSJames Smart cmd = &cmdiocbq->iocb; 31791b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 31803b5dd52aSJames Smart rsp = &rspiocbq->iocb; 31813b5dd52aSJames Smart 31823b5dd52aSJames Smart INIT_LIST_HEAD(&head); 31833b5dd52aSJames Smart list_add_tail(&head, &txbuffer->dma.list); 31843b5dd52aSJames Smart list_for_each_entry(curr, &head, list) { 31853b5dd52aSJames Smart segment_len = ((struct lpfc_dmabufext *)curr)->size; 31863b5dd52aSJames Smart if (current_offset == 0) { 31873b5dd52aSJames Smart ctreq = curr->virt; 31883b5dd52aSJames Smart memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); 31893b5dd52aSJames Smart ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; 31903b5dd52aSJames Smart ctreq->RevisionId.bits.InId = 0; 31913b5dd52aSJames Smart ctreq->FsType = SLI_CT_ELX_LOOPBACK; 31923b5dd52aSJames Smart ctreq->FsSubType = 0; 31933b5dd52aSJames Smart ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_DATA; 31943b5dd52aSJames Smart ctreq->CommandResponse.bits.Size = size; 31953b5dd52aSJames Smart segment_offset = ELX_LOOPBACK_HEADER_SZ; 31963b5dd52aSJames Smart } else 31973b5dd52aSJames Smart segment_offset = 0; 31983b5dd52aSJames Smart 31993b5dd52aSJames Smart BUG_ON(segment_offset >= segment_len); 32003b5dd52aSJames Smart memcpy(curr->virt + segment_offset, 32013b5dd52aSJames Smart ptr + current_offset, 32023b5dd52aSJames Smart segment_len - segment_offset); 32033b5dd52aSJames Smart 32043b5dd52aSJames Smart current_offset += segment_len - segment_offset; 32053b5dd52aSJames Smart BUG_ON(current_offset > size); 32063b5dd52aSJames Smart } 32073b5dd52aSJames Smart list_del(&head); 32083b5dd52aSJames Smart 32093b5dd52aSJames Smart /* Build the XMIT_SEQUENCE iocb */ 32103b5dd52aSJames Smart num_bde = (uint32_t)txbuffer->flag; 32113b5dd52aSJames Smart 32123b5dd52aSJames Smart cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(txbmp->phys); 32133b5dd52aSJames Smart cmd->un.xseq64.bdl.addrLow = putPaddrLow(txbmp->phys); 32143b5dd52aSJames Smart cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 32153b5dd52aSJames Smart cmd->un.xseq64.bdl.bdeSize = (num_bde * sizeof(struct ulp_bde64)); 32163b5dd52aSJames Smart 32173b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); 32183b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Dfctl = 0; 32193b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; 32203b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; 32213b5dd52aSJames Smart 32223b5dd52aSJames Smart cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; 32233b5dd52aSJames Smart cmd->ulpBdeCount = 1; 32243b5dd52aSJames Smart cmd->ulpLe = 1; 32253b5dd52aSJames Smart cmd->ulpClass = CLASS3; 32263b5dd52aSJames Smart 32271b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) { 32281b51197dSJames Smart cmd->ulpContext = txxri; 32291b51197dSJames Smart } else { 32301b51197dSJames Smart cmd->un.xseq64.bdl.ulpIoTag32 = 0; 32311b51197dSJames Smart cmd->un.ulpWord[3] = phba->sli4_hba.rpi_ids[rpi]; 32321b51197dSJames Smart cmdiocbq->context3 = txbmp; 32331b51197dSJames Smart cmdiocbq->sli4_xritag = NO_XRI; 32341b51197dSJames Smart cmd->unsli3.rcvsli3.ox_id = 0xffff; 32351b51197dSJames Smart } 32363b5dd52aSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 32376c7cf486SJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LOOPBACK; 32383b5dd52aSJames Smart cmdiocbq->vport = phba->pport; 32395a0916b4SJames Smart cmdiocbq->iocb_cmpl = NULL; 3240d439d286SJames Smart iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, 3241d439d286SJames Smart rspiocbq, (phba->fc_ratov * 2) + 3242d439d286SJames Smart LPFC_DRVR_TIMEOUT); 32433b5dd52aSJames Smart 324453151bbbSJames Smart if ((iocb_stat != IOCB_SUCCESS) || 324553151bbbSJames Smart ((phba->sli_rev < LPFC_SLI_REV4) && 324653151bbbSJames Smart (rsp->ulpStatus != IOSTAT_SUCCESS))) { 32471b51197dSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 32481b51197dSJames Smart "3126 Failed loopback test issue iocb: " 32491b51197dSJames Smart "iocb_stat:x%x\n", iocb_stat); 32503b5dd52aSJames Smart rc = -EIO; 32513b5dd52aSJames Smart goto err_loopback_test_exit; 32523b5dd52aSJames Smart } 32533b5dd52aSJames Smart 32543b5dd52aSJames Smart evt->waiting = 1; 3255d439d286SJames Smart time_left = wait_event_interruptible_timeout( 32563b5dd52aSJames Smart evt->wq, !list_empty(&evt->events_to_see), 3257256ec0d0SJames Smart msecs_to_jiffies(1000 * 3258256ec0d0SJames Smart ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT))); 32593b5dd52aSJames Smart evt->waiting = 0; 32601b51197dSJames Smart if (list_empty(&evt->events_to_see)) { 3261d439d286SJames Smart rc = (time_left) ? -EINTR : -ETIMEDOUT; 32621b51197dSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 32631b51197dSJames Smart "3125 Not receiving unsolicited event, " 32641b51197dSJames Smart "rc:x%x\n", rc); 32651b51197dSJames Smart } else { 32663b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 32673b5dd52aSJames Smart list_move(evt->events_to_see.prev, &evt->events_to_get); 32683b5dd52aSJames Smart evdat = list_entry(evt->events_to_get.prev, 32693b5dd52aSJames Smart typeof(*evdat), node); 32703b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 32713b5dd52aSJames Smart rx_databuf = evdat->data; 32723b5dd52aSJames Smart if (evdat->len != full_size) { 32733b5dd52aSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 32743b5dd52aSJames Smart "1603 Loopback test did not receive expected " 32753b5dd52aSJames Smart "data length. actual length 0x%x expected " 32763b5dd52aSJames Smart "length 0x%x\n", 32773b5dd52aSJames Smart evdat->len, full_size); 32783b5dd52aSJames Smart rc = -EIO; 32793b5dd52aSJames Smart } else if (rx_databuf == NULL) 32803b5dd52aSJames Smart rc = -EIO; 32813b5dd52aSJames Smart else { 32823b5dd52aSJames Smart rc = IOCB_SUCCESS; 32833b5dd52aSJames Smart /* skip over elx loopback header */ 32843b5dd52aSJames Smart rx_databuf += ELX_LOOPBACK_HEADER_SZ; 328501e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 32863b5dd52aSJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 32873b5dd52aSJames Smart job->reply_payload.sg_cnt, 32883b5dd52aSJames Smart rx_databuf, size); 328901e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = size; 32903b5dd52aSJames Smart } 32913b5dd52aSJames Smart } 32923b5dd52aSJames Smart 32933b5dd52aSJames Smart err_loopback_test_exit: 32943b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 32953b5dd52aSJames Smart 32963b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 32973b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* release ref */ 32983b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* delete */ 32993b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 33003b5dd52aSJames Smart 33015a0916b4SJames Smart if ((cmdiocbq != NULL) && (iocb_stat != IOCB_TIMEDOUT)) 33023b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 33033b5dd52aSJames Smart 33043b5dd52aSJames Smart if (rspiocbq != NULL) 33053b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, rspiocbq); 33063b5dd52aSJames Smart 33073b5dd52aSJames Smart if (txbmp != NULL) { 33083b5dd52aSJames Smart if (txbpl != NULL) { 33093b5dd52aSJames Smart if (txbuffer != NULL) 33103b5dd52aSJames Smart diag_cmd_data_free(phba, txbuffer); 33113b5dd52aSJames Smart lpfc_mbuf_free(phba, txbmp->virt, txbmp->phys); 33123b5dd52aSJames Smart } 33133b5dd52aSJames Smart kfree(txbmp); 33143b5dd52aSJames Smart } 33153b5dd52aSJames Smart 33163b5dd52aSJames Smart loopback_test_exit: 33173b5dd52aSJames Smart kfree(dataout); 33183b5dd52aSJames Smart /* make error code available to userspace */ 331901e0e15cSJohannes Thumshirn bsg_reply->result = rc; 33203b5dd52aSJames Smart job->dd_data = NULL; 33213b5dd52aSJames Smart /* complete the job back to userspace if no error */ 33221b51197dSJames Smart if (rc == IOCB_SUCCESS) 332306548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 33241abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 33253b5dd52aSJames Smart return rc; 33263b5dd52aSJames Smart } 33273b5dd52aSJames Smart 33283b5dd52aSJames Smart /** 33293b5dd52aSJames Smart * lpfc_bsg_get_dfc_rev - process a GET_DFC_REV bsg vendor command 33303b5dd52aSJames Smart * @job: GET_DFC_REV fc_bsg_job 33313b5dd52aSJames Smart **/ 33323b5dd52aSJames Smart static int 333375cc8cfcSJohannes Thumshirn lpfc_bsg_get_dfc_rev(struct bsg_job *job) 33343b5dd52aSJames Smart { 3335cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 333601e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 33373b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 33383b5dd52aSJames Smart struct get_mgmt_rev_reply *event_reply; 33393b5dd52aSJames Smart int rc = 0; 33403b5dd52aSJames Smart 33413b5dd52aSJames Smart if (job->request_len < 33423b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev)) { 33433b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 33443b5dd52aSJames Smart "2740 Received GET_DFC_REV request below " 33453b5dd52aSJames Smart "minimum size\n"); 33463b5dd52aSJames Smart rc = -EINVAL; 33473b5dd52aSJames Smart goto job_error; 33483b5dd52aSJames Smart } 33493b5dd52aSJames Smart 33503b5dd52aSJames Smart event_reply = (struct get_mgmt_rev_reply *) 335101e0e15cSJohannes Thumshirn bsg_reply->reply_data.vendor_reply.vendor_rsp; 33523b5dd52aSJames Smart 33533b5dd52aSJames Smart if (job->reply_len < 33543b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev_reply)) { 33553b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 33563b5dd52aSJames Smart "2741 Received GET_DFC_REV reply below " 33573b5dd52aSJames Smart "minimum size\n"); 33583b5dd52aSJames Smart rc = -EINVAL; 33593b5dd52aSJames Smart goto job_error; 33603b5dd52aSJames Smart } 33613b5dd52aSJames Smart 33623b5dd52aSJames Smart event_reply->info.a_Major = MANAGEMENT_MAJOR_REV; 33633b5dd52aSJames Smart event_reply->info.a_Minor = MANAGEMENT_MINOR_REV; 33643b5dd52aSJames Smart job_error: 336501e0e15cSJohannes Thumshirn bsg_reply->result = rc; 33663b5dd52aSJames Smart if (rc == 0) 336706548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 33681abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 33693b5dd52aSJames Smart return rc; 33703b5dd52aSJames Smart } 33713b5dd52aSJames Smart 33723b5dd52aSJames Smart /** 33737ad20aa9SJames Smart * lpfc_bsg_issue_mbox_cmpl - lpfc_bsg_issue_mbox mbox completion handler 33743b5dd52aSJames Smart * @phba: Pointer to HBA context object. 33753b5dd52aSJames Smart * @pmboxq: Pointer to mailbox command. 33763b5dd52aSJames Smart * 33773b5dd52aSJames Smart * This is completion handler function for mailbox commands issued from 33783b5dd52aSJames Smart * lpfc_bsg_issue_mbox function. This function is called by the 33793b5dd52aSJames Smart * mailbox event handler function with no lock held. This function 33803b5dd52aSJames Smart * will wake up thread waiting on the wait queue pointed by context1 33813b5dd52aSJames Smart * of the mailbox. 33823b5dd52aSJames Smart **/ 33839ab9b134SRashika Kheria static void 33847ad20aa9SJames Smart lpfc_bsg_issue_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) 33853b5dd52aSJames Smart { 33863b5dd52aSJames Smart struct bsg_job_data *dd_data; 338701e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 338875cc8cfcSJohannes Thumshirn struct bsg_job *job; 33893b5dd52aSJames Smart uint32_t size; 33903b5dd52aSJames Smart unsigned long flags; 33917ad20aa9SJames Smart uint8_t *pmb, *pmb_buf; 33923b5dd52aSJames Smart 33933b5dd52aSJames Smart dd_data = pmboxq->context1; 33943b5dd52aSJames Smart 33957ad20aa9SJames Smart /* 33967ad20aa9SJames Smart * The outgoing buffer is readily referred from the dma buffer, 33977ad20aa9SJames Smart * just need to get header part from mailboxq structure. 33987a470277SJames Smart */ 33997ad20aa9SJames Smart pmb = (uint8_t *)&pmboxq->u.mb; 34007ad20aa9SJames Smart pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb; 34017ad20aa9SJames Smart memcpy(pmb_buf, pmb, sizeof(MAILBOX_t)); 3402515e0aa2SJames Smart 3403a33c4f7bSJames Smart /* Determine if job has been aborted */ 3404a33c4f7bSJames Smart 3405a33c4f7bSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 3406a33c4f7bSJames Smart job = dd_data->set_job; 3407a33c4f7bSJames Smart if (job) { 3408a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 3409a33c4f7bSJames Smart job->dd_data = NULL; 3410a33c4f7bSJames Smart } 3411a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 3412a33c4f7bSJames Smart 3413a33c4f7bSJames Smart /* Copy the mailbox data to the job if it is still active */ 3414a33c4f7bSJames Smart 34155a6f133eSJames Smart if (job) { 341601e0e15cSJohannes Thumshirn bsg_reply = job->reply; 34177a470277SJames Smart size = job->reply_payload.payload_len; 341801e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 34193b5dd52aSJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 34203b5dd52aSJames Smart job->reply_payload.sg_cnt, 34217ad20aa9SJames Smart pmb_buf, size); 3422b6e3b9c6SJames Smart } 34237a470277SJames Smart 3424a33c4f7bSJames Smart dd_data->set_job = NULL; 34253b5dd52aSJames Smart mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool); 34267ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dd_data->context_un.mbox.dmabuffers); 34273b5dd52aSJames Smart kfree(dd_data); 34287ad20aa9SJames Smart 3429a33c4f7bSJames Smart /* Complete the job if the job is still active */ 3430a33c4f7bSJames Smart 34317ad20aa9SJames Smart if (job) { 343201e0e15cSJohannes Thumshirn bsg_reply->result = 0; 343306548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 34341abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 34357ad20aa9SJames Smart } 34363b5dd52aSJames Smart return; 34373b5dd52aSJames Smart } 34383b5dd52aSJames Smart 34393b5dd52aSJames Smart /** 34403b5dd52aSJames Smart * lpfc_bsg_check_cmd_access - test for a supported mailbox command 34413b5dd52aSJames Smart * @phba: Pointer to HBA context object. 34423b5dd52aSJames Smart * @mb: Pointer to a mailbox object. 34433b5dd52aSJames Smart * @vport: Pointer to a vport object. 34443b5dd52aSJames Smart * 34453b5dd52aSJames Smart * Some commands require the port to be offline, some may not be called from 34463b5dd52aSJames Smart * the application. 34473b5dd52aSJames Smart **/ 34483b5dd52aSJames Smart static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, 34493b5dd52aSJames Smart MAILBOX_t *mb, struct lpfc_vport *vport) 34503b5dd52aSJames Smart { 34513b5dd52aSJames Smart /* return negative error values for bsg job */ 34523b5dd52aSJames Smart switch (mb->mbxCommand) { 34533b5dd52aSJames Smart /* Offline only */ 34543b5dd52aSJames Smart case MBX_INIT_LINK: 34553b5dd52aSJames Smart case MBX_DOWN_LINK: 34563b5dd52aSJames Smart case MBX_CONFIG_LINK: 34573b5dd52aSJames Smart case MBX_CONFIG_RING: 34583b5dd52aSJames Smart case MBX_RESET_RING: 34593b5dd52aSJames Smart case MBX_UNREG_LOGIN: 34603b5dd52aSJames Smart case MBX_CLEAR_LA: 34613b5dd52aSJames Smart case MBX_DUMP_CONTEXT: 34623b5dd52aSJames Smart case MBX_RUN_DIAGS: 34633b5dd52aSJames Smart case MBX_RESTART: 34643b5dd52aSJames Smart case MBX_SET_MASK: 34653b5dd52aSJames Smart if (!(vport->fc_flag & FC_OFFLINE_MODE)) { 34663b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 34673b5dd52aSJames Smart "2743 Command 0x%x is illegal in on-line " 34683b5dd52aSJames Smart "state\n", 34693b5dd52aSJames Smart mb->mbxCommand); 34703b5dd52aSJames Smart return -EPERM; 34713b5dd52aSJames Smart } 34723b5dd52aSJames Smart case MBX_WRITE_NV: 34733b5dd52aSJames Smart case MBX_WRITE_VPARMS: 34743b5dd52aSJames Smart case MBX_LOAD_SM: 34753b5dd52aSJames Smart case MBX_READ_NV: 34763b5dd52aSJames Smart case MBX_READ_CONFIG: 34773b5dd52aSJames Smart case MBX_READ_RCONFIG: 34783b5dd52aSJames Smart case MBX_READ_STATUS: 34793b5dd52aSJames Smart case MBX_READ_XRI: 34803b5dd52aSJames Smart case MBX_READ_REV: 34813b5dd52aSJames Smart case MBX_READ_LNK_STAT: 34823b5dd52aSJames Smart case MBX_DUMP_MEMORY: 34833b5dd52aSJames Smart case MBX_DOWN_LOAD: 34843b5dd52aSJames Smart case MBX_UPDATE_CFG: 34853b5dd52aSJames Smart case MBX_KILL_BOARD: 348606f35551SJames Smart case MBX_READ_TOPOLOGY: 34873b5dd52aSJames Smart case MBX_LOAD_AREA: 34883b5dd52aSJames Smart case MBX_LOAD_EXP_ROM: 34893b5dd52aSJames Smart case MBX_BEACON: 34903b5dd52aSJames Smart case MBX_DEL_LD_ENTRY: 34913b5dd52aSJames Smart case MBX_SET_DEBUG: 34923b5dd52aSJames Smart case MBX_WRITE_WWN: 34933b5dd52aSJames Smart case MBX_SLI4_CONFIG: 3494c7495937SJames Smart case MBX_READ_EVENT_LOG: 34953b5dd52aSJames Smart case MBX_READ_EVENT_LOG_STATUS: 34963b5dd52aSJames Smart case MBX_WRITE_EVENT_LOG: 34973b5dd52aSJames Smart case MBX_PORT_CAPABILITIES: 34983b5dd52aSJames Smart case MBX_PORT_IOV_CONTROL: 34997a470277SJames Smart case MBX_RUN_BIU_DIAG64: 35003b5dd52aSJames Smart break; 35013b5dd52aSJames Smart case MBX_SET_VARIABLE: 3502e2aed29fSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_INIT, 3503e2aed29fSJames Smart "1226 mbox: set_variable 0x%x, 0x%x\n", 3504e2aed29fSJames Smart mb->un.varWords[0], 3505e2aed29fSJames Smart mb->un.varWords[1]); 3506e2aed29fSJames Smart if ((mb->un.varWords[0] == SETVAR_MLOMNT) 3507e2aed29fSJames Smart && (mb->un.varWords[1] == 1)) { 3508e2aed29fSJames Smart phba->wait_4_mlo_maint_flg = 1; 3509e2aed29fSJames Smart } else if (mb->un.varWords[0] == SETVAR_MLORST) { 35101b51197dSJames Smart spin_lock_irq(&phba->hbalock); 3511e2aed29fSJames Smart phba->link_flag &= ~LS_LOOPBACK_MODE; 35121b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 351376a95d75SJames Smart phba->fc_topology = LPFC_TOPOLOGY_PT_PT; 3514e2aed29fSJames Smart } 3515e2aed29fSJames Smart break; 35163b5dd52aSJames Smart case MBX_READ_SPARM64: 35173b5dd52aSJames Smart case MBX_REG_LOGIN: 35183b5dd52aSJames Smart case MBX_REG_LOGIN64: 35193b5dd52aSJames Smart case MBX_CONFIG_PORT: 35203b5dd52aSJames Smart case MBX_RUN_BIU_DIAG: 35213b5dd52aSJames Smart default: 35223b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 35233b5dd52aSJames Smart "2742 Unknown Command 0x%x\n", 35243b5dd52aSJames Smart mb->mbxCommand); 35253b5dd52aSJames Smart return -EPERM; 35263b5dd52aSJames Smart } 35273b5dd52aSJames Smart 35283b5dd52aSJames Smart return 0; /* ok */ 35293b5dd52aSJames Smart } 35303b5dd52aSJames Smart 35313b5dd52aSJames Smart /** 35327ad20aa9SJames Smart * lpfc_bsg_mbox_ext_cleanup - clean up context of multi-buffer mbox session 35337ad20aa9SJames Smart * @phba: Pointer to HBA context object. 35347ad20aa9SJames Smart * 35357ad20aa9SJames Smart * This is routine clean up and reset BSG handling of multi-buffer mbox 35367ad20aa9SJames Smart * command session. 35377ad20aa9SJames Smart **/ 35387ad20aa9SJames Smart static void 35397ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(struct lpfc_hba *phba) 35407ad20aa9SJames Smart { 35417ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_IDLE) 35427ad20aa9SJames Smart return; 35437ad20aa9SJames Smart 35447ad20aa9SJames Smart /* free all memory, including dma buffers */ 35457ad20aa9SJames Smart lpfc_bsg_dma_page_list_free(phba, 35467ad20aa9SJames Smart &phba->mbox_ext_buf_ctx.ext_dmabuf_list); 35477ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, phba->mbox_ext_buf_ctx.mbx_dmabuf); 35487ad20aa9SJames Smart /* multi-buffer write mailbox command pass-through complete */ 35497ad20aa9SJames Smart memset((char *)&phba->mbox_ext_buf_ctx, 0, 35507ad20aa9SJames Smart sizeof(struct lpfc_mbox_ext_buf_ctx)); 35517ad20aa9SJames Smart INIT_LIST_HEAD(&phba->mbox_ext_buf_ctx.ext_dmabuf_list); 35527ad20aa9SJames Smart 35537ad20aa9SJames Smart return; 35547ad20aa9SJames Smart } 35557ad20aa9SJames Smart 35567ad20aa9SJames Smart /** 35577ad20aa9SJames Smart * lpfc_bsg_issue_mbox_ext_handle_job - job handler for multi-buffer mbox cmpl 35587ad20aa9SJames Smart * @phba: Pointer to HBA context object. 35597ad20aa9SJames Smart * @pmboxq: Pointer to mailbox command. 35607ad20aa9SJames Smart * 35617ad20aa9SJames Smart * This is routine handles BSG job for mailbox commands completions with 35627ad20aa9SJames Smart * multiple external buffers. 35637ad20aa9SJames Smart **/ 356475cc8cfcSJohannes Thumshirn static struct bsg_job * 35657ad20aa9SJames Smart lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) 35667ad20aa9SJames Smart { 35677ad20aa9SJames Smart struct bsg_job_data *dd_data; 356875cc8cfcSJohannes Thumshirn struct bsg_job *job; 356901e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 35707ad20aa9SJames Smart uint8_t *pmb, *pmb_buf; 35717ad20aa9SJames Smart unsigned long flags; 35727ad20aa9SJames Smart uint32_t size; 35737ad20aa9SJames Smart int rc = 0; 3574026abb87SJames Smart struct lpfc_dmabuf *dmabuf; 3575026abb87SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 3576026abb87SJames Smart uint8_t *pmbx; 35777ad20aa9SJames Smart 35787ad20aa9SJames Smart dd_data = pmboxq->context1; 3579a33c4f7bSJames Smart 3580a33c4f7bSJames Smart /* Determine if job has been aborted */ 3581a33c4f7bSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 3582a33c4f7bSJames Smart job = dd_data->set_job; 3583a33c4f7bSJames Smart if (job) { 358401e0e15cSJohannes Thumshirn bsg_reply = job->reply; 3585a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 3586a33c4f7bSJames Smart job->dd_data = NULL; 35877ad20aa9SJames Smart } 3588a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 35897ad20aa9SJames Smart 35907ad20aa9SJames Smart /* 35917ad20aa9SJames Smart * The outgoing buffer is readily referred from the dma buffer, 35927ad20aa9SJames Smart * just need to get header part from mailboxq structure. 35937ad20aa9SJames Smart */ 3594a33c4f7bSJames Smart 35957ad20aa9SJames Smart pmb = (uint8_t *)&pmboxq->u.mb; 35967ad20aa9SJames Smart pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb; 3597026abb87SJames Smart /* Copy the byte swapped response mailbox back to the user */ 35987ad20aa9SJames Smart memcpy(pmb_buf, pmb, sizeof(MAILBOX_t)); 3599026abb87SJames Smart /* if there is any non-embedded extended data copy that too */ 3600026abb87SJames Smart dmabuf = phba->mbox_ext_buf_ctx.mbx_dmabuf; 3601026abb87SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; 3602026abb87SJames Smart if (!bsg_bf_get(lpfc_mbox_hdr_emb, 3603026abb87SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) { 3604026abb87SJames Smart pmbx = (uint8_t *)dmabuf->virt; 3605026abb87SJames Smart /* byte swap the extended data following the mailbox command */ 3606026abb87SJames Smart lpfc_sli_pcimem_bcopy(&pmbx[sizeof(MAILBOX_t)], 3607026abb87SJames Smart &pmbx[sizeof(MAILBOX_t)], 3608026abb87SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys.mse[0].buf_len); 3609026abb87SJames Smart } 36107ad20aa9SJames Smart 3611a33c4f7bSJames Smart /* Complete the job if the job is still active */ 3612a33c4f7bSJames Smart 36137ad20aa9SJames Smart if (job) { 36147ad20aa9SJames Smart size = job->reply_payload.payload_len; 361501e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 36167ad20aa9SJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 36177ad20aa9SJames Smart job->reply_payload.sg_cnt, 36187ad20aa9SJames Smart pmb_buf, size); 3619a33c4f7bSJames Smart 36207ad20aa9SJames Smart /* result for successful */ 362101e0e15cSJohannes Thumshirn bsg_reply->result = 0; 3622a33c4f7bSJames Smart 36237ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 36247ad20aa9SJames Smart "2937 SLI_CONFIG ext-buffer maibox command " 36257ad20aa9SJames Smart "(x%x/x%x) complete bsg job done, bsize:%d\n", 36267ad20aa9SJames Smart phba->mbox_ext_buf_ctx.nembType, 36277ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType, size); 3628b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, 3629b76f2dc9SJames Smart phba->mbox_ext_buf_ctx.nembType, 3630b76f2dc9SJames Smart phba->mbox_ext_buf_ctx.mboxType, 3631b76f2dc9SJames Smart dma_ebuf, sta_pos_addr, 3632b76f2dc9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf, 0); 3633a33c4f7bSJames Smart } else { 36347ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 36357ad20aa9SJames Smart "2938 SLI_CONFIG ext-buffer maibox " 36367ad20aa9SJames Smart "command (x%x/x%x) failure, rc:x%x\n", 36377ad20aa9SJames Smart phba->mbox_ext_buf_ctx.nembType, 36387ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType, rc); 3639a33c4f7bSJames Smart } 3640a33c4f7bSJames Smart 3641a33c4f7bSJames Smart 36427ad20aa9SJames Smart /* state change */ 36437ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_DONE; 36447ad20aa9SJames Smart kfree(dd_data); 36457ad20aa9SJames Smart return job; 36467ad20aa9SJames Smart } 36477ad20aa9SJames Smart 36487ad20aa9SJames Smart /** 36497ad20aa9SJames Smart * lpfc_bsg_issue_read_mbox_ext_cmpl - compl handler for multi-buffer read mbox 36507ad20aa9SJames Smart * @phba: Pointer to HBA context object. 36517ad20aa9SJames Smart * @pmboxq: Pointer to mailbox command. 36527ad20aa9SJames Smart * 36537ad20aa9SJames Smart * This is completion handler function for mailbox read commands with multiple 36547ad20aa9SJames Smart * external buffers. 36557ad20aa9SJames Smart **/ 36567ad20aa9SJames Smart static void 36577ad20aa9SJames Smart lpfc_bsg_issue_read_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) 36587ad20aa9SJames Smart { 365975cc8cfcSJohannes Thumshirn struct bsg_job *job; 36601abaede7SJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 36617ad20aa9SJames Smart 3662a33c4f7bSJames Smart job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq); 3663a33c4f7bSJames Smart 36647ad20aa9SJames Smart /* handle the BSG job with mailbox command */ 3665a33c4f7bSJames Smart if (!job) 36667ad20aa9SJames Smart pmboxq->u.mb.mbxStatus = MBXERR_ERROR; 36677ad20aa9SJames Smart 36687ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 36697ad20aa9SJames Smart "2939 SLI_CONFIG ext-buffer rd maibox command " 36707ad20aa9SJames Smart "complete, ctxState:x%x, mbxStatus:x%x\n", 36717ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus); 36727ad20aa9SJames Smart 36737ad20aa9SJames Smart if (pmboxq->u.mb.mbxStatus || phba->mbox_ext_buf_ctx.numBuf == 1) 36747ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 36757ad20aa9SJames Smart 36767ad20aa9SJames Smart /* free base driver mailbox structure memory */ 36777ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 36787ad20aa9SJames Smart 3679a33c4f7bSJames Smart /* if the job is still active, call job done */ 36801abaede7SJohannes Thumshirn if (job) { 36811abaede7SJohannes Thumshirn bsg_reply = job->reply; 368206548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 36831abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 36841abaede7SJohannes Thumshirn } 36857ad20aa9SJames Smart return; 36867ad20aa9SJames Smart } 36877ad20aa9SJames Smart 36887ad20aa9SJames Smart /** 36897ad20aa9SJames Smart * lpfc_bsg_issue_write_mbox_ext_cmpl - cmpl handler for multi-buffer write mbox 36907ad20aa9SJames Smart * @phba: Pointer to HBA context object. 36917ad20aa9SJames Smart * @pmboxq: Pointer to mailbox command. 36927ad20aa9SJames Smart * 36937ad20aa9SJames Smart * This is completion handler function for mailbox write commands with multiple 36947ad20aa9SJames Smart * external buffers. 36957ad20aa9SJames Smart **/ 36967ad20aa9SJames Smart static void 36977ad20aa9SJames Smart lpfc_bsg_issue_write_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) 36987ad20aa9SJames Smart { 369975cc8cfcSJohannes Thumshirn struct bsg_job *job; 37001abaede7SJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 37017ad20aa9SJames Smart 3702a33c4f7bSJames Smart job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq); 3703a33c4f7bSJames Smart 37047ad20aa9SJames Smart /* handle the BSG job with the mailbox command */ 3705a33c4f7bSJames Smart if (!job) 37067ad20aa9SJames Smart pmboxq->u.mb.mbxStatus = MBXERR_ERROR; 37077ad20aa9SJames Smart 37087ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 37097ad20aa9SJames Smart "2940 SLI_CONFIG ext-buffer wr maibox command " 37107ad20aa9SJames Smart "complete, ctxState:x%x, mbxStatus:x%x\n", 37117ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus); 37127ad20aa9SJames Smart 37137ad20aa9SJames Smart /* free all memory, including dma buffers */ 37147ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 37157ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 37167ad20aa9SJames Smart 3717a33c4f7bSJames Smart /* if the job is still active, call job done */ 37181abaede7SJohannes Thumshirn if (job) { 37191abaede7SJohannes Thumshirn bsg_reply = job->reply; 372006548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 37211abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 37221abaede7SJohannes Thumshirn } 37237ad20aa9SJames Smart 37247ad20aa9SJames Smart return; 37257ad20aa9SJames Smart } 37267ad20aa9SJames Smart 37277ad20aa9SJames Smart static void 37287ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(struct lpfc_hba *phba, enum nemb_type nemb_tp, 37297ad20aa9SJames Smart uint32_t index, struct lpfc_dmabuf *mbx_dmabuf, 37307ad20aa9SJames Smart struct lpfc_dmabuf *ext_dmabuf) 37317ad20aa9SJames Smart { 37327ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 37337ad20aa9SJames Smart 37347ad20aa9SJames Smart /* pointer to the start of mailbox command */ 37357ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)mbx_dmabuf->virt; 37367ad20aa9SJames Smart 37377ad20aa9SJames Smart if (nemb_tp == nemb_mse) { 37387ad20aa9SJames Smart if (index == 0) { 37397ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37407ad20aa9SJames Smart mse[index].pa_hi = 37417ad20aa9SJames Smart putPaddrHigh(mbx_dmabuf->phys + 37427ad20aa9SJames Smart sizeof(MAILBOX_t)); 37437ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37447ad20aa9SJames Smart mse[index].pa_lo = 37457ad20aa9SJames Smart putPaddrLow(mbx_dmabuf->phys + 37467ad20aa9SJames Smart sizeof(MAILBOX_t)); 37477ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 37487ad20aa9SJames Smart "2943 SLI_CONFIG(mse)[%d], " 37497ad20aa9SJames Smart "bufLen:%d, addrHi:x%x, addrLo:x%x\n", 37507ad20aa9SJames Smart index, 37517ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37527ad20aa9SJames Smart mse[index].buf_len, 37537ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37547ad20aa9SJames Smart mse[index].pa_hi, 37557ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37567ad20aa9SJames Smart mse[index].pa_lo); 37577ad20aa9SJames Smart } else { 37587ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37597ad20aa9SJames Smart mse[index].pa_hi = 37607ad20aa9SJames Smart putPaddrHigh(ext_dmabuf->phys); 37617ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37627ad20aa9SJames Smart mse[index].pa_lo = 37637ad20aa9SJames Smart putPaddrLow(ext_dmabuf->phys); 37647ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 37657ad20aa9SJames Smart "2944 SLI_CONFIG(mse)[%d], " 37667ad20aa9SJames Smart "bufLen:%d, addrHi:x%x, addrLo:x%x\n", 37677ad20aa9SJames Smart index, 37687ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37697ad20aa9SJames Smart mse[index].buf_len, 37707ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37717ad20aa9SJames Smart mse[index].pa_hi, 37727ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37737ad20aa9SJames Smart mse[index].pa_lo); 37747ad20aa9SJames Smart } 37757ad20aa9SJames Smart } else { 37767ad20aa9SJames Smart if (index == 0) { 37777ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 37787ad20aa9SJames Smart hbd[index].pa_hi = 37797ad20aa9SJames Smart putPaddrHigh(mbx_dmabuf->phys + 37807ad20aa9SJames Smart sizeof(MAILBOX_t)); 37817ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 37827ad20aa9SJames Smart hbd[index].pa_lo = 37837ad20aa9SJames Smart putPaddrLow(mbx_dmabuf->phys + 37847ad20aa9SJames Smart sizeof(MAILBOX_t)); 37857ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 37867ad20aa9SJames Smart "3007 SLI_CONFIG(hbd)[%d], " 37877ad20aa9SJames Smart "bufLen:%d, addrHi:x%x, addrLo:x%x\n", 37887ad20aa9SJames Smart index, 37897ad20aa9SJames Smart bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, 37907ad20aa9SJames Smart &sli_cfg_mbx->un. 37917ad20aa9SJames Smart sli_config_emb1_subsys.hbd[index]), 37927ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 37937ad20aa9SJames Smart hbd[index].pa_hi, 37947ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 37957ad20aa9SJames Smart hbd[index].pa_lo); 37967ad20aa9SJames Smart 37977ad20aa9SJames Smart } else { 37987ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 37997ad20aa9SJames Smart hbd[index].pa_hi = 38007ad20aa9SJames Smart putPaddrHigh(ext_dmabuf->phys); 38017ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 38027ad20aa9SJames Smart hbd[index].pa_lo = 38037ad20aa9SJames Smart putPaddrLow(ext_dmabuf->phys); 38047ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 38057ad20aa9SJames Smart "3008 SLI_CONFIG(hbd)[%d], " 38067ad20aa9SJames Smart "bufLen:%d, addrHi:x%x, addrLo:x%x\n", 38077ad20aa9SJames Smart index, 38087ad20aa9SJames Smart bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, 38097ad20aa9SJames Smart &sli_cfg_mbx->un. 38107ad20aa9SJames Smart sli_config_emb1_subsys.hbd[index]), 38117ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 38127ad20aa9SJames Smart hbd[index].pa_hi, 38137ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 38147ad20aa9SJames Smart hbd[index].pa_lo); 38157ad20aa9SJames Smart } 38167ad20aa9SJames Smart } 38177ad20aa9SJames Smart return; 38187ad20aa9SJames Smart } 38197ad20aa9SJames Smart 38207ad20aa9SJames Smart /** 38217ad20aa9SJames Smart * lpfc_bsg_sli_cfg_mse_read_cmd_ext - sli_config non-embedded mailbox cmd read 38227ad20aa9SJames Smart * @phba: Pointer to HBA context object. 38237ad20aa9SJames Smart * @mb: Pointer to a BSG mailbox object. 38247ad20aa9SJames Smart * @nemb_tp: Enumerate of non-embedded mailbox command type. 38257ad20aa9SJames Smart * @dmabuff: Pointer to a DMA buffer descriptor. 38267ad20aa9SJames Smart * 38277ad20aa9SJames Smart * This routine performs SLI_CONFIG (0x9B) read mailbox command operation with 38287ad20aa9SJames Smart * non-embedded external bufffers. 38297ad20aa9SJames Smart **/ 38307ad20aa9SJames Smart static int 383175cc8cfcSJohannes Thumshirn lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job, 38327ad20aa9SJames Smart enum nemb_type nemb_tp, 38337ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 38347ad20aa9SJames Smart { 383501e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 38367ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 38377ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 38387ad20aa9SJames Smart struct lpfc_dmabuf *curr_dmabuf, *next_dmabuf; 38397ad20aa9SJames Smart uint32_t ext_buf_cnt, ext_buf_index; 38407ad20aa9SJames Smart struct lpfc_dmabuf *ext_dmabuf = NULL; 38417ad20aa9SJames Smart struct bsg_job_data *dd_data = NULL; 38427ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq = NULL; 38437ad20aa9SJames Smart MAILBOX_t *pmb; 38447ad20aa9SJames Smart uint8_t *pmbx; 38457ad20aa9SJames Smart int rc, i; 38467ad20aa9SJames Smart 38477ad20aa9SJames Smart mbox_req = 384801e0e15cSJohannes Thumshirn (struct dfc_mbox_req *)bsg_request->rqst_data.h_vendor.vendor_cmd; 38497ad20aa9SJames Smart 38507ad20aa9SJames Smart /* pointer to the start of mailbox command */ 38517ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; 38527ad20aa9SJames Smart 38537ad20aa9SJames Smart if (nemb_tp == nemb_mse) { 38547ad20aa9SJames Smart ext_buf_cnt = bsg_bf_get(lpfc_mbox_hdr_mse_cnt, 38557ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr); 38567ad20aa9SJames Smart if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_MSE) { 38577ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 38587ad20aa9SJames Smart "2945 Handled SLI_CONFIG(mse) rd, " 38597ad20aa9SJames Smart "ext_buf_cnt(%d) out of range(%d)\n", 38607ad20aa9SJames Smart ext_buf_cnt, 38617ad20aa9SJames Smart LPFC_MBX_SLI_CONFIG_MAX_MSE); 38627ad20aa9SJames Smart rc = -ERANGE; 38637ad20aa9SJames Smart goto job_error; 38647ad20aa9SJames Smart } 38657ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 38667ad20aa9SJames Smart "2941 Handled SLI_CONFIG(mse) rd, " 38677ad20aa9SJames Smart "ext_buf_cnt:%d\n", ext_buf_cnt); 38687ad20aa9SJames Smart } else { 38697ad20aa9SJames Smart /* sanity check on interface type for support */ 38707ad20aa9SJames Smart if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != 38717ad20aa9SJames Smart LPFC_SLI_INTF_IF_TYPE_2) { 38727ad20aa9SJames Smart rc = -ENODEV; 38737ad20aa9SJames Smart goto job_error; 38747ad20aa9SJames Smart } 38757ad20aa9SJames Smart /* nemb_tp == nemb_hbd */ 38767ad20aa9SJames Smart ext_buf_cnt = sli_cfg_mbx->un.sli_config_emb1_subsys.hbd_count; 38777ad20aa9SJames Smart if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_HBD) { 38787ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 38797ad20aa9SJames Smart "2946 Handled SLI_CONFIG(hbd) rd, " 38807ad20aa9SJames Smart "ext_buf_cnt(%d) out of range(%d)\n", 38817ad20aa9SJames Smart ext_buf_cnt, 38827ad20aa9SJames Smart LPFC_MBX_SLI_CONFIG_MAX_HBD); 38837ad20aa9SJames Smart rc = -ERANGE; 38847ad20aa9SJames Smart goto job_error; 38857ad20aa9SJames Smart } 38867ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 38877ad20aa9SJames Smart "2942 Handled SLI_CONFIG(hbd) rd, " 38887ad20aa9SJames Smart "ext_buf_cnt:%d\n", ext_buf_cnt); 38897ad20aa9SJames Smart } 38907ad20aa9SJames Smart 3891b76f2dc9SJames Smart /* before dma descriptor setup */ 3892b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_rd, dma_mbox, 3893b76f2dc9SJames Smart sta_pre_addr, dmabuf, ext_buf_cnt); 3894b76f2dc9SJames Smart 38957ad20aa9SJames Smart /* reject non-embedded mailbox command with none external buffer */ 38967ad20aa9SJames Smart if (ext_buf_cnt == 0) { 38977ad20aa9SJames Smart rc = -EPERM; 38987ad20aa9SJames Smart goto job_error; 38997ad20aa9SJames Smart } else if (ext_buf_cnt > 1) { 39007ad20aa9SJames Smart /* additional external read buffers */ 39017ad20aa9SJames Smart for (i = 1; i < ext_buf_cnt; i++) { 39027ad20aa9SJames Smart ext_dmabuf = lpfc_bsg_dma_page_alloc(phba); 39037ad20aa9SJames Smart if (!ext_dmabuf) { 39047ad20aa9SJames Smart rc = -ENOMEM; 39057ad20aa9SJames Smart goto job_error; 39067ad20aa9SJames Smart } 39077ad20aa9SJames Smart list_add_tail(&ext_dmabuf->list, 39087ad20aa9SJames Smart &phba->mbox_ext_buf_ctx.ext_dmabuf_list); 39097ad20aa9SJames Smart } 39107ad20aa9SJames Smart } 39117ad20aa9SJames Smart 39127ad20aa9SJames Smart /* bsg tracking structure */ 39137ad20aa9SJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 39147ad20aa9SJames Smart if (!dd_data) { 39157ad20aa9SJames Smart rc = -ENOMEM; 39167ad20aa9SJames Smart goto job_error; 39177ad20aa9SJames Smart } 39187ad20aa9SJames Smart 39197ad20aa9SJames Smart /* mailbox command structure for base driver */ 39207ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 39217ad20aa9SJames Smart if (!pmboxq) { 39227ad20aa9SJames Smart rc = -ENOMEM; 39237ad20aa9SJames Smart goto job_error; 39247ad20aa9SJames Smart } 39257ad20aa9SJames Smart memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 39267ad20aa9SJames Smart 39277ad20aa9SJames Smart /* for the first external buffer */ 39287ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 0, dmabuf, dmabuf); 39297ad20aa9SJames Smart 39307ad20aa9SJames Smart /* for the rest of external buffer descriptors if any */ 39317ad20aa9SJames Smart if (ext_buf_cnt > 1) { 39327ad20aa9SJames Smart ext_buf_index = 1; 39337ad20aa9SJames Smart list_for_each_entry_safe(curr_dmabuf, next_dmabuf, 39347ad20aa9SJames Smart &phba->mbox_ext_buf_ctx.ext_dmabuf_list, list) { 39357ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 39367ad20aa9SJames Smart ext_buf_index, dmabuf, 39377ad20aa9SJames Smart curr_dmabuf); 39387ad20aa9SJames Smart ext_buf_index++; 39397ad20aa9SJames Smart } 39407ad20aa9SJames Smart } 39417ad20aa9SJames Smart 3942b76f2dc9SJames Smart /* after dma descriptor setup */ 3943b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_rd, dma_mbox, 3944b76f2dc9SJames Smart sta_pos_addr, dmabuf, ext_buf_cnt); 3945b76f2dc9SJames Smart 39467ad20aa9SJames Smart /* construct base driver mbox command */ 39477ad20aa9SJames Smart pmb = &pmboxq->u.mb; 39487ad20aa9SJames Smart pmbx = (uint8_t *)dmabuf->virt; 39497ad20aa9SJames Smart memcpy(pmb, pmbx, sizeof(*pmb)); 39507ad20aa9SJames Smart pmb->mbxOwner = OWN_HOST; 39517ad20aa9SJames Smart pmboxq->vport = phba->pport; 39527ad20aa9SJames Smart 39537ad20aa9SJames Smart /* multi-buffer handling context */ 39547ad20aa9SJames Smart phba->mbox_ext_buf_ctx.nembType = nemb_tp; 39557ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType = mbox_rd; 39567ad20aa9SJames Smart phba->mbox_ext_buf_ctx.numBuf = ext_buf_cnt; 39577ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbxTag = mbox_req->extMboxTag; 39587ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum = mbox_req->extSeqNum; 39597ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf = dmabuf; 39607ad20aa9SJames Smart 39617ad20aa9SJames Smart /* callback for multi-buffer read mailbox command */ 39627ad20aa9SJames Smart pmboxq->mbox_cmpl = lpfc_bsg_issue_read_mbox_ext_cmpl; 39637ad20aa9SJames Smart 39647ad20aa9SJames Smart /* context fields to callback function */ 39657ad20aa9SJames Smart pmboxq->context1 = dd_data; 39667ad20aa9SJames Smart dd_data->type = TYPE_MBOX; 3967a33c4f7bSJames Smart dd_data->set_job = job; 39687ad20aa9SJames Smart dd_data->context_un.mbox.pmboxq = pmboxq; 39697ad20aa9SJames Smart dd_data->context_un.mbox.mb = (MAILBOX_t *)pmbx; 39707ad20aa9SJames Smart job->dd_data = dd_data; 39717ad20aa9SJames Smart 39727ad20aa9SJames Smart /* state change */ 39737ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT; 39747ad20aa9SJames Smart 3975026abb87SJames Smart /* 3976026abb87SJames Smart * Non-embedded mailbox subcommand data gets byte swapped here because 3977026abb87SJames Smart * the lower level driver code only does the first 64 mailbox words. 3978026abb87SJames Smart */ 3979026abb87SJames Smart if ((!bsg_bf_get(lpfc_mbox_hdr_emb, 3980026abb87SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) && 3981026abb87SJames Smart (nemb_tp == nemb_mse)) 3982026abb87SJames Smart lpfc_sli_pcimem_bcopy(&pmbx[sizeof(MAILBOX_t)], 3983026abb87SJames Smart &pmbx[sizeof(MAILBOX_t)], 3984026abb87SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 3985026abb87SJames Smart mse[0].buf_len); 3986026abb87SJames Smart 39877ad20aa9SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); 39887ad20aa9SJames Smart if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { 39897ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 39907ad20aa9SJames Smart "2947 Issued SLI_CONFIG ext-buffer " 39917ad20aa9SJames Smart "maibox command, rc:x%x\n", rc); 399288a2cfbbSJames Smart return SLI_CONFIG_HANDLED; 39937ad20aa9SJames Smart } 39947ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 39957ad20aa9SJames Smart "2948 Failed to issue SLI_CONFIG ext-buffer " 39967ad20aa9SJames Smart "maibox command, rc:x%x\n", rc); 39977ad20aa9SJames Smart rc = -EPIPE; 39987ad20aa9SJames Smart 39997ad20aa9SJames Smart job_error: 40007ad20aa9SJames Smart if (pmboxq) 40017ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 40027ad20aa9SJames Smart lpfc_bsg_dma_page_list_free(phba, 40037ad20aa9SJames Smart &phba->mbox_ext_buf_ctx.ext_dmabuf_list); 40047ad20aa9SJames Smart kfree(dd_data); 40057ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_IDLE; 40067ad20aa9SJames Smart return rc; 40077ad20aa9SJames Smart } 40087ad20aa9SJames Smart 40097ad20aa9SJames Smart /** 40107ad20aa9SJames Smart * lpfc_bsg_sli_cfg_write_cmd_ext - sli_config non-embedded mailbox cmd write 40117ad20aa9SJames Smart * @phba: Pointer to HBA context object. 40127ad20aa9SJames Smart * @mb: Pointer to a BSG mailbox object. 40137ad20aa9SJames Smart * @dmabuff: Pointer to a DMA buffer descriptor. 40147ad20aa9SJames Smart * 40157ad20aa9SJames Smart * This routine performs SLI_CONFIG (0x9B) write mailbox command operation with 40167ad20aa9SJames Smart * non-embedded external bufffers. 40177ad20aa9SJames Smart **/ 40187ad20aa9SJames Smart static int 401975cc8cfcSJohannes Thumshirn lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job, 40207ad20aa9SJames Smart enum nemb_type nemb_tp, 40217ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 40227ad20aa9SJames Smart { 402301e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 402401e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 40257ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 40267ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 40277ad20aa9SJames Smart uint32_t ext_buf_cnt; 40287ad20aa9SJames Smart struct bsg_job_data *dd_data = NULL; 40297ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq = NULL; 40307ad20aa9SJames Smart MAILBOX_t *pmb; 40317ad20aa9SJames Smart uint8_t *mbx; 403288a2cfbbSJames Smart int rc = SLI_CONFIG_NOT_HANDLED, i; 40337ad20aa9SJames Smart 40347ad20aa9SJames Smart mbox_req = 403501e0e15cSJohannes Thumshirn (struct dfc_mbox_req *)bsg_request->rqst_data.h_vendor.vendor_cmd; 40367ad20aa9SJames Smart 40377ad20aa9SJames Smart /* pointer to the start of mailbox command */ 40387ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; 40397ad20aa9SJames Smart 40407ad20aa9SJames Smart if (nemb_tp == nemb_mse) { 40417ad20aa9SJames Smart ext_buf_cnt = bsg_bf_get(lpfc_mbox_hdr_mse_cnt, 40427ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr); 40437ad20aa9SJames Smart if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_MSE) { 40447ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 4045026abb87SJames Smart "2953 Failed SLI_CONFIG(mse) wr, " 40467ad20aa9SJames Smart "ext_buf_cnt(%d) out of range(%d)\n", 40477ad20aa9SJames Smart ext_buf_cnt, 40487ad20aa9SJames Smart LPFC_MBX_SLI_CONFIG_MAX_MSE); 40497ad20aa9SJames Smart return -ERANGE; 40507ad20aa9SJames Smart } 40517ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 40527ad20aa9SJames Smart "2949 Handled SLI_CONFIG(mse) wr, " 40537ad20aa9SJames Smart "ext_buf_cnt:%d\n", ext_buf_cnt); 40547ad20aa9SJames Smart } else { 40557ad20aa9SJames Smart /* sanity check on interface type for support */ 40567ad20aa9SJames Smart if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != 40577ad20aa9SJames Smart LPFC_SLI_INTF_IF_TYPE_2) 40587ad20aa9SJames Smart return -ENODEV; 40597ad20aa9SJames Smart /* nemb_tp == nemb_hbd */ 40607ad20aa9SJames Smart ext_buf_cnt = sli_cfg_mbx->un.sli_config_emb1_subsys.hbd_count; 40617ad20aa9SJames Smart if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_HBD) { 40627ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 4063026abb87SJames Smart "2954 Failed SLI_CONFIG(hbd) wr, " 40647ad20aa9SJames Smart "ext_buf_cnt(%d) out of range(%d)\n", 40657ad20aa9SJames Smart ext_buf_cnt, 40667ad20aa9SJames Smart LPFC_MBX_SLI_CONFIG_MAX_HBD); 40677ad20aa9SJames Smart return -ERANGE; 40687ad20aa9SJames Smart } 40697ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 40707ad20aa9SJames Smart "2950 Handled SLI_CONFIG(hbd) wr, " 40717ad20aa9SJames Smart "ext_buf_cnt:%d\n", ext_buf_cnt); 40727ad20aa9SJames Smart } 40737ad20aa9SJames Smart 4074b76f2dc9SJames Smart /* before dma buffer descriptor setup */ 4075b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_wr, dma_mbox, 4076b76f2dc9SJames Smart sta_pre_addr, dmabuf, ext_buf_cnt); 4077b76f2dc9SJames Smart 40787ad20aa9SJames Smart if (ext_buf_cnt == 0) 40797ad20aa9SJames Smart return -EPERM; 40807ad20aa9SJames Smart 40817ad20aa9SJames Smart /* for the first external buffer */ 40827ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 0, dmabuf, dmabuf); 40837ad20aa9SJames Smart 4084b76f2dc9SJames Smart /* after dma descriptor setup */ 4085b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_wr, dma_mbox, 4086b76f2dc9SJames Smart sta_pos_addr, dmabuf, ext_buf_cnt); 4087b76f2dc9SJames Smart 40887ad20aa9SJames Smart /* log for looking forward */ 40897ad20aa9SJames Smart for (i = 1; i < ext_buf_cnt; i++) { 40907ad20aa9SJames Smart if (nemb_tp == nemb_mse) 40917ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 40927ad20aa9SJames Smart "2951 SLI_CONFIG(mse), buf[%d]-length:%d\n", 40937ad20aa9SJames Smart i, sli_cfg_mbx->un.sli_config_emb0_subsys. 40947ad20aa9SJames Smart mse[i].buf_len); 40957ad20aa9SJames Smart else 40967ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 40977ad20aa9SJames Smart "2952 SLI_CONFIG(hbd), buf[%d]-length:%d\n", 40987ad20aa9SJames Smart i, bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, 40997ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb1_subsys. 41007ad20aa9SJames Smart hbd[i])); 41017ad20aa9SJames Smart } 41027ad20aa9SJames Smart 41037ad20aa9SJames Smart /* multi-buffer handling context */ 41047ad20aa9SJames Smart phba->mbox_ext_buf_ctx.nembType = nemb_tp; 41057ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType = mbox_wr; 41067ad20aa9SJames Smart phba->mbox_ext_buf_ctx.numBuf = ext_buf_cnt; 41077ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbxTag = mbox_req->extMboxTag; 41087ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum = mbox_req->extSeqNum; 41097ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf = dmabuf; 41107ad20aa9SJames Smart 41117ad20aa9SJames Smart if (ext_buf_cnt == 1) { 41127ad20aa9SJames Smart /* bsg tracking structure */ 41137ad20aa9SJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 41147ad20aa9SJames Smart if (!dd_data) { 41157ad20aa9SJames Smart rc = -ENOMEM; 41167ad20aa9SJames Smart goto job_error; 41177ad20aa9SJames Smart } 41187ad20aa9SJames Smart 41197ad20aa9SJames Smart /* mailbox command structure for base driver */ 41207ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 41217ad20aa9SJames Smart if (!pmboxq) { 41227ad20aa9SJames Smart rc = -ENOMEM; 41237ad20aa9SJames Smart goto job_error; 41247ad20aa9SJames Smart } 41257ad20aa9SJames Smart memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 41267ad20aa9SJames Smart pmb = &pmboxq->u.mb; 41277ad20aa9SJames Smart mbx = (uint8_t *)dmabuf->virt; 41287ad20aa9SJames Smart memcpy(pmb, mbx, sizeof(*pmb)); 41297ad20aa9SJames Smart pmb->mbxOwner = OWN_HOST; 41307ad20aa9SJames Smart pmboxq->vport = phba->pport; 41317ad20aa9SJames Smart 41327ad20aa9SJames Smart /* callback for multi-buffer read mailbox command */ 41337ad20aa9SJames Smart pmboxq->mbox_cmpl = lpfc_bsg_issue_write_mbox_ext_cmpl; 41347ad20aa9SJames Smart 41357ad20aa9SJames Smart /* context fields to callback function */ 41367ad20aa9SJames Smart pmboxq->context1 = dd_data; 41377ad20aa9SJames Smart dd_data->type = TYPE_MBOX; 4138a33c4f7bSJames Smart dd_data->set_job = job; 41397ad20aa9SJames Smart dd_data->context_un.mbox.pmboxq = pmboxq; 41407ad20aa9SJames Smart dd_data->context_un.mbox.mb = (MAILBOX_t *)mbx; 41417ad20aa9SJames Smart job->dd_data = dd_data; 41427ad20aa9SJames Smart 41437ad20aa9SJames Smart /* state change */ 41447ad20aa9SJames Smart 4145a33c4f7bSJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT; 41467ad20aa9SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); 41477ad20aa9SJames Smart if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { 41487ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 41497ad20aa9SJames Smart "2955 Issued SLI_CONFIG ext-buffer " 41507ad20aa9SJames Smart "maibox command, rc:x%x\n", rc); 415188a2cfbbSJames Smart return SLI_CONFIG_HANDLED; 41527ad20aa9SJames Smart } 41537ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 41547ad20aa9SJames Smart "2956 Failed to issue SLI_CONFIG ext-buffer " 41557ad20aa9SJames Smart "maibox command, rc:x%x\n", rc); 41567ad20aa9SJames Smart rc = -EPIPE; 4157026abb87SJames Smart goto job_error; 41587ad20aa9SJames Smart } 41597ad20aa9SJames Smart 416088a2cfbbSJames Smart /* wait for additoinal external buffers */ 4161a33c4f7bSJames Smart 416201e0e15cSJohannes Thumshirn bsg_reply->result = 0; 416306548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 41641abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 416588a2cfbbSJames Smart return SLI_CONFIG_HANDLED; 416688a2cfbbSJames Smart 41677ad20aa9SJames Smart job_error: 41687ad20aa9SJames Smart if (pmboxq) 41697ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 41707ad20aa9SJames Smart kfree(dd_data); 41717ad20aa9SJames Smart 41727ad20aa9SJames Smart return rc; 41737ad20aa9SJames Smart } 41747ad20aa9SJames Smart 41757ad20aa9SJames Smart /** 41767ad20aa9SJames Smart * lpfc_bsg_handle_sli_cfg_mbox - handle sli-cfg mailbox cmd with ext buffer 41777ad20aa9SJames Smart * @phba: Pointer to HBA context object. 41787ad20aa9SJames Smart * @mb: Pointer to a BSG mailbox object. 41797ad20aa9SJames Smart * @dmabuff: Pointer to a DMA buffer descriptor. 41807ad20aa9SJames Smart * 41817ad20aa9SJames Smart * This routine handles SLI_CONFIG (0x9B) mailbox command with non-embedded 41827ad20aa9SJames Smart * external bufffers, including both 0x9B with non-embedded MSEs and 0x9B 41837ad20aa9SJames Smart * with embedded sussystem 0x1 and opcodes with external HBDs. 41847ad20aa9SJames Smart **/ 41857ad20aa9SJames Smart static int 418675cc8cfcSJohannes Thumshirn lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct bsg_job *job, 41877ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 41887ad20aa9SJames Smart { 41897ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 41907ad20aa9SJames Smart uint32_t subsys; 41917ad20aa9SJames Smart uint32_t opcode; 41927ad20aa9SJames Smart int rc = SLI_CONFIG_NOT_HANDLED; 41937ad20aa9SJames Smart 4194026abb87SJames Smart /* state change on new multi-buffer pass-through mailbox command */ 41957ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_HOST; 41967ad20aa9SJames Smart 41977ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; 41987ad20aa9SJames Smart 41997ad20aa9SJames Smart if (!bsg_bf_get(lpfc_mbox_hdr_emb, 42007ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) { 42017ad20aa9SJames Smart subsys = bsg_bf_get(lpfc_emb0_subcmnd_subsys, 42027ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys); 42037ad20aa9SJames Smart opcode = bsg_bf_get(lpfc_emb0_subcmnd_opcode, 42047ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys); 42057ad20aa9SJames Smart if (subsys == SLI_CONFIG_SUBSYS_FCOE) { 42067ad20aa9SJames Smart switch (opcode) { 42077ad20aa9SJames Smart case FCOE_OPCODE_READ_FCF: 42082a2719d3SJames Smart case FCOE_OPCODE_GET_DPORT_RESULTS: 42097ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 42107ad20aa9SJames Smart "2957 Handled SLI_CONFIG " 42117ad20aa9SJames Smart "subsys_fcoe, opcode:x%x\n", 42127ad20aa9SJames Smart opcode); 42137ad20aa9SJames Smart rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job, 42147ad20aa9SJames Smart nemb_mse, dmabuf); 42157ad20aa9SJames Smart break; 42167ad20aa9SJames Smart case FCOE_OPCODE_ADD_FCF: 42172a2719d3SJames Smart case FCOE_OPCODE_SET_DPORT_MODE: 42182a2719d3SJames Smart case LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE: 42197ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 42207ad20aa9SJames Smart "2958 Handled SLI_CONFIG " 42217ad20aa9SJames Smart "subsys_fcoe, opcode:x%x\n", 42227ad20aa9SJames Smart opcode); 42237ad20aa9SJames Smart rc = lpfc_bsg_sli_cfg_write_cmd_ext(phba, job, 42247ad20aa9SJames Smart nemb_mse, dmabuf); 42257ad20aa9SJames Smart break; 42267ad20aa9SJames Smart default: 42277ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4228026abb87SJames Smart "2959 Reject SLI_CONFIG " 42297ad20aa9SJames Smart "subsys_fcoe, opcode:x%x\n", 42307ad20aa9SJames Smart opcode); 4231026abb87SJames Smart rc = -EPERM; 4232026abb87SJames Smart break; 4233026abb87SJames Smart } 4234026abb87SJames Smart } else if (subsys == SLI_CONFIG_SUBSYS_COMN) { 4235026abb87SJames Smart switch (opcode) { 4236026abb87SJames Smart case COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES: 4237b99570ddSJames Smart case COMN_OPCODE_GET_CNTL_ATTRIBUTES: 4238c6377970SJames Smart case COMN_OPCODE_GET_PROFILE_CONFIG: 4239026abb87SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4240026abb87SJames Smart "3106 Handled SLI_CONFIG " 42416b5151fdSJames Smart "subsys_comn, opcode:x%x\n", 4242026abb87SJames Smart opcode); 4243026abb87SJames Smart rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job, 4244026abb87SJames Smart nemb_mse, dmabuf); 4245026abb87SJames Smart break; 4246026abb87SJames Smart default: 4247026abb87SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4248026abb87SJames Smart "3107 Reject SLI_CONFIG " 42496b5151fdSJames Smart "subsys_comn, opcode:x%x\n", 4250026abb87SJames Smart opcode); 4251026abb87SJames Smart rc = -EPERM; 42527ad20aa9SJames Smart break; 42537ad20aa9SJames Smart } 42547ad20aa9SJames Smart } else { 42557ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4256026abb87SJames Smart "2977 Reject SLI_CONFIG " 42577ad20aa9SJames Smart "subsys:x%d, opcode:x%x\n", 42587ad20aa9SJames Smart subsys, opcode); 4259026abb87SJames Smart rc = -EPERM; 42607ad20aa9SJames Smart } 42617ad20aa9SJames Smart } else { 42627ad20aa9SJames Smart subsys = bsg_bf_get(lpfc_emb1_subcmnd_subsys, 42637ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb1_subsys); 42647ad20aa9SJames Smart opcode = bsg_bf_get(lpfc_emb1_subcmnd_opcode, 42657ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb1_subsys); 42667ad20aa9SJames Smart if (subsys == SLI_CONFIG_SUBSYS_COMN) { 42677ad20aa9SJames Smart switch (opcode) { 42687ad20aa9SJames Smart case COMN_OPCODE_READ_OBJECT: 42697ad20aa9SJames Smart case COMN_OPCODE_READ_OBJECT_LIST: 42707ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 42717ad20aa9SJames Smart "2960 Handled SLI_CONFIG " 42727ad20aa9SJames Smart "subsys_comn, opcode:x%x\n", 42737ad20aa9SJames Smart opcode); 42747ad20aa9SJames Smart rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job, 42757ad20aa9SJames Smart nemb_hbd, dmabuf); 42767ad20aa9SJames Smart break; 42777ad20aa9SJames Smart case COMN_OPCODE_WRITE_OBJECT: 42787ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 42797ad20aa9SJames Smart "2961 Handled SLI_CONFIG " 42807ad20aa9SJames Smart "subsys_comn, opcode:x%x\n", 42817ad20aa9SJames Smart opcode); 42827ad20aa9SJames Smart rc = lpfc_bsg_sli_cfg_write_cmd_ext(phba, job, 42837ad20aa9SJames Smart nemb_hbd, dmabuf); 42847ad20aa9SJames Smart break; 42857ad20aa9SJames Smart default: 42867ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 42877ad20aa9SJames Smart "2962 Not handled SLI_CONFIG " 42887ad20aa9SJames Smart "subsys_comn, opcode:x%x\n", 42897ad20aa9SJames Smart opcode); 42907ad20aa9SJames Smart rc = SLI_CONFIG_NOT_HANDLED; 42917ad20aa9SJames Smart break; 42927ad20aa9SJames Smart } 42937ad20aa9SJames Smart } else { 42947ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4295026abb87SJames Smart "2978 Not handled SLI_CONFIG " 42967ad20aa9SJames Smart "subsys:x%d, opcode:x%x\n", 42977ad20aa9SJames Smart subsys, opcode); 42987ad20aa9SJames Smart rc = SLI_CONFIG_NOT_HANDLED; 42997ad20aa9SJames Smart } 43007ad20aa9SJames Smart } 4301026abb87SJames Smart 4302026abb87SJames Smart /* state reset on not handled new multi-buffer mailbox command */ 4303026abb87SJames Smart if (rc != SLI_CONFIG_HANDLED) 4304026abb87SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_IDLE; 4305026abb87SJames Smart 43067ad20aa9SJames Smart return rc; 43077ad20aa9SJames Smart } 43087ad20aa9SJames Smart 43097ad20aa9SJames Smart /** 43107ad20aa9SJames Smart * lpfc_bsg_mbox_ext_abort_req - request to abort mbox command with ext buffers 43117ad20aa9SJames Smart * @phba: Pointer to HBA context object. 43127ad20aa9SJames Smart * 43137ad20aa9SJames Smart * This routine is for requesting to abort a pass-through mailbox command with 43147ad20aa9SJames Smart * multiple external buffers due to error condition. 43157ad20aa9SJames Smart **/ 43167ad20aa9SJames Smart static void 43177ad20aa9SJames Smart lpfc_bsg_mbox_ext_abort(struct lpfc_hba *phba) 43187ad20aa9SJames Smart { 43197ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_PORT) 43207ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_ABTS; 43217ad20aa9SJames Smart else 43227ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 43237ad20aa9SJames Smart return; 43247ad20aa9SJames Smart } 43257ad20aa9SJames Smart 43267ad20aa9SJames Smart /** 43277ad20aa9SJames Smart * lpfc_bsg_read_ebuf_get - get the next mailbox read external buffer 43287ad20aa9SJames Smart * @phba: Pointer to HBA context object. 43297ad20aa9SJames Smart * @dmabuf: Pointer to a DMA buffer descriptor. 43307ad20aa9SJames Smart * 43317ad20aa9SJames Smart * This routine extracts the next mailbox read external buffer back to 43327ad20aa9SJames Smart * user space through BSG. 43337ad20aa9SJames Smart **/ 43347ad20aa9SJames Smart static int 433575cc8cfcSJohannes Thumshirn lpfc_bsg_read_ebuf_get(struct lpfc_hba *phba, struct bsg_job *job) 43367ad20aa9SJames Smart { 433701e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 43387ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 43397ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf; 43407ad20aa9SJames Smart uint8_t *pbuf; 43417ad20aa9SJames Smart uint32_t size; 43427ad20aa9SJames Smart uint32_t index; 43437ad20aa9SJames Smart 43447ad20aa9SJames Smart index = phba->mbox_ext_buf_ctx.seqNum; 43457ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum++; 43467ad20aa9SJames Smart 43477ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *) 43487ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf->virt; 43497ad20aa9SJames Smart 43507ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.nembType == nemb_mse) { 43517ad20aa9SJames Smart size = bsg_bf_get(lpfc_mbox_sli_config_mse_len, 43527ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.mse[index]); 43537ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 43547ad20aa9SJames Smart "2963 SLI_CONFIG (mse) ext-buffer rd get " 43557ad20aa9SJames Smart "buffer[%d], size:%d\n", index, size); 43567ad20aa9SJames Smart } else { 43577ad20aa9SJames Smart size = bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, 43587ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb1_subsys.hbd[index]); 43597ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 43607ad20aa9SJames Smart "2964 SLI_CONFIG (hbd) ext-buffer rd get " 43617ad20aa9SJames Smart "buffer[%d], size:%d\n", index, size); 43627ad20aa9SJames Smart } 43637ad20aa9SJames Smart if (list_empty(&phba->mbox_ext_buf_ctx.ext_dmabuf_list)) 43647ad20aa9SJames Smart return -EPIPE; 43657ad20aa9SJames Smart dmabuf = list_first_entry(&phba->mbox_ext_buf_ctx.ext_dmabuf_list, 43667ad20aa9SJames Smart struct lpfc_dmabuf, list); 43677ad20aa9SJames Smart list_del_init(&dmabuf->list); 4368b76f2dc9SJames Smart 4369b76f2dc9SJames Smart /* after dma buffer descriptor setup */ 4370b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, phba->mbox_ext_buf_ctx.nembType, 4371b76f2dc9SJames Smart mbox_rd, dma_ebuf, sta_pos_addr, 4372b76f2dc9SJames Smart dmabuf, index); 4373b76f2dc9SJames Smart 43747ad20aa9SJames Smart pbuf = (uint8_t *)dmabuf->virt; 437501e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 43767ad20aa9SJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 43777ad20aa9SJames Smart job->reply_payload.sg_cnt, 43787ad20aa9SJames Smart pbuf, size); 43797ad20aa9SJames Smart 43807ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 43817ad20aa9SJames Smart 43827ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.seqNum == phba->mbox_ext_buf_ctx.numBuf) { 43837ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 43847ad20aa9SJames Smart "2965 SLI_CONFIG (hbd) ext-buffer rd mbox " 43857ad20aa9SJames Smart "command session done\n"); 43867ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 43877ad20aa9SJames Smart } 43887ad20aa9SJames Smart 438901e0e15cSJohannes Thumshirn bsg_reply->result = 0; 439006548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 43911abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 43927ad20aa9SJames Smart 43937ad20aa9SJames Smart return SLI_CONFIG_HANDLED; 43947ad20aa9SJames Smart } 43957ad20aa9SJames Smart 43967ad20aa9SJames Smart /** 43977ad20aa9SJames Smart * lpfc_bsg_write_ebuf_set - set the next mailbox write external buffer 43987ad20aa9SJames Smart * @phba: Pointer to HBA context object. 43997ad20aa9SJames Smart * @dmabuf: Pointer to a DMA buffer descriptor. 44007ad20aa9SJames Smart * 44017ad20aa9SJames Smart * This routine sets up the next mailbox read external buffer obtained 44027ad20aa9SJames Smart * from user space through BSG. 44037ad20aa9SJames Smart **/ 44047ad20aa9SJames Smart static int 440575cc8cfcSJohannes Thumshirn lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct bsg_job *job, 44067ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 44077ad20aa9SJames Smart { 440801e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 44097ad20aa9SJames Smart struct bsg_job_data *dd_data = NULL; 44107ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq = NULL; 44117ad20aa9SJames Smart MAILBOX_t *pmb; 44127ad20aa9SJames Smart enum nemb_type nemb_tp; 44137ad20aa9SJames Smart uint8_t *pbuf; 44147ad20aa9SJames Smart uint32_t size; 44157ad20aa9SJames Smart uint32_t index; 44167ad20aa9SJames Smart int rc; 44177ad20aa9SJames Smart 44187ad20aa9SJames Smart index = phba->mbox_ext_buf_ctx.seqNum; 44197ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum++; 44207ad20aa9SJames Smart nemb_tp = phba->mbox_ext_buf_ctx.nembType; 44217ad20aa9SJames Smart 44227ad20aa9SJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 44237ad20aa9SJames Smart if (!dd_data) { 44247ad20aa9SJames Smart rc = -ENOMEM; 44257ad20aa9SJames Smart goto job_error; 44267ad20aa9SJames Smart } 44277ad20aa9SJames Smart 44287ad20aa9SJames Smart pbuf = (uint8_t *)dmabuf->virt; 44297ad20aa9SJames Smart size = job->request_payload.payload_len; 44307ad20aa9SJames Smart sg_copy_to_buffer(job->request_payload.sg_list, 44317ad20aa9SJames Smart job->request_payload.sg_cnt, 44327ad20aa9SJames Smart pbuf, size); 44337ad20aa9SJames Smart 44347ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.nembType == nemb_mse) { 44357ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 44367ad20aa9SJames Smart "2966 SLI_CONFIG (mse) ext-buffer wr set " 44377ad20aa9SJames Smart "buffer[%d], size:%d\n", 44387ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum, size); 44397ad20aa9SJames Smart 44407ad20aa9SJames Smart } else { 44417ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 44427ad20aa9SJames Smart "2967 SLI_CONFIG (hbd) ext-buffer wr set " 44437ad20aa9SJames Smart "buffer[%d], size:%d\n", 44447ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum, size); 44457ad20aa9SJames Smart 44467ad20aa9SJames Smart } 44477ad20aa9SJames Smart 44487ad20aa9SJames Smart /* set up external buffer descriptor and add to external buffer list */ 44497ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, index, 44507ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf, 44517ad20aa9SJames Smart dmabuf); 44527ad20aa9SJames Smart list_add_tail(&dmabuf->list, &phba->mbox_ext_buf_ctx.ext_dmabuf_list); 44537ad20aa9SJames Smart 4454b76f2dc9SJames Smart /* after write dma buffer */ 4455b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, phba->mbox_ext_buf_ctx.nembType, 4456b76f2dc9SJames Smart mbox_wr, dma_ebuf, sta_pos_addr, 4457b76f2dc9SJames Smart dmabuf, index); 4458b76f2dc9SJames Smart 44597ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.seqNum == phba->mbox_ext_buf_ctx.numBuf) { 44607ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 44617ad20aa9SJames Smart "2968 SLI_CONFIG ext-buffer wr all %d " 44627ad20aa9SJames Smart "ebuffers received\n", 44637ad20aa9SJames Smart phba->mbox_ext_buf_ctx.numBuf); 44647ad20aa9SJames Smart /* mailbox command structure for base driver */ 44657ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 44667ad20aa9SJames Smart if (!pmboxq) { 44677ad20aa9SJames Smart rc = -ENOMEM; 44687ad20aa9SJames Smart goto job_error; 44697ad20aa9SJames Smart } 44707ad20aa9SJames Smart memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 44717ad20aa9SJames Smart pbuf = (uint8_t *)phba->mbox_ext_buf_ctx.mbx_dmabuf->virt; 44727ad20aa9SJames Smart pmb = &pmboxq->u.mb; 44737ad20aa9SJames Smart memcpy(pmb, pbuf, sizeof(*pmb)); 44747ad20aa9SJames Smart pmb->mbxOwner = OWN_HOST; 44757ad20aa9SJames Smart pmboxq->vport = phba->pport; 44767ad20aa9SJames Smart 44777ad20aa9SJames Smart /* callback for multi-buffer write mailbox command */ 44787ad20aa9SJames Smart pmboxq->mbox_cmpl = lpfc_bsg_issue_write_mbox_ext_cmpl; 44797ad20aa9SJames Smart 44807ad20aa9SJames Smart /* context fields to callback function */ 44817ad20aa9SJames Smart pmboxq->context1 = dd_data; 44827ad20aa9SJames Smart dd_data->type = TYPE_MBOX; 4483a33c4f7bSJames Smart dd_data->set_job = job; 44847ad20aa9SJames Smart dd_data->context_un.mbox.pmboxq = pmboxq; 44857ad20aa9SJames Smart dd_data->context_un.mbox.mb = (MAILBOX_t *)pbuf; 44867ad20aa9SJames Smart job->dd_data = dd_data; 44877ad20aa9SJames Smart 44887ad20aa9SJames Smart /* state change */ 44897ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT; 44907ad20aa9SJames Smart 44917ad20aa9SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); 44927ad20aa9SJames Smart if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { 44937ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 44947ad20aa9SJames Smart "2969 Issued SLI_CONFIG ext-buffer " 44957ad20aa9SJames Smart "maibox command, rc:x%x\n", rc); 449688a2cfbbSJames Smart return SLI_CONFIG_HANDLED; 44977ad20aa9SJames Smart } 44987ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 44997ad20aa9SJames Smart "2970 Failed to issue SLI_CONFIG ext-buffer " 45007ad20aa9SJames Smart "maibox command, rc:x%x\n", rc); 45017ad20aa9SJames Smart rc = -EPIPE; 45027ad20aa9SJames Smart goto job_error; 45037ad20aa9SJames Smart } 45047ad20aa9SJames Smart 45057ad20aa9SJames Smart /* wait for additoinal external buffers */ 450601e0e15cSJohannes Thumshirn bsg_reply->result = 0; 450706548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 45081abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 45097ad20aa9SJames Smart return SLI_CONFIG_HANDLED; 45107ad20aa9SJames Smart 45117ad20aa9SJames Smart job_error: 45127ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 45137ad20aa9SJames Smart kfree(dd_data); 45147ad20aa9SJames Smart 45157ad20aa9SJames Smart return rc; 45167ad20aa9SJames Smart } 45177ad20aa9SJames Smart 45187ad20aa9SJames Smart /** 45197ad20aa9SJames Smart * lpfc_bsg_handle_sli_cfg_ebuf - handle ext buffer with sli-cfg mailbox cmd 45207ad20aa9SJames Smart * @phba: Pointer to HBA context object. 45217ad20aa9SJames Smart * @mb: Pointer to a BSG mailbox object. 45227ad20aa9SJames Smart * @dmabuff: Pointer to a DMA buffer descriptor. 45237ad20aa9SJames Smart * 45247ad20aa9SJames Smart * This routine handles the external buffer with SLI_CONFIG (0x9B) mailbox 45257ad20aa9SJames Smart * command with multiple non-embedded external buffers. 45267ad20aa9SJames Smart **/ 45277ad20aa9SJames Smart static int 452875cc8cfcSJohannes Thumshirn lpfc_bsg_handle_sli_cfg_ebuf(struct lpfc_hba *phba, struct bsg_job *job, 45297ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 45307ad20aa9SJames Smart { 45317ad20aa9SJames Smart int rc; 45327ad20aa9SJames Smart 45337ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 45347ad20aa9SJames Smart "2971 SLI_CONFIG buffer (type:x%x)\n", 45357ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType); 45367ad20aa9SJames Smart 45377ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.mboxType == mbox_rd) { 45387ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state != LPFC_BSG_MBOX_DONE) { 45397ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 45407ad20aa9SJames Smart "2972 SLI_CONFIG rd buffer state " 45417ad20aa9SJames Smart "mismatch:x%x\n", 45427ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state); 45437ad20aa9SJames Smart lpfc_bsg_mbox_ext_abort(phba); 45447ad20aa9SJames Smart return -EPIPE; 45457ad20aa9SJames Smart } 45467ad20aa9SJames Smart rc = lpfc_bsg_read_ebuf_get(phba, job); 45477ad20aa9SJames Smart if (rc == SLI_CONFIG_HANDLED) 45487ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 45497ad20aa9SJames Smart } else { /* phba->mbox_ext_buf_ctx.mboxType == mbox_wr */ 45507ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state != LPFC_BSG_MBOX_HOST) { 45517ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 45527ad20aa9SJames Smart "2973 SLI_CONFIG wr buffer state " 45537ad20aa9SJames Smart "mismatch:x%x\n", 45547ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state); 45557ad20aa9SJames Smart lpfc_bsg_mbox_ext_abort(phba); 45567ad20aa9SJames Smart return -EPIPE; 45577ad20aa9SJames Smart } 45587ad20aa9SJames Smart rc = lpfc_bsg_write_ebuf_set(phba, job, dmabuf); 45597ad20aa9SJames Smart } 45607ad20aa9SJames Smart return rc; 45617ad20aa9SJames Smart } 45627ad20aa9SJames Smart 45637ad20aa9SJames Smart /** 45647ad20aa9SJames Smart * lpfc_bsg_handle_sli_cfg_ext - handle sli-cfg mailbox with external buffer 45657ad20aa9SJames Smart * @phba: Pointer to HBA context object. 45667ad20aa9SJames Smart * @mb: Pointer to a BSG mailbox object. 45677ad20aa9SJames Smart * @dmabuff: Pointer to a DMA buffer descriptor. 45687ad20aa9SJames Smart * 45697ad20aa9SJames Smart * This routine checkes and handles non-embedded multi-buffer SLI_CONFIG 45707ad20aa9SJames Smart * (0x9B) mailbox commands and external buffers. 45717ad20aa9SJames Smart **/ 45727ad20aa9SJames Smart static int 457375cc8cfcSJohannes Thumshirn lpfc_bsg_handle_sli_cfg_ext(struct lpfc_hba *phba, struct bsg_job *job, 45747ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 45757ad20aa9SJames Smart { 457601e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 45777ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 457888a2cfbbSJames Smart int rc = SLI_CONFIG_NOT_HANDLED; 45797ad20aa9SJames Smart 45807ad20aa9SJames Smart mbox_req = 458101e0e15cSJohannes Thumshirn (struct dfc_mbox_req *)bsg_request->rqst_data.h_vendor.vendor_cmd; 45827ad20aa9SJames Smart 45837ad20aa9SJames Smart /* mbox command with/without single external buffer */ 45847ad20aa9SJames Smart if (mbox_req->extMboxTag == 0 && mbox_req->extSeqNum == 0) 458588a2cfbbSJames Smart return rc; 45867ad20aa9SJames Smart 45877ad20aa9SJames Smart /* mbox command and first external buffer */ 45887ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_IDLE) { 45897ad20aa9SJames Smart if (mbox_req->extSeqNum == 1) { 45907ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 45917ad20aa9SJames Smart "2974 SLI_CONFIG mailbox: tag:%d, " 45927ad20aa9SJames Smart "seq:%d\n", mbox_req->extMboxTag, 45937ad20aa9SJames Smart mbox_req->extSeqNum); 45947ad20aa9SJames Smart rc = lpfc_bsg_handle_sli_cfg_mbox(phba, job, dmabuf); 45957ad20aa9SJames Smart return rc; 45967ad20aa9SJames Smart } else 45977ad20aa9SJames Smart goto sli_cfg_ext_error; 45987ad20aa9SJames Smart } 45997ad20aa9SJames Smart 46007ad20aa9SJames Smart /* 46017ad20aa9SJames Smart * handle additional external buffers 46027ad20aa9SJames Smart */ 46037ad20aa9SJames Smart 46047ad20aa9SJames Smart /* check broken pipe conditions */ 46057ad20aa9SJames Smart if (mbox_req->extMboxTag != phba->mbox_ext_buf_ctx.mbxTag) 46067ad20aa9SJames Smart goto sli_cfg_ext_error; 46077ad20aa9SJames Smart if (mbox_req->extSeqNum > phba->mbox_ext_buf_ctx.numBuf) 46087ad20aa9SJames Smart goto sli_cfg_ext_error; 46097ad20aa9SJames Smart if (mbox_req->extSeqNum != phba->mbox_ext_buf_ctx.seqNum + 1) 46107ad20aa9SJames Smart goto sli_cfg_ext_error; 46117ad20aa9SJames Smart 46127ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 46137ad20aa9SJames Smart "2975 SLI_CONFIG mailbox external buffer: " 46147ad20aa9SJames Smart "extSta:x%x, tag:%d, seq:%d\n", 46157ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state, mbox_req->extMboxTag, 46167ad20aa9SJames Smart mbox_req->extSeqNum); 46177ad20aa9SJames Smart rc = lpfc_bsg_handle_sli_cfg_ebuf(phba, job, dmabuf); 46187ad20aa9SJames Smart return rc; 46197ad20aa9SJames Smart 46207ad20aa9SJames Smart sli_cfg_ext_error: 46217ad20aa9SJames Smart /* all other cases, broken pipe */ 46227ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 46237ad20aa9SJames Smart "2976 SLI_CONFIG mailbox broken pipe: " 46247ad20aa9SJames Smart "ctxSta:x%x, ctxNumBuf:%d " 46257ad20aa9SJames Smart "ctxTag:%d, ctxSeq:%d, tag:%d, seq:%d\n", 46267ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state, 46277ad20aa9SJames Smart phba->mbox_ext_buf_ctx.numBuf, 46287ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbxTag, 46297ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum, 46307ad20aa9SJames Smart mbox_req->extMboxTag, mbox_req->extSeqNum); 46317ad20aa9SJames Smart 46327ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 46337ad20aa9SJames Smart 46347ad20aa9SJames Smart return -EPIPE; 46357ad20aa9SJames Smart } 46367ad20aa9SJames Smart 46377ad20aa9SJames Smart /** 46383b5dd52aSJames Smart * lpfc_bsg_issue_mbox - issues a mailbox command on behalf of an app 46393b5dd52aSJames Smart * @phba: Pointer to HBA context object. 46403b5dd52aSJames Smart * @mb: Pointer to a mailbox object. 46413b5dd52aSJames Smart * @vport: Pointer to a vport object. 46423b5dd52aSJames Smart * 46433b5dd52aSJames Smart * Allocate a tracking object, mailbox command memory, get a mailbox 46443b5dd52aSJames Smart * from the mailbox pool, copy the caller mailbox command. 46453b5dd52aSJames Smart * 46463b5dd52aSJames Smart * If offline and the sli is active we need to poll for the command (port is 46473b5dd52aSJames Smart * being reset) and com-plete the job, otherwise issue the mailbox command and 46483b5dd52aSJames Smart * let our completion handler finish the command. 46493b5dd52aSJames Smart **/ 4650a2fc4aefSJames Smart static int 465175cc8cfcSJohannes Thumshirn lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct bsg_job *job, 46523b5dd52aSJames Smart struct lpfc_vport *vport) 46533b5dd52aSJames Smart { 465401e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 465501e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 46567a470277SJames Smart LPFC_MBOXQ_t *pmboxq = NULL; /* internal mailbox queue */ 46577a470277SJames Smart MAILBOX_t *pmb; /* shortcut to the pmboxq mailbox */ 46587a470277SJames Smart /* a 4k buffer to hold the mb and extended data from/to the bsg */ 46597ad20aa9SJames Smart uint8_t *pmbx = NULL; 46607a470277SJames Smart struct bsg_job_data *dd_data = NULL; /* bsg data tracking structure */ 46617ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf = NULL; 46627ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 4663b6e3b9c6SJames Smart struct READ_EVENT_LOG_VAR *rdEventLog; 4664b6e3b9c6SJames Smart uint32_t transmit_length, receive_length, mode; 46657ad20aa9SJames Smart struct lpfc_mbx_sli4_config *sli4_config; 4666b6e3b9c6SJames Smart struct lpfc_mbx_nembed_cmd *nembed_sge; 4667b6e3b9c6SJames Smart struct ulp_bde64 *bde; 46687a470277SJames Smart uint8_t *ext = NULL; 46693b5dd52aSJames Smart int rc = 0; 46707a470277SJames Smart uint8_t *from; 46717ad20aa9SJames Smart uint32_t size; 46727ad20aa9SJames Smart 46737a470277SJames Smart /* in case no data is transferred */ 467401e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 46757a470277SJames Smart 4676b6e3b9c6SJames Smart /* sanity check to protect driver */ 4677b6e3b9c6SJames Smart if (job->reply_payload.payload_len > BSG_MBOX_SIZE || 4678b6e3b9c6SJames Smart job->request_payload.payload_len > BSG_MBOX_SIZE) { 4679b6e3b9c6SJames Smart rc = -ERANGE; 4680b6e3b9c6SJames Smart goto job_done; 4681b6e3b9c6SJames Smart } 4682b6e3b9c6SJames Smart 46837ad20aa9SJames Smart /* 46847ad20aa9SJames Smart * Don't allow mailbox commands to be sent when blocked or when in 46857ad20aa9SJames Smart * the middle of discovery 46867ad20aa9SJames Smart */ 46877ad20aa9SJames Smart if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { 46887ad20aa9SJames Smart rc = -EAGAIN; 46897ad20aa9SJames Smart goto job_done; 46907ad20aa9SJames Smart } 46917ad20aa9SJames Smart 46927ad20aa9SJames Smart mbox_req = 469301e0e15cSJohannes Thumshirn (struct dfc_mbox_req *)bsg_request->rqst_data.h_vendor.vendor_cmd; 46947ad20aa9SJames Smart 46957a470277SJames Smart /* check if requested extended data lengths are valid */ 4696b6e3b9c6SJames Smart if ((mbox_req->inExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t)) || 4697b6e3b9c6SJames Smart (mbox_req->outExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t))) { 46987a470277SJames Smart rc = -ERANGE; 46997a470277SJames Smart goto job_done; 47007a470277SJames Smart } 47013b5dd52aSJames Smart 47027ad20aa9SJames Smart dmabuf = lpfc_bsg_dma_page_alloc(phba); 47037ad20aa9SJames Smart if (!dmabuf || !dmabuf->virt) { 47047ad20aa9SJames Smart rc = -ENOMEM; 47057ad20aa9SJames Smart goto job_done; 47067ad20aa9SJames Smart } 47077ad20aa9SJames Smart 47087ad20aa9SJames Smart /* Get the mailbox command or external buffer from BSG */ 47097ad20aa9SJames Smart pmbx = (uint8_t *)dmabuf->virt; 47107ad20aa9SJames Smart size = job->request_payload.payload_len; 47117ad20aa9SJames Smart sg_copy_to_buffer(job->request_payload.sg_list, 47127ad20aa9SJames Smart job->request_payload.sg_cnt, pmbx, size); 47137ad20aa9SJames Smart 47147ad20aa9SJames Smart /* Handle possible SLI_CONFIG with non-embedded payloads */ 47157ad20aa9SJames Smart if (phba->sli_rev == LPFC_SLI_REV4) { 47167ad20aa9SJames Smart rc = lpfc_bsg_handle_sli_cfg_ext(phba, job, dmabuf); 47177ad20aa9SJames Smart if (rc == SLI_CONFIG_HANDLED) 47187ad20aa9SJames Smart goto job_cont; 47197ad20aa9SJames Smart if (rc) 47207ad20aa9SJames Smart goto job_done; 47217ad20aa9SJames Smart /* SLI_CONFIG_NOT_HANDLED for other mailbox commands */ 47227ad20aa9SJames Smart } 47237ad20aa9SJames Smart 47247ad20aa9SJames Smart rc = lpfc_bsg_check_cmd_access(phba, (MAILBOX_t *)pmbx, vport); 47257ad20aa9SJames Smart if (rc != 0) 47267ad20aa9SJames Smart goto job_done; /* must be negative */ 47277ad20aa9SJames Smart 47283b5dd52aSJames Smart /* allocate our bsg tracking structure */ 47293b5dd52aSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 47303b5dd52aSJames Smart if (!dd_data) { 47313b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 47323b5dd52aSJames Smart "2727 Failed allocation of dd_data\n"); 47337a470277SJames Smart rc = -ENOMEM; 47347a470277SJames Smart goto job_done; 47353b5dd52aSJames Smart } 47363b5dd52aSJames Smart 47373b5dd52aSJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 47383b5dd52aSJames Smart if (!pmboxq) { 47397a470277SJames Smart rc = -ENOMEM; 47407a470277SJames Smart goto job_done; 47413b5dd52aSJames Smart } 47427a470277SJames Smart memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 47433b5dd52aSJames Smart 47443b5dd52aSJames Smart pmb = &pmboxq->u.mb; 47457ad20aa9SJames Smart memcpy(pmb, pmbx, sizeof(*pmb)); 47463b5dd52aSJames Smart pmb->mbxOwner = OWN_HOST; 47473b5dd52aSJames Smart pmboxq->vport = vport; 47483b5dd52aSJames Smart 4749c7495937SJames Smart /* If HBA encountered an error attention, allow only DUMP 4750c7495937SJames Smart * or RESTART mailbox commands until the HBA is restarted. 4751c7495937SJames Smart */ 4752c7495937SJames Smart if (phba->pport->stopped && 4753c7495937SJames Smart pmb->mbxCommand != MBX_DUMP_MEMORY && 4754c7495937SJames Smart pmb->mbxCommand != MBX_RESTART && 4755c7495937SJames Smart pmb->mbxCommand != MBX_WRITE_VPARMS && 4756c7495937SJames Smart pmb->mbxCommand != MBX_WRITE_WWN) 4757c7495937SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, 4758c7495937SJames Smart "2797 mbox: Issued mailbox cmd " 4759c7495937SJames Smart "0x%x while in stopped state.\n", 4760c7495937SJames Smart pmb->mbxCommand); 4761c7495937SJames Smart 47627a470277SJames Smart /* extended mailbox commands will need an extended buffer */ 4763c7495937SJames Smart if (mbox_req->inExtWLen || mbox_req->outExtWLen) { 47647ad20aa9SJames Smart from = pmbx; 47657ad20aa9SJames Smart ext = from + sizeof(MAILBOX_t); 47667a470277SJames Smart pmboxq->context2 = ext; 47677a470277SJames Smart pmboxq->in_ext_byte_len = 47687a470277SJames Smart mbox_req->inExtWLen * sizeof(uint32_t); 47697a470277SJames Smart pmboxq->out_ext_byte_len = 4770c7495937SJames Smart mbox_req->outExtWLen * sizeof(uint32_t); 47717a470277SJames Smart pmboxq->mbox_offset_word = mbox_req->mbOffset; 47727a470277SJames Smart } 47737a470277SJames Smart 47747a470277SJames Smart /* biu diag will need a kernel buffer to transfer the data 47757a470277SJames Smart * allocate our own buffer and setup the mailbox command to 47767a470277SJames Smart * use ours 47777a470277SJames Smart */ 47787a470277SJames Smart if (pmb->mbxCommand == MBX_RUN_BIU_DIAG64) { 4779b6e3b9c6SJames Smart transmit_length = pmb->un.varWords[1]; 4780b6e3b9c6SJames Smart receive_length = pmb->un.varWords[4]; 4781c7495937SJames Smart /* transmit length cannot be greater than receive length or 4782c7495937SJames Smart * mailbox extension size 4783c7495937SJames Smart */ 4784c7495937SJames Smart if ((transmit_length > receive_length) || 478588a2cfbbSJames Smart (transmit_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t))) { 4786c7495937SJames Smart rc = -ERANGE; 4787c7495937SJames Smart goto job_done; 4788c7495937SJames Smart } 47897a470277SJames Smart pmb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh = 47907ad20aa9SJames Smart putPaddrHigh(dmabuf->phys + sizeof(MAILBOX_t)); 47917a470277SJames Smart pmb->un.varBIUdiag.un.s2.xmit_bde64.addrLow = 47927ad20aa9SJames Smart putPaddrLow(dmabuf->phys + sizeof(MAILBOX_t)); 47937a470277SJames Smart 47947a470277SJames Smart pmb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh = 47957ad20aa9SJames Smart putPaddrHigh(dmabuf->phys + sizeof(MAILBOX_t) 47967ad20aa9SJames Smart + pmb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize); 47977a470277SJames Smart pmb->un.varBIUdiag.un.s2.rcv_bde64.addrLow = 47987ad20aa9SJames Smart putPaddrLow(dmabuf->phys + sizeof(MAILBOX_t) 47997ad20aa9SJames Smart + pmb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize); 4800c7495937SJames Smart } else if (pmb->mbxCommand == MBX_READ_EVENT_LOG) { 4801b6e3b9c6SJames Smart rdEventLog = &pmb->un.varRdEventLog; 4802b6e3b9c6SJames Smart receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize; 4803b6e3b9c6SJames Smart mode = bf_get(lpfc_event_log, rdEventLog); 4804c7495937SJames Smart 4805c7495937SJames Smart /* receive length cannot be greater than mailbox 4806c7495937SJames Smart * extension size 4807c7495937SJames Smart */ 480888a2cfbbSJames Smart if (receive_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t)) { 4809c7495937SJames Smart rc = -ERANGE; 4810c7495937SJames Smart goto job_done; 4811c7495937SJames Smart } 4812c7495937SJames Smart 4813c7495937SJames Smart /* mode zero uses a bde like biu diags command */ 4814c7495937SJames Smart if (mode == 0) { 48157ad20aa9SJames Smart pmb->un.varWords[3] = putPaddrLow(dmabuf->phys 48167ad20aa9SJames Smart + sizeof(MAILBOX_t)); 48177ad20aa9SJames Smart pmb->un.varWords[4] = putPaddrHigh(dmabuf->phys 48187ad20aa9SJames Smart + sizeof(MAILBOX_t)); 4819c7495937SJames Smart } 4820c7495937SJames Smart } else if (phba->sli_rev == LPFC_SLI_REV4) { 48213ef6d24cSJames Smart /* Let type 4 (well known data) through because the data is 48223ef6d24cSJames Smart * returned in varwords[4-8] 48233ef6d24cSJames Smart * otherwise check the recieve length and fetch the buffer addr 48243ef6d24cSJames Smart */ 48253ef6d24cSJames Smart if ((pmb->mbxCommand == MBX_DUMP_MEMORY) && 48263ef6d24cSJames Smart (pmb->un.varDmp.type != DMP_WELL_KNOWN)) { 4827c7495937SJames Smart /* rebuild the command for sli4 using our own buffers 4828c7495937SJames Smart * like we do for biu diags 4829c7495937SJames Smart */ 4830b6e3b9c6SJames Smart receive_length = pmb->un.varWords[2]; 4831c7495937SJames Smart /* receive length cannot be greater than mailbox 4832c7495937SJames Smart * extension size 4833c7495937SJames Smart */ 48347ad20aa9SJames Smart if (receive_length == 0) { 4835c7495937SJames Smart rc = -ERANGE; 4836c7495937SJames Smart goto job_done; 4837c7495937SJames Smart } 48387ad20aa9SJames Smart pmb->un.varWords[3] = putPaddrLow(dmabuf->phys 48397ad20aa9SJames Smart + sizeof(MAILBOX_t)); 48407ad20aa9SJames Smart pmb->un.varWords[4] = putPaddrHigh(dmabuf->phys 48417ad20aa9SJames Smart + sizeof(MAILBOX_t)); 4842c7495937SJames Smart } else if ((pmb->mbxCommand == MBX_UPDATE_CFG) && 4843c7495937SJames Smart pmb->un.varUpdateCfg.co) { 4844b6e3b9c6SJames Smart bde = (struct ulp_bde64 *)&pmb->un.varWords[4]; 4845c7495937SJames Smart 4846c7495937SJames Smart /* bde size cannot be greater than mailbox ext size */ 484788a2cfbbSJames Smart if (bde->tus.f.bdeSize > 484888a2cfbbSJames Smart BSG_MBOX_SIZE - sizeof(MAILBOX_t)) { 4849c7495937SJames Smart rc = -ERANGE; 4850c7495937SJames Smart goto job_done; 4851c7495937SJames Smart } 48527ad20aa9SJames Smart bde->addrHigh = putPaddrHigh(dmabuf->phys 48537ad20aa9SJames Smart + sizeof(MAILBOX_t)); 48547ad20aa9SJames Smart bde->addrLow = putPaddrLow(dmabuf->phys 48557ad20aa9SJames Smart + sizeof(MAILBOX_t)); 4856515e0aa2SJames Smart } else if (pmb->mbxCommand == MBX_SLI4_CONFIG) { 48577ad20aa9SJames Smart /* Handling non-embedded SLI_CONFIG mailbox command */ 48587ad20aa9SJames Smart sli4_config = &pmboxq->u.mqe.un.sli4_config; 48597ad20aa9SJames Smart if (!bf_get(lpfc_mbox_hdr_emb, 48607ad20aa9SJames Smart &sli4_config->header.cfg_mhdr)) { 48617ad20aa9SJames Smart /* rebuild the command for sli4 using our 48627ad20aa9SJames Smart * own buffers like we do for biu diags 4863515e0aa2SJames Smart */ 4864515e0aa2SJames Smart nembed_sge = (struct lpfc_mbx_nembed_cmd *) 4865515e0aa2SJames Smart &pmb->un.varWords[0]; 4866515e0aa2SJames Smart receive_length = nembed_sge->sge[0].length; 4867515e0aa2SJames Smart 48687ad20aa9SJames Smart /* receive length cannot be greater than 48697ad20aa9SJames Smart * mailbox extension size 4870515e0aa2SJames Smart */ 4871515e0aa2SJames Smart if ((receive_length == 0) || 487288a2cfbbSJames Smart (receive_length > 487388a2cfbbSJames Smart BSG_MBOX_SIZE - sizeof(MAILBOX_t))) { 4874515e0aa2SJames Smart rc = -ERANGE; 4875515e0aa2SJames Smart goto job_done; 4876515e0aa2SJames Smart } 4877515e0aa2SJames Smart 48787ad20aa9SJames Smart nembed_sge->sge[0].pa_hi = 48797ad20aa9SJames Smart putPaddrHigh(dmabuf->phys 48807ad20aa9SJames Smart + sizeof(MAILBOX_t)); 48817ad20aa9SJames Smart nembed_sge->sge[0].pa_lo = 48827ad20aa9SJames Smart putPaddrLow(dmabuf->phys 48837ad20aa9SJames Smart + sizeof(MAILBOX_t)); 4884515e0aa2SJames Smart } 4885c7495937SJames Smart } 4886c7495937SJames Smart } 4887c7495937SJames Smart 48887ad20aa9SJames Smart dd_data->context_un.mbox.dmabuffers = dmabuf; 48893b5dd52aSJames Smart 48903b5dd52aSJames Smart /* setup wake call as IOCB callback */ 48917ad20aa9SJames Smart pmboxq->mbox_cmpl = lpfc_bsg_issue_mbox_cmpl; 48927a470277SJames Smart 48933b5dd52aSJames Smart /* setup context field to pass wait_queue pointer to wake function */ 48943b5dd52aSJames Smart pmboxq->context1 = dd_data; 48953b5dd52aSJames Smart dd_data->type = TYPE_MBOX; 4896a33c4f7bSJames Smart dd_data->set_job = job; 48973b5dd52aSJames Smart dd_data->context_un.mbox.pmboxq = pmboxq; 48987ad20aa9SJames Smart dd_data->context_un.mbox.mb = (MAILBOX_t *)pmbx; 48997a470277SJames Smart dd_data->context_un.mbox.ext = ext; 49007a470277SJames Smart dd_data->context_un.mbox.mbOffset = mbox_req->mbOffset; 49017a470277SJames Smart dd_data->context_un.mbox.inExtWLen = mbox_req->inExtWLen; 4902c7495937SJames Smart dd_data->context_un.mbox.outExtWLen = mbox_req->outExtWLen; 49033b5dd52aSJames Smart job->dd_data = dd_data; 49047a470277SJames Smart 49057a470277SJames Smart if ((vport->fc_flag & FC_OFFLINE_MODE) || 49067a470277SJames Smart (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { 49077a470277SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); 49087a470277SJames Smart if (rc != MBX_SUCCESS) { 49097a470277SJames Smart rc = (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; 49107a470277SJames Smart goto job_done; 49113b5dd52aSJames Smart } 49123b5dd52aSJames Smart 49137a470277SJames Smart /* job finished, copy the data */ 49147ad20aa9SJames Smart memcpy(pmbx, pmb, sizeof(*pmb)); 491501e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 49167a470277SJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 49177a470277SJames Smart job->reply_payload.sg_cnt, 49187ad20aa9SJames Smart pmbx, size); 49197a470277SJames Smart /* not waiting mbox already done */ 49207a470277SJames Smart rc = 0; 49217a470277SJames Smart goto job_done; 49227a470277SJames Smart } 49237a470277SJames Smart 49247a470277SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); 49257a470277SJames Smart if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) 49267a470277SJames Smart return 1; /* job started */ 49277a470277SJames Smart 49287a470277SJames Smart job_done: 49297a470277SJames Smart /* common exit for error or job completed inline */ 49307a470277SJames Smart if (pmboxq) 49317a470277SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 49327ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 49337a470277SJames Smart kfree(dd_data); 49347a470277SJames Smart 49357ad20aa9SJames Smart job_cont: 49367a470277SJames Smart return rc; 49373b5dd52aSJames Smart } 49383b5dd52aSJames Smart 49393b5dd52aSJames Smart /** 49403b5dd52aSJames Smart * lpfc_bsg_mbox_cmd - process an fc bsg LPFC_BSG_VENDOR_MBOX command 49413b5dd52aSJames Smart * @job: MBOX fc_bsg_job for LPFC_BSG_VENDOR_MBOX. 49423b5dd52aSJames Smart **/ 49433b5dd52aSJames Smart static int 494475cc8cfcSJohannes Thumshirn lpfc_bsg_mbox_cmd(struct bsg_job *job) 49453b5dd52aSJames Smart { 4946cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 494701e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 494801e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 49493b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 49507ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 49513b5dd52aSJames Smart int rc = 0; 49523b5dd52aSJames Smart 49537ad20aa9SJames Smart /* mix-and-match backward compatibility */ 495401e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 49553b5dd52aSJames Smart if (job->request_len < 49563b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct dfc_mbox_req)) { 49577ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 49581051e9b3SMasanari Iida "2737 Mix-and-match backward compatibility " 49597ad20aa9SJames Smart "between MBOX_REQ old size:%d and " 49607ad20aa9SJames Smart "new request size:%d\n", 49617ad20aa9SJames Smart (int)(job->request_len - 49627ad20aa9SJames Smart sizeof(struct fc_bsg_request)), 49637ad20aa9SJames Smart (int)sizeof(struct dfc_mbox_req)); 49647ad20aa9SJames Smart mbox_req = (struct dfc_mbox_req *) 496501e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 49667ad20aa9SJames Smart mbox_req->extMboxTag = 0; 49677ad20aa9SJames Smart mbox_req->extSeqNum = 0; 49683b5dd52aSJames Smart } 49693b5dd52aSJames Smart 49703b5dd52aSJames Smart rc = lpfc_bsg_issue_mbox(phba, job, vport); 49713b5dd52aSJames Smart 49723b5dd52aSJames Smart if (rc == 0) { 49733b5dd52aSJames Smart /* job done */ 497401e0e15cSJohannes Thumshirn bsg_reply->result = 0; 49753b5dd52aSJames Smart job->dd_data = NULL; 497606548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 49771abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 49783b5dd52aSJames Smart } else if (rc == 1) 49793b5dd52aSJames Smart /* job submitted, will complete later*/ 49803b5dd52aSJames Smart rc = 0; /* return zero, no error */ 49813b5dd52aSJames Smart else { 49823b5dd52aSJames Smart /* some error occurred */ 498301e0e15cSJohannes Thumshirn bsg_reply->result = rc; 49843b5dd52aSJames Smart job->dd_data = NULL; 49853b5dd52aSJames Smart } 49863b5dd52aSJames Smart 49873b5dd52aSJames Smart return rc; 49883b5dd52aSJames Smart } 49893b5dd52aSJames Smart 49903b5dd52aSJames Smart /** 4991e2aed29fSJames Smart * lpfc_bsg_menlo_cmd_cmp - lpfc_menlo_cmd completion handler 4992e2aed29fSJames Smart * @phba: Pointer to HBA context object. 4993e2aed29fSJames Smart * @cmdiocbq: Pointer to command iocb. 4994e2aed29fSJames Smart * @rspiocbq: Pointer to response iocb. 4995e2aed29fSJames Smart * 4996e2aed29fSJames Smart * This function is the completion handler for iocbs issued using 4997e2aed29fSJames Smart * lpfc_menlo_cmd function. This function is called by the 4998e2aed29fSJames Smart * ring event handler function without any lock held. This function 4999e2aed29fSJames Smart * can be called from both worker thread context and interrupt 5000e2aed29fSJames Smart * context. This function also can be called from another thread which 5001e2aed29fSJames Smart * cleans up the SLI layer objects. 5002e2aed29fSJames Smart * This function copies the contents of the response iocb to the 5003e2aed29fSJames Smart * response iocb memory object provided by the caller of 5004e2aed29fSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 5005e2aed29fSJames Smart * sleeps for the iocb completion. 5006e2aed29fSJames Smart **/ 5007e2aed29fSJames Smart static void 5008e2aed29fSJames Smart lpfc_bsg_menlo_cmd_cmp(struct lpfc_hba *phba, 5009e2aed29fSJames Smart struct lpfc_iocbq *cmdiocbq, 5010e2aed29fSJames Smart struct lpfc_iocbq *rspiocbq) 5011e2aed29fSJames Smart { 5012e2aed29fSJames Smart struct bsg_job_data *dd_data; 501375cc8cfcSJohannes Thumshirn struct bsg_job *job; 501401e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 5015e2aed29fSJames Smart IOCB_t *rsp; 5016a33c4f7bSJames Smart struct lpfc_dmabuf *bmp, *cmp, *rmp; 5017e2aed29fSJames Smart struct lpfc_bsg_menlo *menlo; 5018e2aed29fSJames Smart unsigned long flags; 5019e2aed29fSJames Smart struct menlo_response *menlo_resp; 5020a33c4f7bSJames Smart unsigned int rsp_size; 5021e2aed29fSJames Smart int rc = 0; 5022e2aed29fSJames Smart 5023e2aed29fSJames Smart dd_data = cmdiocbq->context1; 5024a33c4f7bSJames Smart cmp = cmdiocbq->context2; 5025a33c4f7bSJames Smart bmp = cmdiocbq->context3; 5026e2aed29fSJames Smart menlo = &dd_data->context_un.menlo; 5027a33c4f7bSJames Smart rmp = menlo->rmp; 5028e2aed29fSJames Smart rsp = &rspiocbq->iocb; 5029e2aed29fSJames Smart 5030a33c4f7bSJames Smart /* Determine if job has been aborted */ 5031a33c4f7bSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 5032a33c4f7bSJames Smart job = dd_data->set_job; 5033a33c4f7bSJames Smart if (job) { 503401e0e15cSJohannes Thumshirn bsg_reply = job->reply; 5035a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 5036a33c4f7bSJames Smart job->dd_data = NULL; 5037a33c4f7bSJames Smart } 5038a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 5039e2aed29fSJames Smart 5040a33c4f7bSJames Smart /* Copy the job data or set the failing status for the job */ 5041a33c4f7bSJames Smart 5042a33c4f7bSJames Smart if (job) { 5043e2aed29fSJames Smart /* always return the xri, this would be used in the case 5044a33c4f7bSJames Smart * of a menlo download to allow the data to be sent as a 5045a33c4f7bSJames Smart * continuation of the exchange. 5046e2aed29fSJames Smart */ 5047a33c4f7bSJames Smart 5048e2aed29fSJames Smart menlo_resp = (struct menlo_response *) 504901e0e15cSJohannes Thumshirn bsg_reply->reply_data.vendor_reply.vendor_rsp; 5050e2aed29fSJames Smart menlo_resp->xri = rsp->ulpContext; 5051e2aed29fSJames Smart if (rsp->ulpStatus) { 5052e2aed29fSJames Smart if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { 5053e3d2b802SJames Smart switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) { 5054e2aed29fSJames Smart case IOERR_SEQUENCE_TIMEOUT: 5055e2aed29fSJames Smart rc = -ETIMEDOUT; 5056e2aed29fSJames Smart break; 5057e2aed29fSJames Smart case IOERR_INVALID_RPI: 5058e2aed29fSJames Smart rc = -EFAULT; 5059e2aed29fSJames Smart break; 5060e2aed29fSJames Smart default: 5061e2aed29fSJames Smart rc = -EACCES; 5062e2aed29fSJames Smart break; 5063e2aed29fSJames Smart } 5064a33c4f7bSJames Smart } else { 5065e2aed29fSJames Smart rc = -EACCES; 5066a33c4f7bSJames Smart } 5067a33c4f7bSJames Smart } else { 5068a33c4f7bSJames Smart rsp_size = rsp->un.genreq64.bdl.bdeSize; 506901e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 5070a33c4f7bSJames Smart lpfc_bsg_copy_data(rmp, &job->reply_payload, 5071a33c4f7bSJames Smart rsp_size, 0); 5072a33c4f7bSJames Smart } 5073e2aed29fSJames Smart 5074a33c4f7bSJames Smart } 5075a33c4f7bSJames Smart 5076e2aed29fSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 5077a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 5078a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, rmp); 5079a33c4f7bSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 5080e2aed29fSJames Smart kfree(bmp); 5081e2aed29fSJames Smart kfree(dd_data); 5082a33c4f7bSJames Smart 5083a33c4f7bSJames Smart /* Complete the job if active */ 5084a33c4f7bSJames Smart 5085a33c4f7bSJames Smart if (job) { 508601e0e15cSJohannes Thumshirn bsg_reply->result = rc; 508706548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 50881abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 5089a33c4f7bSJames Smart } 5090a33c4f7bSJames Smart 5091e2aed29fSJames Smart return; 5092e2aed29fSJames Smart } 5093e2aed29fSJames Smart 5094e2aed29fSJames Smart /** 5095e2aed29fSJames Smart * lpfc_menlo_cmd - send an ioctl for menlo hardware 5096e2aed29fSJames Smart * @job: fc_bsg_job to handle 5097e2aed29fSJames Smart * 5098e2aed29fSJames Smart * This function issues a gen request 64 CR ioctl for all menlo cmd requests, 5099e2aed29fSJames Smart * all the command completions will return the xri for the command. 5100e2aed29fSJames Smart * For menlo data requests a gen request 64 CX is used to continue the exchange 5101e2aed29fSJames Smart * supplied in the menlo request header xri field. 5102e2aed29fSJames Smart **/ 5103e2aed29fSJames Smart static int 510475cc8cfcSJohannes Thumshirn lpfc_menlo_cmd(struct bsg_job *job) 5105e2aed29fSJames Smart { 5106cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 510701e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 510801e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 5109e2aed29fSJames Smart struct lpfc_hba *phba = vport->phba; 5110a33c4f7bSJames Smart struct lpfc_iocbq *cmdiocbq; 5111a33c4f7bSJames Smart IOCB_t *cmd; 5112e2aed29fSJames Smart int rc = 0; 5113e2aed29fSJames Smart struct menlo_command *menlo_cmd; 5114a33c4f7bSJames Smart struct lpfc_dmabuf *bmp = NULL, *cmp = NULL, *rmp = NULL; 5115e2aed29fSJames Smart int request_nseg; 5116e2aed29fSJames Smart int reply_nseg; 5117e2aed29fSJames Smart struct bsg_job_data *dd_data; 5118e2aed29fSJames Smart struct ulp_bde64 *bpl = NULL; 5119e2aed29fSJames Smart 5120e2aed29fSJames Smart /* in case no data is returned return just the return code */ 512101e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 5122e2aed29fSJames Smart 5123e2aed29fSJames Smart if (job->request_len < 5124e2aed29fSJames Smart sizeof(struct fc_bsg_request) + 5125e2aed29fSJames Smart sizeof(struct menlo_command)) { 5126e2aed29fSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 5127e2aed29fSJames Smart "2784 Received MENLO_CMD request below " 5128e2aed29fSJames Smart "minimum size\n"); 5129e2aed29fSJames Smart rc = -ERANGE; 5130e2aed29fSJames Smart goto no_dd_data; 5131e2aed29fSJames Smart } 5132e2aed29fSJames Smart 5133e2aed29fSJames Smart if (job->reply_len < 5134e2aed29fSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct menlo_response)) { 5135e2aed29fSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 5136e2aed29fSJames Smart "2785 Received MENLO_CMD reply below " 5137e2aed29fSJames Smart "minimum size\n"); 5138e2aed29fSJames Smart rc = -ERANGE; 5139e2aed29fSJames Smart goto no_dd_data; 5140e2aed29fSJames Smart } 5141e2aed29fSJames Smart 5142e2aed29fSJames Smart if (!(phba->menlo_flag & HBA_MENLO_SUPPORT)) { 5143e2aed29fSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 5144e2aed29fSJames Smart "2786 Adapter does not support menlo " 5145e2aed29fSJames Smart "commands\n"); 5146e2aed29fSJames Smart rc = -EPERM; 5147e2aed29fSJames Smart goto no_dd_data; 5148e2aed29fSJames Smart } 5149e2aed29fSJames Smart 5150e2aed29fSJames Smart menlo_cmd = (struct menlo_command *) 515101e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 5152e2aed29fSJames Smart 5153e2aed29fSJames Smart /* allocate our bsg tracking structure */ 5154e2aed29fSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 5155e2aed29fSJames Smart if (!dd_data) { 5156e2aed29fSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 5157e2aed29fSJames Smart "2787 Failed allocation of dd_data\n"); 5158e2aed29fSJames Smart rc = -ENOMEM; 5159e2aed29fSJames Smart goto no_dd_data; 5160e2aed29fSJames Smart } 5161e2aed29fSJames Smart 5162e2aed29fSJames Smart bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 5163e2aed29fSJames Smart if (!bmp) { 5164e2aed29fSJames Smart rc = -ENOMEM; 5165e2aed29fSJames Smart goto free_dd; 5166e2aed29fSJames Smart } 5167e2aed29fSJames Smart 5168a33c4f7bSJames Smart bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); 5169a33c4f7bSJames Smart if (!bmp->virt) { 5170e2aed29fSJames Smart rc = -ENOMEM; 5171e2aed29fSJames Smart goto free_bmp; 5172e2aed29fSJames Smart } 5173e2aed29fSJames Smart 5174e2aed29fSJames Smart INIT_LIST_HEAD(&bmp->list); 5175a33c4f7bSJames Smart 5176e2aed29fSJames Smart bpl = (struct ulp_bde64 *)bmp->virt; 5177a33c4f7bSJames Smart request_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64); 5178a33c4f7bSJames Smart cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len, 5179a33c4f7bSJames Smart 1, bpl, &request_nseg); 5180a33c4f7bSJames Smart if (!cmp) { 5181a33c4f7bSJames Smart rc = -ENOMEM; 5182a33c4f7bSJames Smart goto free_bmp; 5183a33c4f7bSJames Smart } 5184a33c4f7bSJames Smart lpfc_bsg_copy_data(cmp, &job->request_payload, 5185a33c4f7bSJames Smart job->request_payload.payload_len, 1); 5186a33c4f7bSJames Smart 5187a33c4f7bSJames Smart bpl += request_nseg; 5188a33c4f7bSJames Smart reply_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64) - request_nseg; 5189a33c4f7bSJames Smart rmp = lpfc_alloc_bsg_buffers(phba, job->reply_payload.payload_len, 0, 5190a33c4f7bSJames Smart bpl, &reply_nseg); 5191a33c4f7bSJames Smart if (!rmp) { 5192a33c4f7bSJames Smart rc = -ENOMEM; 5193a33c4f7bSJames Smart goto free_cmp; 5194e2aed29fSJames Smart } 5195e2aed29fSJames Smart 5196a33c4f7bSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 5197a33c4f7bSJames Smart if (!cmdiocbq) { 5198a33c4f7bSJames Smart rc = -ENOMEM; 5199a33c4f7bSJames Smart goto free_rmp; 5200e2aed29fSJames Smart } 5201e2aed29fSJames Smart 5202e2aed29fSJames Smart cmd = &cmdiocbq->iocb; 5203e2aed29fSJames Smart cmd->un.genreq64.bdl.ulpIoTag32 = 0; 5204e2aed29fSJames Smart cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); 5205e2aed29fSJames Smart cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); 5206e2aed29fSJames Smart cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 5207e2aed29fSJames Smart cmd->un.genreq64.bdl.bdeSize = 5208e2aed29fSJames Smart (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); 5209e2aed29fSJames Smart cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); 5210e2aed29fSJames Smart cmd->un.genreq64.w5.hcsw.Dfctl = 0; 5211e2aed29fSJames Smart cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CMD; 5212e2aed29fSJames Smart cmd->un.genreq64.w5.hcsw.Type = MENLO_TRANSPORT_TYPE; /* 0xfe */ 5213e2aed29fSJames Smart cmd->ulpBdeCount = 1; 5214e2aed29fSJames Smart cmd->ulpClass = CLASS3; 5215e2aed29fSJames Smart cmd->ulpOwner = OWN_CHIP; 5216e2aed29fSJames Smart cmd->ulpLe = 1; /* Limited Edition */ 5217e2aed29fSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 5218e2aed29fSJames Smart cmdiocbq->vport = phba->pport; 5219e2aed29fSJames Smart /* We want the firmware to timeout before we do */ 5220e2aed29fSJames Smart cmd->ulpTimeout = MENLO_TIMEOUT - 5; 5221e2aed29fSJames Smart cmdiocbq->iocb_cmpl = lpfc_bsg_menlo_cmd_cmp; 5222e2aed29fSJames Smart cmdiocbq->context1 = dd_data; 5223a33c4f7bSJames Smart cmdiocbq->context2 = cmp; 5224a33c4f7bSJames Smart cmdiocbq->context3 = bmp; 5225e2aed29fSJames Smart if (menlo_cmd->cmd == LPFC_BSG_VENDOR_MENLO_CMD) { 5226e2aed29fSJames Smart cmd->ulpCommand = CMD_GEN_REQUEST64_CR; 5227e2aed29fSJames Smart cmd->ulpPU = MENLO_PU; /* 3 */ 5228e2aed29fSJames Smart cmd->un.ulpWord[4] = MENLO_DID; /* 0x0000FC0E */ 5229e2aed29fSJames Smart cmd->ulpContext = MENLO_CONTEXT; /* 0 */ 5230e2aed29fSJames Smart } else { 5231e2aed29fSJames Smart cmd->ulpCommand = CMD_GEN_REQUEST64_CX; 5232e2aed29fSJames Smart cmd->ulpPU = 1; 5233e2aed29fSJames Smart cmd->un.ulpWord[4] = 0; 5234e2aed29fSJames Smart cmd->ulpContext = menlo_cmd->xri; 5235e2aed29fSJames Smart } 5236e2aed29fSJames Smart 5237e2aed29fSJames Smart dd_data->type = TYPE_MENLO; 5238a33c4f7bSJames Smart dd_data->set_job = job; 5239e2aed29fSJames Smart dd_data->context_un.menlo.cmdiocbq = cmdiocbq; 5240a33c4f7bSJames Smart dd_data->context_un.menlo.rmp = rmp; 5241a33c4f7bSJames Smart job->dd_data = dd_data; 5242e2aed29fSJames Smart 5243e2aed29fSJames Smart rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 5244e2aed29fSJames Smart MENLO_TIMEOUT - 5); 5245e2aed29fSJames Smart if (rc == IOCB_SUCCESS) 5246e2aed29fSJames Smart return 0; /* done for now */ 5247e2aed29fSJames Smart 5248e2aed29fSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 5249a33c4f7bSJames Smart 5250a33c4f7bSJames Smart free_rmp: 5251a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, rmp); 5252a33c4f7bSJames Smart free_cmp: 5253a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 5254e2aed29fSJames Smart free_bmp: 5255a33c4f7bSJames Smart if (bmp->virt) 5256a33c4f7bSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 5257e2aed29fSJames Smart kfree(bmp); 5258e2aed29fSJames Smart free_dd: 5259e2aed29fSJames Smart kfree(dd_data); 5260e2aed29fSJames Smart no_dd_data: 5261e2aed29fSJames Smart /* make error code available to userspace */ 526201e0e15cSJohannes Thumshirn bsg_reply->result = rc; 5263e2aed29fSJames Smart job->dd_data = NULL; 5264e2aed29fSJames Smart return rc; 5265e2aed29fSJames Smart } 5266b6e3b9c6SJames Smart 5267c691816eSJames Smart static int 526875cc8cfcSJohannes Thumshirn lpfc_forced_link_speed(struct bsg_job *job) 5269c691816eSJames Smart { 5270cd21c605SJohannes Thumshirn struct Scsi_Host *shost = fc_bsg_to_shost(job); 5271c691816eSJames Smart struct lpfc_vport *vport = shost_priv(shost); 5272c691816eSJames Smart struct lpfc_hba *phba = vport->phba; 527301e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 5274c691816eSJames Smart struct forced_link_speed_support_reply *forced_reply; 5275c691816eSJames Smart int rc = 0; 5276c691816eSJames Smart 5277c691816eSJames Smart if (job->request_len < 5278c691816eSJames Smart sizeof(struct fc_bsg_request) + 5279c691816eSJames Smart sizeof(struct get_forced_link_speed_support)) { 5280c691816eSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 5281c691816eSJames Smart "0048 Received FORCED_LINK_SPEED request " 5282c691816eSJames Smart "below minimum size\n"); 5283c691816eSJames Smart rc = -EINVAL; 5284c691816eSJames Smart goto job_error; 5285c691816eSJames Smart } 5286c691816eSJames Smart 5287c691816eSJames Smart forced_reply = (struct forced_link_speed_support_reply *) 528801e0e15cSJohannes Thumshirn bsg_reply->reply_data.vendor_reply.vendor_rsp; 5289c691816eSJames Smart 5290c691816eSJames Smart if (job->reply_len < 5291c691816eSJames Smart sizeof(struct fc_bsg_request) + 5292c691816eSJames Smart sizeof(struct forced_link_speed_support_reply)) { 5293c691816eSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 5294c691816eSJames Smart "0049 Received FORCED_LINK_SPEED reply below " 5295c691816eSJames Smart "minimum size\n"); 5296c691816eSJames Smart rc = -EINVAL; 5297c691816eSJames Smart goto job_error; 5298c691816eSJames Smart } 5299c691816eSJames Smart 5300c691816eSJames Smart forced_reply->supported = (phba->hba_flag & HBA_FORCED_LINK_SPEED) 5301c691816eSJames Smart ? LPFC_FORCED_LINK_SPEED_SUPPORTED 5302c691816eSJames Smart : LPFC_FORCED_LINK_SPEED_NOT_SUPPORTED; 5303c691816eSJames Smart job_error: 530401e0e15cSJohannes Thumshirn bsg_reply->result = rc; 5305c691816eSJames Smart if (rc == 0) 530606548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 53071abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 5308c691816eSJames Smart return rc; 5309c691816eSJames Smart } 5310c691816eSJames Smart 5311e2aed29fSJames Smart /** 5312f1c3b0fcSJames Smart * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job 5313f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 53143b5dd52aSJames Smart **/ 5315f1c3b0fcSJames Smart static int 531675cc8cfcSJohannes Thumshirn lpfc_bsg_hst_vendor(struct bsg_job *job) 5317f1c3b0fcSJames Smart { 531801e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 531901e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 532001e0e15cSJohannes Thumshirn int command = bsg_request->rqst_data.h_vendor.vendor_cmd[0]; 53214cc0e56eSJames Smart int rc; 5322f1c3b0fcSJames Smart 5323f1c3b0fcSJames Smart switch (command) { 5324f1c3b0fcSJames Smart case LPFC_BSG_VENDOR_SET_CT_EVENT: 53254cc0e56eSJames Smart rc = lpfc_bsg_hba_set_event(job); 5326f1c3b0fcSJames Smart break; 5327f1c3b0fcSJames Smart case LPFC_BSG_VENDOR_GET_CT_EVENT: 53284cc0e56eSJames Smart rc = lpfc_bsg_hba_get_event(job); 5329f1c3b0fcSJames Smart break; 53303b5dd52aSJames Smart case LPFC_BSG_VENDOR_SEND_MGMT_RESP: 53313b5dd52aSJames Smart rc = lpfc_bsg_send_mgmt_rsp(job); 53323b5dd52aSJames Smart break; 53333b5dd52aSJames Smart case LPFC_BSG_VENDOR_DIAG_MODE: 53347ad20aa9SJames Smart rc = lpfc_bsg_diag_loopback_mode(job); 53353b5dd52aSJames Smart break; 53367ad20aa9SJames Smart case LPFC_BSG_VENDOR_DIAG_MODE_END: 53377ad20aa9SJames Smart rc = lpfc_sli4_bsg_diag_mode_end(job); 53387ad20aa9SJames Smart break; 53397ad20aa9SJames Smart case LPFC_BSG_VENDOR_DIAG_RUN_LOOPBACK: 53407ad20aa9SJames Smart rc = lpfc_bsg_diag_loopback_run(job); 53417ad20aa9SJames Smart break; 53427ad20aa9SJames Smart case LPFC_BSG_VENDOR_LINK_DIAG_TEST: 53437ad20aa9SJames Smart rc = lpfc_sli4_bsg_link_diag_test(job); 53443b5dd52aSJames Smart break; 53453b5dd52aSJames Smart case LPFC_BSG_VENDOR_GET_MGMT_REV: 53463b5dd52aSJames Smart rc = lpfc_bsg_get_dfc_rev(job); 53473b5dd52aSJames Smart break; 53483b5dd52aSJames Smart case LPFC_BSG_VENDOR_MBOX: 53493b5dd52aSJames Smart rc = lpfc_bsg_mbox_cmd(job); 53503b5dd52aSJames Smart break; 5351e2aed29fSJames Smart case LPFC_BSG_VENDOR_MENLO_CMD: 5352e2aed29fSJames Smart case LPFC_BSG_VENDOR_MENLO_DATA: 5353e2aed29fSJames Smart rc = lpfc_menlo_cmd(job); 5354e2aed29fSJames Smart break; 5355c691816eSJames Smart case LPFC_BSG_VENDOR_FORCED_LINK_SPEED: 5356c691816eSJames Smart rc = lpfc_forced_link_speed(job); 5357c691816eSJames Smart break; 5358f1c3b0fcSJames Smart default: 53594cc0e56eSJames Smart rc = -EINVAL; 536001e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 53614cc0e56eSJames Smart /* make error code available to userspace */ 536201e0e15cSJohannes Thumshirn bsg_reply->result = rc; 53634cc0e56eSJames Smart break; 5364f1c3b0fcSJames Smart } 53654cc0e56eSJames Smart 53664cc0e56eSJames Smart return rc; 5367f1c3b0fcSJames Smart } 5368f1c3b0fcSJames Smart 5369f1c3b0fcSJames Smart /** 5370f1c3b0fcSJames Smart * lpfc_bsg_request - handle a bsg request from the FC transport 5371f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 53723b5dd52aSJames Smart **/ 5373f1c3b0fcSJames Smart int 537475cc8cfcSJohannes Thumshirn lpfc_bsg_request(struct bsg_job *job) 5375f1c3b0fcSJames Smart { 537601e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 537701e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 5378f1c3b0fcSJames Smart uint32_t msgcode; 53794cc0e56eSJames Smart int rc; 5380f1c3b0fcSJames Smart 538101e0e15cSJohannes Thumshirn msgcode = bsg_request->msgcode; 5382f1c3b0fcSJames Smart switch (msgcode) { 5383f1c3b0fcSJames Smart case FC_BSG_HST_VENDOR: 5384f1c3b0fcSJames Smart rc = lpfc_bsg_hst_vendor(job); 5385f1c3b0fcSJames Smart break; 5386f1c3b0fcSJames Smart case FC_BSG_RPT_ELS: 5387f1c3b0fcSJames Smart rc = lpfc_bsg_rport_els(job); 5388f1c3b0fcSJames Smart break; 5389f1c3b0fcSJames Smart case FC_BSG_RPT_CT: 53904cc0e56eSJames Smart rc = lpfc_bsg_send_mgmt_cmd(job); 5391f1c3b0fcSJames Smart break; 5392f1c3b0fcSJames Smart default: 53934cc0e56eSJames Smart rc = -EINVAL; 539401e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 53954cc0e56eSJames Smart /* make error code available to userspace */ 539601e0e15cSJohannes Thumshirn bsg_reply->result = rc; 5397f1c3b0fcSJames Smart break; 5398f1c3b0fcSJames Smart } 5399f1c3b0fcSJames Smart 5400f1c3b0fcSJames Smart return rc; 5401f1c3b0fcSJames Smart } 5402f1c3b0fcSJames Smart 5403f1c3b0fcSJames Smart /** 5404f1c3b0fcSJames Smart * lpfc_bsg_timeout - handle timeout of a bsg request from the FC transport 5405f1c3b0fcSJames Smart * @job: fc_bsg_job that has timed out 5406f1c3b0fcSJames Smart * 5407f1c3b0fcSJames Smart * This function just aborts the job's IOCB. The aborted IOCB will return to 5408f1c3b0fcSJames Smart * the waiting function which will handle passing the error back to userspace 54093b5dd52aSJames Smart **/ 5410f1c3b0fcSJames Smart int 541175cc8cfcSJohannes Thumshirn lpfc_bsg_timeout(struct bsg_job *job) 5412f1c3b0fcSJames Smart { 5413cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 5414f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 54154cc0e56eSJames Smart struct lpfc_iocbq *cmdiocb; 5416895427bdSJames Smart struct lpfc_sli_ring *pring; 54174cc0e56eSJames Smart struct bsg_job_data *dd_data; 54184cc0e56eSJames Smart unsigned long flags; 5419a33c4f7bSJames Smart int rc = 0; 5420a33c4f7bSJames Smart LIST_HEAD(completions); 5421a33c4f7bSJames Smart struct lpfc_iocbq *check_iocb, *next_iocb; 5422a33c4f7bSJames Smart 5423895427bdSJames Smart pring = lpfc_phba_elsring(phba); 5424*1234a6d5SDick Kennedy if (unlikely(!pring)) 5425*1234a6d5SDick Kennedy return -EIO; 5426895427bdSJames Smart 5427a33c4f7bSJames Smart /* if job's driver data is NULL, the command completed or is in the 5428a33c4f7bSJames Smart * the process of completing. In this case, return status to request 5429a33c4f7bSJames Smart * so the timeout is retried. This avoids double completion issues 5430a33c4f7bSJames Smart * and the request will be pulled off the timer queue when the 5431a33c4f7bSJames Smart * command's completion handler executes. Otherwise, prevent the 5432a33c4f7bSJames Smart * command's completion handler from executing the job done callback 5433a33c4f7bSJames Smart * and continue processing to abort the outstanding the command. 5434a33c4f7bSJames Smart */ 5435f1c3b0fcSJames Smart 54364cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 54374cc0e56eSJames Smart dd_data = (struct bsg_job_data *)job->dd_data; 5438a33c4f7bSJames Smart if (dd_data) { 5439a33c4f7bSJames Smart dd_data->set_job = NULL; 5440a33c4f7bSJames Smart job->dd_data = NULL; 5441a33c4f7bSJames Smart } else { 54424cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 5443a33c4f7bSJames Smart return -EAGAIN; 54444cc0e56eSJames Smart } 54454cc0e56eSJames Smart 54464cc0e56eSJames Smart switch (dd_data->type) { 54474cc0e56eSJames Smart case TYPE_IOCB: 5448a33c4f7bSJames Smart /* Check to see if IOCB was issued to the port or not. If not, 5449a33c4f7bSJames Smart * remove it from the txq queue and call cancel iocbs. 5450a33c4f7bSJames Smart * Otherwise, call abort iotag 5451a33c4f7bSJames Smart */ 5452a33c4f7bSJames Smart cmdiocb = dd_data->context_un.iocb.cmdiocbq; 5453b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 5454b5a9b2dfSJames Smart 5455b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 5456b5a9b2dfSJames Smart /* make sure the I/O abort window is still open */ 54571b8d11abSJames Smart if (!(cmdiocb->iocb_flag & LPFC_IO_CMD_OUTSTANDING)) { 5458b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 5459b5a9b2dfSJames Smart return -EAGAIN; 5460b5a9b2dfSJames Smart } 5461a33c4f7bSJames Smart list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq, 5462a33c4f7bSJames Smart list) { 5463a33c4f7bSJames Smart if (check_iocb == cmdiocb) { 5464a33c4f7bSJames Smart list_move_tail(&check_iocb->list, &completions); 5465a33c4f7bSJames Smart break; 5466a33c4f7bSJames Smart } 5467a33c4f7bSJames Smart } 5468a33c4f7bSJames Smart if (list_empty(&completions)) 5469f1c3b0fcSJames Smart lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); 5470b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 5471a33c4f7bSJames Smart if (!list_empty(&completions)) { 5472a33c4f7bSJames Smart lpfc_sli_cancel_iocbs(phba, &completions, 5473a33c4f7bSJames Smart IOSTAT_LOCAL_REJECT, 5474a33c4f7bSJames Smart IOERR_SLI_ABORTED); 5475a33c4f7bSJames Smart } 54764cc0e56eSJames Smart break; 5477a33c4f7bSJames Smart 54784cc0e56eSJames Smart case TYPE_EVT: 54794cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 54804cc0e56eSJames Smart break; 5481a33c4f7bSJames Smart 54823b5dd52aSJames Smart case TYPE_MBOX: 5483a33c4f7bSJames Smart /* Update the ext buf ctx state if needed */ 5484a33c4f7bSJames Smart 54857ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_PORT) 54867ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_ABTS; 5487a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 54883b5dd52aSJames Smart break; 5489e2aed29fSJames Smart case TYPE_MENLO: 5490a33c4f7bSJames Smart /* Check to see if IOCB was issued to the port or not. If not, 5491a33c4f7bSJames Smart * remove it from the txq queue and call cancel iocbs. 5492a33c4f7bSJames Smart * Otherwise, call abort iotag. 5493a33c4f7bSJames Smart */ 5494a33c4f7bSJames Smart cmdiocb = dd_data->context_un.menlo.cmdiocbq; 5495b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 5496b5a9b2dfSJames Smart 5497b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 5498a33c4f7bSJames Smart list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq, 5499a33c4f7bSJames Smart list) { 5500a33c4f7bSJames Smart if (check_iocb == cmdiocb) { 5501a33c4f7bSJames Smart list_move_tail(&check_iocb->list, &completions); 5502a33c4f7bSJames Smart break; 5503a33c4f7bSJames Smart } 5504a33c4f7bSJames Smart } 5505a33c4f7bSJames Smart if (list_empty(&completions)) 5506e2aed29fSJames Smart lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); 5507b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 5508a33c4f7bSJames Smart if (!list_empty(&completions)) { 5509a33c4f7bSJames Smart lpfc_sli_cancel_iocbs(phba, &completions, 5510a33c4f7bSJames Smart IOSTAT_LOCAL_REJECT, 5511a33c4f7bSJames Smart IOERR_SLI_ABORTED); 5512a33c4f7bSJames Smart } 5513e2aed29fSJames Smart break; 55144cc0e56eSJames Smart default: 55154cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 55164cc0e56eSJames Smart break; 55174cc0e56eSJames Smart } 5518f1c3b0fcSJames Smart 55194cc0e56eSJames Smart /* scsi transport fc fc_bsg_job_timeout expects a zero return code, 55204cc0e56eSJames Smart * otherwise an error message will be displayed on the console 55214cc0e56eSJames Smart * so always return success (zero) 55224cc0e56eSJames Smart */ 5523a33c4f7bSJames Smart return rc; 5524f1c3b0fcSJames Smart } 5525