1f1c3b0fcSJames Smart /******************************************************************* 2f1c3b0fcSJames Smart * This file is part of the Emulex Linux Device Driver for * 3f1c3b0fcSJames Smart * Fibre Channel Host Bus Adapters. * 4983f761cSJames Smart * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term * 54ae2ebdeSJames Smart * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * 6f25e8e79SJames Smart * Copyright (C) 2009-2015 Emulex. All rights reserved. * 7f1c3b0fcSJames Smart * EMULEX and SLI are trademarks of Emulex. * 8d080abe0SJames Smart * www.broadcom.com * 9f1c3b0fcSJames Smart * * 10f1c3b0fcSJames Smart * This program is free software; you can redistribute it and/or * 11f1c3b0fcSJames Smart * modify it under the terms of version 2 of the GNU General * 12f1c3b0fcSJames Smart * Public License as published by the Free Software Foundation. * 13f1c3b0fcSJames Smart * This program is distributed in the hope that it will be useful. * 14f1c3b0fcSJames Smart * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * 15f1c3b0fcSJames Smart * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * 16f1c3b0fcSJames Smart * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * 17f1c3b0fcSJames Smart * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * 18f1c3b0fcSJames Smart * TO BE LEGALLY INVALID. See the GNU General Public License for * 19f1c3b0fcSJames Smart * more details, a copy of which can be found in the file COPYING * 20f1c3b0fcSJames Smart * included with this package. * 21f1c3b0fcSJames Smart *******************************************************************/ 22f1c3b0fcSJames Smart 23f1c3b0fcSJames Smart #include <linux/interrupt.h> 24f1c3b0fcSJames Smart #include <linux/mempool.h> 25f1c3b0fcSJames Smart #include <linux/pci.h> 265a0e3ad6STejun Heo #include <linux/slab.h> 27277e76f1SJames Smart #include <linux/delay.h> 287ad20aa9SJames Smart #include <linux/list.h> 29eb340948SJohannes Thumshirn #include <linux/bsg-lib.h> 30d2cc9bcdSJames Smart #include <linux/vmalloc.h> 31f1c3b0fcSJames Smart 32f1c3b0fcSJames Smart #include <scsi/scsi.h> 33f1c3b0fcSJames Smart #include <scsi/scsi_host.h> 34f1c3b0fcSJames Smart #include <scsi/scsi_transport_fc.h> 35f1c3b0fcSJames Smart #include <scsi/scsi_bsg_fc.h> 366a9c52cfSJames Smart #include <scsi/fc/fc_fs.h> 37f1c3b0fcSJames Smart 38f1c3b0fcSJames Smart #include "lpfc_hw4.h" 39f1c3b0fcSJames Smart #include "lpfc_hw.h" 40f1c3b0fcSJames Smart #include "lpfc_sli.h" 41f1c3b0fcSJames Smart #include "lpfc_sli4.h" 42f1c3b0fcSJames Smart #include "lpfc_nl.h" 434fede78fSJames Smart #include "lpfc_bsg.h" 44f1c3b0fcSJames Smart #include "lpfc_disc.h" 45f1c3b0fcSJames Smart #include "lpfc_scsi.h" 46f1c3b0fcSJames Smart #include "lpfc.h" 47f1c3b0fcSJames Smart #include "lpfc_logmsg.h" 48f1c3b0fcSJames Smart #include "lpfc_crtn.h" 49b76f2dc9SJames Smart #include "lpfc_debugfs.h" 50f1c3b0fcSJames Smart #include "lpfc_vport.h" 51f1c3b0fcSJames Smart #include "lpfc_version.h" 52f1c3b0fcSJames Smart 534cc0e56eSJames Smart struct lpfc_bsg_event { 544cc0e56eSJames Smart struct list_head node; 554cc0e56eSJames Smart struct kref kref; 564cc0e56eSJames Smart wait_queue_head_t wq; 574cc0e56eSJames Smart 584cc0e56eSJames Smart /* Event type and waiter identifiers */ 594cc0e56eSJames Smart uint32_t type_mask; 604cc0e56eSJames Smart uint32_t req_id; 614cc0e56eSJames Smart uint32_t reg_id; 624cc0e56eSJames Smart 634cc0e56eSJames Smart /* next two flags are here for the auto-delete logic */ 644cc0e56eSJames Smart unsigned long wait_time_stamp; 654cc0e56eSJames Smart int waiting; 664cc0e56eSJames Smart 674cc0e56eSJames Smart /* seen and not seen events */ 684cc0e56eSJames Smart struct list_head events_to_get; 694cc0e56eSJames Smart struct list_head events_to_see; 704cc0e56eSJames Smart 71a33c4f7bSJames Smart /* driver data associated with the job */ 72a33c4f7bSJames Smart void *dd_data; 734cc0e56eSJames Smart }; 744cc0e56eSJames Smart 754cc0e56eSJames Smart struct lpfc_bsg_iocb { 764cc0e56eSJames Smart struct lpfc_iocbq *cmdiocbq; 77a33c4f7bSJames Smart struct lpfc_dmabuf *rmp; 784cc0e56eSJames Smart struct lpfc_nodelist *ndlp; 794cc0e56eSJames Smart }; 804cc0e56eSJames Smart 813b5dd52aSJames Smart struct lpfc_bsg_mbox { 823b5dd52aSJames Smart LPFC_MBOXQ_t *pmboxq; 833b5dd52aSJames Smart MAILBOX_t *mb; 847ad20aa9SJames Smart struct lpfc_dmabuf *dmabuffers; /* for BIU diags */ 857a470277SJames Smart uint8_t *ext; /* extended mailbox data */ 867a470277SJames Smart uint32_t mbOffset; /* from app */ 877a470277SJames Smart uint32_t inExtWLen; /* from app */ 88c7495937SJames Smart uint32_t outExtWLen; /* from app */ 893b5dd52aSJames Smart }; 903b5dd52aSJames Smart 91e2aed29fSJames Smart #define MENLO_DID 0x0000FC0E 92e2aed29fSJames Smart 93e2aed29fSJames Smart struct lpfc_bsg_menlo { 94e2aed29fSJames Smart struct lpfc_iocbq *cmdiocbq; 95a33c4f7bSJames Smart struct lpfc_dmabuf *rmp; 96e2aed29fSJames Smart }; 97e2aed29fSJames Smart 984cc0e56eSJames Smart #define TYPE_EVT 1 994cc0e56eSJames Smart #define TYPE_IOCB 2 1003b5dd52aSJames Smart #define TYPE_MBOX 3 101e2aed29fSJames Smart #define TYPE_MENLO 4 1024cc0e56eSJames Smart struct bsg_job_data { 1034cc0e56eSJames Smart uint32_t type; 10475cc8cfcSJohannes Thumshirn struct bsg_job *set_job; /* job waiting for this iocb to finish */ 1054cc0e56eSJames Smart union { 1064cc0e56eSJames Smart struct lpfc_bsg_event *evt; 1074cc0e56eSJames Smart struct lpfc_bsg_iocb iocb; 1083b5dd52aSJames Smart struct lpfc_bsg_mbox mbox; 109e2aed29fSJames Smart struct lpfc_bsg_menlo menlo; 1104cc0e56eSJames Smart } context_un; 1114cc0e56eSJames Smart }; 1124cc0e56eSJames Smart 1134cc0e56eSJames Smart struct event_data { 1144cc0e56eSJames Smart struct list_head node; 1154cc0e56eSJames Smart uint32_t type; 1164cc0e56eSJames Smart uint32_t immed_dat; 1174cc0e56eSJames Smart void *data; 1184cc0e56eSJames Smart uint32_t len; 1194cc0e56eSJames Smart }; 1204cc0e56eSJames Smart 1213b5dd52aSJames Smart #define BUF_SZ_4K 4096 1224cc0e56eSJames Smart #define SLI_CT_ELX_LOOPBACK 0x10 1234cc0e56eSJames Smart 1244cc0e56eSJames Smart enum ELX_LOOPBACK_CMD { 1254cc0e56eSJames Smart ELX_LOOPBACK_XRI_SETUP, 1264cc0e56eSJames Smart ELX_LOOPBACK_DATA, 1274cc0e56eSJames Smart }; 1284cc0e56eSJames Smart 1293b5dd52aSJames Smart #define ELX_LOOPBACK_HEADER_SZ \ 1303b5dd52aSJames Smart (size_t)(&((struct lpfc_sli_ct_request *)NULL)->un) 1313b5dd52aSJames Smart 1324cc0e56eSJames Smart struct lpfc_dmabufext { 1334cc0e56eSJames Smart struct lpfc_dmabuf dma; 1344cc0e56eSJames Smart uint32_t size; 1354cc0e56eSJames Smart uint32_t flag; 1364cc0e56eSJames Smart }; 1374cc0e56eSJames Smart 138a33c4f7bSJames Smart static void 139a33c4f7bSJames Smart lpfc_free_bsg_buffers(struct lpfc_hba *phba, struct lpfc_dmabuf *mlist) 140a33c4f7bSJames Smart { 141a33c4f7bSJames Smart struct lpfc_dmabuf *mlast, *next_mlast; 142a33c4f7bSJames Smart 143a33c4f7bSJames Smart if (mlist) { 144a33c4f7bSJames Smart list_for_each_entry_safe(mlast, next_mlast, &mlist->list, 145a33c4f7bSJames Smart list) { 146a33c4f7bSJames Smart lpfc_mbuf_free(phba, mlast->virt, mlast->phys); 147a33c4f7bSJames Smart list_del(&mlast->list); 148a33c4f7bSJames Smart kfree(mlast); 149a33c4f7bSJames Smart } 150a33c4f7bSJames Smart lpfc_mbuf_free(phba, mlist->virt, mlist->phys); 151a33c4f7bSJames Smart kfree(mlist); 152a33c4f7bSJames Smart } 153a33c4f7bSJames Smart return; 154a33c4f7bSJames Smart } 155a33c4f7bSJames Smart 156a33c4f7bSJames Smart static struct lpfc_dmabuf * 157a33c4f7bSJames Smart lpfc_alloc_bsg_buffers(struct lpfc_hba *phba, unsigned int size, 158a33c4f7bSJames Smart int outbound_buffers, struct ulp_bde64 *bpl, 159a33c4f7bSJames Smart int *bpl_entries) 160a33c4f7bSJames Smart { 161a33c4f7bSJames Smart struct lpfc_dmabuf *mlist = NULL; 162a33c4f7bSJames Smart struct lpfc_dmabuf *mp; 163a33c4f7bSJames Smart unsigned int bytes_left = size; 164a33c4f7bSJames Smart 165a33c4f7bSJames Smart /* Verify we can support the size specified */ 166a33c4f7bSJames Smart if (!size || (size > (*bpl_entries * LPFC_BPL_SIZE))) 167a33c4f7bSJames Smart return NULL; 168a33c4f7bSJames Smart 169a33c4f7bSJames Smart /* Determine the number of dma buffers to allocate */ 170a33c4f7bSJames Smart *bpl_entries = (size % LPFC_BPL_SIZE ? size/LPFC_BPL_SIZE + 1 : 171a33c4f7bSJames Smart size/LPFC_BPL_SIZE); 172a33c4f7bSJames Smart 173a33c4f7bSJames Smart /* Allocate dma buffer and place in BPL passed */ 174a33c4f7bSJames Smart while (bytes_left) { 175a33c4f7bSJames Smart /* Allocate dma buffer */ 176a33c4f7bSJames Smart mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 177a33c4f7bSJames Smart if (!mp) { 178a33c4f7bSJames Smart if (mlist) 179a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, mlist); 180a33c4f7bSJames Smart return NULL; 181a33c4f7bSJames Smart } 182a33c4f7bSJames Smart 183a33c4f7bSJames Smart INIT_LIST_HEAD(&mp->list); 184a33c4f7bSJames Smart mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys)); 185a33c4f7bSJames Smart 186a33c4f7bSJames Smart if (!mp->virt) { 187a33c4f7bSJames Smart kfree(mp); 188a33c4f7bSJames Smart if (mlist) 189a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, mlist); 190a33c4f7bSJames Smart return NULL; 191a33c4f7bSJames Smart } 192a33c4f7bSJames Smart 193a33c4f7bSJames Smart /* Queue it to a linked list */ 194a33c4f7bSJames Smart if (!mlist) 195a33c4f7bSJames Smart mlist = mp; 196a33c4f7bSJames Smart else 197a33c4f7bSJames Smart list_add_tail(&mp->list, &mlist->list); 198a33c4f7bSJames Smart 199a33c4f7bSJames Smart /* Add buffer to buffer pointer list */ 200a33c4f7bSJames Smart if (outbound_buffers) 201a33c4f7bSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; 202a33c4f7bSJames Smart else 203a33c4f7bSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; 204a33c4f7bSJames Smart bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys)); 205a33c4f7bSJames Smart bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys)); 206a33c4f7bSJames Smart bpl->tus.f.bdeSize = (uint16_t) 207a33c4f7bSJames Smart (bytes_left >= LPFC_BPL_SIZE ? LPFC_BPL_SIZE : 208a33c4f7bSJames Smart bytes_left); 209a33c4f7bSJames Smart bytes_left -= bpl->tus.f.bdeSize; 210a33c4f7bSJames Smart bpl->tus.w = le32_to_cpu(bpl->tus.w); 211a33c4f7bSJames Smart bpl++; 212a33c4f7bSJames Smart } 213a33c4f7bSJames Smart return mlist; 214a33c4f7bSJames Smart } 215a33c4f7bSJames Smart 216a33c4f7bSJames Smart static unsigned int 217a33c4f7bSJames Smart lpfc_bsg_copy_data(struct lpfc_dmabuf *dma_buffers, 218eb340948SJohannes Thumshirn struct bsg_buffer *bsg_buffers, 219a33c4f7bSJames Smart unsigned int bytes_to_transfer, int to_buffers) 220a33c4f7bSJames Smart { 221a33c4f7bSJames Smart 222a33c4f7bSJames Smart struct lpfc_dmabuf *mp; 223a33c4f7bSJames Smart unsigned int transfer_bytes, bytes_copied = 0; 224a33c4f7bSJames Smart unsigned int sg_offset, dma_offset; 225a33c4f7bSJames Smart unsigned char *dma_address, *sg_address; 226a33c4f7bSJames Smart LIST_HEAD(temp_list); 227d5ce53b7SJames Smart struct sg_mapping_iter miter; 228d5ce53b7SJames Smart unsigned long flags; 229d5ce53b7SJames Smart unsigned int sg_flags = SG_MITER_ATOMIC; 230d5ce53b7SJames Smart bool sg_valid; 231a33c4f7bSJames Smart 232a33c4f7bSJames Smart list_splice_init(&dma_buffers->list, &temp_list); 233a33c4f7bSJames Smart list_add(&dma_buffers->list, &temp_list); 234a33c4f7bSJames Smart sg_offset = 0; 235d5ce53b7SJames Smart if (to_buffers) 236d5ce53b7SJames Smart sg_flags |= SG_MITER_FROM_SG; 237d5ce53b7SJames Smart else 238d5ce53b7SJames Smart sg_flags |= SG_MITER_TO_SG; 239d5ce53b7SJames Smart sg_miter_start(&miter, bsg_buffers->sg_list, bsg_buffers->sg_cnt, 240d5ce53b7SJames Smart sg_flags); 241d5ce53b7SJames Smart local_irq_save(flags); 242d5ce53b7SJames Smart sg_valid = sg_miter_next(&miter); 243a33c4f7bSJames Smart list_for_each_entry(mp, &temp_list, list) { 244a33c4f7bSJames Smart dma_offset = 0; 245d5ce53b7SJames Smart while (bytes_to_transfer && sg_valid && 246a33c4f7bSJames Smart (dma_offset < LPFC_BPL_SIZE)) { 247a33c4f7bSJames Smart dma_address = mp->virt + dma_offset; 248a33c4f7bSJames Smart if (sg_offset) { 249a33c4f7bSJames Smart /* Continue previous partial transfer of sg */ 250d5ce53b7SJames Smart sg_address = miter.addr + sg_offset; 251d5ce53b7SJames Smart transfer_bytes = miter.length - sg_offset; 252a33c4f7bSJames Smart } else { 253d5ce53b7SJames Smart sg_address = miter.addr; 254d5ce53b7SJames Smart transfer_bytes = miter.length; 255a33c4f7bSJames Smart } 256a33c4f7bSJames Smart if (bytes_to_transfer < transfer_bytes) 257a33c4f7bSJames Smart transfer_bytes = bytes_to_transfer; 258a33c4f7bSJames Smart if (transfer_bytes > (LPFC_BPL_SIZE - dma_offset)) 259a33c4f7bSJames Smart transfer_bytes = LPFC_BPL_SIZE - dma_offset; 260a33c4f7bSJames Smart if (to_buffers) 261a33c4f7bSJames Smart memcpy(dma_address, sg_address, transfer_bytes); 262a33c4f7bSJames Smart else 263a33c4f7bSJames Smart memcpy(sg_address, dma_address, transfer_bytes); 264a33c4f7bSJames Smart dma_offset += transfer_bytes; 265a33c4f7bSJames Smart sg_offset += transfer_bytes; 266a33c4f7bSJames Smart bytes_to_transfer -= transfer_bytes; 267a33c4f7bSJames Smart bytes_copied += transfer_bytes; 268d5ce53b7SJames Smart if (sg_offset >= miter.length) { 269a33c4f7bSJames Smart sg_offset = 0; 270d5ce53b7SJames Smart sg_valid = sg_miter_next(&miter); 271a33c4f7bSJames Smart } 272a33c4f7bSJames Smart } 273a33c4f7bSJames Smart } 274d5ce53b7SJames Smart sg_miter_stop(&miter); 275d5ce53b7SJames Smart local_irq_restore(flags); 276a33c4f7bSJames Smart list_del_init(&dma_buffers->list); 277a33c4f7bSJames Smart list_splice(&temp_list, &dma_buffers->list); 278a33c4f7bSJames Smart return bytes_copied; 279a33c4f7bSJames Smart } 280a33c4f7bSJames Smart 281f1c3b0fcSJames Smart /** 2824cc0e56eSJames Smart * lpfc_bsg_send_mgmt_cmd_cmp - lpfc_bsg_send_mgmt_cmd's completion handler 2834cc0e56eSJames Smart * @phba: Pointer to HBA context object. 2844cc0e56eSJames Smart * @cmdiocbq: Pointer to command iocb. 2854cc0e56eSJames Smart * @rspiocbq: Pointer to response iocb. 2864cc0e56eSJames Smart * 2874cc0e56eSJames Smart * This function is the completion handler for iocbs issued using 2884cc0e56eSJames Smart * lpfc_bsg_send_mgmt_cmd function. This function is called by the 2894cc0e56eSJames Smart * ring event handler function without any lock held. This function 2904cc0e56eSJames Smart * can be called from both worker thread context and interrupt 2914cc0e56eSJames Smart * context. This function also can be called from another thread which 2924cc0e56eSJames Smart * cleans up the SLI layer objects. 2934cc0e56eSJames Smart * This function copies the contents of the response iocb to the 2944cc0e56eSJames Smart * response iocb memory object provided by the caller of 2954cc0e56eSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 2964cc0e56eSJames Smart * sleeps for the iocb completion. 2974cc0e56eSJames Smart **/ 2984cc0e56eSJames Smart static void 2994cc0e56eSJames Smart lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, 3004cc0e56eSJames Smart struct lpfc_iocbq *cmdiocbq, 3014cc0e56eSJames Smart struct lpfc_iocbq *rspiocbq) 3024cc0e56eSJames Smart { 3034cc0e56eSJames Smart struct bsg_job_data *dd_data; 30475cc8cfcSJohannes Thumshirn struct bsg_job *job; 30501e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 3064cc0e56eSJames Smart IOCB_t *rsp; 307a33c4f7bSJames Smart struct lpfc_dmabuf *bmp, *cmp, *rmp; 3084cc0e56eSJames Smart struct lpfc_nodelist *ndlp; 3094cc0e56eSJames Smart struct lpfc_bsg_iocb *iocb; 3104cc0e56eSJames Smart unsigned long flags; 311a33c4f7bSJames Smart unsigned int rsp_size; 3124cc0e56eSJames Smart int rc = 0; 3134cc0e56eSJames Smart 314a33c4f7bSJames Smart dd_data = cmdiocbq->context1; 315a33c4f7bSJames Smart 316a33c4f7bSJames Smart /* Determine if job has been aborted */ 3174cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 318a33c4f7bSJames Smart job = dd_data->set_job; 319a33c4f7bSJames Smart if (job) { 32001e0e15cSJohannes Thumshirn bsg_reply = job->reply; 321a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 322a33c4f7bSJames Smart job->dd_data = NULL; 3234cc0e56eSJames Smart } 324a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 3254cc0e56eSJames Smart 326b5a9b2dfSJames Smart /* Close the timeout handler abort window */ 327b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 3281b8d11abSJames Smart cmdiocbq->iocb_flag &= ~LPFC_IO_CMD_OUTSTANDING; 329b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 330b5a9b2dfSJames Smart 3314cc0e56eSJames Smart iocb = &dd_data->context_un.iocb; 3324430f7fdSJames Smart ndlp = iocb->cmdiocbq->context_un.ndlp; 333a33c4f7bSJames Smart rmp = iocb->rmp; 334a33c4f7bSJames Smart cmp = cmdiocbq->context2; 335a33c4f7bSJames Smart bmp = cmdiocbq->context3; 3364cc0e56eSJames Smart rsp = &rspiocbq->iocb; 3374cc0e56eSJames Smart 338a33c4f7bSJames Smart /* Copy the completed data or set the error status */ 3394cc0e56eSJames Smart 340a33c4f7bSJames Smart if (job) { 3414cc0e56eSJames Smart if (rsp->ulpStatus) { 3424cc0e56eSJames Smart if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { 343e3d2b802SJames Smart switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) { 3444cc0e56eSJames Smart case IOERR_SEQUENCE_TIMEOUT: 3454cc0e56eSJames Smart rc = -ETIMEDOUT; 3464cc0e56eSJames Smart break; 3474cc0e56eSJames Smart case IOERR_INVALID_RPI: 3484cc0e56eSJames Smart rc = -EFAULT; 3494cc0e56eSJames Smart break; 3504cc0e56eSJames Smart default: 3514cc0e56eSJames Smart rc = -EACCES; 3524cc0e56eSJames Smart break; 3534cc0e56eSJames Smart } 354a33c4f7bSJames Smart } else { 3554cc0e56eSJames Smart rc = -EACCES; 356a33c4f7bSJames Smart } 357a33c4f7bSJames Smart } else { 358a33c4f7bSJames Smart rsp_size = rsp->un.genreq64.bdl.bdeSize; 35901e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 360a33c4f7bSJames Smart lpfc_bsg_copy_data(rmp, &job->reply_payload, 361a33c4f7bSJames Smart rsp_size, 0); 362a33c4f7bSJames Smart } 363a33c4f7bSJames Smart } 3644cc0e56eSJames Smart 365a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 366a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, rmp); 3674cc0e56eSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 368a33c4f7bSJames Smart kfree(bmp); 3694cc0e56eSJames Smart lpfc_nlp_put(ndlp); 3704430f7fdSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 3714cc0e56eSJames Smart kfree(dd_data); 372a33c4f7bSJames Smart 373a33c4f7bSJames Smart /* Complete the job if the job is still active */ 374a33c4f7bSJames Smart 375a33c4f7bSJames Smart if (job) { 37601e0e15cSJohannes Thumshirn bsg_reply->result = rc; 37706548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 3781abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 379a33c4f7bSJames Smart } 3804cc0e56eSJames Smart return; 3814cc0e56eSJames Smart } 3824cc0e56eSJames Smart 3834cc0e56eSJames Smart /** 3844cc0e56eSJames Smart * lpfc_bsg_send_mgmt_cmd - send a CT command from a bsg request 385f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 3863b5dd52aSJames Smart **/ 387f1c3b0fcSJames Smart static int 38875cc8cfcSJohannes Thumshirn lpfc_bsg_send_mgmt_cmd(struct bsg_job *job) 389f1c3b0fcSJames Smart { 390cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 391f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 3921d69b122SJohannes Thumshirn struct lpfc_rport_data *rdata = fc_bsg_to_rport(job)->dd_data; 393f1c3b0fcSJames Smart struct lpfc_nodelist *ndlp = rdata->pnode; 39401e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 395f1c3b0fcSJames Smart struct ulp_bde64 *bpl = NULL; 396f1c3b0fcSJames Smart uint32_t timeout; 397f1c3b0fcSJames Smart struct lpfc_iocbq *cmdiocbq = NULL; 398f1c3b0fcSJames Smart IOCB_t *cmd; 399a33c4f7bSJames Smart struct lpfc_dmabuf *bmp = NULL, *cmp = NULL, *rmp = NULL; 400f1c3b0fcSJames Smart int request_nseg; 401f1c3b0fcSJames Smart int reply_nseg; 4024cc0e56eSJames Smart struct bsg_job_data *dd_data; 403b5a9b2dfSJames Smart unsigned long flags; 4044cc0e56eSJames Smart uint32_t creg_val; 405f1c3b0fcSJames Smart int rc = 0; 406d439d286SJames Smart int iocb_stat; 407f1c3b0fcSJames Smart 408f1c3b0fcSJames Smart /* in case no data is transferred */ 40901e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 410f1c3b0fcSJames Smart 4114430f7fdSJames Smart if (ndlp->nlp_flag & NLP_ELS_SND_MASK) 4124430f7fdSJames Smart return -ENODEV; 4134430f7fdSJames Smart 4144cc0e56eSJames Smart /* allocate our bsg tracking structure */ 4154cc0e56eSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 4164cc0e56eSJames Smart if (!dd_data) { 4174cc0e56eSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 4184cc0e56eSJames Smart "2733 Failed allocation of dd_data\n"); 4194cc0e56eSJames Smart rc = -ENOMEM; 4204cc0e56eSJames Smart goto no_dd_data; 4214cc0e56eSJames Smart } 4224cc0e56eSJames Smart 423f1c3b0fcSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 424f1c3b0fcSJames Smart if (!cmdiocbq) { 425f1c3b0fcSJames Smart rc = -ENOMEM; 4264430f7fdSJames Smart goto free_dd; 427f1c3b0fcSJames Smart } 428f1c3b0fcSJames Smart 4294cc0e56eSJames Smart cmd = &cmdiocbq->iocb; 430a33c4f7bSJames Smart 431a33c4f7bSJames Smart bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 432a33c4f7bSJames Smart if (!bmp) { 433f1c3b0fcSJames Smart rc = -ENOMEM; 434be858b65SJames Smart goto free_cmdiocbq; 435f1c3b0fcSJames Smart } 436a33c4f7bSJames Smart bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); 437a33c4f7bSJames Smart if (!bmp->virt) { 438a33c4f7bSJames Smart rc = -ENOMEM; 439a33c4f7bSJames Smart goto free_bmp; 440f1c3b0fcSJames Smart } 441f1c3b0fcSJames Smart 442a33c4f7bSJames Smart INIT_LIST_HEAD(&bmp->list); 443a33c4f7bSJames Smart 444a33c4f7bSJames Smart bpl = (struct ulp_bde64 *) bmp->virt; 445a33c4f7bSJames Smart request_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64); 446a33c4f7bSJames Smart cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len, 447a33c4f7bSJames Smart 1, bpl, &request_nseg); 448a33c4f7bSJames Smart if (!cmp) { 449a33c4f7bSJames Smart rc = -ENOMEM; 450a33c4f7bSJames Smart goto free_bmp; 451a33c4f7bSJames Smart } 452a33c4f7bSJames Smart lpfc_bsg_copy_data(cmp, &job->request_payload, 453a33c4f7bSJames Smart job->request_payload.payload_len, 1); 454a33c4f7bSJames Smart 455a33c4f7bSJames Smart bpl += request_nseg; 456a33c4f7bSJames Smart reply_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64) - request_nseg; 457a33c4f7bSJames Smart rmp = lpfc_alloc_bsg_buffers(phba, job->reply_payload.payload_len, 0, 458a33c4f7bSJames Smart bpl, &reply_nseg); 459a33c4f7bSJames Smart if (!rmp) { 460a33c4f7bSJames Smart rc = -ENOMEM; 461a33c4f7bSJames Smart goto free_cmp; 462f1c3b0fcSJames Smart } 463f1c3b0fcSJames Smart 464f1c3b0fcSJames Smart cmd->un.genreq64.bdl.ulpIoTag32 = 0; 465f1c3b0fcSJames Smart cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); 466f1c3b0fcSJames Smart cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); 467f1c3b0fcSJames Smart cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 468f1c3b0fcSJames Smart cmd->un.genreq64.bdl.bdeSize = 469f1c3b0fcSJames Smart (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); 470f1c3b0fcSJames Smart cmd->ulpCommand = CMD_GEN_REQUEST64_CR; 471f1c3b0fcSJames Smart cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); 472f1c3b0fcSJames Smart cmd->un.genreq64.w5.hcsw.Dfctl = 0; 4736a9c52cfSJames Smart cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; 4746a9c52cfSJames Smart cmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT; 475f1c3b0fcSJames Smart cmd->ulpBdeCount = 1; 476f1c3b0fcSJames Smart cmd->ulpLe = 1; 477f1c3b0fcSJames Smart cmd->ulpClass = CLASS3; 478f1c3b0fcSJames Smart cmd->ulpContext = ndlp->nlp_rpi; 4796d368e53SJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 4806d368e53SJames Smart cmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; 481f1c3b0fcSJames Smart cmd->ulpOwner = OWN_CHIP; 482f1c3b0fcSJames Smart cmdiocbq->vport = phba->pport; 4834cc0e56eSJames Smart cmdiocbq->context3 = bmp; 484f1c3b0fcSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 485f1c3b0fcSJames Smart timeout = phba->fc_ratov * 2; 4864cc0e56eSJames Smart cmd->ulpTimeout = timeout; 487f1c3b0fcSJames Smart 4884cc0e56eSJames Smart cmdiocbq->iocb_cmpl = lpfc_bsg_send_mgmt_cmd_cmp; 489a33c4f7bSJames Smart cmdiocbq->context1 = dd_data; 490a33c4f7bSJames Smart cmdiocbq->context2 = cmp; 491a33c4f7bSJames Smart cmdiocbq->context3 = bmp; 4924430f7fdSJames Smart 4934cc0e56eSJames Smart dd_data->type = TYPE_IOCB; 494a33c4f7bSJames Smart dd_data->set_job = job; 4954cc0e56eSJames Smart dd_data->context_un.iocb.cmdiocbq = cmdiocbq; 496a33c4f7bSJames Smart dd_data->context_un.iocb.rmp = rmp; 497a33c4f7bSJames Smart job->dd_data = dd_data; 498f1c3b0fcSJames Smart 4994cc0e56eSJames Smart if (phba->cfg_poll & DISABLE_FCP_RING_INT) { 5009940b97bSJames Smart if (lpfc_readl(phba->HCregaddr, &creg_val)) { 5019940b97bSJames Smart rc = -EIO ; 502a33c4f7bSJames Smart goto free_rmp; 5039940b97bSJames Smart } 5044cc0e56eSJames Smart creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); 5054cc0e56eSJames Smart writel(creg_val, phba->HCregaddr); 5064cc0e56eSJames Smart readl(phba->HCregaddr); /* flush */ 5074cc0e56eSJames Smart } 5084cc0e56eSJames Smart 5094430f7fdSJames Smart cmdiocbq->context_un.ndlp = lpfc_nlp_get(ndlp); 5104430f7fdSJames Smart if (!cmdiocbq->context_un.ndlp) { 5114430f7fdSJames Smart rc = -ENODEV; 5124430f7fdSJames Smart goto free_rmp; 5134430f7fdSJames Smart } 514b5a9b2dfSJames Smart 5154430f7fdSJames Smart iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); 516b5a9b2dfSJames Smart if (iocb_stat == IOCB_SUCCESS) { 517b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 518b5a9b2dfSJames Smart /* make sure the I/O had not been completed yet */ 519b5a9b2dfSJames Smart if (cmdiocbq->iocb_flag & LPFC_IO_LIBDFC) { 520b5a9b2dfSJames Smart /* open up abort window to timeout handler */ 5211b8d11abSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_CMD_OUTSTANDING; 522b5a9b2dfSJames Smart } 523b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 5244cc0e56eSJames Smart return 0; /* done for now */ 525b5a9b2dfSJames Smart } else if (iocb_stat == IOCB_BUSY) { 526d439d286SJames Smart rc = -EAGAIN; 527b5a9b2dfSJames Smart } else { 528d439d286SJames Smart rc = -EIO; 529b5a9b2dfSJames Smart } 5302a9bf3d0SJames Smart 5314cc0e56eSJames Smart /* iocb failed so cleanup */ 5324430f7fdSJames Smart lpfc_nlp_put(ndlp); 533f1c3b0fcSJames Smart 534a33c4f7bSJames Smart free_rmp: 535a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, rmp); 536a33c4f7bSJames Smart free_cmp: 537a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 538a33c4f7bSJames Smart free_bmp: 539a33c4f7bSJames Smart if (bmp->virt) 540f1c3b0fcSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 541a33c4f7bSJames Smart kfree(bmp); 542f1c3b0fcSJames Smart free_cmdiocbq: 543f1c3b0fcSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 5444430f7fdSJames Smart free_dd: 5454cc0e56eSJames Smart kfree(dd_data); 5464cc0e56eSJames Smart no_dd_data: 547f1c3b0fcSJames Smart /* make error code available to userspace */ 54801e0e15cSJohannes Thumshirn bsg_reply->result = rc; 5494cc0e56eSJames Smart job->dd_data = NULL; 5504cc0e56eSJames Smart return rc; 5514cc0e56eSJames Smart } 5524cc0e56eSJames Smart 5534cc0e56eSJames Smart /** 5544cc0e56eSJames Smart * lpfc_bsg_rport_els_cmp - lpfc_bsg_rport_els's completion handler 5554cc0e56eSJames Smart * @phba: Pointer to HBA context object. 5564cc0e56eSJames Smart * @cmdiocbq: Pointer to command iocb. 5574cc0e56eSJames Smart * @rspiocbq: Pointer to response iocb. 5584cc0e56eSJames Smart * 5594cc0e56eSJames Smart * This function is the completion handler for iocbs issued using 5604cc0e56eSJames Smart * lpfc_bsg_rport_els_cmp function. This function is called by the 5614cc0e56eSJames Smart * ring event handler function without any lock held. This function 5624cc0e56eSJames Smart * can be called from both worker thread context and interrupt 5634cc0e56eSJames Smart * context. This function also can be called from other thread which 5644cc0e56eSJames Smart * cleans up the SLI layer objects. 5653b5dd52aSJames Smart * This function copies the contents of the response iocb to the 5664cc0e56eSJames Smart * response iocb memory object provided by the caller of 5674cc0e56eSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 5684cc0e56eSJames Smart * sleeps for the iocb completion. 5694cc0e56eSJames Smart **/ 5704cc0e56eSJames Smart static void 5714cc0e56eSJames Smart lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba, 5724cc0e56eSJames Smart struct lpfc_iocbq *cmdiocbq, 5734cc0e56eSJames Smart struct lpfc_iocbq *rspiocbq) 5744cc0e56eSJames Smart { 5754cc0e56eSJames Smart struct bsg_job_data *dd_data; 57675cc8cfcSJohannes Thumshirn struct bsg_job *job; 57701e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 5784cc0e56eSJames Smart IOCB_t *rsp; 5794cc0e56eSJames Smart struct lpfc_nodelist *ndlp; 580a33c4f7bSJames Smart struct lpfc_dmabuf *pcmd = NULL, *prsp = NULL; 5814cc0e56eSJames Smart struct fc_bsg_ctels_reply *els_reply; 5824cc0e56eSJames Smart uint8_t *rjt_data; 5834cc0e56eSJames Smart unsigned long flags; 584a33c4f7bSJames Smart unsigned int rsp_size; 5854cc0e56eSJames Smart int rc = 0; 5864cc0e56eSJames Smart 5874cc0e56eSJames Smart dd_data = cmdiocbq->context1; 5884cc0e56eSJames Smart ndlp = dd_data->context_un.iocb.ndlp; 589a33c4f7bSJames Smart cmdiocbq->context1 = ndlp; 5904cc0e56eSJames Smart 591a33c4f7bSJames Smart /* Determine if job has been aborted */ 592a33c4f7bSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 593a33c4f7bSJames Smart job = dd_data->set_job; 594a33c4f7bSJames Smart if (job) { 59501e0e15cSJohannes Thumshirn bsg_reply = job->reply; 596a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 597a33c4f7bSJames Smart job->dd_data = NULL; 598a33c4f7bSJames Smart } 599a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 6004cc0e56eSJames Smart 601b5a9b2dfSJames Smart /* Close the timeout handler abort window */ 602b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 6031b8d11abSJames Smart cmdiocbq->iocb_flag &= ~LPFC_IO_CMD_OUTSTANDING; 604b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 605b5a9b2dfSJames Smart 606a33c4f7bSJames Smart rsp = &rspiocbq->iocb; 607a33c4f7bSJames Smart pcmd = (struct lpfc_dmabuf *)cmdiocbq->context2; 608a33c4f7bSJames Smart prsp = (struct lpfc_dmabuf *)pcmd->list.next; 609a33c4f7bSJames Smart 610a33c4f7bSJames Smart /* Copy the completed job data or determine the job status if job is 611a33c4f7bSJames Smart * still active 612a33c4f7bSJames Smart */ 613a33c4f7bSJames Smart 614a33c4f7bSJames Smart if (job) { 615a33c4f7bSJames Smart if (rsp->ulpStatus == IOSTAT_SUCCESS) { 616a33c4f7bSJames Smart rsp_size = rsp->un.elsreq64.bdl.bdeSize; 61701e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 618a33c4f7bSJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 619a33c4f7bSJames Smart job->reply_payload.sg_cnt, 620a33c4f7bSJames Smart prsp->virt, 621a33c4f7bSJames Smart rsp_size); 622a33c4f7bSJames Smart } else if (rsp->ulpStatus == IOSTAT_LS_RJT) { 62301e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 6244cc0e56eSJames Smart sizeof(struct fc_bsg_ctels_reply); 6254cc0e56eSJames Smart /* LS_RJT data returned in word 4 */ 6264cc0e56eSJames Smart rjt_data = (uint8_t *)&rsp->un.ulpWord[4]; 62701e0e15cSJohannes Thumshirn els_reply = &bsg_reply->reply_data.ctels_reply; 6284cc0e56eSJames Smart els_reply->status = FC_CTELS_STATUS_REJECT; 6294cc0e56eSJames Smart els_reply->rjt_data.action = rjt_data[3]; 6304cc0e56eSJames Smart els_reply->rjt_data.reason_code = rjt_data[2]; 6314cc0e56eSJames Smart els_reply->rjt_data.reason_explanation = rjt_data[1]; 6324cc0e56eSJames Smart els_reply->rjt_data.vendor_unique = rjt_data[0]; 633a33c4f7bSJames Smart } else { 6344cc0e56eSJames Smart rc = -EIO; 635a33c4f7bSJames Smart } 636a33c4f7bSJames Smart } 6374cc0e56eSJames Smart 638a33c4f7bSJames Smart lpfc_els_free_iocb(phba, cmdiocbq); 6394430f7fdSJames Smart 6404430f7fdSJames Smart lpfc_nlp_put(ndlp); 6414cc0e56eSJames Smart kfree(dd_data); 642a33c4f7bSJames Smart 643a33c4f7bSJames Smart /* Complete the job if the job is still active */ 644a33c4f7bSJames Smart 645a33c4f7bSJames Smart if (job) { 64601e0e15cSJohannes Thumshirn bsg_reply->result = rc; 64706548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 6481abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 649a33c4f7bSJames Smart } 6504cc0e56eSJames Smart return; 651f1c3b0fcSJames Smart } 652f1c3b0fcSJames Smart 653f1c3b0fcSJames Smart /** 654f1c3b0fcSJames Smart * lpfc_bsg_rport_els - send an ELS command from a bsg request 655f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 6563b5dd52aSJames Smart **/ 657f1c3b0fcSJames Smart static int 65875cc8cfcSJohannes Thumshirn lpfc_bsg_rport_els(struct bsg_job *job) 659f1c3b0fcSJames Smart { 660cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 661f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 6621d69b122SJohannes Thumshirn struct lpfc_rport_data *rdata = fc_bsg_to_rport(job)->dd_data; 663f1c3b0fcSJames Smart struct lpfc_nodelist *ndlp = rdata->pnode; 66401e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 66501e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 666f1c3b0fcSJames Smart uint32_t elscmd; 667f1c3b0fcSJames Smart uint32_t cmdsize; 668f1c3b0fcSJames Smart struct lpfc_iocbq *cmdiocbq; 669f1c3b0fcSJames Smart uint16_t rpi = 0; 6704cc0e56eSJames Smart struct bsg_job_data *dd_data; 671b5a9b2dfSJames Smart unsigned long flags; 6724cc0e56eSJames Smart uint32_t creg_val; 673f1c3b0fcSJames Smart int rc = 0; 674f1c3b0fcSJames Smart 675f1c3b0fcSJames Smart /* in case no data is transferred */ 67601e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 677f1c3b0fcSJames Smart 678a33c4f7bSJames Smart /* verify the els command is not greater than the 679a33c4f7bSJames Smart * maximum ELS transfer size. 680a33c4f7bSJames Smart */ 681a33c4f7bSJames Smart 682a33c4f7bSJames Smart if (job->request_payload.payload_len > FCELSSIZE) { 683a33c4f7bSJames Smart rc = -EINVAL; 684a33c4f7bSJames Smart goto no_dd_data; 685a33c4f7bSJames Smart } 686a33c4f7bSJames Smart 6874cc0e56eSJames Smart /* allocate our bsg tracking structure */ 6884cc0e56eSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 6894cc0e56eSJames Smart if (!dd_data) { 6904cc0e56eSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 6914cc0e56eSJames Smart "2735 Failed allocation of dd_data\n"); 6924cc0e56eSJames Smart rc = -ENOMEM; 6934cc0e56eSJames Smart goto no_dd_data; 6944cc0e56eSJames Smart } 6954cc0e56eSJames Smart 69601e0e15cSJohannes Thumshirn elscmd = bsg_request->rqst_data.r_els.els_code; 697a33c4f7bSJames Smart cmdsize = job->request_payload.payload_len; 698a33c4f7bSJames Smart 699f1c3b0fcSJames Smart if (!lpfc_nlp_get(ndlp)) { 700f1c3b0fcSJames Smart rc = -ENODEV; 7014cc0e56eSJames Smart goto free_dd_data; 702f1c3b0fcSJames Smart } 703f1c3b0fcSJames Smart 704a33c4f7bSJames Smart /* We will use the allocated dma buffers by prep els iocb for command 705a33c4f7bSJames Smart * and response to ensure if the job times out and the request is freed, 706a33c4f7bSJames Smart * we won't be dma into memory that is no longer allocated to for the 707a33c4f7bSJames Smart * request. 708a33c4f7bSJames Smart */ 709f1c3b0fcSJames Smart 7104cc0e56eSJames Smart cmdiocbq = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, 711f1c3b0fcSJames Smart ndlp->nlp_DID, elscmd); 712f1c3b0fcSJames Smart if (!cmdiocbq) { 7134cc0e56eSJames Smart rc = -EIO; 714a33c4f7bSJames Smart goto release_ndlp; 715f1c3b0fcSJames Smart } 716f1c3b0fcSJames Smart 717a33c4f7bSJames Smart /* Transfer the request payload to allocated command dma buffer */ 718a33c4f7bSJames Smart sg_copy_to_buffer(job->request_payload.sg_list, 719a33c4f7bSJames Smart job->request_payload.sg_cnt, 720a33c4f7bSJames Smart ((struct lpfc_dmabuf *)cmdiocbq->context2)->virt, 721a33c4f7bSJames Smart cmdsize); 722f1c3b0fcSJames Smart 7234430f7fdSJames Smart rpi = ndlp->nlp_rpi; 7244430f7fdSJames Smart 7253ef6d24cSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 7263ef6d24cSJames Smart cmdiocbq->iocb.ulpContext = phba->sli4_hba.rpi_ids[rpi]; 7273ef6d24cSJames Smart else 728f1c3b0fcSJames Smart cmdiocbq->iocb.ulpContext = rpi; 729f1c3b0fcSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 7304cc0e56eSJames Smart cmdiocbq->context1 = dd_data; 73193d1379eSJames Smart cmdiocbq->context_un.ndlp = ndlp; 732a33c4f7bSJames Smart cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp; 7334cc0e56eSJames Smart dd_data->type = TYPE_IOCB; 734a33c4f7bSJames Smart dd_data->set_job = job; 7354cc0e56eSJames Smart dd_data->context_un.iocb.cmdiocbq = cmdiocbq; 7364cc0e56eSJames Smart dd_data->context_un.iocb.ndlp = ndlp; 737a33c4f7bSJames Smart dd_data->context_un.iocb.rmp = NULL; 738a33c4f7bSJames Smart job->dd_data = dd_data; 739f1c3b0fcSJames Smart 7404cc0e56eSJames Smart if (phba->cfg_poll & DISABLE_FCP_RING_INT) { 7419940b97bSJames Smart if (lpfc_readl(phba->HCregaddr, &creg_val)) { 7429940b97bSJames Smart rc = -EIO; 7439940b97bSJames Smart goto linkdown_err; 7449940b97bSJames Smart } 7454cc0e56eSJames Smart creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); 7464cc0e56eSJames Smart writel(creg_val, phba->HCregaddr); 7474cc0e56eSJames Smart readl(phba->HCregaddr); /* flush */ 7484cc0e56eSJames Smart } 749a33c4f7bSJames Smart 7504430f7fdSJames Smart cmdiocbq->context1 = lpfc_nlp_get(ndlp); 7514430f7fdSJames Smart if (!cmdiocbq->context1) { 7524430f7fdSJames Smart rc = -EIO; 7534430f7fdSJames Smart goto linkdown_err; 7544430f7fdSJames Smart } 755a33c4f7bSJames Smart 7564430f7fdSJames Smart rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); 757b5a9b2dfSJames Smart if (rc == IOCB_SUCCESS) { 758b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 759b5a9b2dfSJames Smart /* make sure the I/O had not been completed/released */ 760b5a9b2dfSJames Smart if (cmdiocbq->iocb_flag & LPFC_IO_LIBDFC) { 761b5a9b2dfSJames Smart /* open up abort window to timeout handler */ 7621b8d11abSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_CMD_OUTSTANDING; 763b5a9b2dfSJames Smart } 764b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 7654cc0e56eSJames Smart return 0; /* done for now */ 766b5a9b2dfSJames Smart } else if (rc == IOCB_BUSY) { 767d439d286SJames Smart rc = -EAGAIN; 768b5a9b2dfSJames Smart } else { 769d439d286SJames Smart rc = -EIO; 770b5a9b2dfSJames Smart } 771b5a9b2dfSJames Smart 7724430f7fdSJames Smart /* I/O issue failed. Cleanup resources. */ 7734cc0e56eSJames Smart 7749940b97bSJames Smart linkdown_err: 775a33c4f7bSJames Smart lpfc_els_free_iocb(phba, cmdiocbq); 776f1c3b0fcSJames Smart 777a33c4f7bSJames Smart release_ndlp: 778a33c4f7bSJames Smart lpfc_nlp_put(ndlp); 779f1c3b0fcSJames Smart 7804cc0e56eSJames Smart free_dd_data: 7814cc0e56eSJames Smart kfree(dd_data); 7824cc0e56eSJames Smart 7834cc0e56eSJames Smart no_dd_data: 784f1c3b0fcSJames Smart /* make error code available to userspace */ 78501e0e15cSJohannes Thumshirn bsg_reply->result = rc; 7864cc0e56eSJames Smart job->dd_data = NULL; 7874cc0e56eSJames Smart return rc; 788f1c3b0fcSJames Smart } 789f1c3b0fcSJames Smart 7903b5dd52aSJames Smart /** 7913b5dd52aSJames Smart * lpfc_bsg_event_free - frees an allocated event structure 7923b5dd52aSJames Smart * @kref: Pointer to a kref. 7933b5dd52aSJames Smart * 7943b5dd52aSJames Smart * Called from kref_put. Back cast the kref into an event structure address. 7953b5dd52aSJames Smart * Free any events to get, delete associated nodes, free any events to see, 7963b5dd52aSJames Smart * free any data then free the event itself. 7973b5dd52aSJames Smart **/ 798f1c3b0fcSJames Smart static void 7994cc0e56eSJames Smart lpfc_bsg_event_free(struct kref *kref) 800f1c3b0fcSJames Smart { 8014cc0e56eSJames Smart struct lpfc_bsg_event *evt = container_of(kref, struct lpfc_bsg_event, 8024cc0e56eSJames Smart kref); 803f1c3b0fcSJames Smart struct event_data *ed; 804f1c3b0fcSJames Smart 805f1c3b0fcSJames Smart list_del(&evt->node); 806f1c3b0fcSJames Smart 807f1c3b0fcSJames Smart while (!list_empty(&evt->events_to_get)) { 808f1c3b0fcSJames Smart ed = list_entry(evt->events_to_get.next, typeof(*ed), node); 809f1c3b0fcSJames Smart list_del(&ed->node); 810f1c3b0fcSJames Smart kfree(ed->data); 811f1c3b0fcSJames Smart kfree(ed); 812f1c3b0fcSJames Smart } 813f1c3b0fcSJames Smart 814f1c3b0fcSJames Smart while (!list_empty(&evt->events_to_see)) { 815f1c3b0fcSJames Smart ed = list_entry(evt->events_to_see.next, typeof(*ed), node); 816f1c3b0fcSJames Smart list_del(&ed->node); 817f1c3b0fcSJames Smart kfree(ed->data); 818f1c3b0fcSJames Smart kfree(ed); 819f1c3b0fcSJames Smart } 820f1c3b0fcSJames Smart 821a33c4f7bSJames Smart kfree(evt->dd_data); 822f1c3b0fcSJames Smart kfree(evt); 823f1c3b0fcSJames Smart } 824f1c3b0fcSJames Smart 8253b5dd52aSJames Smart /** 8263b5dd52aSJames Smart * lpfc_bsg_event_ref - increments the kref for an event 8273b5dd52aSJames Smart * @evt: Pointer to an event structure. 8283b5dd52aSJames Smart **/ 829f1c3b0fcSJames Smart static inline void 8304cc0e56eSJames Smart lpfc_bsg_event_ref(struct lpfc_bsg_event *evt) 831f1c3b0fcSJames Smart { 8324cc0e56eSJames Smart kref_get(&evt->kref); 833f1c3b0fcSJames Smart } 834f1c3b0fcSJames Smart 8353b5dd52aSJames Smart /** 8363b5dd52aSJames Smart * lpfc_bsg_event_unref - Uses kref_put to free an event structure 8373b5dd52aSJames Smart * @evt: Pointer to an event structure. 8383b5dd52aSJames Smart **/ 839f1c3b0fcSJames Smart static inline void 8404cc0e56eSJames Smart lpfc_bsg_event_unref(struct lpfc_bsg_event *evt) 841f1c3b0fcSJames Smart { 8424cc0e56eSJames Smart kref_put(&evt->kref, lpfc_bsg_event_free); 843f1c3b0fcSJames Smart } 844f1c3b0fcSJames Smart 8453b5dd52aSJames Smart /** 8463b5dd52aSJames Smart * lpfc_bsg_event_new - allocate and initialize a event structure 8473b5dd52aSJames Smart * @ev_mask: Mask of events. 8483b5dd52aSJames Smart * @ev_reg_id: Event reg id. 8493b5dd52aSJames Smart * @ev_req_id: Event request id. 8503b5dd52aSJames Smart **/ 8514cc0e56eSJames Smart static struct lpfc_bsg_event * 8524cc0e56eSJames Smart lpfc_bsg_event_new(uint32_t ev_mask, int ev_reg_id, uint32_t ev_req_id) 8534cc0e56eSJames Smart { 8544cc0e56eSJames Smart struct lpfc_bsg_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL); 855f1c3b0fcSJames Smart 8564cc0e56eSJames Smart if (!evt) 8574cc0e56eSJames Smart return NULL; 8584cc0e56eSJames Smart 8594cc0e56eSJames Smart INIT_LIST_HEAD(&evt->events_to_get); 8604cc0e56eSJames Smart INIT_LIST_HEAD(&evt->events_to_see); 8614cc0e56eSJames Smart evt->type_mask = ev_mask; 8624cc0e56eSJames Smart evt->req_id = ev_req_id; 8634cc0e56eSJames Smart evt->reg_id = ev_reg_id; 8644cc0e56eSJames Smart evt->wait_time_stamp = jiffies; 865a33c4f7bSJames Smart evt->dd_data = NULL; 8664cc0e56eSJames Smart init_waitqueue_head(&evt->wq); 8674cc0e56eSJames Smart kref_init(&evt->kref); 8684cc0e56eSJames Smart return evt; 8694cc0e56eSJames Smart } 8704cc0e56eSJames Smart 8713b5dd52aSJames Smart /** 8723b5dd52aSJames Smart * diag_cmd_data_free - Frees an lpfc dma buffer extension 8733b5dd52aSJames Smart * @phba: Pointer to HBA context object. 8743b5dd52aSJames Smart * @mlist: Pointer to an lpfc dma buffer extension. 8753b5dd52aSJames Smart **/ 8764cc0e56eSJames Smart static int 8773b5dd52aSJames Smart diag_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist) 8784cc0e56eSJames Smart { 8794cc0e56eSJames Smart struct lpfc_dmabufext *mlast; 8804cc0e56eSJames Smart struct pci_dev *pcidev; 8814cc0e56eSJames Smart struct list_head head, *curr, *next; 8824cc0e56eSJames Smart 8834cc0e56eSJames Smart if ((!mlist) || (!lpfc_is_link_up(phba) && 8844cc0e56eSJames Smart (phba->link_flag & LS_LOOPBACK_MODE))) { 8854cc0e56eSJames Smart return 0; 8864cc0e56eSJames Smart } 8874cc0e56eSJames Smart 8884cc0e56eSJames Smart pcidev = phba->pcidev; 8894cc0e56eSJames Smart list_add_tail(&head, &mlist->dma.list); 8904cc0e56eSJames Smart 8914cc0e56eSJames Smart list_for_each_safe(curr, next, &head) { 8924cc0e56eSJames Smart mlast = list_entry(curr, struct lpfc_dmabufext , dma.list); 8934cc0e56eSJames Smart if (mlast->dma.virt) 8944cc0e56eSJames Smart dma_free_coherent(&pcidev->dev, 8954cc0e56eSJames Smart mlast->size, 8964cc0e56eSJames Smart mlast->dma.virt, 8974cc0e56eSJames Smart mlast->dma.phys); 8984cc0e56eSJames Smart kfree(mlast); 8994cc0e56eSJames Smart } 9004cc0e56eSJames Smart return 0; 9014cc0e56eSJames Smart } 902f1c3b0fcSJames Smart 903ea085dabSLee Jones /* 904f1c3b0fcSJames Smart * lpfc_bsg_ct_unsol_event - process an unsolicited CT command 905f1c3b0fcSJames Smart * 906f1c3b0fcSJames Smart * This function is called when an unsolicited CT command is received. It 9074cc0e56eSJames Smart * forwards the event to any processes registered to receive CT events. 9083b5dd52aSJames Smart **/ 9094fede78fSJames Smart int 910f1c3b0fcSJames Smart lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, 911f1c3b0fcSJames Smart struct lpfc_iocbq *piocbq) 912f1c3b0fcSJames Smart { 913f1c3b0fcSJames Smart uint32_t evt_req_id = 0; 914f1c3b0fcSJames Smart uint32_t cmd; 915f1c3b0fcSJames Smart struct lpfc_dmabuf *dmabuf = NULL; 9164cc0e56eSJames Smart struct lpfc_bsg_event *evt; 917f1c3b0fcSJames Smart struct event_data *evt_dat = NULL; 918f1c3b0fcSJames Smart struct lpfc_iocbq *iocbq; 919f1c3b0fcSJames Smart size_t offset = 0; 920f1c3b0fcSJames Smart struct list_head head; 921f1c3b0fcSJames Smart struct ulp_bde64 *bde; 922f1c3b0fcSJames Smart dma_addr_t dma_addr; 923f1c3b0fcSJames Smart int i; 924f1c3b0fcSJames Smart struct lpfc_dmabuf *bdeBuf1 = piocbq->context2; 925f1c3b0fcSJames Smart struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; 926f1c3b0fcSJames Smart struct lpfc_hbq_entry *hbqe; 927f1c3b0fcSJames Smart struct lpfc_sli_ct_request *ct_req; 92875cc8cfcSJohannes Thumshirn struct bsg_job *job = NULL; 92901e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 930a33c4f7bSJames Smart struct bsg_job_data *dd_data = NULL; 9314fede78fSJames Smart unsigned long flags; 9324cc0e56eSJames Smart int size = 0; 933f1c3b0fcSJames Smart 934f1c3b0fcSJames Smart INIT_LIST_HEAD(&head); 935f1c3b0fcSJames Smart list_add_tail(&head, &piocbq->list); 936f1c3b0fcSJames Smart 937b67b5944SJames Smart ct_req = (struct lpfc_sli_ct_request *)bdeBuf1; 938f1c3b0fcSJames Smart evt_req_id = ct_req->FsType; 939f1c3b0fcSJames Smart cmd = ct_req->CommandResponse.bits.CmdRsp; 940f1c3b0fcSJames Smart 9414fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 942f1c3b0fcSJames Smart list_for_each_entry(evt, &phba->ct_ev_waiters, node) { 9434cc0e56eSJames Smart if (!(evt->type_mask & FC_REG_CT_EVENT) || 9444cc0e56eSJames Smart evt->req_id != evt_req_id) 945f1c3b0fcSJames Smart continue; 946f1c3b0fcSJames Smart 9474cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 9484cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 949f1c3b0fcSJames Smart evt_dat = kzalloc(sizeof(*evt_dat), GFP_KERNEL); 9504cc0e56eSJames Smart if (evt_dat == NULL) { 9514cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 9524cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 953f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 954f1c3b0fcSJames Smart "2614 Memory allocation failed for " 955f1c3b0fcSJames Smart "CT event\n"); 956f1c3b0fcSJames Smart break; 957f1c3b0fcSJames Smart } 958f1c3b0fcSJames Smart 959f1c3b0fcSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 960f1c3b0fcSJames Smart /* take accumulated byte count from the last iocbq */ 961f1c3b0fcSJames Smart iocbq = list_entry(head.prev, typeof(*iocbq), list); 962f1c3b0fcSJames Smart evt_dat->len = iocbq->iocb.unsli3.rcvsli3.acc_len; 963f1c3b0fcSJames Smart } else { 964f1c3b0fcSJames Smart list_for_each_entry(iocbq, &head, list) { 965f1c3b0fcSJames Smart for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) 966f1c3b0fcSJames Smart evt_dat->len += 967f1c3b0fcSJames Smart iocbq->iocb.un.cont64[i].tus.f.bdeSize; 968f1c3b0fcSJames Smart } 969f1c3b0fcSJames Smart } 970f1c3b0fcSJames Smart 971f1c3b0fcSJames Smart evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL); 9724cc0e56eSJames Smart if (evt_dat->data == NULL) { 973f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 974f1c3b0fcSJames Smart "2615 Memory allocation failed for " 975f1c3b0fcSJames Smart "CT event data, size %d\n", 976f1c3b0fcSJames Smart evt_dat->len); 977f1c3b0fcSJames Smart kfree(evt_dat); 9784fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 9794cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 9804fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 981f1c3b0fcSJames Smart goto error_ct_unsol_exit; 982f1c3b0fcSJames Smart } 983f1c3b0fcSJames Smart 984f1c3b0fcSJames Smart list_for_each_entry(iocbq, &head, list) { 9854cc0e56eSJames Smart size = 0; 986f1c3b0fcSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 987f1c3b0fcSJames Smart bdeBuf1 = iocbq->context2; 988f1c3b0fcSJames Smart bdeBuf2 = iocbq->context3; 989f1c3b0fcSJames Smart } 990f1c3b0fcSJames Smart for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) { 991f1c3b0fcSJames Smart if (phba->sli3_options & 992f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED) { 993f1c3b0fcSJames Smart if (i == 0) { 994f1c3b0fcSJames Smart hbqe = (struct lpfc_hbq_entry *) 995f1c3b0fcSJames Smart &iocbq->iocb.un.ulpWord[0]; 996f1c3b0fcSJames Smart size = hbqe->bde.tus.f.bdeSize; 997f1c3b0fcSJames Smart dmabuf = bdeBuf1; 998f1c3b0fcSJames Smart } else if (i == 1) { 999f1c3b0fcSJames Smart hbqe = (struct lpfc_hbq_entry *) 1000f1c3b0fcSJames Smart &iocbq->iocb.unsli3. 1001f1c3b0fcSJames Smart sli3Words[4]; 1002f1c3b0fcSJames Smart size = hbqe->bde.tus.f.bdeSize; 1003f1c3b0fcSJames Smart dmabuf = bdeBuf2; 1004f1c3b0fcSJames Smart } 1005f1c3b0fcSJames Smart if ((offset + size) > evt_dat->len) 1006f1c3b0fcSJames Smart size = evt_dat->len - offset; 1007f1c3b0fcSJames Smart } else { 1008f1c3b0fcSJames Smart size = iocbq->iocb.un.cont64[i]. 1009f1c3b0fcSJames Smart tus.f.bdeSize; 1010f1c3b0fcSJames Smart bde = &iocbq->iocb.un.cont64[i]; 1011f1c3b0fcSJames Smart dma_addr = getPaddr(bde->addrHigh, 1012f1c3b0fcSJames Smart bde->addrLow); 1013f1c3b0fcSJames Smart dmabuf = lpfc_sli_ringpostbuf_get(phba, 1014f1c3b0fcSJames Smart pring, dma_addr); 1015f1c3b0fcSJames Smart } 1016f1c3b0fcSJames Smart if (!dmabuf) { 1017f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_ERR, 1018f1c3b0fcSJames Smart LOG_LIBDFC, "2616 No dmabuf " 101932350664SJames Smart "found for iocbq x%px\n", 1020f1c3b0fcSJames Smart iocbq); 1021f1c3b0fcSJames Smart kfree(evt_dat->data); 1022f1c3b0fcSJames Smart kfree(evt_dat); 10234fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, 10244fede78fSJames Smart flags); 10254cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 10264fede78fSJames Smart spin_unlock_irqrestore( 10274fede78fSJames Smart &phba->ct_ev_lock, flags); 1028f1c3b0fcSJames Smart goto error_ct_unsol_exit; 1029f1c3b0fcSJames Smart } 1030f1c3b0fcSJames Smart memcpy((char *)(evt_dat->data) + offset, 1031f1c3b0fcSJames Smart dmabuf->virt, size); 1032f1c3b0fcSJames Smart offset += size; 1033f1c3b0fcSJames Smart if (evt_req_id != SLI_CT_ELX_LOOPBACK && 1034f1c3b0fcSJames Smart !(phba->sli3_options & 1035f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED)) { 1036f1c3b0fcSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, 1037f1c3b0fcSJames Smart dmabuf); 1038f1c3b0fcSJames Smart } else { 1039f1c3b0fcSJames Smart switch (cmd) { 10404cc0e56eSJames Smart case ELX_LOOPBACK_DATA: 10411b51197dSJames Smart if (phba->sli_rev < 10421b51197dSJames Smart LPFC_SLI_REV4) 10433b5dd52aSJames Smart diag_cmd_data_free(phba, 10441b51197dSJames Smart (struct lpfc_dmabufext 10451b51197dSJames Smart *)dmabuf); 10464cc0e56eSJames Smart break; 1047f1c3b0fcSJames Smart case ELX_LOOPBACK_XRI_SETUP: 10484cc0e56eSJames Smart if ((phba->sli_rev == 10494cc0e56eSJames Smart LPFC_SLI_REV2) || 10504cc0e56eSJames Smart (phba->sli3_options & 10514cc0e56eSJames Smart LPFC_SLI3_HBQ_ENABLED 10524cc0e56eSJames Smart )) { 10534cc0e56eSJames Smart lpfc_in_buf_free(phba, 10544cc0e56eSJames Smart dmabuf); 10554cc0e56eSJames Smart } else { 1056f1c3b0fcSJames Smart lpfc_post_buffer(phba, 1057f1c3b0fcSJames Smart pring, 1058f1c3b0fcSJames Smart 1); 10594cc0e56eSJames Smart } 1060f1c3b0fcSJames Smart break; 1061f1c3b0fcSJames Smart default: 1062f1c3b0fcSJames Smart if (!(phba->sli3_options & 1063f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED)) 1064f1c3b0fcSJames Smart lpfc_post_buffer(phba, 1065f1c3b0fcSJames Smart pring, 1066f1c3b0fcSJames Smart 1); 1067f1c3b0fcSJames Smart break; 1068f1c3b0fcSJames Smart } 1069f1c3b0fcSJames Smart } 1070f1c3b0fcSJames Smart } 1071f1c3b0fcSJames Smart } 1072f1c3b0fcSJames Smart 10734fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1074f1c3b0fcSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) { 1075f1c3b0fcSJames Smart evt_dat->immed_dat = phba->ctx_idx; 10766dd9e31cSJames Smart phba->ctx_idx = (phba->ctx_idx + 1) % LPFC_CT_CTX_MAX; 1077589a52d6SJames Smart /* Provide warning for over-run of the ct_ctx array */ 10786dd9e31cSJames Smart if (phba->ct_ctx[evt_dat->immed_dat].valid == 1079589a52d6SJames Smart UNSOL_VALID) 1080589a52d6SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, 1081589a52d6SJames Smart "2717 CT context array entry " 1082589a52d6SJames Smart "[%d] over-run: oxid:x%x, " 1083589a52d6SJames Smart "sid:x%x\n", phba->ctx_idx, 1084589a52d6SJames Smart phba->ct_ctx[ 1085589a52d6SJames Smart evt_dat->immed_dat].oxid, 1086589a52d6SJames Smart phba->ct_ctx[ 1087589a52d6SJames Smart evt_dat->immed_dat].SID); 10887851fe2cSJames Smart phba->ct_ctx[evt_dat->immed_dat].rxid = 1089f1c3b0fcSJames Smart piocbq->iocb.ulpContext; 10907851fe2cSJames Smart phba->ct_ctx[evt_dat->immed_dat].oxid = 10917851fe2cSJames Smart piocbq->iocb.unsli3.rcvsli3.ox_id; 1092f1c3b0fcSJames Smart phba->ct_ctx[evt_dat->immed_dat].SID = 1093f1c3b0fcSJames Smart piocbq->iocb.un.rcvels.remoteID; 10946dd9e31cSJames Smart phba->ct_ctx[evt_dat->immed_dat].valid = UNSOL_VALID; 1095f1c3b0fcSJames Smart } else 1096f1c3b0fcSJames Smart evt_dat->immed_dat = piocbq->iocb.ulpContext; 1097f1c3b0fcSJames Smart 1098f1c3b0fcSJames Smart evt_dat->type = FC_REG_CT_EVENT; 1099f1c3b0fcSJames Smart list_add(&evt_dat->node, &evt->events_to_see); 11004cc0e56eSJames Smart if (evt_req_id == SLI_CT_ELX_LOOPBACK) { 1101f1c3b0fcSJames Smart wake_up_interruptible(&evt->wq); 11024cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 1103f1c3b0fcSJames Smart break; 1104f1c3b0fcSJames Smart } 11054cc0e56eSJames Smart 11064cc0e56eSJames Smart list_move(evt->events_to_see.prev, &evt->events_to_get); 11074cc0e56eSJames Smart 1108a33c4f7bSJames Smart dd_data = (struct bsg_job_data *)evt->dd_data; 1109a33c4f7bSJames Smart job = dd_data->set_job; 1110a33c4f7bSJames Smart dd_data->set_job = NULL; 1111a33c4f7bSJames Smart lpfc_bsg_event_unref(evt); 11124cc0e56eSJames Smart if (job) { 111301e0e15cSJohannes Thumshirn bsg_reply = job->reply; 111401e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = size; 11154cc0e56eSJames Smart /* make error code available to userspace */ 111601e0e15cSJohannes Thumshirn bsg_reply->result = 0; 11174cc0e56eSJames Smart job->dd_data = NULL; 11184cc0e56eSJames Smart /* complete the job back to userspace */ 11194cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 112006548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 11211abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 11224cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 11234cc0e56eSJames Smart } 11244cc0e56eSJames Smart } 11254fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 1126f1c3b0fcSJames Smart 1127f1c3b0fcSJames Smart error_ct_unsol_exit: 1128f1c3b0fcSJames Smart if (!list_empty(&head)) 1129f1c3b0fcSJames Smart list_del(&head); 11301b51197dSJames Smart if ((phba->sli_rev < LPFC_SLI_REV4) && 11311b51197dSJames Smart (evt_req_id == SLI_CT_ELX_LOOPBACK)) 11324cc0e56eSJames Smart return 0; 11334fede78fSJames Smart return 1; 1134f1c3b0fcSJames Smart } 1135f1c3b0fcSJames Smart 1136f1c3b0fcSJames Smart /** 11376dd9e31cSJames Smart * lpfc_bsg_ct_unsol_abort - handler ct abort to management plane 11386dd9e31cSJames Smart * @phba: Pointer to HBA context object. 11396dd9e31cSJames Smart * @dmabuf: pointer to a dmabuf that describes the FC sequence 11406dd9e31cSJames Smart * 11416dd9e31cSJames Smart * This function handles abort to the CT command toward management plane 11426dd9e31cSJames Smart * for SLI4 port. 11436dd9e31cSJames Smart * 11446dd9e31cSJames Smart * If the pending context of a CT command to management plane present, clears 11456dd9e31cSJames Smart * such context and returns 1 for handled; otherwise, it returns 0 indicating 11466dd9e31cSJames Smart * no context exists. 11476dd9e31cSJames Smart **/ 11486dd9e31cSJames Smart int 11496dd9e31cSJames Smart lpfc_bsg_ct_unsol_abort(struct lpfc_hba *phba, struct hbq_dmabuf *dmabuf) 11506dd9e31cSJames Smart { 11516dd9e31cSJames Smart struct fc_frame_header fc_hdr; 11526dd9e31cSJames Smart struct fc_frame_header *fc_hdr_ptr = &fc_hdr; 11536dd9e31cSJames Smart int ctx_idx, handled = 0; 11546dd9e31cSJames Smart uint16_t oxid, rxid; 11556dd9e31cSJames Smart uint32_t sid; 11566dd9e31cSJames Smart 11576dd9e31cSJames Smart memcpy(fc_hdr_ptr, dmabuf->hbuf.virt, sizeof(struct fc_frame_header)); 11586dd9e31cSJames Smart sid = sli4_sid_from_fc_hdr(fc_hdr_ptr); 11596dd9e31cSJames Smart oxid = be16_to_cpu(fc_hdr_ptr->fh_ox_id); 11606dd9e31cSJames Smart rxid = be16_to_cpu(fc_hdr_ptr->fh_rx_id); 11616dd9e31cSJames Smart 11626dd9e31cSJames Smart for (ctx_idx = 0; ctx_idx < LPFC_CT_CTX_MAX; ctx_idx++) { 11636dd9e31cSJames Smart if (phba->ct_ctx[ctx_idx].valid != UNSOL_VALID) 11646dd9e31cSJames Smart continue; 11656dd9e31cSJames Smart if (phba->ct_ctx[ctx_idx].rxid != rxid) 11666dd9e31cSJames Smart continue; 11676dd9e31cSJames Smart if (phba->ct_ctx[ctx_idx].oxid != oxid) 11686dd9e31cSJames Smart continue; 11696dd9e31cSJames Smart if (phba->ct_ctx[ctx_idx].SID != sid) 11706dd9e31cSJames Smart continue; 11716dd9e31cSJames Smart phba->ct_ctx[ctx_idx].valid = UNSOL_INVALID; 11726dd9e31cSJames Smart handled = 1; 11736dd9e31cSJames Smart } 11746dd9e31cSJames Smart return handled; 11756dd9e31cSJames Smart } 11766dd9e31cSJames Smart 11776dd9e31cSJames Smart /** 11784cc0e56eSJames Smart * lpfc_bsg_hba_set_event - process a SET_EVENT bsg vendor command 1179f1c3b0fcSJames Smart * @job: SET_EVENT fc_bsg_job 11803b5dd52aSJames Smart **/ 1181f1c3b0fcSJames Smart static int 118275cc8cfcSJohannes Thumshirn lpfc_bsg_hba_set_event(struct bsg_job *job) 1183f1c3b0fcSJames Smart { 1184cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 1185f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 118601e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 1187f1c3b0fcSJames Smart struct set_ct_event *event_req; 11884cc0e56eSJames Smart struct lpfc_bsg_event *evt; 1189f1c3b0fcSJames Smart int rc = 0; 11904cc0e56eSJames Smart struct bsg_job_data *dd_data = NULL; 11914cc0e56eSJames Smart uint32_t ev_mask; 11924cc0e56eSJames Smart unsigned long flags; 1193f1c3b0fcSJames Smart 1194f1c3b0fcSJames Smart if (job->request_len < 1195f1c3b0fcSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct set_ct_event)) { 1196f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1197f1c3b0fcSJames Smart "2612 Received SET_CT_EVENT below minimum " 1198f1c3b0fcSJames Smart "size\n"); 11994cc0e56eSJames Smart rc = -EINVAL; 12004cc0e56eSJames Smart goto job_error; 12014cc0e56eSJames Smart } 12024cc0e56eSJames Smart 1203f1c3b0fcSJames Smart event_req = (struct set_ct_event *) 120401e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 12054cc0e56eSJames Smart ev_mask = ((uint32_t)(unsigned long)event_req->type_mask & 12064cc0e56eSJames Smart FC_REG_EVENT_MASK); 12074fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1208f1c3b0fcSJames Smart list_for_each_entry(evt, &phba->ct_ev_waiters, node) { 1209f1c3b0fcSJames Smart if (evt->reg_id == event_req->ev_reg_id) { 12104cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 1211f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 1212a33c4f7bSJames Smart dd_data = (struct bsg_job_data *)evt->dd_data; 1213f1c3b0fcSJames Smart break; 1214f1c3b0fcSJames Smart } 1215f1c3b0fcSJames Smart } 12164fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 1217f1c3b0fcSJames Smart 1218f1c3b0fcSJames Smart if (&evt->node == &phba->ct_ev_waiters) { 1219f1c3b0fcSJames Smart /* no event waiting struct yet - first call */ 1220a33c4f7bSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 1221a33c4f7bSJames Smart if (dd_data == NULL) { 1222a33c4f7bSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1223a33c4f7bSJames Smart "2734 Failed allocation of dd_data\n"); 1224a33c4f7bSJames Smart rc = -ENOMEM; 1225a33c4f7bSJames Smart goto job_error; 1226a33c4f7bSJames Smart } 12274cc0e56eSJames Smart evt = lpfc_bsg_event_new(ev_mask, event_req->ev_reg_id, 1228f1c3b0fcSJames Smart event_req->ev_req_id); 1229f1c3b0fcSJames Smart if (!evt) { 1230f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1231f1c3b0fcSJames Smart "2617 Failed allocation of event " 1232f1c3b0fcSJames Smart "waiter\n"); 12334cc0e56eSJames Smart rc = -ENOMEM; 12344cc0e56eSJames Smart goto job_error; 1235f1c3b0fcSJames Smart } 1236a33c4f7bSJames Smart dd_data->type = TYPE_EVT; 1237a33c4f7bSJames Smart dd_data->set_job = NULL; 1238a33c4f7bSJames Smart dd_data->context_un.evt = evt; 1239a33c4f7bSJames Smart evt->dd_data = (void *)dd_data; 12404fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1241f1c3b0fcSJames Smart list_add(&evt->node, &phba->ct_ev_waiters); 12424cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 1243f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 12444cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 12454cc0e56eSJames Smart } 1246f1c3b0fcSJames Smart 12474fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 12484cc0e56eSJames Smart evt->waiting = 1; 1249a33c4f7bSJames Smart dd_data->set_job = job; /* for unsolicited command */ 12504cc0e56eSJames Smart job->dd_data = dd_data; /* for fc transport timeout callback*/ 12514fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 12524cc0e56eSJames Smart return 0; /* call job done later */ 1253f1c3b0fcSJames Smart 12544cc0e56eSJames Smart job_error: 12554cc0e56eSJames Smart kfree(dd_data); 12564cc0e56eSJames Smart job->dd_data = NULL; 12574cc0e56eSJames Smart return rc; 1258f1c3b0fcSJames Smart } 1259f1c3b0fcSJames Smart 1260f1c3b0fcSJames Smart /** 12614cc0e56eSJames Smart * lpfc_bsg_hba_get_event - process a GET_EVENT bsg vendor command 1262f1c3b0fcSJames Smart * @job: GET_EVENT fc_bsg_job 12633b5dd52aSJames Smart **/ 1264f1c3b0fcSJames Smart static int 126575cc8cfcSJohannes Thumshirn lpfc_bsg_hba_get_event(struct bsg_job *job) 1266f1c3b0fcSJames Smart { 1267cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 1268f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 126901e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 127001e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 1271f1c3b0fcSJames Smart struct get_ct_event *event_req; 1272f1c3b0fcSJames Smart struct get_ct_event_reply *event_reply; 12739a803a74SJames Smart struct lpfc_bsg_event *evt, *evt_next; 1274f1c3b0fcSJames Smart struct event_data *evt_dat = NULL; 12754fede78fSJames Smart unsigned long flags; 12764cc0e56eSJames Smart uint32_t rc = 0; 1277f1c3b0fcSJames Smart 1278f1c3b0fcSJames Smart if (job->request_len < 1279f1c3b0fcSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct get_ct_event)) { 1280f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1281f1c3b0fcSJames Smart "2613 Received GET_CT_EVENT request below " 1282f1c3b0fcSJames Smart "minimum size\n"); 12834cc0e56eSJames Smart rc = -EINVAL; 12844cc0e56eSJames Smart goto job_error; 1285f1c3b0fcSJames Smart } 1286f1c3b0fcSJames Smart 1287f1c3b0fcSJames Smart event_req = (struct get_ct_event *) 128801e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 1289f1c3b0fcSJames Smart 1290f1c3b0fcSJames Smart event_reply = (struct get_ct_event_reply *) 129101e0e15cSJohannes Thumshirn bsg_reply->reply_data.vendor_reply.vendor_rsp; 12924fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 12939a803a74SJames Smart list_for_each_entry_safe(evt, evt_next, &phba->ct_ev_waiters, node) { 1294f1c3b0fcSJames Smart if (evt->reg_id == event_req->ev_reg_id) { 1295f1c3b0fcSJames Smart if (list_empty(&evt->events_to_get)) 1296f1c3b0fcSJames Smart break; 12974cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 1298f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 1299f1c3b0fcSJames Smart evt_dat = list_entry(evt->events_to_get.prev, 1300f1c3b0fcSJames Smart struct event_data, node); 1301f1c3b0fcSJames Smart list_del(&evt_dat->node); 1302f1c3b0fcSJames Smart break; 1303f1c3b0fcSJames Smart } 1304f1c3b0fcSJames Smart } 13054fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 1306f1c3b0fcSJames Smart 13074cc0e56eSJames Smart /* The app may continue to ask for event data until it gets 13084cc0e56eSJames Smart * an error indicating that there isn't anymore 13094cc0e56eSJames Smart */ 13104cc0e56eSJames Smart if (evt_dat == NULL) { 131101e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 1312f1c3b0fcSJames Smart rc = -ENOENT; 13134cc0e56eSJames Smart goto job_error; 1314f1c3b0fcSJames Smart } 1315f1c3b0fcSJames Smart 13164cc0e56eSJames Smart if (evt_dat->len > job->request_payload.payload_len) { 13174cc0e56eSJames Smart evt_dat->len = job->request_payload.payload_len; 1318f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1319f1c3b0fcSJames Smart "2618 Truncated event data at %d " 1320f1c3b0fcSJames Smart "bytes\n", 13214cc0e56eSJames Smart job->request_payload.payload_len); 1322f1c3b0fcSJames Smart } 1323f1c3b0fcSJames Smart 13244cc0e56eSJames Smart event_reply->type = evt_dat->type; 1325f1c3b0fcSJames Smart event_reply->immed_data = evt_dat->immed_dat; 1326f1c3b0fcSJames Smart if (evt_dat->len > 0) 132701e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 13284cc0e56eSJames Smart sg_copy_from_buffer(job->request_payload.sg_list, 13294cc0e56eSJames Smart job->request_payload.sg_cnt, 1330f1c3b0fcSJames Smart evt_dat->data, evt_dat->len); 1331f1c3b0fcSJames Smart else 133201e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 1333f1c3b0fcSJames Smart 13344cc0e56eSJames Smart if (evt_dat) { 1335f1c3b0fcSJames Smart kfree(evt_dat->data); 1336f1c3b0fcSJames Smart kfree(evt_dat); 13374cc0e56eSJames Smart } 13384cc0e56eSJames Smart 13394fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 13404cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 13414fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 13424cc0e56eSJames Smart job->dd_data = NULL; 134301e0e15cSJohannes Thumshirn bsg_reply->result = 0; 134406548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 13451abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 13464cc0e56eSJames Smart return 0; 1347f1c3b0fcSJames Smart 13484cc0e56eSJames Smart job_error: 13494cc0e56eSJames Smart job->dd_data = NULL; 135001e0e15cSJohannes Thumshirn bsg_reply->result = rc; 1351f1c3b0fcSJames Smart return rc; 1352f1c3b0fcSJames Smart } 1353f1c3b0fcSJames Smart 1354f1c3b0fcSJames Smart /** 13553b5dd52aSJames Smart * lpfc_issue_ct_rsp_cmp - lpfc_issue_ct_rsp's completion handler 13563b5dd52aSJames Smart * @phba: Pointer to HBA context object. 13573b5dd52aSJames Smart * @cmdiocbq: Pointer to command iocb. 13583b5dd52aSJames Smart * @rspiocbq: Pointer to response iocb. 13593b5dd52aSJames Smart * 13603b5dd52aSJames Smart * This function is the completion handler for iocbs issued using 13613b5dd52aSJames Smart * lpfc_issue_ct_rsp_cmp function. This function is called by the 13623b5dd52aSJames Smart * ring event handler function without any lock held. This function 13633b5dd52aSJames Smart * can be called from both worker thread context and interrupt 13643b5dd52aSJames Smart * context. This function also can be called from other thread which 13653b5dd52aSJames Smart * cleans up the SLI layer objects. 13663b5dd52aSJames Smart * This function copy the contents of the response iocb to the 13673b5dd52aSJames Smart * response iocb memory object provided by the caller of 13683b5dd52aSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 13693b5dd52aSJames Smart * sleeps for the iocb completion. 13703b5dd52aSJames Smart **/ 13713b5dd52aSJames Smart static void 13723b5dd52aSJames Smart lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba, 13733b5dd52aSJames Smart struct lpfc_iocbq *cmdiocbq, 13743b5dd52aSJames Smart struct lpfc_iocbq *rspiocbq) 13753b5dd52aSJames Smart { 13763b5dd52aSJames Smart struct bsg_job_data *dd_data; 137775cc8cfcSJohannes Thumshirn struct bsg_job *job; 137801e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 13793b5dd52aSJames Smart IOCB_t *rsp; 1380a33c4f7bSJames Smart struct lpfc_dmabuf *bmp, *cmp; 13813b5dd52aSJames Smart struct lpfc_nodelist *ndlp; 13823b5dd52aSJames Smart unsigned long flags; 13833b5dd52aSJames Smart int rc = 0; 13843b5dd52aSJames Smart 1385a33c4f7bSJames Smart dd_data = cmdiocbq->context1; 1386a33c4f7bSJames Smart 1387a33c4f7bSJames Smart /* Determine if job has been aborted */ 13883b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1389a33c4f7bSJames Smart job = dd_data->set_job; 1390a33c4f7bSJames Smart if (job) { 1391a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 1392a33c4f7bSJames Smart job->dd_data = NULL; 13933b5dd52aSJames Smart } 1394a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 13953b5dd52aSJames Smart 1396b5a9b2dfSJames Smart /* Close the timeout handler abort window */ 1397b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 13981b8d11abSJames Smart cmdiocbq->iocb_flag &= ~LPFC_IO_CMD_OUTSTANDING; 1399b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 1400b5a9b2dfSJames Smart 14013b5dd52aSJames Smart ndlp = dd_data->context_un.iocb.ndlp; 1402a33c4f7bSJames Smart cmp = cmdiocbq->context2; 1403a33c4f7bSJames Smart bmp = cmdiocbq->context3; 1404a33c4f7bSJames Smart rsp = &rspiocbq->iocb; 14053b5dd52aSJames Smart 1406a33c4f7bSJames Smart /* Copy the completed job data or set the error status */ 14073b5dd52aSJames Smart 1408a33c4f7bSJames Smart if (job) { 140901e0e15cSJohannes Thumshirn bsg_reply = job->reply; 14103b5dd52aSJames Smart if (rsp->ulpStatus) { 14113b5dd52aSJames Smart if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { 1412e3d2b802SJames Smart switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) { 14133b5dd52aSJames Smart case IOERR_SEQUENCE_TIMEOUT: 14143b5dd52aSJames Smart rc = -ETIMEDOUT; 14153b5dd52aSJames Smart break; 14163b5dd52aSJames Smart case IOERR_INVALID_RPI: 14173b5dd52aSJames Smart rc = -EFAULT; 14183b5dd52aSJames Smart break; 14193b5dd52aSJames Smart default: 14203b5dd52aSJames Smart rc = -EACCES; 14213b5dd52aSJames Smart break; 14223b5dd52aSJames Smart } 1423a33c4f7bSJames Smart } else { 14243b5dd52aSJames Smart rc = -EACCES; 1425a33c4f7bSJames Smart } 1426a33c4f7bSJames Smart } else { 142701e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 1428a33c4f7bSJames Smart } 1429a33c4f7bSJames Smart } 14303b5dd52aSJames Smart 1431a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 14323b5dd52aSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 1433a33c4f7bSJames Smart kfree(bmp); 14343b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 14353b5dd52aSJames Smart lpfc_nlp_put(ndlp); 14363b5dd52aSJames Smart kfree(dd_data); 1437a33c4f7bSJames Smart 1438a33c4f7bSJames Smart /* Complete the job if the job is still active */ 1439a33c4f7bSJames Smart 1440a33c4f7bSJames Smart if (job) { 144101e0e15cSJohannes Thumshirn bsg_reply->result = rc; 144206548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 14431abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 1444a33c4f7bSJames Smart } 14453b5dd52aSJames Smart return; 14463b5dd52aSJames Smart } 14473b5dd52aSJames Smart 14483b5dd52aSJames Smart /** 14493b5dd52aSJames Smart * lpfc_issue_ct_rsp - issue a ct response 14503b5dd52aSJames Smart * @phba: Pointer to HBA context object. 14513b5dd52aSJames Smart * @job: Pointer to the job object. 14523b5dd52aSJames Smart * @tag: tag index value into the ports context exchange array. 1453ea085dabSLee Jones * @cmp: Pointer to a cmp dma buffer descriptor. 1454ea085dabSLee Jones * @bmp: Pointer to a bmp dma buffer descriptor. 14553b5dd52aSJames Smart * @num_entry: Number of enties in the bde. 14563b5dd52aSJames Smart **/ 14573b5dd52aSJames Smart static int 145875cc8cfcSJohannes Thumshirn lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct bsg_job *job, uint32_t tag, 1459a33c4f7bSJames Smart struct lpfc_dmabuf *cmp, struct lpfc_dmabuf *bmp, 1460a33c4f7bSJames Smart int num_entry) 14613b5dd52aSJames Smart { 14623b5dd52aSJames Smart IOCB_t *icmd; 14633b5dd52aSJames Smart struct lpfc_iocbq *ctiocb = NULL; 14643b5dd52aSJames Smart int rc = 0; 14653b5dd52aSJames Smart struct lpfc_nodelist *ndlp = NULL; 14663b5dd52aSJames Smart struct bsg_job_data *dd_data; 1467b5a9b2dfSJames Smart unsigned long flags; 14683b5dd52aSJames Smart uint32_t creg_val; 14693b5dd52aSJames Smart 14704430f7fdSJames Smart ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID); 14714430f7fdSJames Smart if (!ndlp) { 14724430f7fdSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, 14734430f7fdSJames Smart "2721 ndlp null for oxid %x SID %x\n", 14744430f7fdSJames Smart phba->ct_ctx[tag].rxid, 14754430f7fdSJames Smart phba->ct_ctx[tag].SID); 14764430f7fdSJames Smart return IOCB_ERROR; 14774430f7fdSJames Smart } 14784430f7fdSJames Smart 14793b5dd52aSJames Smart /* allocate our bsg tracking structure */ 14803b5dd52aSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 14813b5dd52aSJames Smart if (!dd_data) { 14823b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 14833b5dd52aSJames Smart "2736 Failed allocation of dd_data\n"); 14843b5dd52aSJames Smart rc = -ENOMEM; 14853b5dd52aSJames Smart goto no_dd_data; 14863b5dd52aSJames Smart } 14873b5dd52aSJames Smart 14883b5dd52aSJames Smart /* Allocate buffer for command iocb */ 14893b5dd52aSJames Smart ctiocb = lpfc_sli_get_iocbq(phba); 14903b5dd52aSJames Smart if (!ctiocb) { 1491d439d286SJames Smart rc = -ENOMEM; 14923b5dd52aSJames Smart goto no_ctiocb; 14933b5dd52aSJames Smart } 14943b5dd52aSJames Smart 14953b5dd52aSJames Smart icmd = &ctiocb->iocb; 14963b5dd52aSJames Smart icmd->un.xseq64.bdl.ulpIoTag32 = 0; 14973b5dd52aSJames Smart icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(bmp->phys); 14983b5dd52aSJames Smart icmd->un.xseq64.bdl.addrLow = putPaddrLow(bmp->phys); 14993b5dd52aSJames Smart icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 15003b5dd52aSJames Smart icmd->un.xseq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64)); 15013b5dd52aSJames Smart icmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); 15023b5dd52aSJames Smart icmd->un.xseq64.w5.hcsw.Dfctl = 0; 15033b5dd52aSJames Smart icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_SOL_CTL; 15043b5dd52aSJames Smart icmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; 15053b5dd52aSJames Smart 15063b5dd52aSJames Smart /* Fill in rest of iocb */ 15073b5dd52aSJames Smart icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; 15083b5dd52aSJames Smart icmd->ulpBdeCount = 1; 15093b5dd52aSJames Smart icmd->ulpLe = 1; 15103b5dd52aSJames Smart icmd->ulpClass = CLASS3; 15113b5dd52aSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) { 15123b5dd52aSJames Smart /* Do not issue unsol response if oxid not marked as valid */ 15136dd9e31cSJames Smart if (phba->ct_ctx[tag].valid != UNSOL_VALID) { 15143b5dd52aSJames Smart rc = IOCB_ERROR; 15153b5dd52aSJames Smart goto issue_ct_rsp_exit; 15163b5dd52aSJames Smart } 15177851fe2cSJames Smart icmd->ulpContext = phba->ct_ctx[tag].rxid; 15187851fe2cSJames Smart icmd->unsli3.rcvsli3.ox_id = phba->ct_ctx[tag].oxid; 15193b5dd52aSJames Smart ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID); 15203b5dd52aSJames Smart if (!ndlp) { 15213b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, 15223b5dd52aSJames Smart "2721 ndlp null for oxid %x SID %x\n", 15233b5dd52aSJames Smart icmd->ulpContext, 15243b5dd52aSJames Smart phba->ct_ctx[tag].SID); 15253b5dd52aSJames Smart rc = IOCB_ERROR; 15263b5dd52aSJames Smart goto issue_ct_rsp_exit; 15273b5dd52aSJames Smart } 1528589a52d6SJames Smart 1529589a52d6SJames Smart /* get a refernece count so the ndlp doesn't go away while 1530589a52d6SJames Smart * we respond 1531589a52d6SJames Smart */ 1532589a52d6SJames Smart if (!lpfc_nlp_get(ndlp)) { 1533a33c4f7bSJames Smart rc = IOCB_ERROR; 1534589a52d6SJames Smart goto issue_ct_rsp_exit; 1535589a52d6SJames Smart } 1536589a52d6SJames Smart 15377851fe2cSJames Smart icmd->un.ulpWord[3] = 15386d368e53SJames Smart phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; 15396d368e53SJames Smart 15403b5dd52aSJames Smart /* The exchange is done, mark the entry as invalid */ 15416dd9e31cSJames Smart phba->ct_ctx[tag].valid = UNSOL_INVALID; 15423b5dd52aSJames Smart } else 15433b5dd52aSJames Smart icmd->ulpContext = (ushort) tag; 15443b5dd52aSJames Smart 15453b5dd52aSJames Smart icmd->ulpTimeout = phba->fc_ratov * 2; 15463b5dd52aSJames Smart 15473b5dd52aSJames Smart /* Xmit CT response on exchange <xid> */ 15483b5dd52aSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_ELS, 15497851fe2cSJames Smart "2722 Xmit CT response on exchange x%x Data: x%x x%x x%x\n", 15507851fe2cSJames Smart icmd->ulpContext, icmd->ulpIoTag, tag, phba->link_state); 15513b5dd52aSJames Smart 15523b5dd52aSJames Smart ctiocb->iocb_flag |= LPFC_IO_LIBDFC; 15533b5dd52aSJames Smart ctiocb->vport = phba->pport; 1554a33c4f7bSJames Smart ctiocb->context1 = dd_data; 1555a33c4f7bSJames Smart ctiocb->context2 = cmp; 15563b5dd52aSJames Smart ctiocb->context3 = bmp; 1557d5ce53b7SJames Smart ctiocb->context_un.ndlp = ndlp; 15583b5dd52aSJames Smart ctiocb->iocb_cmpl = lpfc_issue_ct_rsp_cmp; 1559a33c4f7bSJames Smart 15603b5dd52aSJames Smart dd_data->type = TYPE_IOCB; 1561a33c4f7bSJames Smart dd_data->set_job = job; 15623b5dd52aSJames Smart dd_data->context_un.iocb.cmdiocbq = ctiocb; 15634430f7fdSJames Smart dd_data->context_un.iocb.ndlp = lpfc_nlp_get(ndlp); 15644430f7fdSJames Smart if (!dd_data->context_un.iocb.ndlp) { 15654430f7fdSJames Smart rc = -IOCB_ERROR; 15664430f7fdSJames Smart goto issue_ct_rsp_exit; 15674430f7fdSJames Smart } 1568a33c4f7bSJames Smart dd_data->context_un.iocb.rmp = NULL; 1569a33c4f7bSJames Smart job->dd_data = dd_data; 15703b5dd52aSJames Smart 15713b5dd52aSJames Smart if (phba->cfg_poll & DISABLE_FCP_RING_INT) { 15729940b97bSJames Smart if (lpfc_readl(phba->HCregaddr, &creg_val)) { 15739940b97bSJames Smart rc = -IOCB_ERROR; 15749940b97bSJames Smart goto issue_ct_rsp_exit; 15759940b97bSJames Smart } 15763b5dd52aSJames Smart creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); 15773b5dd52aSJames Smart writel(creg_val, phba->HCregaddr); 15783b5dd52aSJames Smart readl(phba->HCregaddr); /* flush */ 15793b5dd52aSJames Smart } 15803b5dd52aSJames Smart 15813b5dd52aSJames Smart rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); 1582b5a9b2dfSJames Smart if (rc == IOCB_SUCCESS) { 1583b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 1584b5a9b2dfSJames Smart /* make sure the I/O had not been completed/released */ 1585b5a9b2dfSJames Smart if (ctiocb->iocb_flag & LPFC_IO_LIBDFC) { 1586b5a9b2dfSJames Smart /* open up abort window to timeout handler */ 15871b8d11abSJames Smart ctiocb->iocb_flag |= LPFC_IO_CMD_OUTSTANDING; 1588b5a9b2dfSJames Smart } 1589b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 15903b5dd52aSJames Smart return 0; /* done for now */ 1591b5a9b2dfSJames Smart } 1592b5a9b2dfSJames Smart 1593b5a9b2dfSJames Smart /* iocb failed so cleanup */ 1594b5a9b2dfSJames Smart job->dd_data = NULL; 15954430f7fdSJames Smart lpfc_nlp_put(ndlp); 15963b5dd52aSJames Smart 15973b5dd52aSJames Smart issue_ct_rsp_exit: 15983b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, ctiocb); 15993b5dd52aSJames Smart no_ctiocb: 16003b5dd52aSJames Smart kfree(dd_data); 16013b5dd52aSJames Smart no_dd_data: 16023b5dd52aSJames Smart return rc; 16033b5dd52aSJames Smart } 16043b5dd52aSJames Smart 16053b5dd52aSJames Smart /** 16063b5dd52aSJames Smart * lpfc_bsg_send_mgmt_rsp - process a SEND_MGMT_RESP bsg vendor command 16073b5dd52aSJames Smart * @job: SEND_MGMT_RESP fc_bsg_job 16083b5dd52aSJames Smart **/ 16093b5dd52aSJames Smart static int 161075cc8cfcSJohannes Thumshirn lpfc_bsg_send_mgmt_rsp(struct bsg_job *job) 16113b5dd52aSJames Smart { 1612cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 16133b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 161401e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 161501e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 16163b5dd52aSJames Smart struct send_mgmt_resp *mgmt_resp = (struct send_mgmt_resp *) 161701e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 16183b5dd52aSJames Smart struct ulp_bde64 *bpl; 1619a33c4f7bSJames Smart struct lpfc_dmabuf *bmp = NULL, *cmp = NULL; 1620a33c4f7bSJames Smart int bpl_entries; 16213b5dd52aSJames Smart uint32_t tag = mgmt_resp->tag; 16223b5dd52aSJames Smart unsigned long reqbfrcnt = 16233b5dd52aSJames Smart (unsigned long)job->request_payload.payload_len; 16243b5dd52aSJames Smart int rc = 0; 16253b5dd52aSJames Smart 16263b5dd52aSJames Smart /* in case no data is transferred */ 162701e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 16283b5dd52aSJames Smart 16293b5dd52aSJames Smart if (!reqbfrcnt || (reqbfrcnt > (80 * BUF_SZ_4K))) { 16303b5dd52aSJames Smart rc = -ERANGE; 16313b5dd52aSJames Smart goto send_mgmt_rsp_exit; 16323b5dd52aSJames Smart } 16333b5dd52aSJames Smart 16343b5dd52aSJames Smart bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 16353b5dd52aSJames Smart if (!bmp) { 16363b5dd52aSJames Smart rc = -ENOMEM; 16373b5dd52aSJames Smart goto send_mgmt_rsp_exit; 16383b5dd52aSJames Smart } 16393b5dd52aSJames Smart 16403b5dd52aSJames Smart bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); 16413b5dd52aSJames Smart if (!bmp->virt) { 16423b5dd52aSJames Smart rc = -ENOMEM; 16433b5dd52aSJames Smart goto send_mgmt_rsp_free_bmp; 16443b5dd52aSJames Smart } 16453b5dd52aSJames Smart 16463b5dd52aSJames Smart INIT_LIST_HEAD(&bmp->list); 16473b5dd52aSJames Smart bpl = (struct ulp_bde64 *) bmp->virt; 1648a33c4f7bSJames Smart bpl_entries = (LPFC_BPL_SIZE/sizeof(struct ulp_bde64)); 1649a33c4f7bSJames Smart cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len, 1650a33c4f7bSJames Smart 1, bpl, &bpl_entries); 1651a33c4f7bSJames Smart if (!cmp) { 1652a33c4f7bSJames Smart rc = -ENOMEM; 1653a33c4f7bSJames Smart goto send_mgmt_rsp_free_bmp; 16543b5dd52aSJames Smart } 1655a33c4f7bSJames Smart lpfc_bsg_copy_data(cmp, &job->request_payload, 1656a33c4f7bSJames Smart job->request_payload.payload_len, 1); 16573b5dd52aSJames Smart 1658a33c4f7bSJames Smart rc = lpfc_issue_ct_rsp(phba, job, tag, cmp, bmp, bpl_entries); 16593b5dd52aSJames Smart 16603b5dd52aSJames Smart if (rc == IOCB_SUCCESS) 16613b5dd52aSJames Smart return 0; /* done for now */ 16623b5dd52aSJames Smart 16633b5dd52aSJames Smart rc = -EACCES; 1664a33c4f7bSJames Smart 1665a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 16663b5dd52aSJames Smart 16673b5dd52aSJames Smart send_mgmt_rsp_free_bmp: 1668a33c4f7bSJames Smart if (bmp->virt) 1669a33c4f7bSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 16703b5dd52aSJames Smart kfree(bmp); 16713b5dd52aSJames Smart send_mgmt_rsp_exit: 16723b5dd52aSJames Smart /* make error code available to userspace */ 167301e0e15cSJohannes Thumshirn bsg_reply->result = rc; 16743b5dd52aSJames Smart job->dd_data = NULL; 16753b5dd52aSJames Smart return rc; 16763b5dd52aSJames Smart } 16773b5dd52aSJames Smart 16783b5dd52aSJames Smart /** 16797ad20aa9SJames Smart * lpfc_bsg_diag_mode_enter - process preparing into device diag loopback mode 16807ad20aa9SJames Smart * @phba: Pointer to HBA context object. 16813b5dd52aSJames Smart * 16827ad20aa9SJames Smart * This function is responsible for preparing driver for diag loopback 16837ad20aa9SJames Smart * on device. 16843b5dd52aSJames Smart */ 16853b5dd52aSJames Smart static int 168688a2cfbbSJames Smart lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba) 16873b5dd52aSJames Smart { 16883b5dd52aSJames Smart struct lpfc_vport **vports; 16897ad20aa9SJames Smart struct Scsi_Host *shost; 16907ad20aa9SJames Smart struct lpfc_sli *psli; 1691895427bdSJames Smart struct lpfc_queue *qp = NULL; 16927ad20aa9SJames Smart struct lpfc_sli_ring *pring; 16933b5dd52aSJames Smart int i = 0; 16943b5dd52aSJames Smart 16957ad20aa9SJames Smart psli = &phba->sli; 16967ad20aa9SJames Smart if (!psli) 16977ad20aa9SJames Smart return -ENODEV; 16983b5dd52aSJames Smart 16993b5dd52aSJames Smart 17003b5dd52aSJames Smart if ((phba->link_state == LPFC_HBA_ERROR) || 17013b5dd52aSJames Smart (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || 17027ad20aa9SJames Smart (!(psli->sli_flag & LPFC_SLI_ACTIVE))) 17037ad20aa9SJames Smart return -EACCES; 17043b5dd52aSJames Smart 17053b5dd52aSJames Smart vports = lpfc_create_vport_work_array(phba); 17063b5dd52aSJames Smart if (vports) { 17073b5dd52aSJames Smart for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { 17083b5dd52aSJames Smart shost = lpfc_shost_from_vport(vports[i]); 17093b5dd52aSJames Smart scsi_block_requests(shost); 17103b5dd52aSJames Smart } 17113b5dd52aSJames Smart lpfc_destroy_vport_work_array(phba, vports); 17123b5dd52aSJames Smart } else { 17133b5dd52aSJames Smart shost = lpfc_shost_from_vport(phba->pport); 17143b5dd52aSJames Smart scsi_block_requests(shost); 17153b5dd52aSJames Smart } 17163b5dd52aSJames Smart 1717895427bdSJames Smart if (phba->sli_rev != LPFC_SLI_REV4) { 1718895427bdSJames Smart pring = &psli->sli3_ring[LPFC_FCP_RING]; 1719895427bdSJames Smart lpfc_emptyq_wait(phba, &pring->txcmplq, &phba->hbalock); 1720895427bdSJames Smart return 0; 1721895427bdSJames Smart } 1722895427bdSJames Smart list_for_each_entry(qp, &phba->sli4_hba.lpfc_wq_list, wq_list) { 1723895427bdSJames Smart pring = qp->pring; 1724895427bdSJames Smart if (!pring || (pring->ringno != LPFC_FCP_RING)) 1725895427bdSJames Smart continue; 1726895427bdSJames Smart if (!lpfc_emptyq_wait(phba, &pring->txcmplq, 1727895427bdSJames Smart &pring->ring_lock)) 17283b5dd52aSJames Smart break; 17293b5dd52aSJames Smart } 17307ad20aa9SJames Smart return 0; 17317ad20aa9SJames Smart } 17323b5dd52aSJames Smart 17337ad20aa9SJames Smart /** 17347ad20aa9SJames Smart * lpfc_bsg_diag_mode_exit - exit process from device diag loopback mode 17357ad20aa9SJames Smart * @phba: Pointer to HBA context object. 17367ad20aa9SJames Smart * 17377ad20aa9SJames Smart * This function is responsible for driver exit processing of setting up 17387ad20aa9SJames Smart * diag loopback mode on device. 17397ad20aa9SJames Smart */ 17407ad20aa9SJames Smart static void 17417ad20aa9SJames Smart lpfc_bsg_diag_mode_exit(struct lpfc_hba *phba) 17427ad20aa9SJames Smart { 17437ad20aa9SJames Smart struct Scsi_Host *shost; 17447ad20aa9SJames Smart struct lpfc_vport **vports; 17457ad20aa9SJames Smart int i; 17467ad20aa9SJames Smart 17477ad20aa9SJames Smart vports = lpfc_create_vport_work_array(phba); 17487ad20aa9SJames Smart if (vports) { 17497ad20aa9SJames Smart for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { 17507ad20aa9SJames Smart shost = lpfc_shost_from_vport(vports[i]); 17517ad20aa9SJames Smart scsi_unblock_requests(shost); 17527ad20aa9SJames Smart } 17537ad20aa9SJames Smart lpfc_destroy_vport_work_array(phba, vports); 17547ad20aa9SJames Smart } else { 17557ad20aa9SJames Smart shost = lpfc_shost_from_vport(phba->pport); 17567ad20aa9SJames Smart scsi_unblock_requests(shost); 17577ad20aa9SJames Smart } 17587ad20aa9SJames Smart return; 17597ad20aa9SJames Smart } 17607ad20aa9SJames Smart 17617ad20aa9SJames Smart /** 17627ad20aa9SJames Smart * lpfc_sli3_bsg_diag_loopback_mode - process an sli3 bsg vendor command 17637ad20aa9SJames Smart * @phba: Pointer to HBA context object. 17647ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_MODE 17657ad20aa9SJames Smart * 17667ad20aa9SJames Smart * This function is responsible for placing an sli3 port into diagnostic 17677ad20aa9SJames Smart * loopback mode in order to perform a diagnostic loopback test. 17687ad20aa9SJames Smart * All new scsi requests are blocked, a small delay is used to allow the 17697ad20aa9SJames Smart * scsi requests to complete then the link is brought down. If the link is 17707ad20aa9SJames Smart * is placed in loopback mode then scsi requests are again allowed 17717ad20aa9SJames Smart * so the scsi mid-layer doesn't give up on the port. 17727ad20aa9SJames Smart * All of this is done in-line. 17737ad20aa9SJames Smart */ 17747ad20aa9SJames Smart static int 177575cc8cfcSJohannes Thumshirn lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job) 17767ad20aa9SJames Smart { 177701e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 177801e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 17797ad20aa9SJames Smart struct diag_mode_set *loopback_mode; 17807ad20aa9SJames Smart uint32_t link_flags; 17817ad20aa9SJames Smart uint32_t timeout; 17821b51197dSJames Smart LPFC_MBOXQ_t *pmboxq = NULL; 1783b76f2dc9SJames Smart int mbxstatus = MBX_SUCCESS; 17847ad20aa9SJames Smart int i = 0; 17857ad20aa9SJames Smart int rc = 0; 17867ad20aa9SJames Smart 17877ad20aa9SJames Smart /* no data to return just the return code */ 178801e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 17897ad20aa9SJames Smart 17907ad20aa9SJames Smart if (job->request_len < sizeof(struct fc_bsg_request) + 17917ad20aa9SJames Smart sizeof(struct diag_mode_set)) { 17927ad20aa9SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 17937ad20aa9SJames Smart "2738 Received DIAG MODE request size:%d " 17947ad20aa9SJames Smart "below the minimum size:%d\n", 17957ad20aa9SJames Smart job->request_len, 17967ad20aa9SJames Smart (int)(sizeof(struct fc_bsg_request) + 17977ad20aa9SJames Smart sizeof(struct diag_mode_set))); 17987ad20aa9SJames Smart rc = -EINVAL; 17997ad20aa9SJames Smart goto job_error; 18007ad20aa9SJames Smart } 18017ad20aa9SJames Smart 180288a2cfbbSJames Smart rc = lpfc_bsg_diag_mode_enter(phba); 18037ad20aa9SJames Smart if (rc) 18047ad20aa9SJames Smart goto job_error; 18057ad20aa9SJames Smart 18067ad20aa9SJames Smart /* bring the link to diagnostic mode */ 18077ad20aa9SJames Smart loopback_mode = (struct diag_mode_set *) 180801e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 18097ad20aa9SJames Smart link_flags = loopback_mode->type; 18107ad20aa9SJames Smart timeout = loopback_mode->timeout * 100; 18117ad20aa9SJames Smart 18127ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 18137ad20aa9SJames Smart if (!pmboxq) { 18147ad20aa9SJames Smart rc = -ENOMEM; 18157ad20aa9SJames Smart goto loopback_mode_exit; 18167ad20aa9SJames Smart } 18173b5dd52aSJames Smart memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 18183b5dd52aSJames Smart pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK; 18193b5dd52aSJames Smart pmboxq->u.mb.mbxOwner = OWN_HOST; 18203b5dd52aSJames Smart 18213b5dd52aSJames Smart mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); 18223b5dd52aSJames Smart 18233b5dd52aSJames Smart if ((mbxstatus == MBX_SUCCESS) && (pmboxq->u.mb.mbxStatus == 0)) { 18243b5dd52aSJames Smart /* wait for link down before proceeding */ 18253b5dd52aSJames Smart i = 0; 18263b5dd52aSJames Smart while (phba->link_state != LPFC_LINK_DOWN) { 18273b5dd52aSJames Smart if (i++ > timeout) { 18283b5dd52aSJames Smart rc = -ETIMEDOUT; 18293b5dd52aSJames Smart goto loopback_mode_exit; 18303b5dd52aSJames Smart } 18313b5dd52aSJames Smart msleep(10); 18323b5dd52aSJames Smart } 18333b5dd52aSJames Smart 18343b5dd52aSJames Smart memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 18353b5dd52aSJames Smart if (link_flags == INTERNAL_LOOP_BACK) 18363b5dd52aSJames Smart pmboxq->u.mb.un.varInitLnk.link_flags = FLAGS_LOCAL_LB; 18373b5dd52aSJames Smart else 18383b5dd52aSJames Smart pmboxq->u.mb.un.varInitLnk.link_flags = 18393b5dd52aSJames Smart FLAGS_TOPOLOGY_MODE_LOOP; 18403b5dd52aSJames Smart 18413b5dd52aSJames Smart pmboxq->u.mb.mbxCommand = MBX_INIT_LINK; 18423b5dd52aSJames Smart pmboxq->u.mb.mbxOwner = OWN_HOST; 18433b5dd52aSJames Smart 18443b5dd52aSJames Smart mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, 18453b5dd52aSJames Smart LPFC_MBOX_TMO); 18463b5dd52aSJames Smart 18473b5dd52aSJames Smart if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) 18483b5dd52aSJames Smart rc = -ENODEV; 18493b5dd52aSJames Smart else { 18501b51197dSJames Smart spin_lock_irq(&phba->hbalock); 18513b5dd52aSJames Smart phba->link_flag |= LS_LOOPBACK_MODE; 18521b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 18533b5dd52aSJames Smart /* wait for the link attention interrupt */ 18543b5dd52aSJames Smart msleep(100); 18553b5dd52aSJames Smart 18563b5dd52aSJames Smart i = 0; 18573b5dd52aSJames Smart while (phba->link_state != LPFC_HBA_READY) { 18583b5dd52aSJames Smart if (i++ > timeout) { 18593b5dd52aSJames Smart rc = -ETIMEDOUT; 18603b5dd52aSJames Smart break; 18613b5dd52aSJames Smart } 18623b5dd52aSJames Smart 18633b5dd52aSJames Smart msleep(10); 18643b5dd52aSJames Smart } 18653b5dd52aSJames Smart } 18663b5dd52aSJames Smart 18673b5dd52aSJames Smart } else 18683b5dd52aSJames Smart rc = -ENODEV; 18693b5dd52aSJames Smart 18703b5dd52aSJames Smart loopback_mode_exit: 18717ad20aa9SJames Smart lpfc_bsg_diag_mode_exit(phba); 18723b5dd52aSJames Smart 18733b5dd52aSJames Smart /* 18743b5dd52aSJames Smart * Let SLI layer release mboxq if mbox command completed after timeout. 18753b5dd52aSJames Smart */ 18761b51197dSJames Smart if (pmboxq && mbxstatus != MBX_TIMEOUT) 18773b5dd52aSJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 18783b5dd52aSJames Smart 18793b5dd52aSJames Smart job_error: 18803b5dd52aSJames Smart /* make error code available to userspace */ 188101e0e15cSJohannes Thumshirn bsg_reply->result = rc; 18823b5dd52aSJames Smart /* complete the job back to userspace if no error */ 18833b5dd52aSJames Smart if (rc == 0) 188406548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 18851abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 18863b5dd52aSJames Smart return rc; 18873b5dd52aSJames Smart } 18883b5dd52aSJames Smart 18893b5dd52aSJames Smart /** 18907ad20aa9SJames Smart * lpfc_sli4_bsg_set_link_diag_state - set sli4 link diag state 18917ad20aa9SJames Smart * @phba: Pointer to HBA context object. 18927ad20aa9SJames Smart * @diag: Flag for set link to diag or nomral operation state. 18937ad20aa9SJames Smart * 18947ad20aa9SJames Smart * This function is responsible for issuing a sli4 mailbox command for setting 18957ad20aa9SJames Smart * link to either diag state or normal operation state. 18967ad20aa9SJames Smart */ 18977ad20aa9SJames Smart static int 18987ad20aa9SJames Smart lpfc_sli4_bsg_set_link_diag_state(struct lpfc_hba *phba, uint32_t diag) 18997ad20aa9SJames Smart { 19007ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq; 19017ad20aa9SJames Smart struct lpfc_mbx_set_link_diag_state *link_diag_state; 19027ad20aa9SJames Smart uint32_t req_len, alloc_len; 19037ad20aa9SJames Smart int mbxstatus = MBX_SUCCESS, rc; 19047ad20aa9SJames Smart 19057ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 19067ad20aa9SJames Smart if (!pmboxq) 19077ad20aa9SJames Smart return -ENOMEM; 19087ad20aa9SJames Smart 19097ad20aa9SJames Smart req_len = (sizeof(struct lpfc_mbx_set_link_diag_state) - 19107ad20aa9SJames Smart sizeof(struct lpfc_sli4_cfg_mhdr)); 19117ad20aa9SJames Smart alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, 19127ad20aa9SJames Smart LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE, 19137ad20aa9SJames Smart req_len, LPFC_SLI4_MBX_EMBED); 19147ad20aa9SJames Smart if (alloc_len != req_len) { 19157ad20aa9SJames Smart rc = -ENOMEM; 19167ad20aa9SJames Smart goto link_diag_state_set_out; 19177ad20aa9SJames Smart } 19181b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 19191b51197dSJames Smart "3128 Set link to diagnostic state:x%x (x%x/x%x)\n", 19201b51197dSJames Smart diag, phba->sli4_hba.lnk_info.lnk_tp, 19211b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_no); 19221b51197dSJames Smart 19237ad20aa9SJames Smart link_diag_state = &pmboxq->u.mqe.un.link_diag_state; 19249731592bSJames Smart bf_set(lpfc_mbx_set_diag_state_diag_bit_valid, &link_diag_state->u.req, 19259731592bSJames Smart LPFC_DIAG_STATE_DIAG_BIT_VALID_CHANGE); 19267ad20aa9SJames Smart bf_set(lpfc_mbx_set_diag_state_link_num, &link_diag_state->u.req, 19271b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_no); 19287ad20aa9SJames Smart bf_set(lpfc_mbx_set_diag_state_link_type, &link_diag_state->u.req, 19291b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_tp); 19307ad20aa9SJames Smart if (diag) 19317ad20aa9SJames Smart bf_set(lpfc_mbx_set_diag_state_diag, 19327ad20aa9SJames Smart &link_diag_state->u.req, 1); 19337ad20aa9SJames Smart else 19347ad20aa9SJames Smart bf_set(lpfc_mbx_set_diag_state_diag, 19357ad20aa9SJames Smart &link_diag_state->u.req, 0); 19367ad20aa9SJames Smart 19377ad20aa9SJames Smart mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); 19387ad20aa9SJames Smart 19397ad20aa9SJames Smart if ((mbxstatus == MBX_SUCCESS) && (pmboxq->u.mb.mbxStatus == 0)) 19407ad20aa9SJames Smart rc = 0; 19417ad20aa9SJames Smart else 19427ad20aa9SJames Smart rc = -ENODEV; 19437ad20aa9SJames Smart 19447ad20aa9SJames Smart link_diag_state_set_out: 19457ad20aa9SJames Smart if (pmboxq && (mbxstatus != MBX_TIMEOUT)) 19467ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 19477ad20aa9SJames Smart 19487ad20aa9SJames Smart return rc; 19497ad20aa9SJames Smart } 19507ad20aa9SJames Smart 19517ad20aa9SJames Smart /** 19529a66d990SJames Smart * lpfc_sli4_bsg_set_loopback_mode - set sli4 internal loopback diagnostic 19531b51197dSJames Smart * @phba: Pointer to HBA context object. 19549a66d990SJames Smart * @mode: loopback mode to set 19559a66d990SJames Smart * @link_no: link number for loopback mode to set 19561b51197dSJames Smart * 19571b51197dSJames Smart * This function is responsible for issuing a sli4 mailbox command for setting 19589a66d990SJames Smart * up loopback diagnostic for a link. 19591b51197dSJames Smart */ 19601b51197dSJames Smart static int 19619a66d990SJames Smart lpfc_sli4_bsg_set_loopback_mode(struct lpfc_hba *phba, int mode, 19629a66d990SJames Smart uint32_t link_no) 19631b51197dSJames Smart { 19641b51197dSJames Smart LPFC_MBOXQ_t *pmboxq; 19651b51197dSJames Smart uint32_t req_len, alloc_len; 19661b51197dSJames Smart struct lpfc_mbx_set_link_diag_loopback *link_diag_loopback; 19671b51197dSJames Smart int mbxstatus = MBX_SUCCESS, rc = 0; 19681b51197dSJames Smart 19691b51197dSJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 19701b51197dSJames Smart if (!pmboxq) 19711b51197dSJames Smart return -ENOMEM; 19721b51197dSJames Smart req_len = (sizeof(struct lpfc_mbx_set_link_diag_loopback) - 19731b51197dSJames Smart sizeof(struct lpfc_sli4_cfg_mhdr)); 19741b51197dSJames Smart alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, 19751b51197dSJames Smart LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK, 19761b51197dSJames Smart req_len, LPFC_SLI4_MBX_EMBED); 19771b51197dSJames Smart if (alloc_len != req_len) { 19781b51197dSJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 19791b51197dSJames Smart return -ENOMEM; 19801b51197dSJames Smart } 19811b51197dSJames Smart link_diag_loopback = &pmboxq->u.mqe.un.link_diag_loopback; 19821b51197dSJames Smart bf_set(lpfc_mbx_set_diag_state_link_num, 19839a66d990SJames Smart &link_diag_loopback->u.req, link_no); 19849a66d990SJames Smart 19859a66d990SJames Smart if (phba->sli4_hba.conf_trunk & (1 << link_no)) { 19861b51197dSJames Smart bf_set(lpfc_mbx_set_diag_state_link_type, 19879a66d990SJames Smart &link_diag_loopback->u.req, LPFC_LNK_FC_TRUNKED); 19889a66d990SJames Smart } else { 19899a66d990SJames Smart bf_set(lpfc_mbx_set_diag_state_link_type, 19909a66d990SJames Smart &link_diag_loopback->u.req, 19919a66d990SJames Smart phba->sli4_hba.lnk_info.lnk_tp); 19929a66d990SJames Smart } 19939a66d990SJames Smart 19941b51197dSJames Smart bf_set(lpfc_mbx_set_diag_lpbk_type, &link_diag_loopback->u.req, 19959a66d990SJames Smart mode); 19961b51197dSJames Smart 19971b51197dSJames Smart mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); 19981b51197dSJames Smart if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) { 19991b51197dSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 20001b51197dSJames Smart "3127 Failed setup loopback mode mailbox " 20011b51197dSJames Smart "command, rc:x%x, status:x%x\n", mbxstatus, 20021b51197dSJames Smart pmboxq->u.mb.mbxStatus); 20031b51197dSJames Smart rc = -ENODEV; 20041b51197dSJames Smart } 20051b51197dSJames Smart if (pmboxq && (mbxstatus != MBX_TIMEOUT)) 20061b51197dSJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 20071b51197dSJames Smart return rc; 20081b51197dSJames Smart } 20091b51197dSJames Smart 20101b51197dSJames Smart /** 20111b51197dSJames Smart * lpfc_sli4_diag_fcport_reg_setup - setup port registrations for diagnostic 20121b51197dSJames Smart * @phba: Pointer to HBA context object. 20131b51197dSJames Smart * 20141b51197dSJames Smart * This function set up SLI4 FC port registrations for diagnostic run, which 20151b51197dSJames Smart * includes all the rpis, vfi, and also vpi. 20161b51197dSJames Smart */ 20171b51197dSJames Smart static int 20181b51197dSJames Smart lpfc_sli4_diag_fcport_reg_setup(struct lpfc_hba *phba) 20191b51197dSJames Smart { 20201b51197dSJames Smart int rc; 20211b51197dSJames Smart 20221b51197dSJames Smart if (phba->pport->fc_flag & FC_VFI_REGISTERED) { 20231b51197dSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 20241b51197dSJames Smart "3136 Port still had vfi registered: " 20251b51197dSJames Smart "mydid:x%x, fcfi:%d, vfi:%d, vpi:%d\n", 20261b51197dSJames Smart phba->pport->fc_myDID, phba->fcf.fcfi, 20271b51197dSJames Smart phba->sli4_hba.vfi_ids[phba->pport->vfi], 20281b51197dSJames Smart phba->vpi_ids[phba->pport->vpi]); 20291b51197dSJames Smart return -EINVAL; 20301b51197dSJames Smart } 20311b51197dSJames Smart rc = lpfc_issue_reg_vfi(phba->pport); 20321b51197dSJames Smart return rc; 20331b51197dSJames Smart } 20341b51197dSJames Smart 20351b51197dSJames Smart /** 20367ad20aa9SJames Smart * lpfc_sli4_bsg_diag_loopback_mode - process an sli4 bsg vendor command 20377ad20aa9SJames Smart * @phba: Pointer to HBA context object. 20387ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_MODE 20397ad20aa9SJames Smart * 20407ad20aa9SJames Smart * This function is responsible for placing an sli4 port into diagnostic 20417ad20aa9SJames Smart * loopback mode in order to perform a diagnostic loopback test. 20427ad20aa9SJames Smart */ 20437ad20aa9SJames Smart static int 204475cc8cfcSJohannes Thumshirn lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job) 20457ad20aa9SJames Smart { 204601e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 204701e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 20487ad20aa9SJames Smart struct diag_mode_set *loopback_mode; 20499a66d990SJames Smart uint32_t link_flags, timeout, link_no; 20501b51197dSJames Smart int i, rc = 0; 20517ad20aa9SJames Smart 20527ad20aa9SJames Smart /* no data to return just the return code */ 205301e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 20547ad20aa9SJames Smart 20557ad20aa9SJames Smart if (job->request_len < sizeof(struct fc_bsg_request) + 20567ad20aa9SJames Smart sizeof(struct diag_mode_set)) { 20577ad20aa9SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 20587ad20aa9SJames Smart "3011 Received DIAG MODE request size:%d " 20597ad20aa9SJames Smart "below the minimum size:%d\n", 20607ad20aa9SJames Smart job->request_len, 20617ad20aa9SJames Smart (int)(sizeof(struct fc_bsg_request) + 20627ad20aa9SJames Smart sizeof(struct diag_mode_set))); 20637ad20aa9SJames Smart rc = -EINVAL; 20649a66d990SJames Smart goto job_done; 20659a66d990SJames Smart } 20669a66d990SJames Smart 20679a66d990SJames Smart loopback_mode = (struct diag_mode_set *) 20689a66d990SJames Smart bsg_request->rqst_data.h_vendor.vendor_cmd; 20699a66d990SJames Smart link_flags = loopback_mode->type; 20709a66d990SJames Smart timeout = loopback_mode->timeout * 100; 20719a66d990SJames Smart 20729a66d990SJames Smart if (loopback_mode->physical_link == -1) 20739a66d990SJames Smart link_no = phba->sli4_hba.lnk_info.lnk_no; 20749a66d990SJames Smart else 20759a66d990SJames Smart link_no = loopback_mode->physical_link; 20769a66d990SJames Smart 20779a66d990SJames Smart if (link_flags == DISABLE_LOOP_BACK) { 20789a66d990SJames Smart rc = lpfc_sli4_bsg_set_loopback_mode(phba, 20799a66d990SJames Smart LPFC_DIAG_LOOPBACK_TYPE_DISABLE, 20809a66d990SJames Smart link_no); 20819a66d990SJames Smart if (!rc) { 20829a66d990SJames Smart /* Unset the need disable bit */ 20839a66d990SJames Smart phba->sli4_hba.conf_trunk &= ~((1 << link_no) << 4); 20849a66d990SJames Smart } 20859a66d990SJames Smart goto job_done; 20869a66d990SJames Smart } else { 20879a66d990SJames Smart /* Check if we need to disable the loopback state */ 20889a66d990SJames Smart if (phba->sli4_hba.conf_trunk & ((1 << link_no) << 4)) { 20899a66d990SJames Smart rc = -EPERM; 20909a66d990SJames Smart goto job_done; 20919a66d990SJames Smart } 20927ad20aa9SJames Smart } 20937ad20aa9SJames Smart 209488a2cfbbSJames Smart rc = lpfc_bsg_diag_mode_enter(phba); 20957ad20aa9SJames Smart if (rc) 20969a66d990SJames Smart goto job_done; 20977ad20aa9SJames Smart 20981b51197dSJames Smart /* indicate we are in loobpack diagnostic mode */ 20991b51197dSJames Smart spin_lock_irq(&phba->hbalock); 21001b51197dSJames Smart phba->link_flag |= LS_LOOPBACK_MODE; 21011b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 21021b51197dSJames Smart 21031b51197dSJames Smart /* reset port to start frome scratch */ 21041b51197dSJames Smart rc = lpfc_selective_reset(phba); 21051b51197dSJames Smart if (rc) 21069a66d990SJames Smart goto job_done; 21071b51197dSJames Smart 21087ad20aa9SJames Smart /* bring the link to diagnostic mode */ 21091b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 21101b51197dSJames Smart "3129 Bring link to diagnostic state.\n"); 21117ad20aa9SJames Smart 21127ad20aa9SJames Smart rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1); 21131b51197dSJames Smart if (rc) { 21141b51197dSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 21151b51197dSJames Smart "3130 Failed to bring link to diagnostic " 21161b51197dSJames Smart "state, rc:x%x\n", rc); 21177ad20aa9SJames Smart goto loopback_mode_exit; 21181b51197dSJames Smart } 21197ad20aa9SJames Smart 21207ad20aa9SJames Smart /* wait for link down before proceeding */ 21217ad20aa9SJames Smart i = 0; 21227ad20aa9SJames Smart while (phba->link_state != LPFC_LINK_DOWN) { 21237ad20aa9SJames Smart if (i++ > timeout) { 21247ad20aa9SJames Smart rc = -ETIMEDOUT; 21251b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 21261b51197dSJames Smart "3131 Timeout waiting for link to " 21271b51197dSJames Smart "diagnostic mode, timeout:%d ms\n", 21281b51197dSJames Smart timeout * 10); 21297ad20aa9SJames Smart goto loopback_mode_exit; 21307ad20aa9SJames Smart } 21317ad20aa9SJames Smart msleep(10); 21327ad20aa9SJames Smart } 21337ad20aa9SJames Smart 21341b51197dSJames Smart /* set up loopback mode */ 21351b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 21361b51197dSJames Smart "3132 Set up loopback mode:x%x\n", link_flags); 21371b51197dSJames Smart 21389a66d990SJames Smart switch (link_flags) { 21399a66d990SJames Smart case INTERNAL_LOOP_BACK: 21409a66d990SJames Smart if (phba->sli4_hba.conf_trunk & (1 << link_no)) { 21419a66d990SJames Smart rc = lpfc_sli4_bsg_set_loopback_mode(phba, 21429a66d990SJames Smart LPFC_DIAG_LOOPBACK_TYPE_INTERNAL, 21439a66d990SJames Smart link_no); 21449a66d990SJames Smart } else { 21459a66d990SJames Smart /* Trunk is configured, but link is not in this trunk */ 21469a66d990SJames Smart if (phba->sli4_hba.conf_trunk) { 21479a66d990SJames Smart rc = -ELNRNG; 21489a66d990SJames Smart goto loopback_mode_exit; 21499a66d990SJames Smart } 21509a66d990SJames Smart 21519a66d990SJames Smart rc = lpfc_sli4_bsg_set_loopback_mode(phba, 21529a66d990SJames Smart LPFC_DIAG_LOOPBACK_TYPE_INTERNAL, 21539a66d990SJames Smart link_no); 21549a66d990SJames Smart } 21559a66d990SJames Smart 21569a66d990SJames Smart if (!rc) { 21579a66d990SJames Smart /* Set the need disable bit */ 21589a66d990SJames Smart phba->sli4_hba.conf_trunk |= (1 << link_no) << 4; 21599a66d990SJames Smart } 21609a66d990SJames Smart 21619a66d990SJames Smart break; 21629a66d990SJames Smart case EXTERNAL_LOOP_BACK: 21639a66d990SJames Smart if (phba->sli4_hba.conf_trunk & (1 << link_no)) { 21649a66d990SJames Smart rc = lpfc_sli4_bsg_set_loopback_mode(phba, 21659a66d990SJames Smart LPFC_DIAG_LOOPBACK_TYPE_EXTERNAL_TRUNKED, 21669a66d990SJames Smart link_no); 21679a66d990SJames Smart } else { 21689a66d990SJames Smart /* Trunk is configured, but link is not in this trunk */ 21699a66d990SJames Smart if (phba->sli4_hba.conf_trunk) { 21709a66d990SJames Smart rc = -ELNRNG; 21719a66d990SJames Smart goto loopback_mode_exit; 21729a66d990SJames Smart } 21739a66d990SJames Smart 21749a66d990SJames Smart rc = lpfc_sli4_bsg_set_loopback_mode(phba, 21759a66d990SJames Smart LPFC_DIAG_LOOPBACK_TYPE_SERDES, 21769a66d990SJames Smart link_no); 21779a66d990SJames Smart } 21789a66d990SJames Smart 21799a66d990SJames Smart if (!rc) { 21809a66d990SJames Smart /* Set the need disable bit */ 21819a66d990SJames Smart phba->sli4_hba.conf_trunk |= (1 << link_no) << 4; 21829a66d990SJames Smart } 21839a66d990SJames Smart 21849a66d990SJames Smart break; 21859a66d990SJames Smart default: 21861b51197dSJames Smart rc = -EINVAL; 21871b51197dSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 21881b51197dSJames Smart "3141 Loopback mode:x%x not supported\n", 21891b51197dSJames Smart link_flags); 21901b51197dSJames Smart goto loopback_mode_exit; 21911b51197dSJames Smart } 21921b51197dSJames Smart 21931b51197dSJames Smart if (!rc) { 21947ad20aa9SJames Smart /* wait for the link attention interrupt */ 21957ad20aa9SJames Smart msleep(100); 21967ad20aa9SJames Smart i = 0; 21971b51197dSJames Smart while (phba->link_state < LPFC_LINK_UP) { 21981b51197dSJames Smart if (i++ > timeout) { 21991b51197dSJames Smart rc = -ETIMEDOUT; 22001b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 22011b51197dSJames Smart "3137 Timeout waiting for link up " 22021b51197dSJames Smart "in loopback mode, timeout:%d ms\n", 22031b51197dSJames Smart timeout * 10); 22041b51197dSJames Smart break; 22051b51197dSJames Smart } 22061b51197dSJames Smart msleep(10); 22071b51197dSJames Smart } 22081b51197dSJames Smart } 22091b51197dSJames Smart 22101b51197dSJames Smart /* port resource registration setup for loopback diagnostic */ 22111b51197dSJames Smart if (!rc) { 22121b51197dSJames Smart /* set up a none zero myDID for loopback test */ 22131b51197dSJames Smart phba->pport->fc_myDID = 1; 22141b51197dSJames Smart rc = lpfc_sli4_diag_fcport_reg_setup(phba); 22151b51197dSJames Smart } else 22161b51197dSJames Smart goto loopback_mode_exit; 22171b51197dSJames Smart 22181b51197dSJames Smart if (!rc) { 22191b51197dSJames Smart /* wait for the port ready */ 22201b51197dSJames Smart msleep(100); 22211b51197dSJames Smart i = 0; 22227ad20aa9SJames Smart while (phba->link_state != LPFC_HBA_READY) { 22237ad20aa9SJames Smart if (i++ > timeout) { 22247ad20aa9SJames Smart rc = -ETIMEDOUT; 22251b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 22261b51197dSJames Smart "3133 Timeout waiting for port " 22271b51197dSJames Smart "loopback mode ready, timeout:%d ms\n", 22281b51197dSJames Smart timeout * 10); 22297ad20aa9SJames Smart break; 22307ad20aa9SJames Smart } 22317ad20aa9SJames Smart msleep(10); 22327ad20aa9SJames Smart } 22337ad20aa9SJames Smart } 22347ad20aa9SJames Smart 22357ad20aa9SJames Smart loopback_mode_exit: 22361b51197dSJames Smart /* clear loopback diagnostic mode */ 22371b51197dSJames Smart if (rc) { 22381b51197dSJames Smart spin_lock_irq(&phba->hbalock); 22391b51197dSJames Smart phba->link_flag &= ~LS_LOOPBACK_MODE; 22401b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 22411b51197dSJames Smart } 22427ad20aa9SJames Smart lpfc_bsg_diag_mode_exit(phba); 22437ad20aa9SJames Smart 22449a66d990SJames Smart job_done: 22457ad20aa9SJames Smart /* make error code available to userspace */ 224601e0e15cSJohannes Thumshirn bsg_reply->result = rc; 22477ad20aa9SJames Smart /* complete the job back to userspace if no error */ 22487ad20aa9SJames Smart if (rc == 0) 224906548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 22501abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 22517ad20aa9SJames Smart return rc; 22527ad20aa9SJames Smart } 22537ad20aa9SJames Smart 22547ad20aa9SJames Smart /** 22557ad20aa9SJames Smart * lpfc_bsg_diag_loopback_mode - bsg vendor command for diag loopback mode 22567ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_MODE 22577ad20aa9SJames Smart * 22587ad20aa9SJames Smart * This function is responsible for responding to check and dispatch bsg diag 22597ad20aa9SJames Smart * command from the user to proper driver action routines. 22607ad20aa9SJames Smart */ 22617ad20aa9SJames Smart static int 226275cc8cfcSJohannes Thumshirn lpfc_bsg_diag_loopback_mode(struct bsg_job *job) 22637ad20aa9SJames Smart { 22647ad20aa9SJames Smart struct Scsi_Host *shost; 22657ad20aa9SJames Smart struct lpfc_vport *vport; 22667ad20aa9SJames Smart struct lpfc_hba *phba; 22677ad20aa9SJames Smart int rc; 22687ad20aa9SJames Smart 2269cd21c605SJohannes Thumshirn shost = fc_bsg_to_shost(job); 22707ad20aa9SJames Smart if (!shost) 22717ad20aa9SJames Smart return -ENODEV; 2272cd21c605SJohannes Thumshirn vport = shost_priv(shost); 22737ad20aa9SJames Smart if (!vport) 22747ad20aa9SJames Smart return -ENODEV; 22757ad20aa9SJames Smart phba = vport->phba; 22767ad20aa9SJames Smart if (!phba) 22777ad20aa9SJames Smart return -ENODEV; 22787ad20aa9SJames Smart 22797ad20aa9SJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 22807ad20aa9SJames Smart rc = lpfc_sli3_bsg_diag_loopback_mode(phba, job); 2281719162bdSJames Smart else if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >= 22827ad20aa9SJames Smart LPFC_SLI_INTF_IF_TYPE_2) 22837ad20aa9SJames Smart rc = lpfc_sli4_bsg_diag_loopback_mode(phba, job); 22847ad20aa9SJames Smart else 22857ad20aa9SJames Smart rc = -ENODEV; 22867ad20aa9SJames Smart 22877ad20aa9SJames Smart return rc; 22887ad20aa9SJames Smart } 22897ad20aa9SJames Smart 22907ad20aa9SJames Smart /** 22917ad20aa9SJames Smart * lpfc_sli4_bsg_diag_mode_end - sli4 bsg vendor command for ending diag mode 22927ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_MODE_END 22937ad20aa9SJames Smart * 22947ad20aa9SJames Smart * This function is responsible for responding to check and dispatch bsg diag 22957ad20aa9SJames Smart * command from the user to proper driver action routines. 22967ad20aa9SJames Smart */ 22977ad20aa9SJames Smart static int 229875cc8cfcSJohannes Thumshirn lpfc_sli4_bsg_diag_mode_end(struct bsg_job *job) 22997ad20aa9SJames Smart { 230001e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 230101e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 23027ad20aa9SJames Smart struct Scsi_Host *shost; 23037ad20aa9SJames Smart struct lpfc_vport *vport; 23047ad20aa9SJames Smart struct lpfc_hba *phba; 23051b51197dSJames Smart struct diag_mode_set *loopback_mode_end_cmd; 23061b51197dSJames Smart uint32_t timeout; 23071b51197dSJames Smart int rc, i; 23087ad20aa9SJames Smart 2309cd21c605SJohannes Thumshirn shost = fc_bsg_to_shost(job); 23107ad20aa9SJames Smart if (!shost) 23117ad20aa9SJames Smart return -ENODEV; 2312cd21c605SJohannes Thumshirn vport = shost_priv(shost); 23137ad20aa9SJames Smart if (!vport) 23147ad20aa9SJames Smart return -ENODEV; 23157ad20aa9SJames Smart phba = vport->phba; 23167ad20aa9SJames Smart if (!phba) 23177ad20aa9SJames Smart return -ENODEV; 23187ad20aa9SJames Smart 23197ad20aa9SJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 23207ad20aa9SJames Smart return -ENODEV; 2321719162bdSJames Smart if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) < 23227ad20aa9SJames Smart LPFC_SLI_INTF_IF_TYPE_2) 23237ad20aa9SJames Smart return -ENODEV; 23247ad20aa9SJames Smart 23251b51197dSJames Smart /* clear loopback diagnostic mode */ 23261b51197dSJames Smart spin_lock_irq(&phba->hbalock); 23271b51197dSJames Smart phba->link_flag &= ~LS_LOOPBACK_MODE; 23281b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 23291b51197dSJames Smart loopback_mode_end_cmd = (struct diag_mode_set *) 233001e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 23311b51197dSJames Smart timeout = loopback_mode_end_cmd->timeout * 100; 23321b51197dSJames Smart 23337ad20aa9SJames Smart rc = lpfc_sli4_bsg_set_link_diag_state(phba, 0); 23341b51197dSJames Smart if (rc) { 23351b51197dSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 23361b51197dSJames Smart "3139 Failed to bring link to diagnostic " 23371b51197dSJames Smart "state, rc:x%x\n", rc); 23381b51197dSJames Smart goto loopback_mode_end_exit; 23391b51197dSJames Smart } 23407ad20aa9SJames Smart 23411b51197dSJames Smart /* wait for link down before proceeding */ 23421b51197dSJames Smart i = 0; 23431b51197dSJames Smart while (phba->link_state != LPFC_LINK_DOWN) { 23441b51197dSJames Smart if (i++ > timeout) { 23451b51197dSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 23461b51197dSJames Smart "3140 Timeout waiting for link to " 23471b51197dSJames Smart "diagnostic mode_end, timeout:%d ms\n", 23481b51197dSJames Smart timeout * 10); 23491b51197dSJames Smart /* there is nothing much we can do here */ 23501b51197dSJames Smart break; 23511b51197dSJames Smart } 23521b51197dSJames Smart msleep(10); 23531b51197dSJames Smart } 23547ad20aa9SJames Smart 23551b51197dSJames Smart /* reset port resource registrations */ 23561b51197dSJames Smart rc = lpfc_selective_reset(phba); 23571b51197dSJames Smart phba->pport->fc_myDID = 0; 23581b51197dSJames Smart 23591b51197dSJames Smart loopback_mode_end_exit: 23601b51197dSJames Smart /* make return code available to userspace */ 236101e0e15cSJohannes Thumshirn bsg_reply->result = rc; 23621b51197dSJames Smart /* complete the job back to userspace if no error */ 23631b51197dSJames Smart if (rc == 0) 236406548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 23651abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 23667ad20aa9SJames Smart return rc; 23677ad20aa9SJames Smart } 23687ad20aa9SJames Smart 23697ad20aa9SJames Smart /** 23707ad20aa9SJames Smart * lpfc_sli4_bsg_link_diag_test - sli4 bsg vendor command for diag link test 23717ad20aa9SJames Smart * @job: LPFC_BSG_VENDOR_DIAG_LINK_TEST 23727ad20aa9SJames Smart * 23737ad20aa9SJames Smart * This function is to perform SLI4 diag link test request from the user 23747ad20aa9SJames Smart * applicaiton. 23757ad20aa9SJames Smart */ 23767ad20aa9SJames Smart static int 237775cc8cfcSJohannes Thumshirn lpfc_sli4_bsg_link_diag_test(struct bsg_job *job) 23787ad20aa9SJames Smart { 237901e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 238001e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 23817ad20aa9SJames Smart struct Scsi_Host *shost; 23827ad20aa9SJames Smart struct lpfc_vport *vport; 23837ad20aa9SJames Smart struct lpfc_hba *phba; 23847ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq; 23857ad20aa9SJames Smart struct sli4_link_diag *link_diag_test_cmd; 23867ad20aa9SJames Smart uint32_t req_len, alloc_len; 23877ad20aa9SJames Smart struct lpfc_mbx_run_link_diag_test *run_link_diag_test; 23887ad20aa9SJames Smart union lpfc_sli4_cfg_shdr *shdr; 23897ad20aa9SJames Smart uint32_t shdr_status, shdr_add_status; 23907ad20aa9SJames Smart struct diag_status *diag_status_reply; 2391e5fcb81dSDick Kennedy int mbxstatus, rc = -ENODEV, rc1 = 0; 23927ad20aa9SJames Smart 2393cd21c605SJohannes Thumshirn shost = fc_bsg_to_shost(job); 2394e5fcb81dSDick Kennedy if (!shost) 23957ad20aa9SJames Smart goto job_error; 23967ad20aa9SJames Smart 2397e5fcb81dSDick Kennedy vport = shost_priv(shost); 2398e5fcb81dSDick Kennedy if (!vport) 23997ad20aa9SJames Smart goto job_error; 2400e5fcb81dSDick Kennedy 2401e5fcb81dSDick Kennedy phba = vport->phba; 2402e5fcb81dSDick Kennedy if (!phba) 2403e5fcb81dSDick Kennedy goto job_error; 2404e5fcb81dSDick Kennedy 2405e5fcb81dSDick Kennedy 2406e5fcb81dSDick Kennedy if (phba->sli_rev < LPFC_SLI_REV4) 2407e5fcb81dSDick Kennedy goto job_error; 2408e5fcb81dSDick Kennedy 2409719162bdSJames Smart if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) < 2410e5fcb81dSDick Kennedy LPFC_SLI_INTF_IF_TYPE_2) 24117ad20aa9SJames Smart goto job_error; 24127ad20aa9SJames Smart 24137ad20aa9SJames Smart if (job->request_len < sizeof(struct fc_bsg_request) + 24147ad20aa9SJames Smart sizeof(struct sli4_link_diag)) { 24157ad20aa9SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 24167ad20aa9SJames Smart "3013 Received LINK DIAG TEST request " 24177ad20aa9SJames Smart " size:%d below the minimum size:%d\n", 24187ad20aa9SJames Smart job->request_len, 24197ad20aa9SJames Smart (int)(sizeof(struct fc_bsg_request) + 24207ad20aa9SJames Smart sizeof(struct sli4_link_diag))); 24217ad20aa9SJames Smart rc = -EINVAL; 24227ad20aa9SJames Smart goto job_error; 24237ad20aa9SJames Smart } 24247ad20aa9SJames Smart 242588a2cfbbSJames Smart rc = lpfc_bsg_diag_mode_enter(phba); 24267ad20aa9SJames Smart if (rc) 24277ad20aa9SJames Smart goto job_error; 24287ad20aa9SJames Smart 24297ad20aa9SJames Smart link_diag_test_cmd = (struct sli4_link_diag *) 243001e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 24317ad20aa9SJames Smart 24327ad20aa9SJames Smart rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1); 24337ad20aa9SJames Smart 24347ad20aa9SJames Smart if (rc) 24357ad20aa9SJames Smart goto job_error; 24367ad20aa9SJames Smart 24377ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 2438*a1a553e3SJames Smart if (!pmboxq) { 2439*a1a553e3SJames Smart rc = -ENOMEM; 24407ad20aa9SJames Smart goto link_diag_test_exit; 2441*a1a553e3SJames Smart } 24427ad20aa9SJames Smart 24437ad20aa9SJames Smart req_len = (sizeof(struct lpfc_mbx_set_link_diag_state) - 24447ad20aa9SJames Smart sizeof(struct lpfc_sli4_cfg_mhdr)); 24457ad20aa9SJames Smart alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, 24467ad20aa9SJames Smart LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE, 24477ad20aa9SJames Smart req_len, LPFC_SLI4_MBX_EMBED); 2448e5fcb81dSDick Kennedy if (alloc_len != req_len) { 2449e5fcb81dSDick Kennedy rc = -ENOMEM; 24507ad20aa9SJames Smart goto link_diag_test_exit; 2451e5fcb81dSDick Kennedy } 245244ed33e6SGustavo A. R. Silva 24537ad20aa9SJames Smart run_link_diag_test = &pmboxq->u.mqe.un.link_diag_test; 24547ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_link_num, &run_link_diag_test->u.req, 24551b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_no); 24567ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_link_type, &run_link_diag_test->u.req, 24571b51197dSJames Smart phba->sli4_hba.lnk_info.lnk_tp); 24587ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_test_id, &run_link_diag_test->u.req, 24597ad20aa9SJames Smart link_diag_test_cmd->test_id); 24607ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_loops, &run_link_diag_test->u.req, 24617ad20aa9SJames Smart link_diag_test_cmd->loops); 24627ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_test_ver, &run_link_diag_test->u.req, 24637ad20aa9SJames Smart link_diag_test_cmd->test_version); 24647ad20aa9SJames Smart bf_set(lpfc_mbx_run_diag_test_err_act, &run_link_diag_test->u.req, 24657ad20aa9SJames Smart link_diag_test_cmd->error_action); 24667ad20aa9SJames Smart 24677ad20aa9SJames Smart mbxstatus = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); 24687ad20aa9SJames Smart 24697ad20aa9SJames Smart shdr = (union lpfc_sli4_cfg_shdr *) 24707ad20aa9SJames Smart &pmboxq->u.mqe.un.sli4_config.header.cfg_shdr; 24717ad20aa9SJames Smart shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); 24727ad20aa9SJames Smart shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); 24737ad20aa9SJames Smart if (shdr_status || shdr_add_status || mbxstatus) { 24747ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 24757ad20aa9SJames Smart "3010 Run link diag test mailbox failed with " 24767ad20aa9SJames Smart "mbx_status x%x status x%x, add_status x%x\n", 24777ad20aa9SJames Smart mbxstatus, shdr_status, shdr_add_status); 24787ad20aa9SJames Smart } 24797ad20aa9SJames Smart 24807ad20aa9SJames Smart diag_status_reply = (struct diag_status *) 248101e0e15cSJohannes Thumshirn bsg_reply->reply_data.vendor_reply.vendor_rsp; 24827ad20aa9SJames Smart 2483feb3cc57SDick Kennedy if (job->reply_len < sizeof(*bsg_reply) + sizeof(*diag_status_reply)) { 24847ad20aa9SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 24857ad20aa9SJames Smart "3012 Received Run link diag test reply " 24867ad20aa9SJames Smart "below minimum size (%d): reply_len:%d\n", 2487feb3cc57SDick Kennedy (int)(sizeof(*bsg_reply) + 2488feb3cc57SDick Kennedy sizeof(*diag_status_reply)), 24897ad20aa9SJames Smart job->reply_len); 24907ad20aa9SJames Smart rc = -EINVAL; 24917ad20aa9SJames Smart goto job_error; 24927ad20aa9SJames Smart } 24937ad20aa9SJames Smart 24947ad20aa9SJames Smart diag_status_reply->mbox_status = mbxstatus; 24957ad20aa9SJames Smart diag_status_reply->shdr_status = shdr_status; 24967ad20aa9SJames Smart diag_status_reply->shdr_add_status = shdr_add_status; 24977ad20aa9SJames Smart 24987ad20aa9SJames Smart link_diag_test_exit: 2499e5fcb81dSDick Kennedy rc1 = lpfc_sli4_bsg_set_link_diag_state(phba, 0); 25007ad20aa9SJames Smart 25017ad20aa9SJames Smart if (pmboxq) 25027ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 25037ad20aa9SJames Smart 25047ad20aa9SJames Smart lpfc_bsg_diag_mode_exit(phba); 25057ad20aa9SJames Smart 25067ad20aa9SJames Smart job_error: 25077ad20aa9SJames Smart /* make error code available to userspace */ 2508e5fcb81dSDick Kennedy if (rc1 && !rc) 2509e5fcb81dSDick Kennedy rc = rc1; 251001e0e15cSJohannes Thumshirn bsg_reply->result = rc; 25117ad20aa9SJames Smart /* complete the job back to userspace if no error */ 25127ad20aa9SJames Smart if (rc == 0) 251306548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 25141abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 25157ad20aa9SJames Smart return rc; 25167ad20aa9SJames Smart } 25177ad20aa9SJames Smart 25187ad20aa9SJames Smart /** 25193b5dd52aSJames Smart * lpfcdiag_loop_self_reg - obtains a remote port login id 25203b5dd52aSJames Smart * @phba: Pointer to HBA context object 25213b5dd52aSJames Smart * @rpi: Pointer to a remote port login id 25223b5dd52aSJames Smart * 25233b5dd52aSJames Smart * This function obtains a remote port login id so the diag loopback test 25243b5dd52aSJames Smart * can send and receive its own unsolicited CT command. 25253b5dd52aSJames Smart **/ 25263b5dd52aSJames Smart static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t *rpi) 25273b5dd52aSJames Smart { 25283b5dd52aSJames Smart LPFC_MBOXQ_t *mbox; 25293b5dd52aSJames Smart struct lpfc_dmabuf *dmabuff; 25303b5dd52aSJames Smart int status; 25313b5dd52aSJames Smart 25323b5dd52aSJames Smart mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 25333b5dd52aSJames Smart if (!mbox) 2534d439d286SJames Smart return -ENOMEM; 25353b5dd52aSJames Smart 25361b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 25373b5dd52aSJames Smart status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID, 25381b51197dSJames Smart (uint8_t *)&phba->pport->fc_sparam, 25391b51197dSJames Smart mbox, *rpi); 25401b51197dSJames Smart else { 25411b51197dSJames Smart *rpi = lpfc_sli4_alloc_rpi(phba); 25429d3d340dSJames Smart if (*rpi == LPFC_RPI_ALLOC_ERROR) { 25439d3d340dSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 25449d3d340dSJames Smart return -EBUSY; 25459d3d340dSJames Smart } 25461b51197dSJames Smart status = lpfc_reg_rpi(phba, phba->pport->vpi, 25471b51197dSJames Smart phba->pport->fc_myDID, 25481b51197dSJames Smart (uint8_t *)&phba->pport->fc_sparam, 25491b51197dSJames Smart mbox, *rpi); 25501b51197dSJames Smart } 25511b51197dSJames Smart 25523b5dd52aSJames Smart if (status) { 25533b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 25544042629eSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 25554042629eSJames Smart lpfc_sli4_free_rpi(phba, *rpi); 2556d439d286SJames Smart return -ENOMEM; 25573b5dd52aSJames Smart } 25583b5dd52aSJames Smart 25593e1f0718SJames Smart dmabuff = (struct lpfc_dmabuf *)mbox->ctx_buf; 25603e1f0718SJames Smart mbox->ctx_buf = NULL; 25613e1f0718SJames Smart mbox->ctx_ndlp = NULL; 25623b5dd52aSJames Smart status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); 25633b5dd52aSJames Smart 25643b5dd52aSJames Smart if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { 25653b5dd52aSJames Smart lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); 25663b5dd52aSJames Smart kfree(dmabuff); 25673b5dd52aSJames Smart if (status != MBX_TIMEOUT) 25683b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 25694042629eSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 25704042629eSJames Smart lpfc_sli4_free_rpi(phba, *rpi); 2571d439d286SJames Smart return -ENODEV; 25723b5dd52aSJames Smart } 25733b5dd52aSJames Smart 25741b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 25753b5dd52aSJames Smart *rpi = mbox->u.mb.un.varWords[0]; 25763b5dd52aSJames Smart 25773b5dd52aSJames Smart lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); 25783b5dd52aSJames Smart kfree(dmabuff); 25793b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 25803b5dd52aSJames Smart return 0; 25813b5dd52aSJames Smart } 25823b5dd52aSJames Smart 25833b5dd52aSJames Smart /** 25843b5dd52aSJames Smart * lpfcdiag_loop_self_unreg - unregs from the rpi 25853b5dd52aSJames Smart * @phba: Pointer to HBA context object 25863b5dd52aSJames Smart * @rpi: Remote port login id 25873b5dd52aSJames Smart * 25883b5dd52aSJames Smart * This function unregisters the rpi obtained in lpfcdiag_loop_self_reg 25893b5dd52aSJames Smart **/ 25903b5dd52aSJames Smart static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi) 25913b5dd52aSJames Smart { 25923b5dd52aSJames Smart LPFC_MBOXQ_t *mbox; 25933b5dd52aSJames Smart int status; 25943b5dd52aSJames Smart 25953b5dd52aSJames Smart /* Allocate mboxq structure */ 25963b5dd52aSJames Smart mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 25973b5dd52aSJames Smart if (mbox == NULL) 2598d439d286SJames Smart return -ENOMEM; 25993b5dd52aSJames Smart 26001b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 26013b5dd52aSJames Smart lpfc_unreg_login(phba, 0, rpi, mbox); 26021b51197dSJames Smart else 26031b51197dSJames Smart lpfc_unreg_login(phba, phba->pport->vpi, 26041b51197dSJames Smart phba->sli4_hba.rpi_ids[rpi], mbox); 26051b51197dSJames Smart 26063b5dd52aSJames Smart status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); 26073b5dd52aSJames Smart 26083b5dd52aSJames Smart if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { 26093b5dd52aSJames Smart if (status != MBX_TIMEOUT) 26103b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 2611d439d286SJames Smart return -EIO; 26123b5dd52aSJames Smart } 26133b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 26144042629eSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 26154042629eSJames Smart lpfc_sli4_free_rpi(phba, rpi); 26163b5dd52aSJames Smart return 0; 26173b5dd52aSJames Smart } 26183b5dd52aSJames Smart 26193b5dd52aSJames Smart /** 26203b5dd52aSJames Smart * lpfcdiag_loop_get_xri - obtains the transmit and receive ids 26213b5dd52aSJames Smart * @phba: Pointer to HBA context object 26223b5dd52aSJames Smart * @rpi: Remote port login id 26233b5dd52aSJames Smart * @txxri: Pointer to transmit exchange id 26243b5dd52aSJames Smart * @rxxri: Pointer to response exchabge id 26253b5dd52aSJames Smart * 26263b5dd52aSJames Smart * This function obtains the transmit and receive ids required to send 26273b5dd52aSJames Smart * an unsolicited ct command with a payload. A special lpfc FsType and CmdRsp 26283b5dd52aSJames Smart * flags are used to the unsolicted response handler is able to process 26293b5dd52aSJames Smart * the ct command sent on the same port. 26303b5dd52aSJames Smart **/ 26313b5dd52aSJames Smart static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, 26323b5dd52aSJames Smart uint16_t *txxri, uint16_t * rxxri) 26333b5dd52aSJames Smart { 26343b5dd52aSJames Smart struct lpfc_bsg_event *evt; 26353b5dd52aSJames Smart struct lpfc_iocbq *cmdiocbq, *rspiocbq; 26363b5dd52aSJames Smart IOCB_t *cmd, *rsp; 26373b5dd52aSJames Smart struct lpfc_dmabuf *dmabuf; 26383b5dd52aSJames Smart struct ulp_bde64 *bpl = NULL; 26393b5dd52aSJames Smart struct lpfc_sli_ct_request *ctreq = NULL; 26403b5dd52aSJames Smart int ret_val = 0; 2641d439d286SJames Smart int time_left; 26425a0916b4SJames Smart int iocb_stat = IOCB_SUCCESS; 26433b5dd52aSJames Smart unsigned long flags; 26443b5dd52aSJames Smart 26453b5dd52aSJames Smart *txxri = 0; 26463b5dd52aSJames Smart *rxxri = 0; 26473b5dd52aSJames Smart evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, 26483b5dd52aSJames Smart SLI_CT_ELX_LOOPBACK); 26493b5dd52aSJames Smart if (!evt) 2650d439d286SJames Smart return -ENOMEM; 26513b5dd52aSJames Smart 26523b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 26533b5dd52aSJames Smart list_add(&evt->node, &phba->ct_ev_waiters); 26543b5dd52aSJames Smart lpfc_bsg_event_ref(evt); 26553b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 26563b5dd52aSJames Smart 26573b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 26583b5dd52aSJames Smart rspiocbq = lpfc_sli_get_iocbq(phba); 26593b5dd52aSJames Smart 26603b5dd52aSJames Smart dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 26613b5dd52aSJames Smart if (dmabuf) { 26623b5dd52aSJames Smart dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys); 2663c7495937SJames Smart if (dmabuf->virt) { 26643b5dd52aSJames Smart INIT_LIST_HEAD(&dmabuf->list); 26653b5dd52aSJames Smart bpl = (struct ulp_bde64 *) dmabuf->virt; 26663b5dd52aSJames Smart memset(bpl, 0, sizeof(*bpl)); 26673b5dd52aSJames Smart ctreq = (struct lpfc_sli_ct_request *)(bpl + 1); 26683b5dd52aSJames Smart bpl->addrHigh = 2669c7495937SJames Smart le32_to_cpu(putPaddrHigh(dmabuf->phys + 2670c7495937SJames Smart sizeof(*bpl))); 26713b5dd52aSJames Smart bpl->addrLow = 2672c7495937SJames Smart le32_to_cpu(putPaddrLow(dmabuf->phys + 2673c7495937SJames Smart sizeof(*bpl))); 26743b5dd52aSJames Smart bpl->tus.f.bdeFlags = 0; 26753b5dd52aSJames Smart bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ; 26763b5dd52aSJames Smart bpl->tus.w = le32_to_cpu(bpl->tus.w); 26773b5dd52aSJames Smart } 2678c7495937SJames Smart } 26793b5dd52aSJames Smart 26803b5dd52aSJames Smart if (cmdiocbq == NULL || rspiocbq == NULL || 2681c7495937SJames Smart dmabuf == NULL || bpl == NULL || ctreq == NULL || 2682c7495937SJames Smart dmabuf->virt == NULL) { 2683d439d286SJames Smart ret_val = -ENOMEM; 26843b5dd52aSJames Smart goto err_get_xri_exit; 26853b5dd52aSJames Smart } 26863b5dd52aSJames Smart 26873b5dd52aSJames Smart cmd = &cmdiocbq->iocb; 26883b5dd52aSJames Smart rsp = &rspiocbq->iocb; 26893b5dd52aSJames Smart 26903b5dd52aSJames Smart memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); 26913b5dd52aSJames Smart 26923b5dd52aSJames Smart ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; 26933b5dd52aSJames Smart ctreq->RevisionId.bits.InId = 0; 26943b5dd52aSJames Smart ctreq->FsType = SLI_CT_ELX_LOOPBACK; 26953b5dd52aSJames Smart ctreq->FsSubType = 0; 26963b5dd52aSJames Smart ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_XRI_SETUP; 26973b5dd52aSJames Smart ctreq->CommandResponse.bits.Size = 0; 26983b5dd52aSJames Smart 26993b5dd52aSJames Smart 27003b5dd52aSJames Smart cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(dmabuf->phys); 27013b5dd52aSJames Smart cmd->un.xseq64.bdl.addrLow = putPaddrLow(dmabuf->phys); 27023b5dd52aSJames Smart cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 27033b5dd52aSJames Smart cmd->un.xseq64.bdl.bdeSize = sizeof(*bpl); 27043b5dd52aSJames Smart 27053b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Fctl = LA; 27063b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Dfctl = 0; 27073b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; 27083b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; 27093b5dd52aSJames Smart 27103b5dd52aSJames Smart cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CR; 27113b5dd52aSJames Smart cmd->ulpBdeCount = 1; 27123b5dd52aSJames Smart cmd->ulpLe = 1; 27133b5dd52aSJames Smart cmd->ulpClass = CLASS3; 27143b5dd52aSJames Smart cmd->ulpContext = rpi; 27153b5dd52aSJames Smart 27163b5dd52aSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 27173b5dd52aSJames Smart cmdiocbq->vport = phba->pport; 27185a0916b4SJames Smart cmdiocbq->iocb_cmpl = NULL; 27193b5dd52aSJames Smart 2720d439d286SJames Smart iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, 27213b5dd52aSJames Smart rspiocbq, 27223b5dd52aSJames Smart (phba->fc_ratov * 2) 27233b5dd52aSJames Smart + LPFC_DRVR_TIMEOUT); 272453151bbbSJames Smart if ((iocb_stat != IOCB_SUCCESS) || (rsp->ulpStatus != IOSTAT_SUCCESS)) { 2725d439d286SJames Smart ret_val = -EIO; 27263b5dd52aSJames Smart goto err_get_xri_exit; 2727d439d286SJames Smart } 27283b5dd52aSJames Smart *txxri = rsp->ulpContext; 27293b5dd52aSJames Smart 27303b5dd52aSJames Smart evt->waiting = 1; 27313b5dd52aSJames Smart evt->wait_time_stamp = jiffies; 2732d439d286SJames Smart time_left = wait_event_interruptible_timeout( 27333b5dd52aSJames Smart evt->wq, !list_empty(&evt->events_to_see), 2734256ec0d0SJames Smart msecs_to_jiffies(1000 * 2735256ec0d0SJames Smart ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT))); 27363b5dd52aSJames Smart if (list_empty(&evt->events_to_see)) 2737d439d286SJames Smart ret_val = (time_left) ? -EINTR : -ETIMEDOUT; 27383b5dd52aSJames Smart else { 27393b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 27403b5dd52aSJames Smart list_move(evt->events_to_see.prev, &evt->events_to_get); 27413b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 27423b5dd52aSJames Smart *rxxri = (list_entry(evt->events_to_get.prev, 27433b5dd52aSJames Smart typeof(struct event_data), 27443b5dd52aSJames Smart node))->immed_dat; 27453b5dd52aSJames Smart } 27463b5dd52aSJames Smart evt->waiting = 0; 27473b5dd52aSJames Smart 27483b5dd52aSJames Smart err_get_xri_exit: 27493b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 27503b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* release ref */ 27513b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* delete */ 27523b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 27533b5dd52aSJames Smart 27543b5dd52aSJames Smart if (dmabuf) { 27553b5dd52aSJames Smart if (dmabuf->virt) 27563b5dd52aSJames Smart lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); 27573b5dd52aSJames Smart kfree(dmabuf); 27583b5dd52aSJames Smart } 27593b5dd52aSJames Smart 2760d439d286SJames Smart if (cmdiocbq && (iocb_stat != IOCB_TIMEDOUT)) 27613b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 27623b5dd52aSJames Smart if (rspiocbq) 27633b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, rspiocbq); 27643b5dd52aSJames Smart return ret_val; 27653b5dd52aSJames Smart } 27663b5dd52aSJames Smart 27673b5dd52aSJames Smart /** 27687ad20aa9SJames Smart * lpfc_bsg_dma_page_alloc - allocate a bsg mbox page sized dma buffers 27697ad20aa9SJames Smart * @phba: Pointer to HBA context object 27707ad20aa9SJames Smart * 27712ea259eeSJames Smart * This function allocates BSG_MBOX_SIZE (4KB) page size dma buffer and 27729e03aa2fSJoe Perches * returns the pointer to the buffer. 27737ad20aa9SJames Smart **/ 27747ad20aa9SJames Smart static struct lpfc_dmabuf * 27757ad20aa9SJames Smart lpfc_bsg_dma_page_alloc(struct lpfc_hba *phba) 27767ad20aa9SJames Smart { 27777ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf; 27787ad20aa9SJames Smart struct pci_dev *pcidev = phba->pcidev; 27797ad20aa9SJames Smart 27807ad20aa9SJames Smart /* allocate dma buffer struct */ 27817ad20aa9SJames Smart dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 27827ad20aa9SJames Smart if (!dmabuf) 27837ad20aa9SJames Smart return NULL; 27847ad20aa9SJames Smart 27857ad20aa9SJames Smart INIT_LIST_HEAD(&dmabuf->list); 27867ad20aa9SJames Smart 27877ad20aa9SJames Smart /* now, allocate dma buffer */ 2788750afb08SLuis Chamberlain dmabuf->virt = dma_alloc_coherent(&pcidev->dev, BSG_MBOX_SIZE, 27897ad20aa9SJames Smart &(dmabuf->phys), GFP_KERNEL); 27907ad20aa9SJames Smart 27917ad20aa9SJames Smart if (!dmabuf->virt) { 27927ad20aa9SJames Smart kfree(dmabuf); 27937ad20aa9SJames Smart return NULL; 27947ad20aa9SJames Smart } 27957ad20aa9SJames Smart 27967ad20aa9SJames Smart return dmabuf; 27977ad20aa9SJames Smart } 27987ad20aa9SJames Smart 27997ad20aa9SJames Smart /** 28007ad20aa9SJames Smart * lpfc_bsg_dma_page_free - free a bsg mbox page sized dma buffer 28017ad20aa9SJames Smart * @phba: Pointer to HBA context object. 28027ad20aa9SJames Smart * @dmabuf: Pointer to the bsg mbox page sized dma buffer descriptor. 28037ad20aa9SJames Smart * 28047ad20aa9SJames Smart * This routine just simply frees a dma buffer and its associated buffer 28057ad20aa9SJames Smart * descriptor referred by @dmabuf. 28067ad20aa9SJames Smart **/ 28077ad20aa9SJames Smart static void 28087ad20aa9SJames Smart lpfc_bsg_dma_page_free(struct lpfc_hba *phba, struct lpfc_dmabuf *dmabuf) 28097ad20aa9SJames Smart { 28107ad20aa9SJames Smart struct pci_dev *pcidev = phba->pcidev; 28117ad20aa9SJames Smart 28127ad20aa9SJames Smart if (!dmabuf) 28137ad20aa9SJames Smart return; 28147ad20aa9SJames Smart 28157ad20aa9SJames Smart if (dmabuf->virt) 28167ad20aa9SJames Smart dma_free_coherent(&pcidev->dev, BSG_MBOX_SIZE, 28177ad20aa9SJames Smart dmabuf->virt, dmabuf->phys); 28187ad20aa9SJames Smart kfree(dmabuf); 28197ad20aa9SJames Smart return; 28207ad20aa9SJames Smart } 28217ad20aa9SJames Smart 28227ad20aa9SJames Smart /** 28237ad20aa9SJames Smart * lpfc_bsg_dma_page_list_free - free a list of bsg mbox page sized dma buffers 28247ad20aa9SJames Smart * @phba: Pointer to HBA context object. 28257ad20aa9SJames Smart * @dmabuf_list: Pointer to a list of bsg mbox page sized dma buffer descs. 28267ad20aa9SJames Smart * 28277ad20aa9SJames Smart * This routine just simply frees all dma buffers and their associated buffer 28287ad20aa9SJames Smart * descriptors referred by @dmabuf_list. 28297ad20aa9SJames Smart **/ 28307ad20aa9SJames Smart static void 28317ad20aa9SJames Smart lpfc_bsg_dma_page_list_free(struct lpfc_hba *phba, 28327ad20aa9SJames Smart struct list_head *dmabuf_list) 28337ad20aa9SJames Smart { 28347ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf, *next_dmabuf; 28357ad20aa9SJames Smart 28367ad20aa9SJames Smart if (list_empty(dmabuf_list)) 28377ad20aa9SJames Smart return; 28387ad20aa9SJames Smart 28397ad20aa9SJames Smart list_for_each_entry_safe(dmabuf, next_dmabuf, dmabuf_list, list) { 28407ad20aa9SJames Smart list_del_init(&dmabuf->list); 28417ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 28427ad20aa9SJames Smart } 28437ad20aa9SJames Smart return; 28447ad20aa9SJames Smart } 28457ad20aa9SJames Smart 28467ad20aa9SJames Smart /** 28473b5dd52aSJames Smart * diag_cmd_data_alloc - fills in a bde struct with dma buffers 28483b5dd52aSJames Smart * @phba: Pointer to HBA context object 28493b5dd52aSJames Smart * @bpl: Pointer to 64 bit bde structure 28503b5dd52aSJames Smart * @size: Number of bytes to process 28513b5dd52aSJames Smart * @nocopydata: Flag to copy user data into the allocated buffer 28523b5dd52aSJames Smart * 28533b5dd52aSJames Smart * This function allocates page size buffers and populates an lpfc_dmabufext. 28543b5dd52aSJames Smart * If allowed the user data pointed to with indataptr is copied into the kernel 28553b5dd52aSJames Smart * memory. The chained list of page size buffers is returned. 28563b5dd52aSJames Smart **/ 28573b5dd52aSJames Smart static struct lpfc_dmabufext * 28583b5dd52aSJames Smart diag_cmd_data_alloc(struct lpfc_hba *phba, 28593b5dd52aSJames Smart struct ulp_bde64 *bpl, uint32_t size, 28603b5dd52aSJames Smart int nocopydata) 28613b5dd52aSJames Smart { 28623b5dd52aSJames Smart struct lpfc_dmabufext *mlist = NULL; 28633b5dd52aSJames Smart struct lpfc_dmabufext *dmp; 28643b5dd52aSJames Smart int cnt, offset = 0, i = 0; 28653b5dd52aSJames Smart struct pci_dev *pcidev; 28663b5dd52aSJames Smart 28673b5dd52aSJames Smart pcidev = phba->pcidev; 28683b5dd52aSJames Smart 28693b5dd52aSJames Smart while (size) { 28703b5dd52aSJames Smart /* We get chunks of 4K */ 28713b5dd52aSJames Smart if (size > BUF_SZ_4K) 28723b5dd52aSJames Smart cnt = BUF_SZ_4K; 28733b5dd52aSJames Smart else 28743b5dd52aSJames Smart cnt = size; 28753b5dd52aSJames Smart 28763b5dd52aSJames Smart /* allocate struct lpfc_dmabufext buffer header */ 28773b5dd52aSJames Smart dmp = kmalloc(sizeof(struct lpfc_dmabufext), GFP_KERNEL); 28783b5dd52aSJames Smart if (!dmp) 28793b5dd52aSJames Smart goto out; 28803b5dd52aSJames Smart 28813b5dd52aSJames Smart INIT_LIST_HEAD(&dmp->dma.list); 28823b5dd52aSJames Smart 28833b5dd52aSJames Smart /* Queue it to a linked list */ 28843b5dd52aSJames Smart if (mlist) 28853b5dd52aSJames Smart list_add_tail(&dmp->dma.list, &mlist->dma.list); 28863b5dd52aSJames Smart else 28873b5dd52aSJames Smart mlist = dmp; 28883b5dd52aSJames Smart 28893b5dd52aSJames Smart /* allocate buffer */ 28903b5dd52aSJames Smart dmp->dma.virt = dma_alloc_coherent(&pcidev->dev, 28913b5dd52aSJames Smart cnt, 28923b5dd52aSJames Smart &(dmp->dma.phys), 28933b5dd52aSJames Smart GFP_KERNEL); 28943b5dd52aSJames Smart 28953b5dd52aSJames Smart if (!dmp->dma.virt) 28963b5dd52aSJames Smart goto out; 28973b5dd52aSJames Smart 28983b5dd52aSJames Smart dmp->size = cnt; 28993b5dd52aSJames Smart 29003b5dd52aSJames Smart if (nocopydata) { 29013b5dd52aSJames Smart bpl->tus.f.bdeFlags = 0; 29023b5dd52aSJames Smart } else { 29033b5dd52aSJames Smart memset((uint8_t *)dmp->dma.virt, 0, cnt); 29043b5dd52aSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; 29053b5dd52aSJames Smart } 29063b5dd52aSJames Smart 29073b5dd52aSJames Smart /* build buffer ptr list for IOCB */ 29083b5dd52aSJames Smart bpl->addrLow = le32_to_cpu(putPaddrLow(dmp->dma.phys)); 29093b5dd52aSJames Smart bpl->addrHigh = le32_to_cpu(putPaddrHigh(dmp->dma.phys)); 29103b5dd52aSJames Smart bpl->tus.f.bdeSize = (ushort) cnt; 29113b5dd52aSJames Smart bpl->tus.w = le32_to_cpu(bpl->tus.w); 29123b5dd52aSJames Smart bpl++; 29133b5dd52aSJames Smart 29143b5dd52aSJames Smart i++; 29153b5dd52aSJames Smart offset += cnt; 29163b5dd52aSJames Smart size -= cnt; 29173b5dd52aSJames Smart } 29183b5dd52aSJames Smart 2919a2fc4aefSJames Smart if (mlist) { 29203b5dd52aSJames Smart mlist->flag = i; 29213b5dd52aSJames Smart return mlist; 2922a2fc4aefSJames Smart } 29233b5dd52aSJames Smart out: 29243b5dd52aSJames Smart diag_cmd_data_free(phba, mlist); 29253b5dd52aSJames Smart return NULL; 29263b5dd52aSJames Smart } 29273b5dd52aSJames Smart 29283b5dd52aSJames Smart /** 29293b5dd52aSJames Smart * lpfcdiag_loop_post_rxbufs - post the receive buffers for an unsol CT cmd 29303b5dd52aSJames Smart * @phba: Pointer to HBA context object 29313b5dd52aSJames Smart * @rxxri: Receive exchange id 29323b5dd52aSJames Smart * @len: Number of data bytes 29333b5dd52aSJames Smart * 293425985edcSLucas De Marchi * This function allocates and posts a data buffer of sufficient size to receive 29353b5dd52aSJames Smart * an unsolicted CT command. 29363b5dd52aSJames Smart **/ 29373b5dd52aSJames Smart static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, 29383b5dd52aSJames Smart size_t len) 29393b5dd52aSJames Smart { 2940895427bdSJames Smart struct lpfc_sli_ring *pring; 29413b5dd52aSJames Smart struct lpfc_iocbq *cmdiocbq; 29423b5dd52aSJames Smart IOCB_t *cmd = NULL; 29433b5dd52aSJames Smart struct list_head head, *curr, *next; 29443b5dd52aSJames Smart struct lpfc_dmabuf *rxbmp; 29453b5dd52aSJames Smart struct lpfc_dmabuf *dmp; 29463b5dd52aSJames Smart struct lpfc_dmabuf *mp[2] = {NULL, NULL}; 29473b5dd52aSJames Smart struct ulp_bde64 *rxbpl = NULL; 29483b5dd52aSJames Smart uint32_t num_bde; 29493b5dd52aSJames Smart struct lpfc_dmabufext *rxbuffer = NULL; 29503b5dd52aSJames Smart int ret_val = 0; 2951d439d286SJames Smart int iocb_stat; 29523b5dd52aSJames Smart int i = 0; 29533b5dd52aSJames Smart 2954895427bdSJames Smart pring = lpfc_phba_elsring(phba); 2955895427bdSJames Smart 29563b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 29573b5dd52aSJames Smart rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 29583b5dd52aSJames Smart if (rxbmp != NULL) { 29593b5dd52aSJames Smart rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); 2960c7495937SJames Smart if (rxbmp->virt) { 29613b5dd52aSJames Smart INIT_LIST_HEAD(&rxbmp->list); 29623b5dd52aSJames Smart rxbpl = (struct ulp_bde64 *) rxbmp->virt; 29633b5dd52aSJames Smart rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0); 29643b5dd52aSJames Smart } 2965c7495937SJames Smart } 29663b5dd52aSJames Smart 29671234a6d5SDick Kennedy if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer || !pring) { 2968d439d286SJames Smart ret_val = -ENOMEM; 29693b5dd52aSJames Smart goto err_post_rxbufs_exit; 29703b5dd52aSJames Smart } 29713b5dd52aSJames Smart 29723b5dd52aSJames Smart /* Queue buffers for the receive exchange */ 29733b5dd52aSJames Smart num_bde = (uint32_t)rxbuffer->flag; 29743b5dd52aSJames Smart dmp = &rxbuffer->dma; 29753b5dd52aSJames Smart 29763b5dd52aSJames Smart cmd = &cmdiocbq->iocb; 29773b5dd52aSJames Smart i = 0; 29783b5dd52aSJames Smart 29793b5dd52aSJames Smart INIT_LIST_HEAD(&head); 29803b5dd52aSJames Smart list_add_tail(&head, &dmp->list); 29813b5dd52aSJames Smart list_for_each_safe(curr, next, &head) { 29823b5dd52aSJames Smart mp[i] = list_entry(curr, struct lpfc_dmabuf, list); 29833b5dd52aSJames Smart list_del(curr); 29843b5dd52aSJames Smart 29853b5dd52aSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 29863b5dd52aSJames Smart mp[i]->buffer_tag = lpfc_sli_get_buffer_tag(phba); 29873b5dd52aSJames Smart cmd->un.quexri64cx.buff.bde.addrHigh = 29883b5dd52aSJames Smart putPaddrHigh(mp[i]->phys); 29893b5dd52aSJames Smart cmd->un.quexri64cx.buff.bde.addrLow = 29903b5dd52aSJames Smart putPaddrLow(mp[i]->phys); 29913b5dd52aSJames Smart cmd->un.quexri64cx.buff.bde.tus.f.bdeSize = 29923b5dd52aSJames Smart ((struct lpfc_dmabufext *)mp[i])->size; 29933b5dd52aSJames Smart cmd->un.quexri64cx.buff.buffer_tag = mp[i]->buffer_tag; 29943b5dd52aSJames Smart cmd->ulpCommand = CMD_QUE_XRI64_CX; 29953b5dd52aSJames Smart cmd->ulpPU = 0; 29963b5dd52aSJames Smart cmd->ulpLe = 1; 29973b5dd52aSJames Smart cmd->ulpBdeCount = 1; 29983b5dd52aSJames Smart cmd->unsli3.que_xri64cx_ext_words.ebde_count = 0; 29993b5dd52aSJames Smart 30003b5dd52aSJames Smart } else { 30013b5dd52aSJames Smart cmd->un.cont64[i].addrHigh = putPaddrHigh(mp[i]->phys); 30023b5dd52aSJames Smart cmd->un.cont64[i].addrLow = putPaddrLow(mp[i]->phys); 30033b5dd52aSJames Smart cmd->un.cont64[i].tus.f.bdeSize = 30043b5dd52aSJames Smart ((struct lpfc_dmabufext *)mp[i])->size; 30053b5dd52aSJames Smart cmd->ulpBdeCount = ++i; 30063b5dd52aSJames Smart 30073b5dd52aSJames Smart if ((--num_bde > 0) && (i < 2)) 30083b5dd52aSJames Smart continue; 30093b5dd52aSJames Smart 30103b5dd52aSJames Smart cmd->ulpCommand = CMD_QUE_XRI_BUF64_CX; 30113b5dd52aSJames Smart cmd->ulpLe = 1; 30123b5dd52aSJames Smart } 30133b5dd52aSJames Smart 30143b5dd52aSJames Smart cmd->ulpClass = CLASS3; 30153b5dd52aSJames Smart cmd->ulpContext = rxxri; 30163b5dd52aSJames Smart 3017d439d286SJames Smart iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 3018d439d286SJames Smart 0); 3019d439d286SJames Smart if (iocb_stat == IOCB_ERROR) { 30203b5dd52aSJames Smart diag_cmd_data_free(phba, 30213b5dd52aSJames Smart (struct lpfc_dmabufext *)mp[0]); 30223b5dd52aSJames Smart if (mp[1]) 30233b5dd52aSJames Smart diag_cmd_data_free(phba, 30243b5dd52aSJames Smart (struct lpfc_dmabufext *)mp[1]); 30253b5dd52aSJames Smart dmp = list_entry(next, struct lpfc_dmabuf, list); 3026d439d286SJames Smart ret_val = -EIO; 30273b5dd52aSJames Smart goto err_post_rxbufs_exit; 30283b5dd52aSJames Smart } 30293b5dd52aSJames Smart 30303b5dd52aSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, mp[0]); 30313b5dd52aSJames Smart if (mp[1]) { 30323b5dd52aSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, mp[1]); 30333b5dd52aSJames Smart mp[1] = NULL; 30343b5dd52aSJames Smart } 30353b5dd52aSJames Smart 30363b5dd52aSJames Smart /* The iocb was freed by lpfc_sli_issue_iocb */ 30373b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 30383b5dd52aSJames Smart if (!cmdiocbq) { 30393b5dd52aSJames Smart dmp = list_entry(next, struct lpfc_dmabuf, list); 3040d439d286SJames Smart ret_val = -EIO; 30413b5dd52aSJames Smart goto err_post_rxbufs_exit; 30423b5dd52aSJames Smart } 30433b5dd52aSJames Smart 30443b5dd52aSJames Smart cmd = &cmdiocbq->iocb; 30453b5dd52aSJames Smart i = 0; 30463b5dd52aSJames Smart } 30473b5dd52aSJames Smart list_del(&head); 30483b5dd52aSJames Smart 30493b5dd52aSJames Smart err_post_rxbufs_exit: 30503b5dd52aSJames Smart 30513b5dd52aSJames Smart if (rxbmp) { 30523b5dd52aSJames Smart if (rxbmp->virt) 30533b5dd52aSJames Smart lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys); 30543b5dd52aSJames Smart kfree(rxbmp); 30553b5dd52aSJames Smart } 30563b5dd52aSJames Smart 30573b5dd52aSJames Smart if (cmdiocbq) 30583b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 30593b5dd52aSJames Smart return ret_val; 30603b5dd52aSJames Smart } 30613b5dd52aSJames Smart 30623b5dd52aSJames Smart /** 30637ad20aa9SJames Smart * lpfc_bsg_diag_loopback_run - run loopback on a port by issue ct cmd to itself 30643b5dd52aSJames Smart * @job: LPFC_BSG_VENDOR_DIAG_TEST fc_bsg_job 30653b5dd52aSJames Smart * 30663b5dd52aSJames Smart * This function receives a user data buffer to be transmitted and received on 30673b5dd52aSJames Smart * the same port, the link must be up and in loopback mode prior 30683b5dd52aSJames Smart * to being called. 30693b5dd52aSJames Smart * 1. A kernel buffer is allocated to copy the user data into. 30703b5dd52aSJames Smart * 2. The port registers with "itself". 30713b5dd52aSJames Smart * 3. The transmit and receive exchange ids are obtained. 30723b5dd52aSJames Smart * 4. The receive exchange id is posted. 30733b5dd52aSJames Smart * 5. A new els loopback event is created. 30743b5dd52aSJames Smart * 6. The command and response iocbs are allocated. 30753b5dd52aSJames Smart * 7. The cmd iocb FsType is set to elx loopback and the CmdRsp to looppback. 30763b5dd52aSJames Smart * 30773b5dd52aSJames Smart * This function is meant to be called n times while the port is in loopback 30783b5dd52aSJames Smart * so it is the apps responsibility to issue a reset to take the port out 30793b5dd52aSJames Smart * of loopback mode. 30803b5dd52aSJames Smart **/ 30813b5dd52aSJames Smart static int 308275cc8cfcSJohannes Thumshirn lpfc_bsg_diag_loopback_run(struct bsg_job *job) 30833b5dd52aSJames Smart { 3084cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 308501e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 30863b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 30873b5dd52aSJames Smart struct lpfc_bsg_event *evt; 30883b5dd52aSJames Smart struct event_data *evdat; 30893b5dd52aSJames Smart struct lpfc_sli *psli = &phba->sli; 30903b5dd52aSJames Smart uint32_t size; 30913b5dd52aSJames Smart uint32_t full_size; 30923b5dd52aSJames Smart size_t segment_len = 0, segment_offset = 0, current_offset = 0; 30934042629eSJames Smart uint16_t rpi = 0; 30941b51197dSJames Smart struct lpfc_iocbq *cmdiocbq, *rspiocbq = NULL; 30951b51197dSJames Smart IOCB_t *cmd, *rsp = NULL; 30963b5dd52aSJames Smart struct lpfc_sli_ct_request *ctreq; 30973b5dd52aSJames Smart struct lpfc_dmabuf *txbmp; 30983b5dd52aSJames Smart struct ulp_bde64 *txbpl = NULL; 30993b5dd52aSJames Smart struct lpfc_dmabufext *txbuffer = NULL; 31003b5dd52aSJames Smart struct list_head head; 31013b5dd52aSJames Smart struct lpfc_dmabuf *curr; 31021b51197dSJames Smart uint16_t txxri = 0, rxxri; 31033b5dd52aSJames Smart uint32_t num_bde; 31043b5dd52aSJames Smart uint8_t *ptr = NULL, *rx_databuf = NULL; 31053b5dd52aSJames Smart int rc = 0; 3106d439d286SJames Smart int time_left; 31075a0916b4SJames Smart int iocb_stat = IOCB_SUCCESS; 31083b5dd52aSJames Smart unsigned long flags; 31093b5dd52aSJames Smart void *dataout = NULL; 31103b5dd52aSJames Smart uint32_t total_mem; 31113b5dd52aSJames Smart 31123b5dd52aSJames Smart /* in case no data is returned return just the return code */ 311301e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 31143b5dd52aSJames Smart 31153b5dd52aSJames Smart if (job->request_len < 31163b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_test)) { 31173b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 31183b5dd52aSJames Smart "2739 Received DIAG TEST request below minimum " 31193b5dd52aSJames Smart "size\n"); 31203b5dd52aSJames Smart rc = -EINVAL; 31213b5dd52aSJames Smart goto loopback_test_exit; 31223b5dd52aSJames Smart } 31233b5dd52aSJames Smart 31243b5dd52aSJames Smart if (job->request_payload.payload_len != 31253b5dd52aSJames Smart job->reply_payload.payload_len) { 31263b5dd52aSJames Smart rc = -EINVAL; 31273b5dd52aSJames Smart goto loopback_test_exit; 31283b5dd52aSJames Smart } 31293b5dd52aSJames Smart 31303b5dd52aSJames Smart if ((phba->link_state == LPFC_HBA_ERROR) || 31313b5dd52aSJames Smart (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || 31323b5dd52aSJames Smart (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { 31333b5dd52aSJames Smart rc = -EACCES; 31343b5dd52aSJames Smart goto loopback_test_exit; 31353b5dd52aSJames Smart } 31363b5dd52aSJames Smart 31373b5dd52aSJames Smart if (!lpfc_is_link_up(phba) || !(phba->link_flag & LS_LOOPBACK_MODE)) { 31383b5dd52aSJames Smart rc = -EACCES; 31393b5dd52aSJames Smart goto loopback_test_exit; 31403b5dd52aSJames Smart } 31413b5dd52aSJames Smart 31423b5dd52aSJames Smart size = job->request_payload.payload_len; 31433b5dd52aSJames Smart full_size = size + ELX_LOOPBACK_HEADER_SZ; /* plus the header */ 31443b5dd52aSJames Smart 31453b5dd52aSJames Smart if ((size == 0) || (size > 80 * BUF_SZ_4K)) { 31463b5dd52aSJames Smart rc = -ERANGE; 31473b5dd52aSJames Smart goto loopback_test_exit; 31483b5dd52aSJames Smart } 31493b5dd52aSJames Smart 315063e801ceSJames Smart if (full_size >= BUF_SZ_4K) { 31513b5dd52aSJames Smart /* 31523b5dd52aSJames Smart * Allocate memory for ioctl data. If buffer is bigger than 64k, 31533b5dd52aSJames Smart * then we allocate 64k and re-use that buffer over and over to 31543b5dd52aSJames Smart * xfer the whole block. This is because Linux kernel has a 31553b5dd52aSJames Smart * problem allocating more than 120k of kernel space memory. Saw 31563b5dd52aSJames Smart * problem with GET_FCPTARGETMAPPING... 31573b5dd52aSJames Smart */ 31583b5dd52aSJames Smart if (size <= (64 * 1024)) 315963e801ceSJames Smart total_mem = full_size; 31603b5dd52aSJames Smart else 31613b5dd52aSJames Smart total_mem = 64 * 1024; 31623b5dd52aSJames Smart } else 31633b5dd52aSJames Smart /* Allocate memory for ioctl data */ 31643b5dd52aSJames Smart total_mem = BUF_SZ_4K; 31653b5dd52aSJames Smart 31663b5dd52aSJames Smart dataout = kmalloc(total_mem, GFP_KERNEL); 31673b5dd52aSJames Smart if (dataout == NULL) { 31683b5dd52aSJames Smart rc = -ENOMEM; 31693b5dd52aSJames Smart goto loopback_test_exit; 31703b5dd52aSJames Smart } 31713b5dd52aSJames Smart 31723b5dd52aSJames Smart ptr = dataout; 31733b5dd52aSJames Smart ptr += ELX_LOOPBACK_HEADER_SZ; 31743b5dd52aSJames Smart sg_copy_to_buffer(job->request_payload.sg_list, 31753b5dd52aSJames Smart job->request_payload.sg_cnt, 31763b5dd52aSJames Smart ptr, size); 31773b5dd52aSJames Smart rc = lpfcdiag_loop_self_reg(phba, &rpi); 3178d439d286SJames Smart if (rc) 31793b5dd52aSJames Smart goto loopback_test_exit; 31803b5dd52aSJames Smart 31811b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) { 31823b5dd52aSJames Smart rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri); 31833b5dd52aSJames Smart if (rc) { 31843b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 31853b5dd52aSJames Smart goto loopback_test_exit; 31863b5dd52aSJames Smart } 31873b5dd52aSJames Smart 31883b5dd52aSJames Smart rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size); 31893b5dd52aSJames Smart if (rc) { 31903b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 31913b5dd52aSJames Smart goto loopback_test_exit; 31923b5dd52aSJames Smart } 31931b51197dSJames Smart } 31943b5dd52aSJames Smart evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, 31953b5dd52aSJames Smart SLI_CT_ELX_LOOPBACK); 31963b5dd52aSJames Smart if (!evt) { 31973b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 31983b5dd52aSJames Smart rc = -ENOMEM; 31993b5dd52aSJames Smart goto loopback_test_exit; 32003b5dd52aSJames Smart } 32013b5dd52aSJames Smart 32023b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 32033b5dd52aSJames Smart list_add(&evt->node, &phba->ct_ev_waiters); 32043b5dd52aSJames Smart lpfc_bsg_event_ref(evt); 32053b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 32063b5dd52aSJames Smart 32073b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 32081b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 32093b5dd52aSJames Smart rspiocbq = lpfc_sli_get_iocbq(phba); 32103b5dd52aSJames Smart txbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 32113b5dd52aSJames Smart 32123b5dd52aSJames Smart if (txbmp) { 32133b5dd52aSJames Smart txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys); 3214c7495937SJames Smart if (txbmp->virt) { 32153b5dd52aSJames Smart INIT_LIST_HEAD(&txbmp->list); 32163b5dd52aSJames Smart txbpl = (struct ulp_bde64 *) txbmp->virt; 32173b5dd52aSJames Smart txbuffer = diag_cmd_data_alloc(phba, 32183b5dd52aSJames Smart txbpl, full_size, 0); 32193b5dd52aSJames Smart } 3220c7495937SJames Smart } 32213b5dd52aSJames Smart 32221b51197dSJames Smart if (!cmdiocbq || !txbmp || !txbpl || !txbuffer || !txbmp->virt) { 32231b51197dSJames Smart rc = -ENOMEM; 32241b51197dSJames Smart goto err_loopback_test_exit; 32251b51197dSJames Smart } 32261b51197dSJames Smart if ((phba->sli_rev < LPFC_SLI_REV4) && !rspiocbq) { 32273b5dd52aSJames Smart rc = -ENOMEM; 32283b5dd52aSJames Smart goto err_loopback_test_exit; 32293b5dd52aSJames Smart } 32303b5dd52aSJames Smart 32313b5dd52aSJames Smart cmd = &cmdiocbq->iocb; 32321b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) 32333b5dd52aSJames Smart rsp = &rspiocbq->iocb; 32343b5dd52aSJames Smart 32353b5dd52aSJames Smart INIT_LIST_HEAD(&head); 32363b5dd52aSJames Smart list_add_tail(&head, &txbuffer->dma.list); 32373b5dd52aSJames Smart list_for_each_entry(curr, &head, list) { 32383b5dd52aSJames Smart segment_len = ((struct lpfc_dmabufext *)curr)->size; 32393b5dd52aSJames Smart if (current_offset == 0) { 32403b5dd52aSJames Smart ctreq = curr->virt; 32413b5dd52aSJames Smart memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); 32423b5dd52aSJames Smart ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; 32433b5dd52aSJames Smart ctreq->RevisionId.bits.InId = 0; 32443b5dd52aSJames Smart ctreq->FsType = SLI_CT_ELX_LOOPBACK; 32453b5dd52aSJames Smart ctreq->FsSubType = 0; 32463b5dd52aSJames Smart ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_DATA; 32473b5dd52aSJames Smart ctreq->CommandResponse.bits.Size = size; 32483b5dd52aSJames Smart segment_offset = ELX_LOOPBACK_HEADER_SZ; 32493b5dd52aSJames Smart } else 32503b5dd52aSJames Smart segment_offset = 0; 32513b5dd52aSJames Smart 32523b5dd52aSJames Smart BUG_ON(segment_offset >= segment_len); 32533b5dd52aSJames Smart memcpy(curr->virt + segment_offset, 32543b5dd52aSJames Smart ptr + current_offset, 32553b5dd52aSJames Smart segment_len - segment_offset); 32563b5dd52aSJames Smart 32573b5dd52aSJames Smart current_offset += segment_len - segment_offset; 32583b5dd52aSJames Smart BUG_ON(current_offset > size); 32593b5dd52aSJames Smart } 32603b5dd52aSJames Smart list_del(&head); 32613b5dd52aSJames Smart 32623b5dd52aSJames Smart /* Build the XMIT_SEQUENCE iocb */ 32633b5dd52aSJames Smart num_bde = (uint32_t)txbuffer->flag; 32643b5dd52aSJames Smart 32653b5dd52aSJames Smart cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(txbmp->phys); 32663b5dd52aSJames Smart cmd->un.xseq64.bdl.addrLow = putPaddrLow(txbmp->phys); 32673b5dd52aSJames Smart cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 32683b5dd52aSJames Smart cmd->un.xseq64.bdl.bdeSize = (num_bde * sizeof(struct ulp_bde64)); 32693b5dd52aSJames Smart 32703b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); 32713b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Dfctl = 0; 32723b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; 32733b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; 32743b5dd52aSJames Smart 32753b5dd52aSJames Smart cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; 32763b5dd52aSJames Smart cmd->ulpBdeCount = 1; 32773b5dd52aSJames Smart cmd->ulpLe = 1; 32783b5dd52aSJames Smart cmd->ulpClass = CLASS3; 32793b5dd52aSJames Smart 32801b51197dSJames Smart if (phba->sli_rev < LPFC_SLI_REV4) { 32811b51197dSJames Smart cmd->ulpContext = txxri; 32821b51197dSJames Smart } else { 32831b51197dSJames Smart cmd->un.xseq64.bdl.ulpIoTag32 = 0; 32841b51197dSJames Smart cmd->un.ulpWord[3] = phba->sli4_hba.rpi_ids[rpi]; 32851b51197dSJames Smart cmdiocbq->context3 = txbmp; 32861b51197dSJames Smart cmdiocbq->sli4_xritag = NO_XRI; 32871b51197dSJames Smart cmd->unsli3.rcvsli3.ox_id = 0xffff; 32881b51197dSJames Smart } 32893b5dd52aSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 32906c7cf486SJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LOOPBACK; 32913b5dd52aSJames Smart cmdiocbq->vport = phba->pport; 32925a0916b4SJames Smart cmdiocbq->iocb_cmpl = NULL; 3293d439d286SJames Smart iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, 3294d439d286SJames Smart rspiocbq, (phba->fc_ratov * 2) + 3295d439d286SJames Smart LPFC_DRVR_TIMEOUT); 32963b5dd52aSJames Smart 329753151bbbSJames Smart if ((iocb_stat != IOCB_SUCCESS) || 329853151bbbSJames Smart ((phba->sli_rev < LPFC_SLI_REV4) && 329953151bbbSJames Smart (rsp->ulpStatus != IOSTAT_SUCCESS))) { 33001b51197dSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 33011b51197dSJames Smart "3126 Failed loopback test issue iocb: " 33021b51197dSJames Smart "iocb_stat:x%x\n", iocb_stat); 33033b5dd52aSJames Smart rc = -EIO; 33043b5dd52aSJames Smart goto err_loopback_test_exit; 33053b5dd52aSJames Smart } 33063b5dd52aSJames Smart 33073b5dd52aSJames Smart evt->waiting = 1; 3308d439d286SJames Smart time_left = wait_event_interruptible_timeout( 33093b5dd52aSJames Smart evt->wq, !list_empty(&evt->events_to_see), 3310256ec0d0SJames Smart msecs_to_jiffies(1000 * 3311256ec0d0SJames Smart ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT))); 33123b5dd52aSJames Smart evt->waiting = 0; 33131b51197dSJames Smart if (list_empty(&evt->events_to_see)) { 3314d439d286SJames Smart rc = (time_left) ? -EINTR : -ETIMEDOUT; 33151b51197dSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 33161b51197dSJames Smart "3125 Not receiving unsolicited event, " 33171b51197dSJames Smart "rc:x%x\n", rc); 33181b51197dSJames Smart } else { 33193b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 33203b5dd52aSJames Smart list_move(evt->events_to_see.prev, &evt->events_to_get); 33213b5dd52aSJames Smart evdat = list_entry(evt->events_to_get.prev, 33223b5dd52aSJames Smart typeof(*evdat), node); 33233b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 33243b5dd52aSJames Smart rx_databuf = evdat->data; 33253b5dd52aSJames Smart if (evdat->len != full_size) { 33263b5dd52aSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 33273b5dd52aSJames Smart "1603 Loopback test did not receive expected " 33283b5dd52aSJames Smart "data length. actual length 0x%x expected " 33293b5dd52aSJames Smart "length 0x%x\n", 33303b5dd52aSJames Smart evdat->len, full_size); 33313b5dd52aSJames Smart rc = -EIO; 33323b5dd52aSJames Smart } else if (rx_databuf == NULL) 33333b5dd52aSJames Smart rc = -EIO; 33343b5dd52aSJames Smart else { 33353b5dd52aSJames Smart rc = IOCB_SUCCESS; 33363b5dd52aSJames Smart /* skip over elx loopback header */ 33373b5dd52aSJames Smart rx_databuf += ELX_LOOPBACK_HEADER_SZ; 333801e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 33393b5dd52aSJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 33403b5dd52aSJames Smart job->reply_payload.sg_cnt, 33413b5dd52aSJames Smart rx_databuf, size); 334201e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = size; 33433b5dd52aSJames Smart } 33443b5dd52aSJames Smart } 33453b5dd52aSJames Smart 33463b5dd52aSJames Smart err_loopback_test_exit: 33473b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 33483b5dd52aSJames Smart 33493b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 33503b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* release ref */ 33513b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* delete */ 33523b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 33533b5dd52aSJames Smart 33545a0916b4SJames Smart if ((cmdiocbq != NULL) && (iocb_stat != IOCB_TIMEDOUT)) 33553b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 33563b5dd52aSJames Smart 33573b5dd52aSJames Smart if (rspiocbq != NULL) 33583b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, rspiocbq); 33593b5dd52aSJames Smart 33603b5dd52aSJames Smart if (txbmp != NULL) { 33613b5dd52aSJames Smart if (txbpl != NULL) { 33623b5dd52aSJames Smart if (txbuffer != NULL) 33633b5dd52aSJames Smart diag_cmd_data_free(phba, txbuffer); 33643b5dd52aSJames Smart lpfc_mbuf_free(phba, txbmp->virt, txbmp->phys); 33653b5dd52aSJames Smart } 33663b5dd52aSJames Smart kfree(txbmp); 33673b5dd52aSJames Smart } 33683b5dd52aSJames Smart 33693b5dd52aSJames Smart loopback_test_exit: 33703b5dd52aSJames Smart kfree(dataout); 33713b5dd52aSJames Smart /* make error code available to userspace */ 337201e0e15cSJohannes Thumshirn bsg_reply->result = rc; 33733b5dd52aSJames Smart job->dd_data = NULL; 33743b5dd52aSJames Smart /* complete the job back to userspace if no error */ 33751b51197dSJames Smart if (rc == IOCB_SUCCESS) 337606548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 33771abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 33783b5dd52aSJames Smart return rc; 33793b5dd52aSJames Smart } 33803b5dd52aSJames Smart 33813b5dd52aSJames Smart /** 33823b5dd52aSJames Smart * lpfc_bsg_get_dfc_rev - process a GET_DFC_REV bsg vendor command 33833b5dd52aSJames Smart * @job: GET_DFC_REV fc_bsg_job 33843b5dd52aSJames Smart **/ 33853b5dd52aSJames Smart static int 338675cc8cfcSJohannes Thumshirn lpfc_bsg_get_dfc_rev(struct bsg_job *job) 33873b5dd52aSJames Smart { 3388cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 338901e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 33903b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 33913b5dd52aSJames Smart struct get_mgmt_rev_reply *event_reply; 33923b5dd52aSJames Smart int rc = 0; 33933b5dd52aSJames Smart 33943b5dd52aSJames Smart if (job->request_len < 33953b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev)) { 33963b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 33973b5dd52aSJames Smart "2740 Received GET_DFC_REV request below " 33983b5dd52aSJames Smart "minimum size\n"); 33993b5dd52aSJames Smart rc = -EINVAL; 34003b5dd52aSJames Smart goto job_error; 34013b5dd52aSJames Smart } 34023b5dd52aSJames Smart 34033b5dd52aSJames Smart event_reply = (struct get_mgmt_rev_reply *) 340401e0e15cSJohannes Thumshirn bsg_reply->reply_data.vendor_reply.vendor_rsp; 34053b5dd52aSJames Smart 3406feb3cc57SDick Kennedy if (job->reply_len < sizeof(*bsg_reply) + sizeof(*event_reply)) { 34073b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 34083b5dd52aSJames Smart "2741 Received GET_DFC_REV reply below " 34093b5dd52aSJames Smart "minimum size\n"); 34103b5dd52aSJames Smart rc = -EINVAL; 34113b5dd52aSJames Smart goto job_error; 34123b5dd52aSJames Smart } 34133b5dd52aSJames Smart 34143b5dd52aSJames Smart event_reply->info.a_Major = MANAGEMENT_MAJOR_REV; 34153b5dd52aSJames Smart event_reply->info.a_Minor = MANAGEMENT_MINOR_REV; 34163b5dd52aSJames Smart job_error: 341701e0e15cSJohannes Thumshirn bsg_reply->result = rc; 34183b5dd52aSJames Smart if (rc == 0) 341906548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 34201abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 34213b5dd52aSJames Smart return rc; 34223b5dd52aSJames Smart } 34233b5dd52aSJames Smart 34243b5dd52aSJames Smart /** 34257ad20aa9SJames Smart * lpfc_bsg_issue_mbox_cmpl - lpfc_bsg_issue_mbox mbox completion handler 34263b5dd52aSJames Smart * @phba: Pointer to HBA context object. 34273b5dd52aSJames Smart * @pmboxq: Pointer to mailbox command. 34283b5dd52aSJames Smart * 34293b5dd52aSJames Smart * This is completion handler function for mailbox commands issued from 34303b5dd52aSJames Smart * lpfc_bsg_issue_mbox function. This function is called by the 34313b5dd52aSJames Smart * mailbox event handler function with no lock held. This function 34323b5dd52aSJames Smart * will wake up thread waiting on the wait queue pointed by context1 34333b5dd52aSJames Smart * of the mailbox. 34343b5dd52aSJames Smart **/ 34359ab9b134SRashika Kheria static void 34367ad20aa9SJames Smart lpfc_bsg_issue_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) 34373b5dd52aSJames Smart { 34383b5dd52aSJames Smart struct bsg_job_data *dd_data; 343901e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 344075cc8cfcSJohannes Thumshirn struct bsg_job *job; 34413b5dd52aSJames Smart uint32_t size; 34423b5dd52aSJames Smart unsigned long flags; 34437ad20aa9SJames Smart uint8_t *pmb, *pmb_buf; 34443b5dd52aSJames Smart 34453e1f0718SJames Smart dd_data = pmboxq->ctx_ndlp; 34463b5dd52aSJames Smart 34477ad20aa9SJames Smart /* 34487ad20aa9SJames Smart * The outgoing buffer is readily referred from the dma buffer, 34497ad20aa9SJames Smart * just need to get header part from mailboxq structure. 34507a470277SJames Smart */ 34517ad20aa9SJames Smart pmb = (uint8_t *)&pmboxq->u.mb; 34527ad20aa9SJames Smart pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb; 34537ad20aa9SJames Smart memcpy(pmb_buf, pmb, sizeof(MAILBOX_t)); 3454515e0aa2SJames Smart 3455a33c4f7bSJames Smart /* Determine if job has been aborted */ 3456a33c4f7bSJames Smart 3457a33c4f7bSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 3458a33c4f7bSJames Smart job = dd_data->set_job; 3459a33c4f7bSJames Smart if (job) { 3460a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 3461a33c4f7bSJames Smart job->dd_data = NULL; 3462a33c4f7bSJames Smart } 3463a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 3464a33c4f7bSJames Smart 3465a33c4f7bSJames Smart /* Copy the mailbox data to the job if it is still active */ 3466a33c4f7bSJames Smart 34675a6f133eSJames Smart if (job) { 346801e0e15cSJohannes Thumshirn bsg_reply = job->reply; 34697a470277SJames Smart size = job->reply_payload.payload_len; 347001e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 34713b5dd52aSJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 34723b5dd52aSJames Smart job->reply_payload.sg_cnt, 34737ad20aa9SJames Smart pmb_buf, size); 3474b6e3b9c6SJames Smart } 34757a470277SJames Smart 3476a33c4f7bSJames Smart dd_data->set_job = NULL; 34773b5dd52aSJames Smart mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool); 34787ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dd_data->context_un.mbox.dmabuffers); 34793b5dd52aSJames Smart kfree(dd_data); 34807ad20aa9SJames Smart 3481a33c4f7bSJames Smart /* Complete the job if the job is still active */ 3482a33c4f7bSJames Smart 34837ad20aa9SJames Smart if (job) { 348401e0e15cSJohannes Thumshirn bsg_reply->result = 0; 348506548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 34861abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 34877ad20aa9SJames Smart } 34883b5dd52aSJames Smart return; 34893b5dd52aSJames Smart } 34903b5dd52aSJames Smart 34913b5dd52aSJames Smart /** 34923b5dd52aSJames Smart * lpfc_bsg_check_cmd_access - test for a supported mailbox command 34933b5dd52aSJames Smart * @phba: Pointer to HBA context object. 34943b5dd52aSJames Smart * @mb: Pointer to a mailbox object. 34953b5dd52aSJames Smart * @vport: Pointer to a vport object. 34963b5dd52aSJames Smart * 34973b5dd52aSJames Smart * Some commands require the port to be offline, some may not be called from 34983b5dd52aSJames Smart * the application. 34993b5dd52aSJames Smart **/ 35003b5dd52aSJames Smart static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, 35013b5dd52aSJames Smart MAILBOX_t *mb, struct lpfc_vport *vport) 35023b5dd52aSJames Smart { 35033b5dd52aSJames Smart /* return negative error values for bsg job */ 35043b5dd52aSJames Smart switch (mb->mbxCommand) { 35053b5dd52aSJames Smart /* Offline only */ 35063b5dd52aSJames Smart case MBX_INIT_LINK: 35073b5dd52aSJames Smart case MBX_DOWN_LINK: 35083b5dd52aSJames Smart case MBX_CONFIG_LINK: 35093b5dd52aSJames Smart case MBX_CONFIG_RING: 35103b5dd52aSJames Smart case MBX_RESET_RING: 35113b5dd52aSJames Smart case MBX_UNREG_LOGIN: 35123b5dd52aSJames Smart case MBX_CLEAR_LA: 35133b5dd52aSJames Smart case MBX_DUMP_CONTEXT: 35143b5dd52aSJames Smart case MBX_RUN_DIAGS: 35153b5dd52aSJames Smart case MBX_RESTART: 35163b5dd52aSJames Smart case MBX_SET_MASK: 35173b5dd52aSJames Smart if (!(vport->fc_flag & FC_OFFLINE_MODE)) { 35183b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 35193b5dd52aSJames Smart "2743 Command 0x%x is illegal in on-line " 35203b5dd52aSJames Smart "state\n", 35213b5dd52aSJames Smart mb->mbxCommand); 35223b5dd52aSJames Smart return -EPERM; 35233b5dd52aSJames Smart } 3524e9a7c711SGustavo A. R. Silva break; 35253b5dd52aSJames Smart case MBX_WRITE_NV: 35263b5dd52aSJames Smart case MBX_WRITE_VPARMS: 35273b5dd52aSJames Smart case MBX_LOAD_SM: 35283b5dd52aSJames Smart case MBX_READ_NV: 35293b5dd52aSJames Smart case MBX_READ_CONFIG: 35303b5dd52aSJames Smart case MBX_READ_RCONFIG: 35313b5dd52aSJames Smart case MBX_READ_STATUS: 35323b5dd52aSJames Smart case MBX_READ_XRI: 35333b5dd52aSJames Smart case MBX_READ_REV: 35343b5dd52aSJames Smart case MBX_READ_LNK_STAT: 35353b5dd52aSJames Smart case MBX_DUMP_MEMORY: 35363b5dd52aSJames Smart case MBX_DOWN_LOAD: 35373b5dd52aSJames Smart case MBX_UPDATE_CFG: 35383b5dd52aSJames Smart case MBX_KILL_BOARD: 353906f35551SJames Smart case MBX_READ_TOPOLOGY: 35403b5dd52aSJames Smart case MBX_LOAD_AREA: 35413b5dd52aSJames Smart case MBX_LOAD_EXP_ROM: 35423b5dd52aSJames Smart case MBX_BEACON: 35433b5dd52aSJames Smart case MBX_DEL_LD_ENTRY: 35443b5dd52aSJames Smart case MBX_SET_DEBUG: 35453b5dd52aSJames Smart case MBX_WRITE_WWN: 35463b5dd52aSJames Smart case MBX_SLI4_CONFIG: 3547c7495937SJames Smart case MBX_READ_EVENT_LOG: 35483b5dd52aSJames Smart case MBX_READ_EVENT_LOG_STATUS: 35493b5dd52aSJames Smart case MBX_WRITE_EVENT_LOG: 35503b5dd52aSJames Smart case MBX_PORT_CAPABILITIES: 35513b5dd52aSJames Smart case MBX_PORT_IOV_CONTROL: 35527a470277SJames Smart case MBX_RUN_BIU_DIAG64: 35533b5dd52aSJames Smart break; 35543b5dd52aSJames Smart case MBX_SET_VARIABLE: 3555e2aed29fSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_INIT, 3556e2aed29fSJames Smart "1226 mbox: set_variable 0x%x, 0x%x\n", 3557e2aed29fSJames Smart mb->un.varWords[0], 3558e2aed29fSJames Smart mb->un.varWords[1]); 3559e2aed29fSJames Smart if ((mb->un.varWords[0] == SETVAR_MLOMNT) 3560e2aed29fSJames Smart && (mb->un.varWords[1] == 1)) { 3561e2aed29fSJames Smart phba->wait_4_mlo_maint_flg = 1; 3562e2aed29fSJames Smart } else if (mb->un.varWords[0] == SETVAR_MLORST) { 35631b51197dSJames Smart spin_lock_irq(&phba->hbalock); 3564e2aed29fSJames Smart phba->link_flag &= ~LS_LOOPBACK_MODE; 35651b51197dSJames Smart spin_unlock_irq(&phba->hbalock); 356676a95d75SJames Smart phba->fc_topology = LPFC_TOPOLOGY_PT_PT; 3567e2aed29fSJames Smart } 3568e2aed29fSJames Smart break; 35693b5dd52aSJames Smart case MBX_READ_SPARM64: 35703b5dd52aSJames Smart case MBX_REG_LOGIN: 35713b5dd52aSJames Smart case MBX_REG_LOGIN64: 35723b5dd52aSJames Smart case MBX_CONFIG_PORT: 35733b5dd52aSJames Smart case MBX_RUN_BIU_DIAG: 35743b5dd52aSJames Smart default: 35753b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 35763b5dd52aSJames Smart "2742 Unknown Command 0x%x\n", 35773b5dd52aSJames Smart mb->mbxCommand); 35783b5dd52aSJames Smart return -EPERM; 35793b5dd52aSJames Smart } 35803b5dd52aSJames Smart 35813b5dd52aSJames Smart return 0; /* ok */ 35823b5dd52aSJames Smart } 35833b5dd52aSJames Smart 35843b5dd52aSJames Smart /** 35853145d2d6SLee Jones * lpfc_bsg_mbox_ext_session_reset - clean up context of multi-buffer mbox session 35867ad20aa9SJames Smart * @phba: Pointer to HBA context object. 35877ad20aa9SJames Smart * 35887ad20aa9SJames Smart * This is routine clean up and reset BSG handling of multi-buffer mbox 35897ad20aa9SJames Smart * command session. 35907ad20aa9SJames Smart **/ 35917ad20aa9SJames Smart static void 35927ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(struct lpfc_hba *phba) 35937ad20aa9SJames Smart { 35947ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_IDLE) 35957ad20aa9SJames Smart return; 35967ad20aa9SJames Smart 35977ad20aa9SJames Smart /* free all memory, including dma buffers */ 35987ad20aa9SJames Smart lpfc_bsg_dma_page_list_free(phba, 35997ad20aa9SJames Smart &phba->mbox_ext_buf_ctx.ext_dmabuf_list); 36007ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, phba->mbox_ext_buf_ctx.mbx_dmabuf); 36017ad20aa9SJames Smart /* multi-buffer write mailbox command pass-through complete */ 36027ad20aa9SJames Smart memset((char *)&phba->mbox_ext_buf_ctx, 0, 36037ad20aa9SJames Smart sizeof(struct lpfc_mbox_ext_buf_ctx)); 36047ad20aa9SJames Smart INIT_LIST_HEAD(&phba->mbox_ext_buf_ctx.ext_dmabuf_list); 36057ad20aa9SJames Smart 36067ad20aa9SJames Smart return; 36077ad20aa9SJames Smart } 36087ad20aa9SJames Smart 36097ad20aa9SJames Smart /** 36107ad20aa9SJames Smart * lpfc_bsg_issue_mbox_ext_handle_job - job handler for multi-buffer mbox cmpl 36117ad20aa9SJames Smart * @phba: Pointer to HBA context object. 36127ad20aa9SJames Smart * @pmboxq: Pointer to mailbox command. 36137ad20aa9SJames Smart * 36147ad20aa9SJames Smart * This is routine handles BSG job for mailbox commands completions with 36157ad20aa9SJames Smart * multiple external buffers. 36167ad20aa9SJames Smart **/ 361775cc8cfcSJohannes Thumshirn static struct bsg_job * 36187ad20aa9SJames Smart lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) 36197ad20aa9SJames Smart { 36207ad20aa9SJames Smart struct bsg_job_data *dd_data; 362175cc8cfcSJohannes Thumshirn struct bsg_job *job; 362201e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 36237ad20aa9SJames Smart uint8_t *pmb, *pmb_buf; 36247ad20aa9SJames Smart unsigned long flags; 36257ad20aa9SJames Smart uint32_t size; 36267ad20aa9SJames Smart int rc = 0; 3627026abb87SJames Smart struct lpfc_dmabuf *dmabuf; 3628026abb87SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 3629026abb87SJames Smart uint8_t *pmbx; 36307ad20aa9SJames Smart 36313e1f0718SJames Smart dd_data = pmboxq->ctx_buf; 3632a33c4f7bSJames Smart 3633a33c4f7bSJames Smart /* Determine if job has been aborted */ 3634a33c4f7bSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 3635a33c4f7bSJames Smart job = dd_data->set_job; 3636a33c4f7bSJames Smart if (job) { 363701e0e15cSJohannes Thumshirn bsg_reply = job->reply; 3638a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 3639a33c4f7bSJames Smart job->dd_data = NULL; 36407ad20aa9SJames Smart } 3641a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 36427ad20aa9SJames Smart 36437ad20aa9SJames Smart /* 36447ad20aa9SJames Smart * The outgoing buffer is readily referred from the dma buffer, 36457ad20aa9SJames Smart * just need to get header part from mailboxq structure. 36467ad20aa9SJames Smart */ 3647a33c4f7bSJames Smart 36487ad20aa9SJames Smart pmb = (uint8_t *)&pmboxq->u.mb; 36497ad20aa9SJames Smart pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb; 3650026abb87SJames Smart /* Copy the byte swapped response mailbox back to the user */ 36517ad20aa9SJames Smart memcpy(pmb_buf, pmb, sizeof(MAILBOX_t)); 3652026abb87SJames Smart /* if there is any non-embedded extended data copy that too */ 3653026abb87SJames Smart dmabuf = phba->mbox_ext_buf_ctx.mbx_dmabuf; 3654026abb87SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; 3655026abb87SJames Smart if (!bsg_bf_get(lpfc_mbox_hdr_emb, 3656026abb87SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) { 3657026abb87SJames Smart pmbx = (uint8_t *)dmabuf->virt; 3658026abb87SJames Smart /* byte swap the extended data following the mailbox command */ 3659026abb87SJames Smart lpfc_sli_pcimem_bcopy(&pmbx[sizeof(MAILBOX_t)], 3660026abb87SJames Smart &pmbx[sizeof(MAILBOX_t)], 3661026abb87SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys.mse[0].buf_len); 3662026abb87SJames Smart } 36637ad20aa9SJames Smart 3664a33c4f7bSJames Smart /* Complete the job if the job is still active */ 3665a33c4f7bSJames Smart 36667ad20aa9SJames Smart if (job) { 36677ad20aa9SJames Smart size = job->reply_payload.payload_len; 366801e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 36697ad20aa9SJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 36707ad20aa9SJames Smart job->reply_payload.sg_cnt, 36717ad20aa9SJames Smart pmb_buf, size); 3672a33c4f7bSJames Smart 36737ad20aa9SJames Smart /* result for successful */ 367401e0e15cSJohannes Thumshirn bsg_reply->result = 0; 3675a33c4f7bSJames Smart 36767ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 36777afc0ce9SColin Ian King "2937 SLI_CONFIG ext-buffer mailbox command " 36787ad20aa9SJames Smart "(x%x/x%x) complete bsg job done, bsize:%d\n", 36797ad20aa9SJames Smart phba->mbox_ext_buf_ctx.nembType, 36807ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType, size); 3681b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, 3682b76f2dc9SJames Smart phba->mbox_ext_buf_ctx.nembType, 3683b76f2dc9SJames Smart phba->mbox_ext_buf_ctx.mboxType, 3684b76f2dc9SJames Smart dma_ebuf, sta_pos_addr, 3685b76f2dc9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf, 0); 3686a33c4f7bSJames Smart } else { 36877ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 36887afc0ce9SColin Ian King "2938 SLI_CONFIG ext-buffer mailbox " 36897ad20aa9SJames Smart "command (x%x/x%x) failure, rc:x%x\n", 36907ad20aa9SJames Smart phba->mbox_ext_buf_ctx.nembType, 36917ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType, rc); 3692a33c4f7bSJames Smart } 3693a33c4f7bSJames Smart 3694a33c4f7bSJames Smart 36957ad20aa9SJames Smart /* state change */ 36967ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_DONE; 36977ad20aa9SJames Smart kfree(dd_data); 36987ad20aa9SJames Smart return job; 36997ad20aa9SJames Smart } 37007ad20aa9SJames Smart 37017ad20aa9SJames Smart /** 37027ad20aa9SJames Smart * lpfc_bsg_issue_read_mbox_ext_cmpl - compl handler for multi-buffer read mbox 37037ad20aa9SJames Smart * @phba: Pointer to HBA context object. 37047ad20aa9SJames Smart * @pmboxq: Pointer to mailbox command. 37057ad20aa9SJames Smart * 37067ad20aa9SJames Smart * This is completion handler function for mailbox read commands with multiple 37077ad20aa9SJames Smart * external buffers. 37087ad20aa9SJames Smart **/ 37097ad20aa9SJames Smart static void 37107ad20aa9SJames Smart lpfc_bsg_issue_read_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) 37117ad20aa9SJames Smart { 371275cc8cfcSJohannes Thumshirn struct bsg_job *job; 37131abaede7SJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 37147ad20aa9SJames Smart 3715a33c4f7bSJames Smart job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq); 3716a33c4f7bSJames Smart 37177ad20aa9SJames Smart /* handle the BSG job with mailbox command */ 3718a33c4f7bSJames Smart if (!job) 37197ad20aa9SJames Smart pmboxq->u.mb.mbxStatus = MBXERR_ERROR; 37207ad20aa9SJames Smart 37217ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 37227afc0ce9SColin Ian King "2939 SLI_CONFIG ext-buffer rd mailbox command " 37237ad20aa9SJames Smart "complete, ctxState:x%x, mbxStatus:x%x\n", 37247ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus); 37257ad20aa9SJames Smart 37267ad20aa9SJames Smart if (pmboxq->u.mb.mbxStatus || phba->mbox_ext_buf_ctx.numBuf == 1) 37277ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 37287ad20aa9SJames Smart 37297ad20aa9SJames Smart /* free base driver mailbox structure memory */ 37307ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 37317ad20aa9SJames Smart 3732a33c4f7bSJames Smart /* if the job is still active, call job done */ 37331abaede7SJohannes Thumshirn if (job) { 37341abaede7SJohannes Thumshirn bsg_reply = job->reply; 373506548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 37361abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 37371abaede7SJohannes Thumshirn } 37387ad20aa9SJames Smart return; 37397ad20aa9SJames Smart } 37407ad20aa9SJames Smart 37417ad20aa9SJames Smart /** 37427ad20aa9SJames Smart * lpfc_bsg_issue_write_mbox_ext_cmpl - cmpl handler for multi-buffer write mbox 37437ad20aa9SJames Smart * @phba: Pointer to HBA context object. 37447ad20aa9SJames Smart * @pmboxq: Pointer to mailbox command. 37457ad20aa9SJames Smart * 37467ad20aa9SJames Smart * This is completion handler function for mailbox write commands with multiple 37477ad20aa9SJames Smart * external buffers. 37487ad20aa9SJames Smart **/ 37497ad20aa9SJames Smart static void 37507ad20aa9SJames Smart lpfc_bsg_issue_write_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) 37517ad20aa9SJames Smart { 375275cc8cfcSJohannes Thumshirn struct bsg_job *job; 37531abaede7SJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 37547ad20aa9SJames Smart 3755a33c4f7bSJames Smart job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq); 3756a33c4f7bSJames Smart 37577ad20aa9SJames Smart /* handle the BSG job with the mailbox command */ 3758a33c4f7bSJames Smart if (!job) 37597ad20aa9SJames Smart pmboxq->u.mb.mbxStatus = MBXERR_ERROR; 37607ad20aa9SJames Smart 37617ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 37627afc0ce9SColin Ian King "2940 SLI_CONFIG ext-buffer wr mailbox command " 37637ad20aa9SJames Smart "complete, ctxState:x%x, mbxStatus:x%x\n", 37647ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus); 37657ad20aa9SJames Smart 37667ad20aa9SJames Smart /* free all memory, including dma buffers */ 37677ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 37687ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 37697ad20aa9SJames Smart 3770a33c4f7bSJames Smart /* if the job is still active, call job done */ 37711abaede7SJohannes Thumshirn if (job) { 37721abaede7SJohannes Thumshirn bsg_reply = job->reply; 377306548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 37741abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 37751abaede7SJohannes Thumshirn } 37767ad20aa9SJames Smart 37777ad20aa9SJames Smart return; 37787ad20aa9SJames Smart } 37797ad20aa9SJames Smart 37807ad20aa9SJames Smart static void 37817ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(struct lpfc_hba *phba, enum nemb_type nemb_tp, 37827ad20aa9SJames Smart uint32_t index, struct lpfc_dmabuf *mbx_dmabuf, 37837ad20aa9SJames Smart struct lpfc_dmabuf *ext_dmabuf) 37847ad20aa9SJames Smart { 37857ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 37867ad20aa9SJames Smart 37877ad20aa9SJames Smart /* pointer to the start of mailbox command */ 37887ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)mbx_dmabuf->virt; 37897ad20aa9SJames Smart 37907ad20aa9SJames Smart if (nemb_tp == nemb_mse) { 37917ad20aa9SJames Smart if (index == 0) { 37927ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37937ad20aa9SJames Smart mse[index].pa_hi = 37947ad20aa9SJames Smart putPaddrHigh(mbx_dmabuf->phys + 37957ad20aa9SJames Smart sizeof(MAILBOX_t)); 37967ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 37977ad20aa9SJames Smart mse[index].pa_lo = 37987ad20aa9SJames Smart putPaddrLow(mbx_dmabuf->phys + 37997ad20aa9SJames Smart sizeof(MAILBOX_t)); 38007ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 38017ad20aa9SJames Smart "2943 SLI_CONFIG(mse)[%d], " 38027ad20aa9SJames Smart "bufLen:%d, addrHi:x%x, addrLo:x%x\n", 38037ad20aa9SJames Smart index, 38047ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 38057ad20aa9SJames Smart mse[index].buf_len, 38067ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 38077ad20aa9SJames Smart mse[index].pa_hi, 38087ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 38097ad20aa9SJames Smart mse[index].pa_lo); 38107ad20aa9SJames Smart } else { 38117ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 38127ad20aa9SJames Smart mse[index].pa_hi = 38137ad20aa9SJames Smart putPaddrHigh(ext_dmabuf->phys); 38147ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 38157ad20aa9SJames Smart mse[index].pa_lo = 38167ad20aa9SJames Smart putPaddrLow(ext_dmabuf->phys); 38177ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 38187ad20aa9SJames Smart "2944 SLI_CONFIG(mse)[%d], " 38197ad20aa9SJames Smart "bufLen:%d, addrHi:x%x, addrLo:x%x\n", 38207ad20aa9SJames Smart index, 38217ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 38227ad20aa9SJames Smart mse[index].buf_len, 38237ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 38247ad20aa9SJames Smart mse[index].pa_hi, 38257ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 38267ad20aa9SJames Smart mse[index].pa_lo); 38277ad20aa9SJames Smart } 38287ad20aa9SJames Smart } else { 38297ad20aa9SJames Smart if (index == 0) { 38307ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 38317ad20aa9SJames Smart hbd[index].pa_hi = 38327ad20aa9SJames Smart putPaddrHigh(mbx_dmabuf->phys + 38337ad20aa9SJames Smart sizeof(MAILBOX_t)); 38347ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 38357ad20aa9SJames Smart hbd[index].pa_lo = 38367ad20aa9SJames Smart putPaddrLow(mbx_dmabuf->phys + 38377ad20aa9SJames Smart sizeof(MAILBOX_t)); 38387ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 38397ad20aa9SJames Smart "3007 SLI_CONFIG(hbd)[%d], " 38407ad20aa9SJames Smart "bufLen:%d, addrHi:x%x, addrLo:x%x\n", 38417ad20aa9SJames Smart index, 38427ad20aa9SJames Smart bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, 38437ad20aa9SJames Smart &sli_cfg_mbx->un. 38447ad20aa9SJames Smart sli_config_emb1_subsys.hbd[index]), 38457ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 38467ad20aa9SJames Smart hbd[index].pa_hi, 38477ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 38487ad20aa9SJames Smart hbd[index].pa_lo); 38497ad20aa9SJames Smart 38507ad20aa9SJames Smart } else { 38517ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 38527ad20aa9SJames Smart hbd[index].pa_hi = 38537ad20aa9SJames Smart putPaddrHigh(ext_dmabuf->phys); 38547ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 38557ad20aa9SJames Smart hbd[index].pa_lo = 38567ad20aa9SJames Smart putPaddrLow(ext_dmabuf->phys); 38577ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 38587ad20aa9SJames Smart "3008 SLI_CONFIG(hbd)[%d], " 38597ad20aa9SJames Smart "bufLen:%d, addrHi:x%x, addrLo:x%x\n", 38607ad20aa9SJames Smart index, 38617ad20aa9SJames Smart bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, 38627ad20aa9SJames Smart &sli_cfg_mbx->un. 38637ad20aa9SJames Smart sli_config_emb1_subsys.hbd[index]), 38647ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 38657ad20aa9SJames Smart hbd[index].pa_hi, 38667ad20aa9SJames Smart sli_cfg_mbx->un.sli_config_emb1_subsys. 38677ad20aa9SJames Smart hbd[index].pa_lo); 38687ad20aa9SJames Smart } 38697ad20aa9SJames Smart } 38707ad20aa9SJames Smart return; 38717ad20aa9SJames Smart } 38727ad20aa9SJames Smart 38737ad20aa9SJames Smart /** 38743145d2d6SLee Jones * lpfc_bsg_sli_cfg_read_cmd_ext - sli_config non-embedded mailbox cmd read 38757ad20aa9SJames Smart * @phba: Pointer to HBA context object. 3876ea085dabSLee Jones * @job: Pointer to the job object. 38777ad20aa9SJames Smart * @nemb_tp: Enumerate of non-embedded mailbox command type. 3878ea085dabSLee Jones * @dmabuf: Pointer to a DMA buffer descriptor. 38797ad20aa9SJames Smart * 38807ad20aa9SJames Smart * This routine performs SLI_CONFIG (0x9B) read mailbox command operation with 38817ad20aa9SJames Smart * non-embedded external bufffers. 38827ad20aa9SJames Smart **/ 38837ad20aa9SJames Smart static int 388475cc8cfcSJohannes Thumshirn lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job, 38857ad20aa9SJames Smart enum nemb_type nemb_tp, 38867ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 38877ad20aa9SJames Smart { 388801e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 38897ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 38907ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 38917ad20aa9SJames Smart struct lpfc_dmabuf *curr_dmabuf, *next_dmabuf; 38927ad20aa9SJames Smart uint32_t ext_buf_cnt, ext_buf_index; 38937ad20aa9SJames Smart struct lpfc_dmabuf *ext_dmabuf = NULL; 38947ad20aa9SJames Smart struct bsg_job_data *dd_data = NULL; 38957ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq = NULL; 38967ad20aa9SJames Smart MAILBOX_t *pmb; 38977ad20aa9SJames Smart uint8_t *pmbx; 38987ad20aa9SJames Smart int rc, i; 38997ad20aa9SJames Smart 39007ad20aa9SJames Smart mbox_req = 390101e0e15cSJohannes Thumshirn (struct dfc_mbox_req *)bsg_request->rqst_data.h_vendor.vendor_cmd; 39027ad20aa9SJames Smart 39037ad20aa9SJames Smart /* pointer to the start of mailbox command */ 39047ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; 39057ad20aa9SJames Smart 39067ad20aa9SJames Smart if (nemb_tp == nemb_mse) { 39077ad20aa9SJames Smart ext_buf_cnt = bsg_bf_get(lpfc_mbox_hdr_mse_cnt, 39087ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr); 39097ad20aa9SJames Smart if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_MSE) { 39107ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 39117ad20aa9SJames Smart "2945 Handled SLI_CONFIG(mse) rd, " 39127ad20aa9SJames Smart "ext_buf_cnt(%d) out of range(%d)\n", 39137ad20aa9SJames Smart ext_buf_cnt, 39147ad20aa9SJames Smart LPFC_MBX_SLI_CONFIG_MAX_MSE); 39157ad20aa9SJames Smart rc = -ERANGE; 39167ad20aa9SJames Smart goto job_error; 39177ad20aa9SJames Smart } 39187ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 39197ad20aa9SJames Smart "2941 Handled SLI_CONFIG(mse) rd, " 39207ad20aa9SJames Smart "ext_buf_cnt:%d\n", ext_buf_cnt); 39217ad20aa9SJames Smart } else { 39227ad20aa9SJames Smart /* sanity check on interface type for support */ 392327d6ac0aSJames Smart if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) < 39247ad20aa9SJames Smart LPFC_SLI_INTF_IF_TYPE_2) { 39257ad20aa9SJames Smart rc = -ENODEV; 39267ad20aa9SJames Smart goto job_error; 39277ad20aa9SJames Smart } 39287ad20aa9SJames Smart /* nemb_tp == nemb_hbd */ 39297ad20aa9SJames Smart ext_buf_cnt = sli_cfg_mbx->un.sli_config_emb1_subsys.hbd_count; 39307ad20aa9SJames Smart if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_HBD) { 39317ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 39327ad20aa9SJames Smart "2946 Handled SLI_CONFIG(hbd) rd, " 39337ad20aa9SJames Smart "ext_buf_cnt(%d) out of range(%d)\n", 39347ad20aa9SJames Smart ext_buf_cnt, 39357ad20aa9SJames Smart LPFC_MBX_SLI_CONFIG_MAX_HBD); 39367ad20aa9SJames Smart rc = -ERANGE; 39377ad20aa9SJames Smart goto job_error; 39387ad20aa9SJames Smart } 39397ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 39407ad20aa9SJames Smart "2942 Handled SLI_CONFIG(hbd) rd, " 39417ad20aa9SJames Smart "ext_buf_cnt:%d\n", ext_buf_cnt); 39427ad20aa9SJames Smart } 39437ad20aa9SJames Smart 3944b76f2dc9SJames Smart /* before dma descriptor setup */ 3945b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_rd, dma_mbox, 3946b76f2dc9SJames Smart sta_pre_addr, dmabuf, ext_buf_cnt); 3947b76f2dc9SJames Smart 39487ad20aa9SJames Smart /* reject non-embedded mailbox command with none external buffer */ 39497ad20aa9SJames Smart if (ext_buf_cnt == 0) { 39507ad20aa9SJames Smart rc = -EPERM; 39517ad20aa9SJames Smart goto job_error; 39527ad20aa9SJames Smart } else if (ext_buf_cnt > 1) { 39537ad20aa9SJames Smart /* additional external read buffers */ 39547ad20aa9SJames Smart for (i = 1; i < ext_buf_cnt; i++) { 39557ad20aa9SJames Smart ext_dmabuf = lpfc_bsg_dma_page_alloc(phba); 39567ad20aa9SJames Smart if (!ext_dmabuf) { 39577ad20aa9SJames Smart rc = -ENOMEM; 39587ad20aa9SJames Smart goto job_error; 39597ad20aa9SJames Smart } 39607ad20aa9SJames Smart list_add_tail(&ext_dmabuf->list, 39617ad20aa9SJames Smart &phba->mbox_ext_buf_ctx.ext_dmabuf_list); 39627ad20aa9SJames Smart } 39637ad20aa9SJames Smart } 39647ad20aa9SJames Smart 39657ad20aa9SJames Smart /* bsg tracking structure */ 39667ad20aa9SJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 39677ad20aa9SJames Smart if (!dd_data) { 39687ad20aa9SJames Smart rc = -ENOMEM; 39697ad20aa9SJames Smart goto job_error; 39707ad20aa9SJames Smart } 39717ad20aa9SJames Smart 39727ad20aa9SJames Smart /* mailbox command structure for base driver */ 39737ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 39747ad20aa9SJames Smart if (!pmboxq) { 39757ad20aa9SJames Smart rc = -ENOMEM; 39767ad20aa9SJames Smart goto job_error; 39777ad20aa9SJames Smart } 39787ad20aa9SJames Smart memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 39797ad20aa9SJames Smart 39807ad20aa9SJames Smart /* for the first external buffer */ 39817ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 0, dmabuf, dmabuf); 39827ad20aa9SJames Smart 39837ad20aa9SJames Smart /* for the rest of external buffer descriptors if any */ 39847ad20aa9SJames Smart if (ext_buf_cnt > 1) { 39857ad20aa9SJames Smart ext_buf_index = 1; 39867ad20aa9SJames Smart list_for_each_entry_safe(curr_dmabuf, next_dmabuf, 39877ad20aa9SJames Smart &phba->mbox_ext_buf_ctx.ext_dmabuf_list, list) { 39887ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 39897ad20aa9SJames Smart ext_buf_index, dmabuf, 39907ad20aa9SJames Smart curr_dmabuf); 39917ad20aa9SJames Smart ext_buf_index++; 39927ad20aa9SJames Smart } 39937ad20aa9SJames Smart } 39947ad20aa9SJames Smart 3995b76f2dc9SJames Smart /* after dma descriptor setup */ 3996b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_rd, dma_mbox, 3997b76f2dc9SJames Smart sta_pos_addr, dmabuf, ext_buf_cnt); 3998b76f2dc9SJames Smart 39997ad20aa9SJames Smart /* construct base driver mbox command */ 40007ad20aa9SJames Smart pmb = &pmboxq->u.mb; 40017ad20aa9SJames Smart pmbx = (uint8_t *)dmabuf->virt; 40027ad20aa9SJames Smart memcpy(pmb, pmbx, sizeof(*pmb)); 40037ad20aa9SJames Smart pmb->mbxOwner = OWN_HOST; 40047ad20aa9SJames Smart pmboxq->vport = phba->pport; 40057ad20aa9SJames Smart 40067ad20aa9SJames Smart /* multi-buffer handling context */ 40077ad20aa9SJames Smart phba->mbox_ext_buf_ctx.nembType = nemb_tp; 40087ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType = mbox_rd; 40097ad20aa9SJames Smart phba->mbox_ext_buf_ctx.numBuf = ext_buf_cnt; 40107ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbxTag = mbox_req->extMboxTag; 40117ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum = mbox_req->extSeqNum; 40127ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf = dmabuf; 40137ad20aa9SJames Smart 40147ad20aa9SJames Smart /* callback for multi-buffer read mailbox command */ 40157ad20aa9SJames Smart pmboxq->mbox_cmpl = lpfc_bsg_issue_read_mbox_ext_cmpl; 40167ad20aa9SJames Smart 40177ad20aa9SJames Smart /* context fields to callback function */ 40183e1f0718SJames Smart pmboxq->ctx_buf = dd_data; 40197ad20aa9SJames Smart dd_data->type = TYPE_MBOX; 4020a33c4f7bSJames Smart dd_data->set_job = job; 40217ad20aa9SJames Smart dd_data->context_un.mbox.pmboxq = pmboxq; 40227ad20aa9SJames Smart dd_data->context_un.mbox.mb = (MAILBOX_t *)pmbx; 40237ad20aa9SJames Smart job->dd_data = dd_data; 40247ad20aa9SJames Smart 40257ad20aa9SJames Smart /* state change */ 40267ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT; 40277ad20aa9SJames Smart 4028026abb87SJames Smart /* 4029026abb87SJames Smart * Non-embedded mailbox subcommand data gets byte swapped here because 4030026abb87SJames Smart * the lower level driver code only does the first 64 mailbox words. 4031026abb87SJames Smart */ 4032026abb87SJames Smart if ((!bsg_bf_get(lpfc_mbox_hdr_emb, 4033026abb87SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) && 4034026abb87SJames Smart (nemb_tp == nemb_mse)) 4035026abb87SJames Smart lpfc_sli_pcimem_bcopy(&pmbx[sizeof(MAILBOX_t)], 4036026abb87SJames Smart &pmbx[sizeof(MAILBOX_t)], 4037026abb87SJames Smart sli_cfg_mbx->un.sli_config_emb0_subsys. 4038026abb87SJames Smart mse[0].buf_len); 4039026abb87SJames Smart 40407ad20aa9SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); 40417ad20aa9SJames Smart if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { 40427ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 40437ad20aa9SJames Smart "2947 Issued SLI_CONFIG ext-buffer " 40447afc0ce9SColin Ian King "mailbox command, rc:x%x\n", rc); 404588a2cfbbSJames Smart return SLI_CONFIG_HANDLED; 40467ad20aa9SJames Smart } 40477ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 40487ad20aa9SJames Smart "2948 Failed to issue SLI_CONFIG ext-buffer " 40497afc0ce9SColin Ian King "mailbox command, rc:x%x\n", rc); 40507ad20aa9SJames Smart rc = -EPIPE; 40517ad20aa9SJames Smart 40527ad20aa9SJames Smart job_error: 40537ad20aa9SJames Smart if (pmboxq) 40547ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 40557ad20aa9SJames Smart lpfc_bsg_dma_page_list_free(phba, 40567ad20aa9SJames Smart &phba->mbox_ext_buf_ctx.ext_dmabuf_list); 40577ad20aa9SJames Smart kfree(dd_data); 40587ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_IDLE; 40597ad20aa9SJames Smart return rc; 40607ad20aa9SJames Smart } 40617ad20aa9SJames Smart 40627ad20aa9SJames Smart /** 40637ad20aa9SJames Smart * lpfc_bsg_sli_cfg_write_cmd_ext - sli_config non-embedded mailbox cmd write 40647ad20aa9SJames Smart * @phba: Pointer to HBA context object. 4065ea085dabSLee Jones * @job: Pointer to the job object. 4066ea085dabSLee Jones * @nemb_tp: Enumerate of non-embedded mailbox command type. 4067ea085dabSLee Jones * @dmabuf: Pointer to a DMA buffer descriptor. 40687ad20aa9SJames Smart * 40697ad20aa9SJames Smart * This routine performs SLI_CONFIG (0x9B) write mailbox command operation with 40707ad20aa9SJames Smart * non-embedded external bufffers. 40717ad20aa9SJames Smart **/ 40727ad20aa9SJames Smart static int 407375cc8cfcSJohannes Thumshirn lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job, 40747ad20aa9SJames Smart enum nemb_type nemb_tp, 40757ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 40767ad20aa9SJames Smart { 407701e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 407801e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 40797ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 40807ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 40817ad20aa9SJames Smart uint32_t ext_buf_cnt; 40827ad20aa9SJames Smart struct bsg_job_data *dd_data = NULL; 40837ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq = NULL; 40847ad20aa9SJames Smart MAILBOX_t *pmb; 40857ad20aa9SJames Smart uint8_t *mbx; 408688a2cfbbSJames Smart int rc = SLI_CONFIG_NOT_HANDLED, i; 40877ad20aa9SJames Smart 40887ad20aa9SJames Smart mbox_req = 408901e0e15cSJohannes Thumshirn (struct dfc_mbox_req *)bsg_request->rqst_data.h_vendor.vendor_cmd; 40907ad20aa9SJames Smart 40917ad20aa9SJames Smart /* pointer to the start of mailbox command */ 40927ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; 40937ad20aa9SJames Smart 40947ad20aa9SJames Smart if (nemb_tp == nemb_mse) { 40957ad20aa9SJames Smart ext_buf_cnt = bsg_bf_get(lpfc_mbox_hdr_mse_cnt, 40967ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr); 40977ad20aa9SJames Smart if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_MSE) { 40987ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 4099026abb87SJames Smart "2953 Failed SLI_CONFIG(mse) wr, " 41007ad20aa9SJames Smart "ext_buf_cnt(%d) out of range(%d)\n", 41017ad20aa9SJames Smart ext_buf_cnt, 41027ad20aa9SJames Smart LPFC_MBX_SLI_CONFIG_MAX_MSE); 41037ad20aa9SJames Smart return -ERANGE; 41047ad20aa9SJames Smart } 41057ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 41067ad20aa9SJames Smart "2949 Handled SLI_CONFIG(mse) wr, " 41077ad20aa9SJames Smart "ext_buf_cnt:%d\n", ext_buf_cnt); 41087ad20aa9SJames Smart } else { 41097ad20aa9SJames Smart /* sanity check on interface type for support */ 411027d6ac0aSJames Smart if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) < 41117ad20aa9SJames Smart LPFC_SLI_INTF_IF_TYPE_2) 41127ad20aa9SJames Smart return -ENODEV; 41137ad20aa9SJames Smart /* nemb_tp == nemb_hbd */ 41147ad20aa9SJames Smart ext_buf_cnt = sli_cfg_mbx->un.sli_config_emb1_subsys.hbd_count; 41157ad20aa9SJames Smart if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_HBD) { 41167ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 4117026abb87SJames Smart "2954 Failed SLI_CONFIG(hbd) wr, " 41187ad20aa9SJames Smart "ext_buf_cnt(%d) out of range(%d)\n", 41197ad20aa9SJames Smart ext_buf_cnt, 41207ad20aa9SJames Smart LPFC_MBX_SLI_CONFIG_MAX_HBD); 41217ad20aa9SJames Smart return -ERANGE; 41227ad20aa9SJames Smart } 41237ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 41247ad20aa9SJames Smart "2950 Handled SLI_CONFIG(hbd) wr, " 41257ad20aa9SJames Smart "ext_buf_cnt:%d\n", ext_buf_cnt); 41267ad20aa9SJames Smart } 41277ad20aa9SJames Smart 4128b76f2dc9SJames Smart /* before dma buffer descriptor setup */ 4129b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_wr, dma_mbox, 4130b76f2dc9SJames Smart sta_pre_addr, dmabuf, ext_buf_cnt); 4131b76f2dc9SJames Smart 41327ad20aa9SJames Smart if (ext_buf_cnt == 0) 41337ad20aa9SJames Smart return -EPERM; 41347ad20aa9SJames Smart 41357ad20aa9SJames Smart /* for the first external buffer */ 41367ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 0, dmabuf, dmabuf); 41377ad20aa9SJames Smart 4138b76f2dc9SJames Smart /* after dma descriptor setup */ 4139b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_wr, dma_mbox, 4140b76f2dc9SJames Smart sta_pos_addr, dmabuf, ext_buf_cnt); 4141b76f2dc9SJames Smart 41427ad20aa9SJames Smart /* log for looking forward */ 41437ad20aa9SJames Smart for (i = 1; i < ext_buf_cnt; i++) { 41447ad20aa9SJames Smart if (nemb_tp == nemb_mse) 41457ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 41467ad20aa9SJames Smart "2951 SLI_CONFIG(mse), buf[%d]-length:%d\n", 41477ad20aa9SJames Smart i, sli_cfg_mbx->un.sli_config_emb0_subsys. 41487ad20aa9SJames Smart mse[i].buf_len); 41497ad20aa9SJames Smart else 41507ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 41517ad20aa9SJames Smart "2952 SLI_CONFIG(hbd), buf[%d]-length:%d\n", 41527ad20aa9SJames Smart i, bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, 41537ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb1_subsys. 41547ad20aa9SJames Smart hbd[i])); 41557ad20aa9SJames Smart } 41567ad20aa9SJames Smart 41577ad20aa9SJames Smart /* multi-buffer handling context */ 41587ad20aa9SJames Smart phba->mbox_ext_buf_ctx.nembType = nemb_tp; 41597ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType = mbox_wr; 41607ad20aa9SJames Smart phba->mbox_ext_buf_ctx.numBuf = ext_buf_cnt; 41617ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbxTag = mbox_req->extMboxTag; 41627ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum = mbox_req->extSeqNum; 41637ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf = dmabuf; 41647ad20aa9SJames Smart 41657ad20aa9SJames Smart if (ext_buf_cnt == 1) { 41667ad20aa9SJames Smart /* bsg tracking structure */ 41677ad20aa9SJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 41687ad20aa9SJames Smart if (!dd_data) { 41697ad20aa9SJames Smart rc = -ENOMEM; 41707ad20aa9SJames Smart goto job_error; 41717ad20aa9SJames Smart } 41727ad20aa9SJames Smart 41737ad20aa9SJames Smart /* mailbox command structure for base driver */ 41747ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 41757ad20aa9SJames Smart if (!pmboxq) { 41767ad20aa9SJames Smart rc = -ENOMEM; 41777ad20aa9SJames Smart goto job_error; 41787ad20aa9SJames Smart } 41797ad20aa9SJames Smart memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 41807ad20aa9SJames Smart pmb = &pmboxq->u.mb; 41817ad20aa9SJames Smart mbx = (uint8_t *)dmabuf->virt; 41827ad20aa9SJames Smart memcpy(pmb, mbx, sizeof(*pmb)); 41837ad20aa9SJames Smart pmb->mbxOwner = OWN_HOST; 41847ad20aa9SJames Smart pmboxq->vport = phba->pport; 41857ad20aa9SJames Smart 41867ad20aa9SJames Smart /* callback for multi-buffer read mailbox command */ 41877ad20aa9SJames Smart pmboxq->mbox_cmpl = lpfc_bsg_issue_write_mbox_ext_cmpl; 41887ad20aa9SJames Smart 41897ad20aa9SJames Smart /* context fields to callback function */ 41903e1f0718SJames Smart pmboxq->ctx_buf = dd_data; 41917ad20aa9SJames Smart dd_data->type = TYPE_MBOX; 4192a33c4f7bSJames Smart dd_data->set_job = job; 41937ad20aa9SJames Smart dd_data->context_un.mbox.pmboxq = pmboxq; 41947ad20aa9SJames Smart dd_data->context_un.mbox.mb = (MAILBOX_t *)mbx; 41957ad20aa9SJames Smart job->dd_data = dd_data; 41967ad20aa9SJames Smart 41977ad20aa9SJames Smart /* state change */ 41987ad20aa9SJames Smart 4199a33c4f7bSJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT; 42007ad20aa9SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); 42017ad20aa9SJames Smart if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { 42027ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 42037ad20aa9SJames Smart "2955 Issued SLI_CONFIG ext-buffer " 42047afc0ce9SColin Ian King "mailbox command, rc:x%x\n", rc); 420588a2cfbbSJames Smart return SLI_CONFIG_HANDLED; 42067ad20aa9SJames Smart } 42077ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 42087ad20aa9SJames Smart "2956 Failed to issue SLI_CONFIG ext-buffer " 42097afc0ce9SColin Ian King "mailbox command, rc:x%x\n", rc); 42107ad20aa9SJames Smart rc = -EPIPE; 4211026abb87SJames Smart goto job_error; 42127ad20aa9SJames Smart } 42137ad20aa9SJames Smart 421488a2cfbbSJames Smart /* wait for additoinal external buffers */ 4215a33c4f7bSJames Smart 421601e0e15cSJohannes Thumshirn bsg_reply->result = 0; 421706548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 42181abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 421988a2cfbbSJames Smart return SLI_CONFIG_HANDLED; 422088a2cfbbSJames Smart 42217ad20aa9SJames Smart job_error: 42227ad20aa9SJames Smart if (pmboxq) 42237ad20aa9SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 42247ad20aa9SJames Smart kfree(dd_data); 42257ad20aa9SJames Smart 42267ad20aa9SJames Smart return rc; 42277ad20aa9SJames Smart } 42287ad20aa9SJames Smart 42297ad20aa9SJames Smart /** 42307ad20aa9SJames Smart * lpfc_bsg_handle_sli_cfg_mbox - handle sli-cfg mailbox cmd with ext buffer 42317ad20aa9SJames Smart * @phba: Pointer to HBA context object. 4232ea085dabSLee Jones * @job: Pointer to the job object. 4233ea085dabSLee Jones * @dmabuf: Pointer to a DMA buffer descriptor. 42347ad20aa9SJames Smart * 42357ad20aa9SJames Smart * This routine handles SLI_CONFIG (0x9B) mailbox command with non-embedded 42367ad20aa9SJames Smart * external bufffers, including both 0x9B with non-embedded MSEs and 0x9B 42377ad20aa9SJames Smart * with embedded sussystem 0x1 and opcodes with external HBDs. 42387ad20aa9SJames Smart **/ 42397ad20aa9SJames Smart static int 424075cc8cfcSJohannes Thumshirn lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct bsg_job *job, 42417ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 42427ad20aa9SJames Smart { 42437ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 42447ad20aa9SJames Smart uint32_t subsys; 42457ad20aa9SJames Smart uint32_t opcode; 42467ad20aa9SJames Smart int rc = SLI_CONFIG_NOT_HANDLED; 42477ad20aa9SJames Smart 4248026abb87SJames Smart /* state change on new multi-buffer pass-through mailbox command */ 42497ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_HOST; 42507ad20aa9SJames Smart 42517ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; 42527ad20aa9SJames Smart 42537ad20aa9SJames Smart if (!bsg_bf_get(lpfc_mbox_hdr_emb, 42547ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) { 42557ad20aa9SJames Smart subsys = bsg_bf_get(lpfc_emb0_subcmnd_subsys, 42567ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys); 42577ad20aa9SJames Smart opcode = bsg_bf_get(lpfc_emb0_subcmnd_opcode, 42587ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys); 42597ad20aa9SJames Smart if (subsys == SLI_CONFIG_SUBSYS_FCOE) { 42607ad20aa9SJames Smart switch (opcode) { 42617ad20aa9SJames Smart case FCOE_OPCODE_READ_FCF: 42622a2719d3SJames Smart case FCOE_OPCODE_GET_DPORT_RESULTS: 42637ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 42647ad20aa9SJames Smart "2957 Handled SLI_CONFIG " 42657ad20aa9SJames Smart "subsys_fcoe, opcode:x%x\n", 42667ad20aa9SJames Smart opcode); 42677ad20aa9SJames Smart rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job, 42687ad20aa9SJames Smart nemb_mse, dmabuf); 42697ad20aa9SJames Smart break; 42707ad20aa9SJames Smart case FCOE_OPCODE_ADD_FCF: 42712a2719d3SJames Smart case FCOE_OPCODE_SET_DPORT_MODE: 42722a2719d3SJames Smart case LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE: 42737ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 42747ad20aa9SJames Smart "2958 Handled SLI_CONFIG " 42757ad20aa9SJames Smart "subsys_fcoe, opcode:x%x\n", 42767ad20aa9SJames Smart opcode); 42777ad20aa9SJames Smart rc = lpfc_bsg_sli_cfg_write_cmd_ext(phba, job, 42787ad20aa9SJames Smart nemb_mse, dmabuf); 42797ad20aa9SJames Smart break; 42807ad20aa9SJames Smart default: 42817ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4282026abb87SJames Smart "2959 Reject SLI_CONFIG " 42837ad20aa9SJames Smart "subsys_fcoe, opcode:x%x\n", 42847ad20aa9SJames Smart opcode); 4285026abb87SJames Smart rc = -EPERM; 4286026abb87SJames Smart break; 4287026abb87SJames Smart } 4288026abb87SJames Smart } else if (subsys == SLI_CONFIG_SUBSYS_COMN) { 4289026abb87SJames Smart switch (opcode) { 4290026abb87SJames Smart case COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES: 4291b99570ddSJames Smart case COMN_OPCODE_GET_CNTL_ATTRIBUTES: 4292c6377970SJames Smart case COMN_OPCODE_GET_PROFILE_CONFIG: 429345bc4427SDick Kennedy case COMN_OPCODE_SET_FEATURES: 4294026abb87SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4295026abb87SJames Smart "3106 Handled SLI_CONFIG " 42966b5151fdSJames Smart "subsys_comn, opcode:x%x\n", 4297026abb87SJames Smart opcode); 4298026abb87SJames Smart rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job, 4299026abb87SJames Smart nemb_mse, dmabuf); 4300026abb87SJames Smart break; 4301026abb87SJames Smart default: 4302026abb87SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4303026abb87SJames Smart "3107 Reject SLI_CONFIG " 43046b5151fdSJames Smart "subsys_comn, opcode:x%x\n", 4305026abb87SJames Smart opcode); 4306026abb87SJames Smart rc = -EPERM; 43077ad20aa9SJames Smart break; 43087ad20aa9SJames Smart } 43097ad20aa9SJames Smart } else { 43107ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4311026abb87SJames Smart "2977 Reject SLI_CONFIG " 43127ad20aa9SJames Smart "subsys:x%d, opcode:x%x\n", 43137ad20aa9SJames Smart subsys, opcode); 4314026abb87SJames Smart rc = -EPERM; 43157ad20aa9SJames Smart } 43167ad20aa9SJames Smart } else { 43177ad20aa9SJames Smart subsys = bsg_bf_get(lpfc_emb1_subcmnd_subsys, 43187ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb1_subsys); 43197ad20aa9SJames Smart opcode = bsg_bf_get(lpfc_emb1_subcmnd_opcode, 43207ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb1_subsys); 43217ad20aa9SJames Smart if (subsys == SLI_CONFIG_SUBSYS_COMN) { 43227ad20aa9SJames Smart switch (opcode) { 43237ad20aa9SJames Smart case COMN_OPCODE_READ_OBJECT: 43247ad20aa9SJames Smart case COMN_OPCODE_READ_OBJECT_LIST: 43257ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 43267ad20aa9SJames Smart "2960 Handled SLI_CONFIG " 43277ad20aa9SJames Smart "subsys_comn, opcode:x%x\n", 43287ad20aa9SJames Smart opcode); 43297ad20aa9SJames Smart rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job, 43307ad20aa9SJames Smart nemb_hbd, dmabuf); 43317ad20aa9SJames Smart break; 43327ad20aa9SJames Smart case COMN_OPCODE_WRITE_OBJECT: 43337ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 43347ad20aa9SJames Smart "2961 Handled SLI_CONFIG " 43357ad20aa9SJames Smart "subsys_comn, opcode:x%x\n", 43367ad20aa9SJames Smart opcode); 43377ad20aa9SJames Smart rc = lpfc_bsg_sli_cfg_write_cmd_ext(phba, job, 43387ad20aa9SJames Smart nemb_hbd, dmabuf); 43397ad20aa9SJames Smart break; 43407ad20aa9SJames Smart default: 43417ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 43427ad20aa9SJames Smart "2962 Not handled SLI_CONFIG " 43437ad20aa9SJames Smart "subsys_comn, opcode:x%x\n", 43447ad20aa9SJames Smart opcode); 43457ad20aa9SJames Smart rc = SLI_CONFIG_NOT_HANDLED; 43467ad20aa9SJames Smart break; 43477ad20aa9SJames Smart } 43487ad20aa9SJames Smart } else { 43497ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 4350026abb87SJames Smart "2978 Not handled SLI_CONFIG " 43517ad20aa9SJames Smart "subsys:x%d, opcode:x%x\n", 43527ad20aa9SJames Smart subsys, opcode); 43537ad20aa9SJames Smart rc = SLI_CONFIG_NOT_HANDLED; 43547ad20aa9SJames Smart } 43557ad20aa9SJames Smart } 4356026abb87SJames Smart 4357026abb87SJames Smart /* state reset on not handled new multi-buffer mailbox command */ 4358026abb87SJames Smart if (rc != SLI_CONFIG_HANDLED) 4359026abb87SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_IDLE; 4360026abb87SJames Smart 43617ad20aa9SJames Smart return rc; 43627ad20aa9SJames Smart } 43637ad20aa9SJames Smart 43647ad20aa9SJames Smart /** 43653145d2d6SLee Jones * lpfc_bsg_mbox_ext_abort - request to abort mbox command with ext buffers 43667ad20aa9SJames Smart * @phba: Pointer to HBA context object. 43677ad20aa9SJames Smart * 43687ad20aa9SJames Smart * This routine is for requesting to abort a pass-through mailbox command with 43697ad20aa9SJames Smart * multiple external buffers due to error condition. 43707ad20aa9SJames Smart **/ 43717ad20aa9SJames Smart static void 43727ad20aa9SJames Smart lpfc_bsg_mbox_ext_abort(struct lpfc_hba *phba) 43737ad20aa9SJames Smart { 43747ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_PORT) 43757ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_ABTS; 43767ad20aa9SJames Smart else 43777ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 43787ad20aa9SJames Smart return; 43797ad20aa9SJames Smart } 43807ad20aa9SJames Smart 43817ad20aa9SJames Smart /** 43827ad20aa9SJames Smart * lpfc_bsg_read_ebuf_get - get the next mailbox read external buffer 43837ad20aa9SJames Smart * @phba: Pointer to HBA context object. 4384ea085dabSLee Jones * @job: Pointer to the job object. 43857ad20aa9SJames Smart * 43867ad20aa9SJames Smart * This routine extracts the next mailbox read external buffer back to 43877ad20aa9SJames Smart * user space through BSG. 43887ad20aa9SJames Smart **/ 43897ad20aa9SJames Smart static int 439075cc8cfcSJohannes Thumshirn lpfc_bsg_read_ebuf_get(struct lpfc_hba *phba, struct bsg_job *job) 43917ad20aa9SJames Smart { 439201e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 43937ad20aa9SJames Smart struct lpfc_sli_config_mbox *sli_cfg_mbx; 43947ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf; 43957ad20aa9SJames Smart uint8_t *pbuf; 43967ad20aa9SJames Smart uint32_t size; 43977ad20aa9SJames Smart uint32_t index; 43987ad20aa9SJames Smart 43997ad20aa9SJames Smart index = phba->mbox_ext_buf_ctx.seqNum; 44007ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum++; 44017ad20aa9SJames Smart 44027ad20aa9SJames Smart sli_cfg_mbx = (struct lpfc_sli_config_mbox *) 44037ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf->virt; 44047ad20aa9SJames Smart 44057ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.nembType == nemb_mse) { 44067ad20aa9SJames Smart size = bsg_bf_get(lpfc_mbox_sli_config_mse_len, 44077ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb0_subsys.mse[index]); 44087ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 44097ad20aa9SJames Smart "2963 SLI_CONFIG (mse) ext-buffer rd get " 44107ad20aa9SJames Smart "buffer[%d], size:%d\n", index, size); 44117ad20aa9SJames Smart } else { 44127ad20aa9SJames Smart size = bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, 44137ad20aa9SJames Smart &sli_cfg_mbx->un.sli_config_emb1_subsys.hbd[index]); 44147ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 44157ad20aa9SJames Smart "2964 SLI_CONFIG (hbd) ext-buffer rd get " 44167ad20aa9SJames Smart "buffer[%d], size:%d\n", index, size); 44177ad20aa9SJames Smart } 44187ad20aa9SJames Smart if (list_empty(&phba->mbox_ext_buf_ctx.ext_dmabuf_list)) 44197ad20aa9SJames Smart return -EPIPE; 44207ad20aa9SJames Smart dmabuf = list_first_entry(&phba->mbox_ext_buf_ctx.ext_dmabuf_list, 44217ad20aa9SJames Smart struct lpfc_dmabuf, list); 44227ad20aa9SJames Smart list_del_init(&dmabuf->list); 4423b76f2dc9SJames Smart 4424b76f2dc9SJames Smart /* after dma buffer descriptor setup */ 4425b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, phba->mbox_ext_buf_ctx.nembType, 4426b76f2dc9SJames Smart mbox_rd, dma_ebuf, sta_pos_addr, 4427b76f2dc9SJames Smart dmabuf, index); 4428b76f2dc9SJames Smart 44297ad20aa9SJames Smart pbuf = (uint8_t *)dmabuf->virt; 443001e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 44317ad20aa9SJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 44327ad20aa9SJames Smart job->reply_payload.sg_cnt, 44337ad20aa9SJames Smart pbuf, size); 44347ad20aa9SJames Smart 44357ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 44367ad20aa9SJames Smart 44377ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.seqNum == phba->mbox_ext_buf_ctx.numBuf) { 44387ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 44397ad20aa9SJames Smart "2965 SLI_CONFIG (hbd) ext-buffer rd mbox " 44407ad20aa9SJames Smart "command session done\n"); 44417ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 44427ad20aa9SJames Smart } 44437ad20aa9SJames Smart 444401e0e15cSJohannes Thumshirn bsg_reply->result = 0; 444506548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 44461abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 44477ad20aa9SJames Smart 44487ad20aa9SJames Smart return SLI_CONFIG_HANDLED; 44497ad20aa9SJames Smart } 44507ad20aa9SJames Smart 44517ad20aa9SJames Smart /** 44527ad20aa9SJames Smart * lpfc_bsg_write_ebuf_set - set the next mailbox write external buffer 44537ad20aa9SJames Smart * @phba: Pointer to HBA context object. 4454ea085dabSLee Jones * @job: Pointer to the job object. 44557ad20aa9SJames Smart * @dmabuf: Pointer to a DMA buffer descriptor. 44567ad20aa9SJames Smart * 44577ad20aa9SJames Smart * This routine sets up the next mailbox read external buffer obtained 44587ad20aa9SJames Smart * from user space through BSG. 44597ad20aa9SJames Smart **/ 44607ad20aa9SJames Smart static int 446175cc8cfcSJohannes Thumshirn lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct bsg_job *job, 44627ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 44637ad20aa9SJames Smart { 446401e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 44657ad20aa9SJames Smart struct bsg_job_data *dd_data = NULL; 44667ad20aa9SJames Smart LPFC_MBOXQ_t *pmboxq = NULL; 44677ad20aa9SJames Smart MAILBOX_t *pmb; 44687ad20aa9SJames Smart enum nemb_type nemb_tp; 44697ad20aa9SJames Smart uint8_t *pbuf; 44707ad20aa9SJames Smart uint32_t size; 44717ad20aa9SJames Smart uint32_t index; 44727ad20aa9SJames Smart int rc; 44737ad20aa9SJames Smart 44747ad20aa9SJames Smart index = phba->mbox_ext_buf_ctx.seqNum; 44757ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum++; 44767ad20aa9SJames Smart nemb_tp = phba->mbox_ext_buf_ctx.nembType; 44777ad20aa9SJames Smart 44787ad20aa9SJames Smart pbuf = (uint8_t *)dmabuf->virt; 44797ad20aa9SJames Smart size = job->request_payload.payload_len; 44807ad20aa9SJames Smart sg_copy_to_buffer(job->request_payload.sg_list, 44817ad20aa9SJames Smart job->request_payload.sg_cnt, 44827ad20aa9SJames Smart pbuf, size); 44837ad20aa9SJames Smart 44847ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.nembType == nemb_mse) { 44857ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 44867ad20aa9SJames Smart "2966 SLI_CONFIG (mse) ext-buffer wr set " 44877ad20aa9SJames Smart "buffer[%d], size:%d\n", 44887ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum, size); 44897ad20aa9SJames Smart 44907ad20aa9SJames Smart } else { 44917ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 44927ad20aa9SJames Smart "2967 SLI_CONFIG (hbd) ext-buffer wr set " 44937ad20aa9SJames Smart "buffer[%d], size:%d\n", 44947ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum, size); 44957ad20aa9SJames Smart 44967ad20aa9SJames Smart } 44977ad20aa9SJames Smart 44987ad20aa9SJames Smart /* set up external buffer descriptor and add to external buffer list */ 44997ad20aa9SJames Smart lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, index, 45007ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbx_dmabuf, 45017ad20aa9SJames Smart dmabuf); 45027ad20aa9SJames Smart list_add_tail(&dmabuf->list, &phba->mbox_ext_buf_ctx.ext_dmabuf_list); 45037ad20aa9SJames Smart 4504b76f2dc9SJames Smart /* after write dma buffer */ 4505b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(phba, phba->mbox_ext_buf_ctx.nembType, 4506b76f2dc9SJames Smart mbox_wr, dma_ebuf, sta_pos_addr, 4507b76f2dc9SJames Smart dmabuf, index); 4508b76f2dc9SJames Smart 45097ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.seqNum == phba->mbox_ext_buf_ctx.numBuf) { 45107ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 45117ad20aa9SJames Smart "2968 SLI_CONFIG ext-buffer wr all %d " 45127ad20aa9SJames Smart "ebuffers received\n", 45137ad20aa9SJames Smart phba->mbox_ext_buf_ctx.numBuf); 45149a1b0b9aSBo Wu 45159a1b0b9aSBo Wu dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 45169a1b0b9aSBo Wu if (!dd_data) { 45179a1b0b9aSBo Wu rc = -ENOMEM; 45189a1b0b9aSBo Wu goto job_error; 45199a1b0b9aSBo Wu } 45209a1b0b9aSBo Wu 45217ad20aa9SJames Smart /* mailbox command structure for base driver */ 45227ad20aa9SJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 45237ad20aa9SJames Smart if (!pmboxq) { 45247ad20aa9SJames Smart rc = -ENOMEM; 45257ad20aa9SJames Smart goto job_error; 45267ad20aa9SJames Smart } 45277ad20aa9SJames Smart memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 45287ad20aa9SJames Smart pbuf = (uint8_t *)phba->mbox_ext_buf_ctx.mbx_dmabuf->virt; 45297ad20aa9SJames Smart pmb = &pmboxq->u.mb; 45307ad20aa9SJames Smart memcpy(pmb, pbuf, sizeof(*pmb)); 45317ad20aa9SJames Smart pmb->mbxOwner = OWN_HOST; 45327ad20aa9SJames Smart pmboxq->vport = phba->pport; 45337ad20aa9SJames Smart 45347ad20aa9SJames Smart /* callback for multi-buffer write mailbox command */ 45357ad20aa9SJames Smart pmboxq->mbox_cmpl = lpfc_bsg_issue_write_mbox_ext_cmpl; 45367ad20aa9SJames Smart 45377ad20aa9SJames Smart /* context fields to callback function */ 45383e1f0718SJames Smart pmboxq->ctx_buf = dd_data; 45397ad20aa9SJames Smart dd_data->type = TYPE_MBOX; 4540a33c4f7bSJames Smart dd_data->set_job = job; 45417ad20aa9SJames Smart dd_data->context_un.mbox.pmboxq = pmboxq; 45427ad20aa9SJames Smart dd_data->context_un.mbox.mb = (MAILBOX_t *)pbuf; 45437ad20aa9SJames Smart job->dd_data = dd_data; 45447ad20aa9SJames Smart 45457ad20aa9SJames Smart /* state change */ 45467ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT; 45477ad20aa9SJames Smart 45487ad20aa9SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); 45497ad20aa9SJames Smart if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { 45507ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 45517ad20aa9SJames Smart "2969 Issued SLI_CONFIG ext-buffer " 45527afc0ce9SColin Ian King "mailbox command, rc:x%x\n", rc); 455388a2cfbbSJames Smart return SLI_CONFIG_HANDLED; 45547ad20aa9SJames Smart } 45557ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 45567ad20aa9SJames Smart "2970 Failed to issue SLI_CONFIG ext-buffer " 45577afc0ce9SColin Ian King "mailbox command, rc:x%x\n", rc); 45587ad20aa9SJames Smart rc = -EPIPE; 45597ad20aa9SJames Smart goto job_error; 45607ad20aa9SJames Smart } 45617ad20aa9SJames Smart 45627ad20aa9SJames Smart /* wait for additoinal external buffers */ 456301e0e15cSJohannes Thumshirn bsg_reply->result = 0; 456406548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 45651abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 45667ad20aa9SJames Smart return SLI_CONFIG_HANDLED; 45677ad20aa9SJames Smart 45687ad20aa9SJames Smart job_error: 45699a1b0b9aSBo Wu if (pmboxq) 45709a1b0b9aSBo Wu mempool_free(pmboxq, phba->mbox_mem_pool); 45717ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 45727ad20aa9SJames Smart kfree(dd_data); 45737ad20aa9SJames Smart 45747ad20aa9SJames Smart return rc; 45757ad20aa9SJames Smart } 45767ad20aa9SJames Smart 45777ad20aa9SJames Smart /** 45787ad20aa9SJames Smart * lpfc_bsg_handle_sli_cfg_ebuf - handle ext buffer with sli-cfg mailbox cmd 45797ad20aa9SJames Smart * @phba: Pointer to HBA context object. 4580ea085dabSLee Jones * @job: Pointer to the job object. 4581ea085dabSLee Jones * @dmabuf: Pointer to a DMA buffer descriptor. 45827ad20aa9SJames Smart * 45837ad20aa9SJames Smart * This routine handles the external buffer with SLI_CONFIG (0x9B) mailbox 45847ad20aa9SJames Smart * command with multiple non-embedded external buffers. 45857ad20aa9SJames Smart **/ 45867ad20aa9SJames Smart static int 458775cc8cfcSJohannes Thumshirn lpfc_bsg_handle_sli_cfg_ebuf(struct lpfc_hba *phba, struct bsg_job *job, 45887ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 45897ad20aa9SJames Smart { 45907ad20aa9SJames Smart int rc; 45917ad20aa9SJames Smart 45927ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 45937ad20aa9SJames Smart "2971 SLI_CONFIG buffer (type:x%x)\n", 45947ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mboxType); 45957ad20aa9SJames Smart 45967ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.mboxType == mbox_rd) { 45977ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state != LPFC_BSG_MBOX_DONE) { 45987ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 45997ad20aa9SJames Smart "2972 SLI_CONFIG rd buffer state " 46007ad20aa9SJames Smart "mismatch:x%x\n", 46017ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state); 46027ad20aa9SJames Smart lpfc_bsg_mbox_ext_abort(phba); 46037ad20aa9SJames Smart return -EPIPE; 46047ad20aa9SJames Smart } 46057ad20aa9SJames Smart rc = lpfc_bsg_read_ebuf_get(phba, job); 46067ad20aa9SJames Smart if (rc == SLI_CONFIG_HANDLED) 46077ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 46087ad20aa9SJames Smart } else { /* phba->mbox_ext_buf_ctx.mboxType == mbox_wr */ 46097ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state != LPFC_BSG_MBOX_HOST) { 46107ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 46117ad20aa9SJames Smart "2973 SLI_CONFIG wr buffer state " 46127ad20aa9SJames Smart "mismatch:x%x\n", 46137ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state); 46147ad20aa9SJames Smart lpfc_bsg_mbox_ext_abort(phba); 46157ad20aa9SJames Smart return -EPIPE; 46167ad20aa9SJames Smart } 46177ad20aa9SJames Smart rc = lpfc_bsg_write_ebuf_set(phba, job, dmabuf); 46187ad20aa9SJames Smart } 46197ad20aa9SJames Smart return rc; 46207ad20aa9SJames Smart } 46217ad20aa9SJames Smart 46227ad20aa9SJames Smart /** 46237ad20aa9SJames Smart * lpfc_bsg_handle_sli_cfg_ext - handle sli-cfg mailbox with external buffer 46247ad20aa9SJames Smart * @phba: Pointer to HBA context object. 4625ea085dabSLee Jones * @job: Pointer to the job object. 4626ea085dabSLee Jones * @dmabuf: Pointer to a DMA buffer descriptor. 46277ad20aa9SJames Smart * 46287ad20aa9SJames Smart * This routine checkes and handles non-embedded multi-buffer SLI_CONFIG 46297ad20aa9SJames Smart * (0x9B) mailbox commands and external buffers. 46307ad20aa9SJames Smart **/ 46317ad20aa9SJames Smart static int 463275cc8cfcSJohannes Thumshirn lpfc_bsg_handle_sli_cfg_ext(struct lpfc_hba *phba, struct bsg_job *job, 46337ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf) 46347ad20aa9SJames Smart { 463501e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 46367ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 463788a2cfbbSJames Smart int rc = SLI_CONFIG_NOT_HANDLED; 46387ad20aa9SJames Smart 46397ad20aa9SJames Smart mbox_req = 464001e0e15cSJohannes Thumshirn (struct dfc_mbox_req *)bsg_request->rqst_data.h_vendor.vendor_cmd; 46417ad20aa9SJames Smart 46427ad20aa9SJames Smart /* mbox command with/without single external buffer */ 46437ad20aa9SJames Smart if (mbox_req->extMboxTag == 0 && mbox_req->extSeqNum == 0) 464488a2cfbbSJames Smart return rc; 46457ad20aa9SJames Smart 46467ad20aa9SJames Smart /* mbox command and first external buffer */ 46477ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_IDLE) { 46487ad20aa9SJames Smart if (mbox_req->extSeqNum == 1) { 46497ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 46507ad20aa9SJames Smart "2974 SLI_CONFIG mailbox: tag:%d, " 46517ad20aa9SJames Smart "seq:%d\n", mbox_req->extMboxTag, 46527ad20aa9SJames Smart mbox_req->extSeqNum); 46537ad20aa9SJames Smart rc = lpfc_bsg_handle_sli_cfg_mbox(phba, job, dmabuf); 46547ad20aa9SJames Smart return rc; 46557ad20aa9SJames Smart } else 46567ad20aa9SJames Smart goto sli_cfg_ext_error; 46577ad20aa9SJames Smart } 46587ad20aa9SJames Smart 46597ad20aa9SJames Smart /* 46607ad20aa9SJames Smart * handle additional external buffers 46617ad20aa9SJames Smart */ 46627ad20aa9SJames Smart 46637ad20aa9SJames Smart /* check broken pipe conditions */ 46647ad20aa9SJames Smart if (mbox_req->extMboxTag != phba->mbox_ext_buf_ctx.mbxTag) 46657ad20aa9SJames Smart goto sli_cfg_ext_error; 46667ad20aa9SJames Smart if (mbox_req->extSeqNum > phba->mbox_ext_buf_ctx.numBuf) 46677ad20aa9SJames Smart goto sli_cfg_ext_error; 46687ad20aa9SJames Smart if (mbox_req->extSeqNum != phba->mbox_ext_buf_ctx.seqNum + 1) 46697ad20aa9SJames Smart goto sli_cfg_ext_error; 46707ad20aa9SJames Smart 46717ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 46727ad20aa9SJames Smart "2975 SLI_CONFIG mailbox external buffer: " 46737ad20aa9SJames Smart "extSta:x%x, tag:%d, seq:%d\n", 46747ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state, mbox_req->extMboxTag, 46757ad20aa9SJames Smart mbox_req->extSeqNum); 46767ad20aa9SJames Smart rc = lpfc_bsg_handle_sli_cfg_ebuf(phba, job, dmabuf); 46777ad20aa9SJames Smart return rc; 46787ad20aa9SJames Smart 46797ad20aa9SJames Smart sli_cfg_ext_error: 46807ad20aa9SJames Smart /* all other cases, broken pipe */ 46817ad20aa9SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 46827ad20aa9SJames Smart "2976 SLI_CONFIG mailbox broken pipe: " 46837ad20aa9SJames Smart "ctxSta:x%x, ctxNumBuf:%d " 46847ad20aa9SJames Smart "ctxTag:%d, ctxSeq:%d, tag:%d, seq:%d\n", 46857ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state, 46867ad20aa9SJames Smart phba->mbox_ext_buf_ctx.numBuf, 46877ad20aa9SJames Smart phba->mbox_ext_buf_ctx.mbxTag, 46887ad20aa9SJames Smart phba->mbox_ext_buf_ctx.seqNum, 46897ad20aa9SJames Smart mbox_req->extMboxTag, mbox_req->extSeqNum); 46907ad20aa9SJames Smart 46917ad20aa9SJames Smart lpfc_bsg_mbox_ext_session_reset(phba); 46927ad20aa9SJames Smart 46937ad20aa9SJames Smart return -EPIPE; 46947ad20aa9SJames Smart } 46957ad20aa9SJames Smart 46967ad20aa9SJames Smart /** 46973b5dd52aSJames Smart * lpfc_bsg_issue_mbox - issues a mailbox command on behalf of an app 46983b5dd52aSJames Smart * @phba: Pointer to HBA context object. 4699ea085dabSLee Jones * @job: Pointer to the job object. 47003b5dd52aSJames Smart * @vport: Pointer to a vport object. 47013b5dd52aSJames Smart * 47023b5dd52aSJames Smart * Allocate a tracking object, mailbox command memory, get a mailbox 47033b5dd52aSJames Smart * from the mailbox pool, copy the caller mailbox command. 47043b5dd52aSJames Smart * 47053b5dd52aSJames Smart * If offline and the sli is active we need to poll for the command (port is 47063b5dd52aSJames Smart * being reset) and com-plete the job, otherwise issue the mailbox command and 47073b5dd52aSJames Smart * let our completion handler finish the command. 47083b5dd52aSJames Smart **/ 4709a2fc4aefSJames Smart static int 471075cc8cfcSJohannes Thumshirn lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct bsg_job *job, 47113b5dd52aSJames Smart struct lpfc_vport *vport) 47123b5dd52aSJames Smart { 471301e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 471401e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 47157a470277SJames Smart LPFC_MBOXQ_t *pmboxq = NULL; /* internal mailbox queue */ 47167a470277SJames Smart MAILBOX_t *pmb; /* shortcut to the pmboxq mailbox */ 47177a470277SJames Smart /* a 4k buffer to hold the mb and extended data from/to the bsg */ 47187ad20aa9SJames Smart uint8_t *pmbx = NULL; 47197a470277SJames Smart struct bsg_job_data *dd_data = NULL; /* bsg data tracking structure */ 47207ad20aa9SJames Smart struct lpfc_dmabuf *dmabuf = NULL; 47217ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 4722b6e3b9c6SJames Smart struct READ_EVENT_LOG_VAR *rdEventLog; 4723b6e3b9c6SJames Smart uint32_t transmit_length, receive_length, mode; 47247ad20aa9SJames Smart struct lpfc_mbx_sli4_config *sli4_config; 4725b6e3b9c6SJames Smart struct lpfc_mbx_nembed_cmd *nembed_sge; 4726b6e3b9c6SJames Smart struct ulp_bde64 *bde; 47277a470277SJames Smart uint8_t *ext = NULL; 47283b5dd52aSJames Smart int rc = 0; 47297a470277SJames Smart uint8_t *from; 47307ad20aa9SJames Smart uint32_t size; 47317ad20aa9SJames Smart 47327a470277SJames Smart /* in case no data is transferred */ 473301e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 47347a470277SJames Smart 4735b6e3b9c6SJames Smart /* sanity check to protect driver */ 4736b6e3b9c6SJames Smart if (job->reply_payload.payload_len > BSG_MBOX_SIZE || 4737b6e3b9c6SJames Smart job->request_payload.payload_len > BSG_MBOX_SIZE) { 4738b6e3b9c6SJames Smart rc = -ERANGE; 4739b6e3b9c6SJames Smart goto job_done; 4740b6e3b9c6SJames Smart } 4741b6e3b9c6SJames Smart 47427ad20aa9SJames Smart /* 47437ad20aa9SJames Smart * Don't allow mailbox commands to be sent when blocked or when in 47447ad20aa9SJames Smart * the middle of discovery 47457ad20aa9SJames Smart */ 47467ad20aa9SJames Smart if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { 47477ad20aa9SJames Smart rc = -EAGAIN; 47487ad20aa9SJames Smart goto job_done; 47497ad20aa9SJames Smart } 47507ad20aa9SJames Smart 47517ad20aa9SJames Smart mbox_req = 475201e0e15cSJohannes Thumshirn (struct dfc_mbox_req *)bsg_request->rqst_data.h_vendor.vendor_cmd; 47537ad20aa9SJames Smart 47547a470277SJames Smart /* check if requested extended data lengths are valid */ 4755b6e3b9c6SJames Smart if ((mbox_req->inExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t)) || 4756b6e3b9c6SJames Smart (mbox_req->outExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t))) { 47577a470277SJames Smart rc = -ERANGE; 47587a470277SJames Smart goto job_done; 47597a470277SJames Smart } 47603b5dd52aSJames Smart 47617ad20aa9SJames Smart dmabuf = lpfc_bsg_dma_page_alloc(phba); 47627ad20aa9SJames Smart if (!dmabuf || !dmabuf->virt) { 47637ad20aa9SJames Smart rc = -ENOMEM; 47647ad20aa9SJames Smart goto job_done; 47657ad20aa9SJames Smart } 47667ad20aa9SJames Smart 47677ad20aa9SJames Smart /* Get the mailbox command or external buffer from BSG */ 47687ad20aa9SJames Smart pmbx = (uint8_t *)dmabuf->virt; 47697ad20aa9SJames Smart size = job->request_payload.payload_len; 47707ad20aa9SJames Smart sg_copy_to_buffer(job->request_payload.sg_list, 47717ad20aa9SJames Smart job->request_payload.sg_cnt, pmbx, size); 47727ad20aa9SJames Smart 47737ad20aa9SJames Smart /* Handle possible SLI_CONFIG with non-embedded payloads */ 47747ad20aa9SJames Smart if (phba->sli_rev == LPFC_SLI_REV4) { 47757ad20aa9SJames Smart rc = lpfc_bsg_handle_sli_cfg_ext(phba, job, dmabuf); 47767ad20aa9SJames Smart if (rc == SLI_CONFIG_HANDLED) 47777ad20aa9SJames Smart goto job_cont; 47787ad20aa9SJames Smart if (rc) 47797ad20aa9SJames Smart goto job_done; 47807ad20aa9SJames Smart /* SLI_CONFIG_NOT_HANDLED for other mailbox commands */ 47817ad20aa9SJames Smart } 47827ad20aa9SJames Smart 47837ad20aa9SJames Smart rc = lpfc_bsg_check_cmd_access(phba, (MAILBOX_t *)pmbx, vport); 47847ad20aa9SJames Smart if (rc != 0) 47857ad20aa9SJames Smart goto job_done; /* must be negative */ 47867ad20aa9SJames Smart 47873b5dd52aSJames Smart /* allocate our bsg tracking structure */ 47883b5dd52aSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 47893b5dd52aSJames Smart if (!dd_data) { 47903b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 47913b5dd52aSJames Smart "2727 Failed allocation of dd_data\n"); 47927a470277SJames Smart rc = -ENOMEM; 47937a470277SJames Smart goto job_done; 47943b5dd52aSJames Smart } 47953b5dd52aSJames Smart 47963b5dd52aSJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 47973b5dd52aSJames Smart if (!pmboxq) { 47987a470277SJames Smart rc = -ENOMEM; 47997a470277SJames Smart goto job_done; 48003b5dd52aSJames Smart } 48017a470277SJames Smart memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 48023b5dd52aSJames Smart 48033b5dd52aSJames Smart pmb = &pmboxq->u.mb; 48047ad20aa9SJames Smart memcpy(pmb, pmbx, sizeof(*pmb)); 48053b5dd52aSJames Smart pmb->mbxOwner = OWN_HOST; 48063b5dd52aSJames Smart pmboxq->vport = vport; 48073b5dd52aSJames Smart 4808c7495937SJames Smart /* If HBA encountered an error attention, allow only DUMP 4809c7495937SJames Smart * or RESTART mailbox commands until the HBA is restarted. 4810c7495937SJames Smart */ 4811c7495937SJames Smart if (phba->pport->stopped && 4812c7495937SJames Smart pmb->mbxCommand != MBX_DUMP_MEMORY && 4813c7495937SJames Smart pmb->mbxCommand != MBX_RESTART && 4814c7495937SJames Smart pmb->mbxCommand != MBX_WRITE_VPARMS && 4815c7495937SJames Smart pmb->mbxCommand != MBX_WRITE_WWN) 4816c7495937SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, 4817c7495937SJames Smart "2797 mbox: Issued mailbox cmd " 4818c7495937SJames Smart "0x%x while in stopped state.\n", 4819c7495937SJames Smart pmb->mbxCommand); 4820c7495937SJames Smart 48217a470277SJames Smart /* extended mailbox commands will need an extended buffer */ 4822c7495937SJames Smart if (mbox_req->inExtWLen || mbox_req->outExtWLen) { 48237ad20aa9SJames Smart from = pmbx; 48247ad20aa9SJames Smart ext = from + sizeof(MAILBOX_t); 48253e1f0718SJames Smart pmboxq->ctx_buf = ext; 48267a470277SJames Smart pmboxq->in_ext_byte_len = 48277a470277SJames Smart mbox_req->inExtWLen * sizeof(uint32_t); 48287a470277SJames Smart pmboxq->out_ext_byte_len = 4829c7495937SJames Smart mbox_req->outExtWLen * sizeof(uint32_t); 48307a470277SJames Smart pmboxq->mbox_offset_word = mbox_req->mbOffset; 48317a470277SJames Smart } 48327a470277SJames Smart 48337a470277SJames Smart /* biu diag will need a kernel buffer to transfer the data 48347a470277SJames Smart * allocate our own buffer and setup the mailbox command to 48357a470277SJames Smart * use ours 48367a470277SJames Smart */ 48377a470277SJames Smart if (pmb->mbxCommand == MBX_RUN_BIU_DIAG64) { 4838b6e3b9c6SJames Smart transmit_length = pmb->un.varWords[1]; 4839b6e3b9c6SJames Smart receive_length = pmb->un.varWords[4]; 4840c7495937SJames Smart /* transmit length cannot be greater than receive length or 4841c7495937SJames Smart * mailbox extension size 4842c7495937SJames Smart */ 4843c7495937SJames Smart if ((transmit_length > receive_length) || 484488a2cfbbSJames Smart (transmit_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t))) { 4845c7495937SJames Smart rc = -ERANGE; 4846c7495937SJames Smart goto job_done; 4847c7495937SJames Smart } 48487a470277SJames Smart pmb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh = 48497ad20aa9SJames Smart putPaddrHigh(dmabuf->phys + sizeof(MAILBOX_t)); 48507a470277SJames Smart pmb->un.varBIUdiag.un.s2.xmit_bde64.addrLow = 48517ad20aa9SJames Smart putPaddrLow(dmabuf->phys + sizeof(MAILBOX_t)); 48527a470277SJames Smart 48537a470277SJames Smart pmb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh = 48547ad20aa9SJames Smart putPaddrHigh(dmabuf->phys + sizeof(MAILBOX_t) 48557ad20aa9SJames Smart + pmb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize); 48567a470277SJames Smart pmb->un.varBIUdiag.un.s2.rcv_bde64.addrLow = 48577ad20aa9SJames Smart putPaddrLow(dmabuf->phys + sizeof(MAILBOX_t) 48587ad20aa9SJames Smart + pmb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize); 4859c7495937SJames Smart } else if (pmb->mbxCommand == MBX_READ_EVENT_LOG) { 4860b6e3b9c6SJames Smart rdEventLog = &pmb->un.varRdEventLog; 4861b6e3b9c6SJames Smart receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize; 4862b6e3b9c6SJames Smart mode = bf_get(lpfc_event_log, rdEventLog); 4863c7495937SJames Smart 4864c7495937SJames Smart /* receive length cannot be greater than mailbox 4865c7495937SJames Smart * extension size 4866c7495937SJames Smart */ 486788a2cfbbSJames Smart if (receive_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t)) { 4868c7495937SJames Smart rc = -ERANGE; 4869c7495937SJames Smart goto job_done; 4870c7495937SJames Smart } 4871c7495937SJames Smart 4872c7495937SJames Smart /* mode zero uses a bde like biu diags command */ 4873c7495937SJames Smart if (mode == 0) { 48747ad20aa9SJames Smart pmb->un.varWords[3] = putPaddrLow(dmabuf->phys 48757ad20aa9SJames Smart + sizeof(MAILBOX_t)); 48767ad20aa9SJames Smart pmb->un.varWords[4] = putPaddrHigh(dmabuf->phys 48777ad20aa9SJames Smart + sizeof(MAILBOX_t)); 4878c7495937SJames Smart } 4879c7495937SJames Smart } else if (phba->sli_rev == LPFC_SLI_REV4) { 48803ef6d24cSJames Smart /* Let type 4 (well known data) through because the data is 48813ef6d24cSJames Smart * returned in varwords[4-8] 48823ef6d24cSJames Smart * otherwise check the recieve length and fetch the buffer addr 48833ef6d24cSJames Smart */ 48843ef6d24cSJames Smart if ((pmb->mbxCommand == MBX_DUMP_MEMORY) && 48853ef6d24cSJames Smart (pmb->un.varDmp.type != DMP_WELL_KNOWN)) { 4886c7495937SJames Smart /* rebuild the command for sli4 using our own buffers 4887c7495937SJames Smart * like we do for biu diags 4888c7495937SJames Smart */ 4889b6e3b9c6SJames Smart receive_length = pmb->un.varWords[2]; 4890c7495937SJames Smart /* receive length cannot be greater than mailbox 4891c7495937SJames Smart * extension size 4892c7495937SJames Smart */ 48937ad20aa9SJames Smart if (receive_length == 0) { 4894c7495937SJames Smart rc = -ERANGE; 4895c7495937SJames Smart goto job_done; 4896c7495937SJames Smart } 48977ad20aa9SJames Smart pmb->un.varWords[3] = putPaddrLow(dmabuf->phys 48987ad20aa9SJames Smart + sizeof(MAILBOX_t)); 48997ad20aa9SJames Smart pmb->un.varWords[4] = putPaddrHigh(dmabuf->phys 49007ad20aa9SJames Smart + sizeof(MAILBOX_t)); 4901c7495937SJames Smart } else if ((pmb->mbxCommand == MBX_UPDATE_CFG) && 4902c7495937SJames Smart pmb->un.varUpdateCfg.co) { 4903b6e3b9c6SJames Smart bde = (struct ulp_bde64 *)&pmb->un.varWords[4]; 4904c7495937SJames Smart 4905c7495937SJames Smart /* bde size cannot be greater than mailbox ext size */ 490688a2cfbbSJames Smart if (bde->tus.f.bdeSize > 490788a2cfbbSJames Smart BSG_MBOX_SIZE - sizeof(MAILBOX_t)) { 4908c7495937SJames Smart rc = -ERANGE; 4909c7495937SJames Smart goto job_done; 4910c7495937SJames Smart } 49117ad20aa9SJames Smart bde->addrHigh = putPaddrHigh(dmabuf->phys 49127ad20aa9SJames Smart + sizeof(MAILBOX_t)); 49137ad20aa9SJames Smart bde->addrLow = putPaddrLow(dmabuf->phys 49147ad20aa9SJames Smart + sizeof(MAILBOX_t)); 4915515e0aa2SJames Smart } else if (pmb->mbxCommand == MBX_SLI4_CONFIG) { 49167ad20aa9SJames Smart /* Handling non-embedded SLI_CONFIG mailbox command */ 49177ad20aa9SJames Smart sli4_config = &pmboxq->u.mqe.un.sli4_config; 49187ad20aa9SJames Smart if (!bf_get(lpfc_mbox_hdr_emb, 49197ad20aa9SJames Smart &sli4_config->header.cfg_mhdr)) { 49207ad20aa9SJames Smart /* rebuild the command for sli4 using our 49217ad20aa9SJames Smart * own buffers like we do for biu diags 4922515e0aa2SJames Smart */ 4923515e0aa2SJames Smart nembed_sge = (struct lpfc_mbx_nembed_cmd *) 4924515e0aa2SJames Smart &pmb->un.varWords[0]; 4925515e0aa2SJames Smart receive_length = nembed_sge->sge[0].length; 4926515e0aa2SJames Smart 49277ad20aa9SJames Smart /* receive length cannot be greater than 49287ad20aa9SJames Smart * mailbox extension size 4929515e0aa2SJames Smart */ 4930515e0aa2SJames Smart if ((receive_length == 0) || 493188a2cfbbSJames Smart (receive_length > 493288a2cfbbSJames Smart BSG_MBOX_SIZE - sizeof(MAILBOX_t))) { 4933515e0aa2SJames Smart rc = -ERANGE; 4934515e0aa2SJames Smart goto job_done; 4935515e0aa2SJames Smart } 4936515e0aa2SJames Smart 49377ad20aa9SJames Smart nembed_sge->sge[0].pa_hi = 49387ad20aa9SJames Smart putPaddrHigh(dmabuf->phys 49397ad20aa9SJames Smart + sizeof(MAILBOX_t)); 49407ad20aa9SJames Smart nembed_sge->sge[0].pa_lo = 49417ad20aa9SJames Smart putPaddrLow(dmabuf->phys 49427ad20aa9SJames Smart + sizeof(MAILBOX_t)); 4943515e0aa2SJames Smart } 4944c7495937SJames Smart } 4945c7495937SJames Smart } 4946c7495937SJames Smart 49477ad20aa9SJames Smart dd_data->context_un.mbox.dmabuffers = dmabuf; 49483b5dd52aSJames Smart 49493b5dd52aSJames Smart /* setup wake call as IOCB callback */ 49507ad20aa9SJames Smart pmboxq->mbox_cmpl = lpfc_bsg_issue_mbox_cmpl; 49517a470277SJames Smart 49523b5dd52aSJames Smart /* setup context field to pass wait_queue pointer to wake function */ 49533e1f0718SJames Smart pmboxq->ctx_ndlp = dd_data; 49543b5dd52aSJames Smart dd_data->type = TYPE_MBOX; 4955a33c4f7bSJames Smart dd_data->set_job = job; 49563b5dd52aSJames Smart dd_data->context_un.mbox.pmboxq = pmboxq; 49577ad20aa9SJames Smart dd_data->context_un.mbox.mb = (MAILBOX_t *)pmbx; 49587a470277SJames Smart dd_data->context_un.mbox.ext = ext; 49597a470277SJames Smart dd_data->context_un.mbox.mbOffset = mbox_req->mbOffset; 49607a470277SJames Smart dd_data->context_un.mbox.inExtWLen = mbox_req->inExtWLen; 4961c7495937SJames Smart dd_data->context_un.mbox.outExtWLen = mbox_req->outExtWLen; 49623b5dd52aSJames Smart job->dd_data = dd_data; 49637a470277SJames Smart 49647a470277SJames Smart if ((vport->fc_flag & FC_OFFLINE_MODE) || 49657a470277SJames Smart (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { 49667a470277SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); 49677a470277SJames Smart if (rc != MBX_SUCCESS) { 49687a470277SJames Smart rc = (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; 49697a470277SJames Smart goto job_done; 49703b5dd52aSJames Smart } 49713b5dd52aSJames Smart 49727a470277SJames Smart /* job finished, copy the data */ 49737ad20aa9SJames Smart memcpy(pmbx, pmb, sizeof(*pmb)); 497401e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 49757a470277SJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 49767a470277SJames Smart job->reply_payload.sg_cnt, 49777ad20aa9SJames Smart pmbx, size); 49787a470277SJames Smart /* not waiting mbox already done */ 49797a470277SJames Smart rc = 0; 49807a470277SJames Smart goto job_done; 49817a470277SJames Smart } 49827a470277SJames Smart 49837a470277SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); 49847a470277SJames Smart if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) 49857a470277SJames Smart return 1; /* job started */ 49867a470277SJames Smart 49877a470277SJames Smart job_done: 49887a470277SJames Smart /* common exit for error or job completed inline */ 49897a470277SJames Smart if (pmboxq) 49907a470277SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 49917ad20aa9SJames Smart lpfc_bsg_dma_page_free(phba, dmabuf); 49927a470277SJames Smart kfree(dd_data); 49937a470277SJames Smart 49947ad20aa9SJames Smart job_cont: 49957a470277SJames Smart return rc; 49963b5dd52aSJames Smart } 49973b5dd52aSJames Smart 49983b5dd52aSJames Smart /** 49993b5dd52aSJames Smart * lpfc_bsg_mbox_cmd - process an fc bsg LPFC_BSG_VENDOR_MBOX command 50003b5dd52aSJames Smart * @job: MBOX fc_bsg_job for LPFC_BSG_VENDOR_MBOX. 50013b5dd52aSJames Smart **/ 50023b5dd52aSJames Smart static int 500375cc8cfcSJohannes Thumshirn lpfc_bsg_mbox_cmd(struct bsg_job *job) 50043b5dd52aSJames Smart { 5005cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 500601e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 500701e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 50083b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 50097ad20aa9SJames Smart struct dfc_mbox_req *mbox_req; 50103b5dd52aSJames Smart int rc = 0; 50113b5dd52aSJames Smart 50127ad20aa9SJames Smart /* mix-and-match backward compatibility */ 501301e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 50143b5dd52aSJames Smart if (job->request_len < 50153b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct dfc_mbox_req)) { 50167ad20aa9SJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, 50171051e9b3SMasanari Iida "2737 Mix-and-match backward compatibility " 50187ad20aa9SJames Smart "between MBOX_REQ old size:%d and " 50197ad20aa9SJames Smart "new request size:%d\n", 50207ad20aa9SJames Smart (int)(job->request_len - 50217ad20aa9SJames Smart sizeof(struct fc_bsg_request)), 50227ad20aa9SJames Smart (int)sizeof(struct dfc_mbox_req)); 50237ad20aa9SJames Smart mbox_req = (struct dfc_mbox_req *) 502401e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 50257ad20aa9SJames Smart mbox_req->extMboxTag = 0; 50267ad20aa9SJames Smart mbox_req->extSeqNum = 0; 50273b5dd52aSJames Smart } 50283b5dd52aSJames Smart 50293b5dd52aSJames Smart rc = lpfc_bsg_issue_mbox(phba, job, vport); 50303b5dd52aSJames Smart 50313b5dd52aSJames Smart if (rc == 0) { 50323b5dd52aSJames Smart /* job done */ 503301e0e15cSJohannes Thumshirn bsg_reply->result = 0; 50343b5dd52aSJames Smart job->dd_data = NULL; 503506548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 50361abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 50373b5dd52aSJames Smart } else if (rc == 1) 50383b5dd52aSJames Smart /* job submitted, will complete later*/ 50393b5dd52aSJames Smart rc = 0; /* return zero, no error */ 50403b5dd52aSJames Smart else { 50413b5dd52aSJames Smart /* some error occurred */ 504201e0e15cSJohannes Thumshirn bsg_reply->result = rc; 50433b5dd52aSJames Smart job->dd_data = NULL; 50443b5dd52aSJames Smart } 50453b5dd52aSJames Smart 50463b5dd52aSJames Smart return rc; 50473b5dd52aSJames Smart } 50483b5dd52aSJames Smart 50493b5dd52aSJames Smart /** 5050e2aed29fSJames Smart * lpfc_bsg_menlo_cmd_cmp - lpfc_menlo_cmd completion handler 5051e2aed29fSJames Smart * @phba: Pointer to HBA context object. 5052e2aed29fSJames Smart * @cmdiocbq: Pointer to command iocb. 5053e2aed29fSJames Smart * @rspiocbq: Pointer to response iocb. 5054e2aed29fSJames Smart * 5055e2aed29fSJames Smart * This function is the completion handler for iocbs issued using 5056e2aed29fSJames Smart * lpfc_menlo_cmd function. This function is called by the 5057e2aed29fSJames Smart * ring event handler function without any lock held. This function 5058e2aed29fSJames Smart * can be called from both worker thread context and interrupt 5059e2aed29fSJames Smart * context. This function also can be called from another thread which 5060e2aed29fSJames Smart * cleans up the SLI layer objects. 5061e2aed29fSJames Smart * This function copies the contents of the response iocb to the 5062e2aed29fSJames Smart * response iocb memory object provided by the caller of 5063e2aed29fSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 5064e2aed29fSJames Smart * sleeps for the iocb completion. 5065e2aed29fSJames Smart **/ 5066e2aed29fSJames Smart static void 5067e2aed29fSJames Smart lpfc_bsg_menlo_cmd_cmp(struct lpfc_hba *phba, 5068e2aed29fSJames Smart struct lpfc_iocbq *cmdiocbq, 5069e2aed29fSJames Smart struct lpfc_iocbq *rspiocbq) 5070e2aed29fSJames Smart { 5071e2aed29fSJames Smart struct bsg_job_data *dd_data; 507275cc8cfcSJohannes Thumshirn struct bsg_job *job; 507301e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply; 5074e2aed29fSJames Smart IOCB_t *rsp; 5075a33c4f7bSJames Smart struct lpfc_dmabuf *bmp, *cmp, *rmp; 5076e2aed29fSJames Smart struct lpfc_bsg_menlo *menlo; 5077e2aed29fSJames Smart unsigned long flags; 5078e2aed29fSJames Smart struct menlo_response *menlo_resp; 5079a33c4f7bSJames Smart unsigned int rsp_size; 5080e2aed29fSJames Smart int rc = 0; 5081e2aed29fSJames Smart 5082e2aed29fSJames Smart dd_data = cmdiocbq->context1; 5083a33c4f7bSJames Smart cmp = cmdiocbq->context2; 5084a33c4f7bSJames Smart bmp = cmdiocbq->context3; 5085e2aed29fSJames Smart menlo = &dd_data->context_un.menlo; 5086a33c4f7bSJames Smart rmp = menlo->rmp; 5087e2aed29fSJames Smart rsp = &rspiocbq->iocb; 5088e2aed29fSJames Smart 5089a33c4f7bSJames Smart /* Determine if job has been aborted */ 5090a33c4f7bSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 5091a33c4f7bSJames Smart job = dd_data->set_job; 5092a33c4f7bSJames Smart if (job) { 509301e0e15cSJohannes Thumshirn bsg_reply = job->reply; 5094a33c4f7bSJames Smart /* Prevent timeout handling from trying to abort job */ 5095a33c4f7bSJames Smart job->dd_data = NULL; 5096a33c4f7bSJames Smart } 5097a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 5098e2aed29fSJames Smart 5099a33c4f7bSJames Smart /* Copy the job data or set the failing status for the job */ 5100a33c4f7bSJames Smart 5101a33c4f7bSJames Smart if (job) { 5102e2aed29fSJames Smart /* always return the xri, this would be used in the case 5103a33c4f7bSJames Smart * of a menlo download to allow the data to be sent as a 5104a33c4f7bSJames Smart * continuation of the exchange. 5105e2aed29fSJames Smart */ 5106a33c4f7bSJames Smart 5107e2aed29fSJames Smart menlo_resp = (struct menlo_response *) 510801e0e15cSJohannes Thumshirn bsg_reply->reply_data.vendor_reply.vendor_rsp; 5109e2aed29fSJames Smart menlo_resp->xri = rsp->ulpContext; 5110e2aed29fSJames Smart if (rsp->ulpStatus) { 5111e2aed29fSJames Smart if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { 5112e3d2b802SJames Smart switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) { 5113e2aed29fSJames Smart case IOERR_SEQUENCE_TIMEOUT: 5114e2aed29fSJames Smart rc = -ETIMEDOUT; 5115e2aed29fSJames Smart break; 5116e2aed29fSJames Smart case IOERR_INVALID_RPI: 5117e2aed29fSJames Smart rc = -EFAULT; 5118e2aed29fSJames Smart break; 5119e2aed29fSJames Smart default: 5120e2aed29fSJames Smart rc = -EACCES; 5121e2aed29fSJames Smart break; 5122e2aed29fSJames Smart } 5123a33c4f7bSJames Smart } else { 5124e2aed29fSJames Smart rc = -EACCES; 5125a33c4f7bSJames Smart } 5126a33c4f7bSJames Smart } else { 5127a33c4f7bSJames Smart rsp_size = rsp->un.genreq64.bdl.bdeSize; 512801e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 5129a33c4f7bSJames Smart lpfc_bsg_copy_data(rmp, &job->reply_payload, 5130a33c4f7bSJames Smart rsp_size, 0); 5131a33c4f7bSJames Smart } 5132e2aed29fSJames Smart 5133a33c4f7bSJames Smart } 5134a33c4f7bSJames Smart 5135e2aed29fSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 5136a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 5137a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, rmp); 5138a33c4f7bSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 5139e2aed29fSJames Smart kfree(bmp); 5140e2aed29fSJames Smart kfree(dd_data); 5141a33c4f7bSJames Smart 5142a33c4f7bSJames Smart /* Complete the job if active */ 5143a33c4f7bSJames Smart 5144a33c4f7bSJames Smart if (job) { 514501e0e15cSJohannes Thumshirn bsg_reply->result = rc; 514606548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 51471abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 5148a33c4f7bSJames Smart } 5149a33c4f7bSJames Smart 5150e2aed29fSJames Smart return; 5151e2aed29fSJames Smart } 5152e2aed29fSJames Smart 5153e2aed29fSJames Smart /** 5154e2aed29fSJames Smart * lpfc_menlo_cmd - send an ioctl for menlo hardware 5155e2aed29fSJames Smart * @job: fc_bsg_job to handle 5156e2aed29fSJames Smart * 5157e2aed29fSJames Smart * This function issues a gen request 64 CR ioctl for all menlo cmd requests, 5158e2aed29fSJames Smart * all the command completions will return the xri for the command. 5159e2aed29fSJames Smart * For menlo data requests a gen request 64 CX is used to continue the exchange 5160e2aed29fSJames Smart * supplied in the menlo request header xri field. 5161e2aed29fSJames Smart **/ 5162e2aed29fSJames Smart static int 516375cc8cfcSJohannes Thumshirn lpfc_menlo_cmd(struct bsg_job *job) 5164e2aed29fSJames Smart { 5165cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 516601e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 516701e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 5168e2aed29fSJames Smart struct lpfc_hba *phba = vport->phba; 5169a33c4f7bSJames Smart struct lpfc_iocbq *cmdiocbq; 5170a33c4f7bSJames Smart IOCB_t *cmd; 5171e2aed29fSJames Smart int rc = 0; 5172e2aed29fSJames Smart struct menlo_command *menlo_cmd; 5173a33c4f7bSJames Smart struct lpfc_dmabuf *bmp = NULL, *cmp = NULL, *rmp = NULL; 5174e2aed29fSJames Smart int request_nseg; 5175e2aed29fSJames Smart int reply_nseg; 5176e2aed29fSJames Smart struct bsg_job_data *dd_data; 5177e2aed29fSJames Smart struct ulp_bde64 *bpl = NULL; 5178e2aed29fSJames Smart 5179e2aed29fSJames Smart /* in case no data is returned return just the return code */ 518001e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 5181e2aed29fSJames Smart 5182e2aed29fSJames Smart if (job->request_len < 5183e2aed29fSJames Smart sizeof(struct fc_bsg_request) + 5184e2aed29fSJames Smart sizeof(struct menlo_command)) { 5185e2aed29fSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 5186e2aed29fSJames Smart "2784 Received MENLO_CMD request below " 5187e2aed29fSJames Smart "minimum size\n"); 5188e2aed29fSJames Smart rc = -ERANGE; 5189e2aed29fSJames Smart goto no_dd_data; 5190e2aed29fSJames Smart } 5191e2aed29fSJames Smart 5192feb3cc57SDick Kennedy if (job->reply_len < sizeof(*bsg_reply) + 5193feb3cc57SDick Kennedy sizeof(struct menlo_response)) { 5194e2aed29fSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 5195e2aed29fSJames Smart "2785 Received MENLO_CMD reply below " 5196e2aed29fSJames Smart "minimum size\n"); 5197e2aed29fSJames Smart rc = -ERANGE; 5198e2aed29fSJames Smart goto no_dd_data; 5199e2aed29fSJames Smart } 5200e2aed29fSJames Smart 5201e2aed29fSJames Smart if (!(phba->menlo_flag & HBA_MENLO_SUPPORT)) { 5202e2aed29fSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 5203e2aed29fSJames Smart "2786 Adapter does not support menlo " 5204e2aed29fSJames Smart "commands\n"); 5205e2aed29fSJames Smart rc = -EPERM; 5206e2aed29fSJames Smart goto no_dd_data; 5207e2aed29fSJames Smart } 5208e2aed29fSJames Smart 5209e2aed29fSJames Smart menlo_cmd = (struct menlo_command *) 521001e0e15cSJohannes Thumshirn bsg_request->rqst_data.h_vendor.vendor_cmd; 5211e2aed29fSJames Smart 5212e2aed29fSJames Smart /* allocate our bsg tracking structure */ 5213e2aed29fSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 5214e2aed29fSJames Smart if (!dd_data) { 5215e2aed29fSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 5216e2aed29fSJames Smart "2787 Failed allocation of dd_data\n"); 5217e2aed29fSJames Smart rc = -ENOMEM; 5218e2aed29fSJames Smart goto no_dd_data; 5219e2aed29fSJames Smart } 5220e2aed29fSJames Smart 5221e2aed29fSJames Smart bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 5222e2aed29fSJames Smart if (!bmp) { 5223e2aed29fSJames Smart rc = -ENOMEM; 5224e2aed29fSJames Smart goto free_dd; 5225e2aed29fSJames Smart } 5226e2aed29fSJames Smart 5227a33c4f7bSJames Smart bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); 5228a33c4f7bSJames Smart if (!bmp->virt) { 5229e2aed29fSJames Smart rc = -ENOMEM; 5230e2aed29fSJames Smart goto free_bmp; 5231e2aed29fSJames Smart } 5232e2aed29fSJames Smart 5233e2aed29fSJames Smart INIT_LIST_HEAD(&bmp->list); 5234a33c4f7bSJames Smart 5235e2aed29fSJames Smart bpl = (struct ulp_bde64 *)bmp->virt; 5236a33c4f7bSJames Smart request_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64); 5237a33c4f7bSJames Smart cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len, 5238a33c4f7bSJames Smart 1, bpl, &request_nseg); 5239a33c4f7bSJames Smart if (!cmp) { 5240a33c4f7bSJames Smart rc = -ENOMEM; 5241a33c4f7bSJames Smart goto free_bmp; 5242a33c4f7bSJames Smart } 5243a33c4f7bSJames Smart lpfc_bsg_copy_data(cmp, &job->request_payload, 5244a33c4f7bSJames Smart job->request_payload.payload_len, 1); 5245a33c4f7bSJames Smart 5246a33c4f7bSJames Smart bpl += request_nseg; 5247a33c4f7bSJames Smart reply_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64) - request_nseg; 5248a33c4f7bSJames Smart rmp = lpfc_alloc_bsg_buffers(phba, job->reply_payload.payload_len, 0, 5249a33c4f7bSJames Smart bpl, &reply_nseg); 5250a33c4f7bSJames Smart if (!rmp) { 5251a33c4f7bSJames Smart rc = -ENOMEM; 5252a33c4f7bSJames Smart goto free_cmp; 5253e2aed29fSJames Smart } 5254e2aed29fSJames Smart 5255a33c4f7bSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 5256a33c4f7bSJames Smart if (!cmdiocbq) { 5257a33c4f7bSJames Smart rc = -ENOMEM; 5258a33c4f7bSJames Smart goto free_rmp; 5259e2aed29fSJames Smart } 5260e2aed29fSJames Smart 5261e2aed29fSJames Smart cmd = &cmdiocbq->iocb; 5262e2aed29fSJames Smart cmd->un.genreq64.bdl.ulpIoTag32 = 0; 5263e2aed29fSJames Smart cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); 5264e2aed29fSJames Smart cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); 5265e2aed29fSJames Smart cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 5266e2aed29fSJames Smart cmd->un.genreq64.bdl.bdeSize = 5267e2aed29fSJames Smart (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); 5268e2aed29fSJames Smart cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); 5269e2aed29fSJames Smart cmd->un.genreq64.w5.hcsw.Dfctl = 0; 5270e2aed29fSJames Smart cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CMD; 5271e2aed29fSJames Smart cmd->un.genreq64.w5.hcsw.Type = MENLO_TRANSPORT_TYPE; /* 0xfe */ 5272e2aed29fSJames Smart cmd->ulpBdeCount = 1; 5273e2aed29fSJames Smart cmd->ulpClass = CLASS3; 5274e2aed29fSJames Smart cmd->ulpOwner = OWN_CHIP; 5275e2aed29fSJames Smart cmd->ulpLe = 1; /* Limited Edition */ 5276e2aed29fSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 5277e2aed29fSJames Smart cmdiocbq->vport = phba->pport; 5278e2aed29fSJames Smart /* We want the firmware to timeout before we do */ 5279e2aed29fSJames Smart cmd->ulpTimeout = MENLO_TIMEOUT - 5; 5280e2aed29fSJames Smart cmdiocbq->iocb_cmpl = lpfc_bsg_menlo_cmd_cmp; 5281e2aed29fSJames Smart cmdiocbq->context1 = dd_data; 5282a33c4f7bSJames Smart cmdiocbq->context2 = cmp; 5283a33c4f7bSJames Smart cmdiocbq->context3 = bmp; 5284e2aed29fSJames Smart if (menlo_cmd->cmd == LPFC_BSG_VENDOR_MENLO_CMD) { 5285e2aed29fSJames Smart cmd->ulpCommand = CMD_GEN_REQUEST64_CR; 5286e2aed29fSJames Smart cmd->ulpPU = MENLO_PU; /* 3 */ 5287e2aed29fSJames Smart cmd->un.ulpWord[4] = MENLO_DID; /* 0x0000FC0E */ 5288e2aed29fSJames Smart cmd->ulpContext = MENLO_CONTEXT; /* 0 */ 5289e2aed29fSJames Smart } else { 5290e2aed29fSJames Smart cmd->ulpCommand = CMD_GEN_REQUEST64_CX; 5291e2aed29fSJames Smart cmd->ulpPU = 1; 5292e2aed29fSJames Smart cmd->un.ulpWord[4] = 0; 5293e2aed29fSJames Smart cmd->ulpContext = menlo_cmd->xri; 5294e2aed29fSJames Smart } 5295e2aed29fSJames Smart 5296e2aed29fSJames Smart dd_data->type = TYPE_MENLO; 5297a33c4f7bSJames Smart dd_data->set_job = job; 5298e2aed29fSJames Smart dd_data->context_un.menlo.cmdiocbq = cmdiocbq; 5299a33c4f7bSJames Smart dd_data->context_un.menlo.rmp = rmp; 5300a33c4f7bSJames Smart job->dd_data = dd_data; 5301e2aed29fSJames Smart 5302e2aed29fSJames Smart rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 5303e2aed29fSJames Smart MENLO_TIMEOUT - 5); 5304e2aed29fSJames Smart if (rc == IOCB_SUCCESS) 5305e2aed29fSJames Smart return 0; /* done for now */ 5306e2aed29fSJames Smart 5307e2aed29fSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 5308a33c4f7bSJames Smart 5309a33c4f7bSJames Smart free_rmp: 5310a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, rmp); 5311a33c4f7bSJames Smart free_cmp: 5312a33c4f7bSJames Smart lpfc_free_bsg_buffers(phba, cmp); 5313e2aed29fSJames Smart free_bmp: 5314a33c4f7bSJames Smart if (bmp->virt) 5315a33c4f7bSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 5316e2aed29fSJames Smart kfree(bmp); 5317e2aed29fSJames Smart free_dd: 5318e2aed29fSJames Smart kfree(dd_data); 5319e2aed29fSJames Smart no_dd_data: 5320e2aed29fSJames Smart /* make error code available to userspace */ 532101e0e15cSJohannes Thumshirn bsg_reply->result = rc; 5322e2aed29fSJames Smart job->dd_data = NULL; 5323e2aed29fSJames Smart return rc; 5324e2aed29fSJames Smart } 5325b6e3b9c6SJames Smart 5326c691816eSJames Smart static int 532775cc8cfcSJohannes Thumshirn lpfc_forced_link_speed(struct bsg_job *job) 5328c691816eSJames Smart { 5329cd21c605SJohannes Thumshirn struct Scsi_Host *shost = fc_bsg_to_shost(job); 5330c691816eSJames Smart struct lpfc_vport *vport = shost_priv(shost); 5331c691816eSJames Smart struct lpfc_hba *phba = vport->phba; 533201e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 5333c691816eSJames Smart struct forced_link_speed_support_reply *forced_reply; 5334c691816eSJames Smart int rc = 0; 5335c691816eSJames Smart 5336c691816eSJames Smart if (job->request_len < 5337c691816eSJames Smart sizeof(struct fc_bsg_request) + 5338c691816eSJames Smart sizeof(struct get_forced_link_speed_support)) { 5339c691816eSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 5340c691816eSJames Smart "0048 Received FORCED_LINK_SPEED request " 5341c691816eSJames Smart "below minimum size\n"); 5342c691816eSJames Smart rc = -EINVAL; 5343c691816eSJames Smart goto job_error; 5344c691816eSJames Smart } 5345c691816eSJames Smart 5346c691816eSJames Smart forced_reply = (struct forced_link_speed_support_reply *) 534701e0e15cSJohannes Thumshirn bsg_reply->reply_data.vendor_reply.vendor_rsp; 5348c691816eSJames Smart 5349feb3cc57SDick Kennedy if (job->reply_len < sizeof(*bsg_reply) + sizeof(*forced_reply)) { 5350c691816eSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 5351c691816eSJames Smart "0049 Received FORCED_LINK_SPEED reply below " 5352c691816eSJames Smart "minimum size\n"); 5353c691816eSJames Smart rc = -EINVAL; 5354c691816eSJames Smart goto job_error; 5355c691816eSJames Smart } 5356c691816eSJames Smart 5357c691816eSJames Smart forced_reply->supported = (phba->hba_flag & HBA_FORCED_LINK_SPEED) 5358c691816eSJames Smart ? LPFC_FORCED_LINK_SPEED_SUPPORTED 5359c691816eSJames Smart : LPFC_FORCED_LINK_SPEED_NOT_SUPPORTED; 5360c691816eSJames Smart job_error: 536101e0e15cSJohannes Thumshirn bsg_reply->result = rc; 5362c691816eSJames Smart if (rc == 0) 536306548160SJohannes Thumshirn bsg_job_done(job, bsg_reply->result, 53641abaede7SJohannes Thumshirn bsg_reply->reply_payload_rcv_len); 5365c691816eSJames Smart return rc; 5366c691816eSJames Smart } 5367c691816eSJames Smart 5368e2aed29fSJames Smart /** 5369d2cc9bcdSJames Smart * lpfc_check_fwlog_support: Check FW log support on the adapter 5370d2cc9bcdSJames Smart * @phba: Pointer to HBA context object. 5371d2cc9bcdSJames Smart * 5372d2cc9bcdSJames Smart * Check if FW Logging support by the adapter 5373d2cc9bcdSJames Smart **/ 5374d2cc9bcdSJames Smart int 5375d2cc9bcdSJames Smart lpfc_check_fwlog_support(struct lpfc_hba *phba) 5376d2cc9bcdSJames Smart { 5377d2cc9bcdSJames Smart struct lpfc_ras_fwlog *ras_fwlog = NULL; 5378d2cc9bcdSJames Smart 5379d2cc9bcdSJames Smart ras_fwlog = &phba->ras_fwlog; 5380d2cc9bcdSJames Smart 5381af0c94afSYANG LI if (!ras_fwlog->ras_hwsupport) 5382d2cc9bcdSJames Smart return -EACCES; 5383af0c94afSYANG LI else if (!ras_fwlog->ras_enabled) 5384d2cc9bcdSJames Smart return -EPERM; 5385d2cc9bcdSJames Smart else 5386d2cc9bcdSJames Smart return 0; 5387d2cc9bcdSJames Smart } 5388d2cc9bcdSJames Smart 5389d2cc9bcdSJames Smart /** 5390d2cc9bcdSJames Smart * lpfc_bsg_get_ras_config: Get RAS configuration settings 5391d2cc9bcdSJames Smart * @job: fc_bsg_job to handle 5392d2cc9bcdSJames Smart * 5393d2cc9bcdSJames Smart * Get RAS configuration values set. 5394d2cc9bcdSJames Smart **/ 5395d2cc9bcdSJames Smart static int 5396d2cc9bcdSJames Smart lpfc_bsg_get_ras_config(struct bsg_job *job) 5397d2cc9bcdSJames Smart { 5398d2cc9bcdSJames Smart struct Scsi_Host *shost = fc_bsg_to_shost(job); 5399d2cc9bcdSJames Smart struct lpfc_vport *vport = shost_priv(shost); 5400d2cc9bcdSJames Smart struct fc_bsg_reply *bsg_reply = job->reply; 5401d2cc9bcdSJames Smart struct lpfc_hba *phba = vport->phba; 5402d2cc9bcdSJames Smart struct lpfc_bsg_get_ras_config_reply *ras_reply; 5403d2cc9bcdSJames Smart struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog; 5404d2cc9bcdSJames Smart int rc = 0; 5405d2cc9bcdSJames Smart 5406d2cc9bcdSJames Smart if (job->request_len < 5407d2cc9bcdSJames Smart sizeof(struct fc_bsg_request) + 5408d2cc9bcdSJames Smart sizeof(struct lpfc_bsg_ras_req)) { 5409d2cc9bcdSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 5410cb34990bSJames Smart "6192 FW_LOG request received " 5411d2cc9bcdSJames Smart "below minimum size\n"); 5412d2cc9bcdSJames Smart rc = -EINVAL; 5413d2cc9bcdSJames Smart goto ras_job_error; 5414d2cc9bcdSJames Smart } 5415d2cc9bcdSJames Smart 5416d2cc9bcdSJames Smart /* Check FW log status */ 5417d2cc9bcdSJames Smart rc = lpfc_check_fwlog_support(phba); 5418cb34990bSJames Smart if (rc) 5419d2cc9bcdSJames Smart goto ras_job_error; 5420d2cc9bcdSJames Smart 5421d2cc9bcdSJames Smart ras_reply = (struct lpfc_bsg_get_ras_config_reply *) 5422d2cc9bcdSJames Smart bsg_reply->reply_data.vendor_reply.vendor_rsp; 5423d2cc9bcdSJames Smart 5424d2cc9bcdSJames Smart /* Current logging state */ 542595bfc6d8SJames Smart spin_lock_irq(&phba->hbalock); 542695bfc6d8SJames Smart if (ras_fwlog->state == ACTIVE) 5427d2cc9bcdSJames Smart ras_reply->state = LPFC_RASLOG_STATE_RUNNING; 5428d2cc9bcdSJames Smart else 5429d2cc9bcdSJames Smart ras_reply->state = LPFC_RASLOG_STATE_STOPPED; 543095bfc6d8SJames Smart spin_unlock_irq(&phba->hbalock); 5431d2cc9bcdSJames Smart 5432d2cc9bcdSJames Smart ras_reply->log_level = phba->ras_fwlog.fw_loglevel; 5433d2cc9bcdSJames Smart ras_reply->log_buff_sz = phba->cfg_ras_fwlog_buffsize; 5434d2cc9bcdSJames Smart 5435d2cc9bcdSJames Smart ras_job_error: 5436d2cc9bcdSJames Smart /* make error code available to userspace */ 5437d2cc9bcdSJames Smart bsg_reply->result = rc; 5438d2cc9bcdSJames Smart 5439d2cc9bcdSJames Smart /* complete the job back to userspace */ 54406db51abbSJames Smart if (!rc) 54416db51abbSJames Smart bsg_job_done(job, bsg_reply->result, 54426db51abbSJames Smart bsg_reply->reply_payload_rcv_len); 5443d2cc9bcdSJames Smart return rc; 5444d2cc9bcdSJames Smart } 5445d2cc9bcdSJames Smart 5446d2cc9bcdSJames Smart /** 5447d2cc9bcdSJames Smart * lpfc_bsg_set_ras_config: Set FW logging parameters 5448d2cc9bcdSJames Smart * @job: fc_bsg_job to handle 5449d2cc9bcdSJames Smart * 5450d2cc9bcdSJames Smart * Set log-level parameters for FW-logging in host memory 5451d2cc9bcdSJames Smart **/ 5452d2cc9bcdSJames Smart static int 5453d2cc9bcdSJames Smart lpfc_bsg_set_ras_config(struct bsg_job *job) 5454d2cc9bcdSJames Smart { 5455d2cc9bcdSJames Smart struct Scsi_Host *shost = fc_bsg_to_shost(job); 5456d2cc9bcdSJames Smart struct lpfc_vport *vport = shost_priv(shost); 5457d2cc9bcdSJames Smart struct lpfc_hba *phba = vport->phba; 5458d2cc9bcdSJames Smart struct lpfc_bsg_set_ras_config_req *ras_req; 5459d2cc9bcdSJames Smart struct fc_bsg_request *bsg_request = job->request; 5460d2cc9bcdSJames Smart struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog; 5461d2cc9bcdSJames Smart struct fc_bsg_reply *bsg_reply = job->reply; 5462d2cc9bcdSJames Smart uint8_t action = 0, log_level = 0; 5463191e2f74SJames Smart int rc = 0, action_status = 0; 5464d2cc9bcdSJames Smart 5465d2cc9bcdSJames Smart if (job->request_len < 5466d2cc9bcdSJames Smart sizeof(struct fc_bsg_request) + 5467d2cc9bcdSJames Smart sizeof(struct lpfc_bsg_set_ras_config_req)) { 5468d2cc9bcdSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 5469d2cc9bcdSJames Smart "6182 Received RAS_LOG request " 5470d2cc9bcdSJames Smart "below minimum size\n"); 5471d2cc9bcdSJames Smart rc = -EINVAL; 5472d2cc9bcdSJames Smart goto ras_job_error; 5473d2cc9bcdSJames Smart } 5474d2cc9bcdSJames Smart 5475d2cc9bcdSJames Smart /* Check FW log status */ 5476d2cc9bcdSJames Smart rc = lpfc_check_fwlog_support(phba); 5477cb34990bSJames Smart if (rc) 5478d2cc9bcdSJames Smart goto ras_job_error; 5479d2cc9bcdSJames Smart 5480d2cc9bcdSJames Smart ras_req = (struct lpfc_bsg_set_ras_config_req *) 5481d2cc9bcdSJames Smart bsg_request->rqst_data.h_vendor.vendor_cmd; 5482d2cc9bcdSJames Smart action = ras_req->action; 5483d2cc9bcdSJames Smart log_level = ras_req->log_level; 5484d2cc9bcdSJames Smart 5485d2cc9bcdSJames Smart if (action == LPFC_RASACTION_STOP_LOGGING) { 5486d2cc9bcdSJames Smart /* Check if already disabled */ 548795bfc6d8SJames Smart spin_lock_irq(&phba->hbalock); 548895bfc6d8SJames Smart if (ras_fwlog->state != ACTIVE) { 548995bfc6d8SJames Smart spin_unlock_irq(&phba->hbalock); 5490d2cc9bcdSJames Smart rc = -ESRCH; 5491d2cc9bcdSJames Smart goto ras_job_error; 5492d2cc9bcdSJames Smart } 549395bfc6d8SJames Smart spin_unlock_irq(&phba->hbalock); 5494d2cc9bcdSJames Smart 5495d2cc9bcdSJames Smart /* Disable logging */ 5496d2cc9bcdSJames Smart lpfc_ras_stop_fwlog(phba); 5497d2cc9bcdSJames Smart } else { 5498d2cc9bcdSJames Smart /*action = LPFC_RASACTION_START_LOGGING*/ 5499191e2f74SJames Smart 5500191e2f74SJames Smart /* Even though FW-logging is active re-initialize 5501191e2f74SJames Smart * FW-logging with new log-level. Return status 5502191e2f74SJames Smart * "Logging already Running" to caller. 5503191e2f74SJames Smart **/ 550495bfc6d8SJames Smart spin_lock_irq(&phba->hbalock); 550595bfc6d8SJames Smart if (ras_fwlog->state != INACTIVE) 5506191e2f74SJames Smart action_status = -EINPROGRESS; 550795bfc6d8SJames Smart spin_unlock_irq(&phba->hbalock); 5508d2cc9bcdSJames Smart 5509d2cc9bcdSJames Smart /* Enable logging */ 5510d2cc9bcdSJames Smart rc = lpfc_sli4_ras_fwlog_init(phba, log_level, 5511d2cc9bcdSJames Smart LPFC_RAS_ENABLE_LOGGING); 5512191e2f74SJames Smart if (rc) { 5513d2cc9bcdSJames Smart rc = -EINVAL; 5514191e2f74SJames Smart goto ras_job_error; 5515191e2f74SJames Smart } 5516191e2f74SJames Smart 5517191e2f74SJames Smart /* Check if FW-logging is re-initialized */ 5518191e2f74SJames Smart if (action_status == -EINPROGRESS) 5519191e2f74SJames Smart rc = action_status; 5520d2cc9bcdSJames Smart } 5521d2cc9bcdSJames Smart ras_job_error: 5522d2cc9bcdSJames Smart /* make error code available to userspace */ 5523d2cc9bcdSJames Smart bsg_reply->result = rc; 5524d2cc9bcdSJames Smart 5525d2cc9bcdSJames Smart /* complete the job back to userspace */ 55266db51abbSJames Smart if (!rc) 5527d2cc9bcdSJames Smart bsg_job_done(job, bsg_reply->result, 5528d2cc9bcdSJames Smart bsg_reply->reply_payload_rcv_len); 5529d2cc9bcdSJames Smart 5530d2cc9bcdSJames Smart return rc; 5531d2cc9bcdSJames Smart } 5532d2cc9bcdSJames Smart 5533d2cc9bcdSJames Smart /** 5534d2cc9bcdSJames Smart * lpfc_bsg_get_ras_lwpd: Get log write position data 5535d2cc9bcdSJames Smart * @job: fc_bsg_job to handle 5536d2cc9bcdSJames Smart * 5537d2cc9bcdSJames Smart * Get Offset/Wrap count of the log message written 5538d2cc9bcdSJames Smart * in host memory 5539d2cc9bcdSJames Smart **/ 5540d2cc9bcdSJames Smart static int 5541d2cc9bcdSJames Smart lpfc_bsg_get_ras_lwpd(struct bsg_job *job) 5542d2cc9bcdSJames Smart { 5543d2cc9bcdSJames Smart struct Scsi_Host *shost = fc_bsg_to_shost(job); 5544d2cc9bcdSJames Smart struct lpfc_vport *vport = shost_priv(shost); 5545d2cc9bcdSJames Smart struct lpfc_bsg_get_ras_lwpd *ras_reply; 5546d2cc9bcdSJames Smart struct lpfc_hba *phba = vport->phba; 5547d2cc9bcdSJames Smart struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog; 5548d2cc9bcdSJames Smart struct fc_bsg_reply *bsg_reply = job->reply; 5549191e2f74SJames Smart u32 *lwpd_ptr = NULL; 5550d2cc9bcdSJames Smart int rc = 0; 5551d2cc9bcdSJames Smart 5552d2cc9bcdSJames Smart rc = lpfc_check_fwlog_support(phba); 5553cb34990bSJames Smart if (rc) 5554d2cc9bcdSJames Smart goto ras_job_error; 5555d2cc9bcdSJames Smart 5556d2cc9bcdSJames Smart if (job->request_len < 5557d2cc9bcdSJames Smart sizeof(struct fc_bsg_request) + 5558d2cc9bcdSJames Smart sizeof(struct lpfc_bsg_ras_req)) { 5559d2cc9bcdSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 5560d2cc9bcdSJames Smart "6183 Received RAS_LOG request " 5561d2cc9bcdSJames Smart "below minimum size\n"); 5562d2cc9bcdSJames Smart rc = -EINVAL; 5563d2cc9bcdSJames Smart goto ras_job_error; 5564d2cc9bcdSJames Smart } 5565d2cc9bcdSJames Smart 5566d2cc9bcdSJames Smart ras_reply = (struct lpfc_bsg_get_ras_lwpd *) 5567d2cc9bcdSJames Smart bsg_reply->reply_data.vendor_reply.vendor_rsp; 5568d2cc9bcdSJames Smart 5569cb34990bSJames Smart if (!ras_fwlog->lwpd.virt) { 5570cb34990bSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 5571cb34990bSJames Smart "6193 Restart FW Logging\n"); 55721165a5c2SJames Smart rc = -EINVAL; 55731165a5c2SJames Smart goto ras_job_error; 5574cb34990bSJames Smart } 5575cb34990bSJames Smart 5576191e2f74SJames Smart /* Get lwpd offset */ 5577191e2f74SJames Smart lwpd_ptr = (uint32_t *)(ras_fwlog->lwpd.virt); 5578191e2f74SJames Smart ras_reply->offset = be32_to_cpu(*lwpd_ptr & 0xffffffff); 5579d2cc9bcdSJames Smart 5580191e2f74SJames Smart /* Get wrap count */ 5581191e2f74SJames Smart ras_reply->wrap_count = be32_to_cpu(*(++lwpd_ptr) & 0xffffffff); 5582d2cc9bcdSJames Smart 5583d2cc9bcdSJames Smart ras_job_error: 5584d2cc9bcdSJames Smart /* make error code available to userspace */ 5585d2cc9bcdSJames Smart bsg_reply->result = rc; 5586d2cc9bcdSJames Smart 5587d2cc9bcdSJames Smart /* complete the job back to userspace */ 55886db51abbSJames Smart if (!rc) 55896db51abbSJames Smart bsg_job_done(job, bsg_reply->result, 55906db51abbSJames Smart bsg_reply->reply_payload_rcv_len); 5591d2cc9bcdSJames Smart 5592d2cc9bcdSJames Smart return rc; 5593d2cc9bcdSJames Smart } 5594d2cc9bcdSJames Smart 5595d2cc9bcdSJames Smart /** 5596d2cc9bcdSJames Smart * lpfc_bsg_get_ras_fwlog: Read FW log 5597d2cc9bcdSJames Smart * @job: fc_bsg_job to handle 5598d2cc9bcdSJames Smart * 5599d2cc9bcdSJames Smart * Copy the FW log into the passed buffer. 5600d2cc9bcdSJames Smart **/ 5601d2cc9bcdSJames Smart static int 5602d2cc9bcdSJames Smart lpfc_bsg_get_ras_fwlog(struct bsg_job *job) 5603d2cc9bcdSJames Smart { 5604d2cc9bcdSJames Smart struct Scsi_Host *shost = fc_bsg_to_shost(job); 5605d2cc9bcdSJames Smart struct lpfc_vport *vport = shost_priv(shost); 5606d2cc9bcdSJames Smart struct lpfc_hba *phba = vport->phba; 5607d2cc9bcdSJames Smart struct fc_bsg_request *bsg_request = job->request; 5608d2cc9bcdSJames Smart struct fc_bsg_reply *bsg_reply = job->reply; 5609d2cc9bcdSJames Smart struct lpfc_bsg_get_fwlog_req *ras_req; 5610191e2f74SJames Smart u32 rd_offset, rd_index, offset; 5611191e2f74SJames Smart void *src, *fwlog_buff; 5612d2cc9bcdSJames Smart struct lpfc_ras_fwlog *ras_fwlog = NULL; 5613d2cc9bcdSJames Smart struct lpfc_dmabuf *dmabuf, *next; 5614d2cc9bcdSJames Smart int rc = 0; 5615d2cc9bcdSJames Smart 5616d2cc9bcdSJames Smart ras_fwlog = &phba->ras_fwlog; 5617d2cc9bcdSJames Smart 5618d2cc9bcdSJames Smart rc = lpfc_check_fwlog_support(phba); 5619cb34990bSJames Smart if (rc) 5620d2cc9bcdSJames Smart goto ras_job_error; 5621d2cc9bcdSJames Smart 5622d2cc9bcdSJames Smart /* Logging to be stopped before reading */ 562395bfc6d8SJames Smart spin_lock_irq(&phba->hbalock); 562495bfc6d8SJames Smart if (ras_fwlog->state == ACTIVE) { 562595bfc6d8SJames Smart spin_unlock_irq(&phba->hbalock); 5626d2cc9bcdSJames Smart rc = -EINPROGRESS; 5627d2cc9bcdSJames Smart goto ras_job_error; 5628d2cc9bcdSJames Smart } 562995bfc6d8SJames Smart spin_unlock_irq(&phba->hbalock); 5630d2cc9bcdSJames Smart 5631d2cc9bcdSJames Smart if (job->request_len < 5632d2cc9bcdSJames Smart sizeof(struct fc_bsg_request) + 5633d2cc9bcdSJames Smart sizeof(struct lpfc_bsg_get_fwlog_req)) { 5634d2cc9bcdSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 5635d2cc9bcdSJames Smart "6184 Received RAS_LOG request " 5636d2cc9bcdSJames Smart "below minimum size\n"); 5637d2cc9bcdSJames Smart rc = -EINVAL; 5638d2cc9bcdSJames Smart goto ras_job_error; 5639d2cc9bcdSJames Smart } 5640d2cc9bcdSJames Smart 5641d2cc9bcdSJames Smart ras_req = (struct lpfc_bsg_get_fwlog_req *) 5642d2cc9bcdSJames Smart bsg_request->rqst_data.h_vendor.vendor_cmd; 5643d2cc9bcdSJames Smart rd_offset = ras_req->read_offset; 5644d2cc9bcdSJames Smart 5645d2cc9bcdSJames Smart /* Allocate memory to read fw log*/ 5646d2cc9bcdSJames Smart fwlog_buff = vmalloc(ras_req->read_size); 5647d2cc9bcdSJames Smart if (!fwlog_buff) { 5648d2cc9bcdSJames Smart rc = -ENOMEM; 5649d2cc9bcdSJames Smart goto ras_job_error; 5650d2cc9bcdSJames Smart } 5651d2cc9bcdSJames Smart 5652d2cc9bcdSJames Smart rd_index = (rd_offset / LPFC_RAS_MAX_ENTRY_SIZE); 5653d2cc9bcdSJames Smart offset = (rd_offset % LPFC_RAS_MAX_ENTRY_SIZE); 5654d2cc9bcdSJames Smart 5655d2cc9bcdSJames Smart list_for_each_entry_safe(dmabuf, next, 5656d2cc9bcdSJames Smart &ras_fwlog->fwlog_buff_list, list) { 5657d2cc9bcdSJames Smart 5658d2cc9bcdSJames Smart if (dmabuf->buffer_tag < rd_index) 5659d2cc9bcdSJames Smart continue; 5660d2cc9bcdSJames Smart 5661d2cc9bcdSJames Smart src = dmabuf->virt + offset; 5662191e2f74SJames Smart memcpy(fwlog_buff, src, ras_req->read_size); 5663d2cc9bcdSJames Smart break; 5664d2cc9bcdSJames Smart } 5665d2cc9bcdSJames Smart 5666d2cc9bcdSJames Smart bsg_reply->reply_payload_rcv_len = 5667d2cc9bcdSJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 5668d2cc9bcdSJames Smart job->reply_payload.sg_cnt, 5669d2cc9bcdSJames Smart fwlog_buff, ras_req->read_size); 5670d2cc9bcdSJames Smart 5671d2cc9bcdSJames Smart vfree(fwlog_buff); 5672d2cc9bcdSJames Smart 5673d2cc9bcdSJames Smart ras_job_error: 5674d2cc9bcdSJames Smart bsg_reply->result = rc; 56756db51abbSJames Smart if (!rc) 56766db51abbSJames Smart bsg_job_done(job, bsg_reply->result, 56776db51abbSJames Smart bsg_reply->reply_payload_rcv_len); 5678d2cc9bcdSJames Smart 5679d2cc9bcdSJames Smart return rc; 5680d2cc9bcdSJames Smart } 5681d2cc9bcdSJames Smart 56821dc5ec24SJames Smart static int 56831dc5ec24SJames Smart lpfc_get_trunk_info(struct bsg_job *job) 56841dc5ec24SJames Smart { 56851dc5ec24SJames Smart struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 56861dc5ec24SJames Smart struct lpfc_hba *phba = vport->phba; 56871dc5ec24SJames Smart struct fc_bsg_reply *bsg_reply = job->reply; 56881dc5ec24SJames Smart struct lpfc_trunk_info *event_reply; 56891dc5ec24SJames Smart int rc = 0; 56901dc5ec24SJames Smart 56911dc5ec24SJames Smart if (job->request_len < 56921dc5ec24SJames Smart sizeof(struct fc_bsg_request) + sizeof(struct get_trunk_info_req)) { 56931dc5ec24SJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 56941dc5ec24SJames Smart "2744 Received GET TRUNK _INFO request below " 56951dc5ec24SJames Smart "minimum size\n"); 56961dc5ec24SJames Smart rc = -EINVAL; 56971dc5ec24SJames Smart goto job_error; 56981dc5ec24SJames Smart } 56991dc5ec24SJames Smart 57001dc5ec24SJames Smart event_reply = (struct lpfc_trunk_info *) 57011dc5ec24SJames Smart bsg_reply->reply_data.vendor_reply.vendor_rsp; 57021dc5ec24SJames Smart 5703feb3cc57SDick Kennedy if (job->reply_len < sizeof(*bsg_reply) + sizeof(*event_reply)) { 57041dc5ec24SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 57051dc5ec24SJames Smart "2728 Received GET TRUNK _INFO reply below " 57061dc5ec24SJames Smart "minimum size\n"); 57071dc5ec24SJames Smart rc = -EINVAL; 57081dc5ec24SJames Smart goto job_error; 57091dc5ec24SJames Smart } 57101dc5ec24SJames Smart if (event_reply == NULL) { 57111dc5ec24SJames Smart rc = -EINVAL; 57121dc5ec24SJames Smart goto job_error; 57131dc5ec24SJames Smart } 57141dc5ec24SJames Smart 57151dc5ec24SJames Smart bsg_bf_set(lpfc_trunk_info_link_status, event_reply, 57161dc5ec24SJames Smart (phba->link_state >= LPFC_LINK_UP) ? 1 : 0); 57171dc5ec24SJames Smart 57181dc5ec24SJames Smart bsg_bf_set(lpfc_trunk_info_trunk_active0, event_reply, 57191dc5ec24SJames Smart (phba->trunk_link.link0.state == LPFC_LINK_UP) ? 1 : 0); 57201dc5ec24SJames Smart 57211dc5ec24SJames Smart bsg_bf_set(lpfc_trunk_info_trunk_active1, event_reply, 57221dc5ec24SJames Smart (phba->trunk_link.link1.state == LPFC_LINK_UP) ? 1 : 0); 57231dc5ec24SJames Smart 57241dc5ec24SJames Smart bsg_bf_set(lpfc_trunk_info_trunk_active2, event_reply, 57251dc5ec24SJames Smart (phba->trunk_link.link2.state == LPFC_LINK_UP) ? 1 : 0); 57261dc5ec24SJames Smart 57271dc5ec24SJames Smart bsg_bf_set(lpfc_trunk_info_trunk_active3, event_reply, 57281dc5ec24SJames Smart (phba->trunk_link.link3.state == LPFC_LINK_UP) ? 1 : 0); 57291dc5ec24SJames Smart 57301dc5ec24SJames Smart bsg_bf_set(lpfc_trunk_info_trunk_config0, event_reply, 57311dc5ec24SJames Smart bf_get(lpfc_conf_trunk_port0, &phba->sli4_hba)); 57321dc5ec24SJames Smart 57331dc5ec24SJames Smart bsg_bf_set(lpfc_trunk_info_trunk_config1, event_reply, 57341dc5ec24SJames Smart bf_get(lpfc_conf_trunk_port1, &phba->sli4_hba)); 57351dc5ec24SJames Smart 57361dc5ec24SJames Smart bsg_bf_set(lpfc_trunk_info_trunk_config2, event_reply, 57371dc5ec24SJames Smart bf_get(lpfc_conf_trunk_port2, &phba->sli4_hba)); 57381dc5ec24SJames Smart 57391dc5ec24SJames Smart bsg_bf_set(lpfc_trunk_info_trunk_config3, event_reply, 57401dc5ec24SJames Smart bf_get(lpfc_conf_trunk_port3, &phba->sli4_hba)); 57411dc5ec24SJames Smart 57421dc5ec24SJames Smart event_reply->port_speed = phba->sli4_hba.link_state.speed / 1000; 57431dc5ec24SJames Smart event_reply->logical_speed = 5744b8e6f136SJames Smart phba->sli4_hba.link_state.logical_speed / 1000; 57451dc5ec24SJames Smart job_error: 57461dc5ec24SJames Smart bsg_reply->result = rc; 57476db51abbSJames Smart if (!rc) 57481dc5ec24SJames Smart bsg_job_done(job, bsg_reply->result, 57491dc5ec24SJames Smart bsg_reply->reply_payload_rcv_len); 57501dc5ec24SJames Smart return rc; 57511dc5ec24SJames Smart 57521dc5ec24SJames Smart } 5753d2cc9bcdSJames Smart 5754d2cc9bcdSJames Smart /** 5755f1c3b0fcSJames Smart * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job 5756f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 57573b5dd52aSJames Smart **/ 5758f1c3b0fcSJames Smart static int 575975cc8cfcSJohannes Thumshirn lpfc_bsg_hst_vendor(struct bsg_job *job) 5760f1c3b0fcSJames Smart { 576101e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 576201e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 576301e0e15cSJohannes Thumshirn int command = bsg_request->rqst_data.h_vendor.vendor_cmd[0]; 57644cc0e56eSJames Smart int rc; 5765f1c3b0fcSJames Smart 5766f1c3b0fcSJames Smart switch (command) { 5767f1c3b0fcSJames Smart case LPFC_BSG_VENDOR_SET_CT_EVENT: 57684cc0e56eSJames Smart rc = lpfc_bsg_hba_set_event(job); 5769f1c3b0fcSJames Smart break; 5770f1c3b0fcSJames Smart case LPFC_BSG_VENDOR_GET_CT_EVENT: 57714cc0e56eSJames Smart rc = lpfc_bsg_hba_get_event(job); 5772f1c3b0fcSJames Smart break; 57733b5dd52aSJames Smart case LPFC_BSG_VENDOR_SEND_MGMT_RESP: 57743b5dd52aSJames Smart rc = lpfc_bsg_send_mgmt_rsp(job); 57753b5dd52aSJames Smart break; 57763b5dd52aSJames Smart case LPFC_BSG_VENDOR_DIAG_MODE: 57777ad20aa9SJames Smart rc = lpfc_bsg_diag_loopback_mode(job); 57783b5dd52aSJames Smart break; 57797ad20aa9SJames Smart case LPFC_BSG_VENDOR_DIAG_MODE_END: 57807ad20aa9SJames Smart rc = lpfc_sli4_bsg_diag_mode_end(job); 57817ad20aa9SJames Smart break; 57827ad20aa9SJames Smart case LPFC_BSG_VENDOR_DIAG_RUN_LOOPBACK: 57837ad20aa9SJames Smart rc = lpfc_bsg_diag_loopback_run(job); 57847ad20aa9SJames Smart break; 57857ad20aa9SJames Smart case LPFC_BSG_VENDOR_LINK_DIAG_TEST: 57867ad20aa9SJames Smart rc = lpfc_sli4_bsg_link_diag_test(job); 57873b5dd52aSJames Smart break; 57883b5dd52aSJames Smart case LPFC_BSG_VENDOR_GET_MGMT_REV: 57893b5dd52aSJames Smart rc = lpfc_bsg_get_dfc_rev(job); 57903b5dd52aSJames Smart break; 57913b5dd52aSJames Smart case LPFC_BSG_VENDOR_MBOX: 57923b5dd52aSJames Smart rc = lpfc_bsg_mbox_cmd(job); 57933b5dd52aSJames Smart break; 5794e2aed29fSJames Smart case LPFC_BSG_VENDOR_MENLO_CMD: 5795e2aed29fSJames Smart case LPFC_BSG_VENDOR_MENLO_DATA: 5796e2aed29fSJames Smart rc = lpfc_menlo_cmd(job); 5797e2aed29fSJames Smart break; 5798c691816eSJames Smart case LPFC_BSG_VENDOR_FORCED_LINK_SPEED: 5799c691816eSJames Smart rc = lpfc_forced_link_speed(job); 5800c691816eSJames Smart break; 5801d2cc9bcdSJames Smart case LPFC_BSG_VENDOR_RAS_GET_LWPD: 5802d2cc9bcdSJames Smart rc = lpfc_bsg_get_ras_lwpd(job); 5803d2cc9bcdSJames Smart break; 5804d2cc9bcdSJames Smart case LPFC_BSG_VENDOR_RAS_GET_FWLOG: 5805d2cc9bcdSJames Smart rc = lpfc_bsg_get_ras_fwlog(job); 5806d2cc9bcdSJames Smart break; 5807d2cc9bcdSJames Smart case LPFC_BSG_VENDOR_RAS_GET_CONFIG: 5808d2cc9bcdSJames Smart rc = lpfc_bsg_get_ras_config(job); 5809d2cc9bcdSJames Smart break; 5810d2cc9bcdSJames Smart case LPFC_BSG_VENDOR_RAS_SET_CONFIG: 5811d2cc9bcdSJames Smart rc = lpfc_bsg_set_ras_config(job); 5812d2cc9bcdSJames Smart break; 58131dc5ec24SJames Smart case LPFC_BSG_VENDOR_GET_TRUNK_INFO: 58141dc5ec24SJames Smart rc = lpfc_get_trunk_info(job); 58151dc5ec24SJames Smart break; 5816f1c3b0fcSJames Smart default: 58174cc0e56eSJames Smart rc = -EINVAL; 581801e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 58194cc0e56eSJames Smart /* make error code available to userspace */ 582001e0e15cSJohannes Thumshirn bsg_reply->result = rc; 58214cc0e56eSJames Smart break; 5822f1c3b0fcSJames Smart } 58234cc0e56eSJames Smart 58244cc0e56eSJames Smart return rc; 5825f1c3b0fcSJames Smart } 5826f1c3b0fcSJames Smart 5827f1c3b0fcSJames Smart /** 5828f1c3b0fcSJames Smart * lpfc_bsg_request - handle a bsg request from the FC transport 5829d2cc9bcdSJames Smart * @job: bsg_job to handle 58303b5dd52aSJames Smart **/ 5831f1c3b0fcSJames Smart int 583275cc8cfcSJohannes Thumshirn lpfc_bsg_request(struct bsg_job *job) 5833f1c3b0fcSJames Smart { 583401e0e15cSJohannes Thumshirn struct fc_bsg_request *bsg_request = job->request; 583501e0e15cSJohannes Thumshirn struct fc_bsg_reply *bsg_reply = job->reply; 5836f1c3b0fcSJames Smart uint32_t msgcode; 58374cc0e56eSJames Smart int rc; 5838f1c3b0fcSJames Smart 583901e0e15cSJohannes Thumshirn msgcode = bsg_request->msgcode; 5840f1c3b0fcSJames Smart switch (msgcode) { 5841f1c3b0fcSJames Smart case FC_BSG_HST_VENDOR: 5842f1c3b0fcSJames Smart rc = lpfc_bsg_hst_vendor(job); 5843f1c3b0fcSJames Smart break; 5844f1c3b0fcSJames Smart case FC_BSG_RPT_ELS: 5845f1c3b0fcSJames Smart rc = lpfc_bsg_rport_els(job); 5846f1c3b0fcSJames Smart break; 5847f1c3b0fcSJames Smart case FC_BSG_RPT_CT: 58484cc0e56eSJames Smart rc = lpfc_bsg_send_mgmt_cmd(job); 5849f1c3b0fcSJames Smart break; 5850f1c3b0fcSJames Smart default: 58514cc0e56eSJames Smart rc = -EINVAL; 585201e0e15cSJohannes Thumshirn bsg_reply->reply_payload_rcv_len = 0; 58534cc0e56eSJames Smart /* make error code available to userspace */ 585401e0e15cSJohannes Thumshirn bsg_reply->result = rc; 5855f1c3b0fcSJames Smart break; 5856f1c3b0fcSJames Smart } 5857f1c3b0fcSJames Smart 5858f1c3b0fcSJames Smart return rc; 5859f1c3b0fcSJames Smart } 5860f1c3b0fcSJames Smart 5861f1c3b0fcSJames Smart /** 5862f1c3b0fcSJames Smart * lpfc_bsg_timeout - handle timeout of a bsg request from the FC transport 5863d2cc9bcdSJames Smart * @job: bsg_job that has timed out 5864f1c3b0fcSJames Smart * 5865f1c3b0fcSJames Smart * This function just aborts the job's IOCB. The aborted IOCB will return to 5866f1c3b0fcSJames Smart * the waiting function which will handle passing the error back to userspace 58673b5dd52aSJames Smart **/ 5868f1c3b0fcSJames Smart int 586975cc8cfcSJohannes Thumshirn lpfc_bsg_timeout(struct bsg_job *job) 5870f1c3b0fcSJames Smart { 5871cd21c605SJohannes Thumshirn struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); 5872f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 58734cc0e56eSJames Smart struct lpfc_iocbq *cmdiocb; 5874895427bdSJames Smart struct lpfc_sli_ring *pring; 58754cc0e56eSJames Smart struct bsg_job_data *dd_data; 58764cc0e56eSJames Smart unsigned long flags; 5877a33c4f7bSJames Smart int rc = 0; 5878a33c4f7bSJames Smart LIST_HEAD(completions); 5879a33c4f7bSJames Smart struct lpfc_iocbq *check_iocb, *next_iocb; 5880a33c4f7bSJames Smart 5881895427bdSJames Smart pring = lpfc_phba_elsring(phba); 58821234a6d5SDick Kennedy if (unlikely(!pring)) 58831234a6d5SDick Kennedy return -EIO; 5884895427bdSJames Smart 5885a33c4f7bSJames Smart /* if job's driver data is NULL, the command completed or is in the 5886a33c4f7bSJames Smart * the process of completing. In this case, return status to request 5887a33c4f7bSJames Smart * so the timeout is retried. This avoids double completion issues 5888a33c4f7bSJames Smart * and the request will be pulled off the timer queue when the 5889a33c4f7bSJames Smart * command's completion handler executes. Otherwise, prevent the 5890a33c4f7bSJames Smart * command's completion handler from executing the job done callback 5891a33c4f7bSJames Smart * and continue processing to abort the outstanding the command. 5892a33c4f7bSJames Smart */ 5893f1c3b0fcSJames Smart 58944cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 58954cc0e56eSJames Smart dd_data = (struct bsg_job_data *)job->dd_data; 5896a33c4f7bSJames Smart if (dd_data) { 5897a33c4f7bSJames Smart dd_data->set_job = NULL; 5898a33c4f7bSJames Smart job->dd_data = NULL; 5899a33c4f7bSJames Smart } else { 59004cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 5901a33c4f7bSJames Smart return -EAGAIN; 59024cc0e56eSJames Smart } 59034cc0e56eSJames Smart 59044cc0e56eSJames Smart switch (dd_data->type) { 59054cc0e56eSJames Smart case TYPE_IOCB: 5906a33c4f7bSJames Smart /* Check to see if IOCB was issued to the port or not. If not, 5907a33c4f7bSJames Smart * remove it from the txq queue and call cancel iocbs. 5908a33c4f7bSJames Smart * Otherwise, call abort iotag 5909a33c4f7bSJames Smart */ 5910a33c4f7bSJames Smart cmdiocb = dd_data->context_un.iocb.cmdiocbq; 5911b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 5912b5a9b2dfSJames Smart 5913b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 5914b5a9b2dfSJames Smart /* make sure the I/O abort window is still open */ 59151b8d11abSJames Smart if (!(cmdiocb->iocb_flag & LPFC_IO_CMD_OUTSTANDING)) { 5916b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 5917b5a9b2dfSJames Smart return -EAGAIN; 5918b5a9b2dfSJames Smart } 5919a33c4f7bSJames Smart list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq, 5920a33c4f7bSJames Smart list) { 5921a33c4f7bSJames Smart if (check_iocb == cmdiocb) { 5922a33c4f7bSJames Smart list_move_tail(&check_iocb->list, &completions); 5923a33c4f7bSJames Smart break; 5924a33c4f7bSJames Smart } 5925a33c4f7bSJames Smart } 5926a33c4f7bSJames Smart if (list_empty(&completions)) 5927db7531d2SJames Smart lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb, NULL); 5928b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 5929a33c4f7bSJames Smart if (!list_empty(&completions)) { 5930a33c4f7bSJames Smart lpfc_sli_cancel_iocbs(phba, &completions, 5931a33c4f7bSJames Smart IOSTAT_LOCAL_REJECT, 5932a33c4f7bSJames Smart IOERR_SLI_ABORTED); 5933a33c4f7bSJames Smart } 59344cc0e56eSJames Smart break; 5935a33c4f7bSJames Smart 59364cc0e56eSJames Smart case TYPE_EVT: 59374cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 59384cc0e56eSJames Smart break; 5939a33c4f7bSJames Smart 59403b5dd52aSJames Smart case TYPE_MBOX: 5941a33c4f7bSJames Smart /* Update the ext buf ctx state if needed */ 5942a33c4f7bSJames Smart 59437ad20aa9SJames Smart if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_PORT) 59447ad20aa9SJames Smart phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_ABTS; 5945a33c4f7bSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 59463b5dd52aSJames Smart break; 5947e2aed29fSJames Smart case TYPE_MENLO: 5948a33c4f7bSJames Smart /* Check to see if IOCB was issued to the port or not. If not, 5949a33c4f7bSJames Smart * remove it from the txq queue and call cancel iocbs. 5950a33c4f7bSJames Smart * Otherwise, call abort iotag. 5951a33c4f7bSJames Smart */ 5952a33c4f7bSJames Smart cmdiocb = dd_data->context_un.menlo.cmdiocbq; 5953b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 5954b5a9b2dfSJames Smart 5955b5a9b2dfSJames Smart spin_lock_irqsave(&phba->hbalock, flags); 5956a33c4f7bSJames Smart list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq, 5957a33c4f7bSJames Smart list) { 5958a33c4f7bSJames Smart if (check_iocb == cmdiocb) { 5959a33c4f7bSJames Smart list_move_tail(&check_iocb->list, &completions); 5960a33c4f7bSJames Smart break; 5961a33c4f7bSJames Smart } 5962a33c4f7bSJames Smart } 5963a33c4f7bSJames Smart if (list_empty(&completions)) 5964db7531d2SJames Smart lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb, NULL); 5965b5a9b2dfSJames Smart spin_unlock_irqrestore(&phba->hbalock, flags); 5966a33c4f7bSJames Smart if (!list_empty(&completions)) { 5967a33c4f7bSJames Smart lpfc_sli_cancel_iocbs(phba, &completions, 5968a33c4f7bSJames Smart IOSTAT_LOCAL_REJECT, 5969a33c4f7bSJames Smart IOERR_SLI_ABORTED); 5970a33c4f7bSJames Smart } 5971e2aed29fSJames Smart break; 59724cc0e56eSJames Smart default: 59734cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 59744cc0e56eSJames Smart break; 59754cc0e56eSJames Smart } 5976f1c3b0fcSJames Smart 59774cc0e56eSJames Smart /* scsi transport fc fc_bsg_job_timeout expects a zero return code, 59784cc0e56eSJames Smart * otherwise an error message will be displayed on the console 59794cc0e56eSJames Smart * so always return success (zero) 59804cc0e56eSJames Smart */ 5981a33c4f7bSJames Smart return rc; 5982f1c3b0fcSJames Smart } 5983