Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

scsi: lpfc: Reject CT request for MIB commands

Now that MIB support was registered with FDMI, the driver may receive CT
requests for MIB-related commands. At this time, no command is
supported. However, the driver needs to be graceful and reject the CT
request.

This patch adds identification of the requests as well as sending the
reject response.

Link: https://lore.kernel.org/r/20201020202719.54726-9-james.smart@broadcom.com
Co-developed-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <james.smart@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

James Smart and committed by
Martin K. Petersen
b67b5944 8aaa7bcf

+296 -39
+1 -20
drivers/scsi/lpfc/lpfc_bsg.c
··· 939 939 INIT_LIST_HEAD(&head); 940 940 list_add_tail(&head, &piocbq->list); 941 941 942 - if (piocbq->iocb.ulpBdeCount == 0 || 943 - piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0) 944 - goto error_ct_unsol_exit; 945 - 946 - if (phba->link_state == LPFC_HBA_ERROR || 947 - (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) 948 - goto error_ct_unsol_exit; 949 - 950 - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) 951 - dmabuf = bdeBuf1; 952 - else { 953 - dma_addr = getPaddr(piocbq->iocb.un.cont64[0].addrHigh, 954 - piocbq->iocb.un.cont64[0].addrLow); 955 - dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr); 956 - } 957 - if (dmabuf == NULL) 958 - goto error_ct_unsol_exit; 959 - ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt; 942 + ct_req = (struct lpfc_sli_ct_request *)bdeBuf1; 960 943 evt_req_id = ct_req->FsType; 961 944 cmd = ct_req->CommandResponse.bits.CmdRsp; 962 - if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) 963 - lpfc_sli_ringpostbuf_put(phba, pring, dmabuf); 964 945 965 946 spin_lock_irqsave(&phba->ct_ev_lock, flags); 966 947 list_for_each_entry(evt, &phba->ct_ev_waiters, node) {
+292 -19
drivers/scsi/lpfc/lpfc_ct.c
··· 99 99 lpfc_ct_ignore_hbq_buffer(phba, piocbq, mp, size); 100 100 } 101 101 102 + /** 103 + * lpfc_ct_unsol_cmpl : Completion callback function for unsol ct commands 104 + * @phba : pointer to lpfc hba data structure. 105 + * @cmdiocb : pointer to lpfc command iocb data structure. 106 + * @rspiocb : pointer to lpfc response iocb data structure. 107 + * 108 + * This routine is the callback function for issuing unsol ct reject command. 109 + * The memory allocated in the reject command path is freed up here. 110 + **/ 111 + static void 112 + lpfc_ct_unsol_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, 113 + struct lpfc_iocbq *rspiocb) 114 + { 115 + struct lpfc_nodelist *ndlp; 116 + struct lpfc_dmabuf *mp, *bmp; 117 + 118 + ndlp = (struct lpfc_nodelist *)cmdiocb->context1; 119 + if (ndlp) 120 + lpfc_nlp_put(ndlp); 121 + 122 + mp = cmdiocb->context2; 123 + bmp = cmdiocb->context3; 124 + if (mp) { 125 + lpfc_mbuf_free(phba, mp->virt, mp->phys); 126 + kfree(mp); 127 + cmdiocb->context2 = NULL; 128 + } 129 + 130 + if (bmp) { 131 + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 132 + kfree(bmp); 133 + cmdiocb->context3 = NULL; 134 + } 135 + 136 + lpfc_sli_release_iocbq(phba, cmdiocb); 137 + } 138 + 139 + /** 140 + * lpfc_ct_reject_event : Issue reject for unhandled CT MIB commands 141 + * @ndlp : pointer to a node-list data structure. 142 + * ct_req : pointer to the CT request data structure. 143 + * rx_id : rx_id of the received UNSOL CT command 144 + * ox_id : ox_id of the UNSOL CT command 145 + * 146 + * This routine is invoked by the lpfc_ct_handle_mibreq routine for sending 147 + * a reject response. Reject response is sent for the unhandled commands. 148 + **/ 149 + static void 150 + lpfc_ct_reject_event(struct lpfc_nodelist *ndlp, 151 + struct lpfc_sli_ct_request *ct_req, 152 + u16 rx_id, u16 ox_id) 153 + { 154 + struct lpfc_vport *vport = ndlp->vport; 155 + struct lpfc_hba *phba = vport->phba; 156 + struct lpfc_sli_ct_request *ct_rsp; 157 + struct lpfc_iocbq *cmdiocbq = NULL; 158 + struct lpfc_dmabuf *bmp = NULL; 159 + struct lpfc_dmabuf *mp = NULL; 160 + struct ulp_bde64 *bpl; 161 + IOCB_t *icmd; 162 + u8 rc = 0; 163 + 164 + /* fill in BDEs for command */ 165 + mp = kmalloc(sizeof(*mp), GFP_KERNEL); 166 + if (!mp) { 167 + rc = 1; 168 + goto ct_exit; 169 + } 170 + 171 + mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &mp->phys); 172 + if (!mp->virt) { 173 + rc = 2; 174 + goto ct_free_mp; 175 + } 176 + 177 + /* Allocate buffer for Buffer ptr list */ 178 + bmp = kmalloc(sizeof(*bmp), GFP_KERNEL); 179 + if (!bmp) { 180 + rc = 3; 181 + goto ct_free_mpvirt; 182 + } 183 + 184 + bmp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &bmp->phys); 185 + if (!bmp->virt) { 186 + rc = 4; 187 + goto ct_free_bmp; 188 + } 189 + 190 + INIT_LIST_HEAD(&mp->list); 191 + INIT_LIST_HEAD(&bmp->list); 192 + 193 + bpl = (struct ulp_bde64 *)bmp->virt; 194 + memset(bpl, 0, sizeof(struct ulp_bde64)); 195 + bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys)); 196 + bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys)); 197 + bpl->tus.f.bdeFlags = BUFF_TYPE_BLP_64; 198 + bpl->tus.f.bdeSize = (LPFC_CT_PREAMBLE - 4); 199 + bpl->tus.w = le32_to_cpu(bpl->tus.w); 200 + 201 + ct_rsp = (struct lpfc_sli_ct_request *)mp->virt; 202 + memset(ct_rsp, 0, sizeof(struct lpfc_sli_ct_request)); 203 + 204 + ct_rsp->RevisionId.bits.Revision = SLI_CT_REVISION; 205 + ct_rsp->RevisionId.bits.InId = 0; 206 + ct_rsp->FsType = ct_req->FsType; 207 + ct_rsp->FsSubType = ct_req->FsSubType; 208 + ct_rsp->CommandResponse.bits.Size = 0; 209 + ct_rsp->CommandResponse.bits.CmdRsp = 210 + cpu_to_be16(SLI_CT_RESPONSE_FS_RJT); 211 + ct_rsp->ReasonCode = SLI_CT_REQ_NOT_SUPPORTED; 212 + ct_rsp->Explanation = SLI_CT_NO_ADDITIONAL_EXPL; 213 + 214 + cmdiocbq = lpfc_sli_get_iocbq(phba); 215 + if (!cmdiocbq) { 216 + rc = 5; 217 + goto ct_free_bmpvirt; 218 + } 219 + 220 + icmd = &cmdiocbq->iocb; 221 + icmd->un.genreq64.bdl.ulpIoTag32 = 0; 222 + icmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); 223 + icmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); 224 + icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 225 + icmd->un.genreq64.bdl.bdeSize = sizeof(struct ulp_bde64); 226 + icmd->un.genreq64.w5.hcsw.Fctl = (LS | LA); 227 + icmd->un.genreq64.w5.hcsw.Dfctl = 0; 228 + icmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_SOL_CTL; 229 + icmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT; 230 + icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; 231 + icmd->ulpBdeCount = 1; 232 + icmd->ulpLe = 1; 233 + icmd->ulpClass = CLASS3; 234 + 235 + /* Save for completion so we can release these resources */ 236 + cmdiocbq->context1 = lpfc_nlp_get(ndlp); 237 + cmdiocbq->context2 = (uint8_t *)mp; 238 + cmdiocbq->context3 = (uint8_t *)bmp; 239 + cmdiocbq->iocb_cmpl = lpfc_ct_unsol_cmpl; 240 + icmd->ulpContext = rx_id; /* Xri / rx_id */ 241 + icmd->unsli3.rcvsli3.ox_id = ox_id; 242 + icmd->un.ulpWord[3] = 243 + phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; 244 + icmd->ulpTimeout = (3 * phba->fc_ratov); 245 + 246 + cmdiocbq->retry = 0; 247 + cmdiocbq->vport = vport; 248 + cmdiocbq->context_un.ndlp = NULL; 249 + cmdiocbq->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT; 250 + 251 + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); 252 + if (!rc) 253 + return; 254 + 255 + rc = 6; 256 + lpfc_nlp_put(ndlp); 257 + lpfc_sli_release_iocbq(phba, cmdiocbq); 258 + ct_free_bmpvirt: 259 + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 260 + ct_free_bmp: 261 + kfree(bmp); 262 + ct_free_mpvirt: 263 + lpfc_mbuf_free(phba, mp->virt, mp->phys); 264 + ct_free_mp: 265 + kfree(mp); 266 + ct_exit: 267 + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, 268 + "6440 Unsol CT: Rsp err %d Data: x%x\n", 269 + rc, vport->fc_flag); 270 + } 271 + 272 + /** 273 + * lpfc_ct_handle_mibreq - Process an unsolicited CT MIB request data buffer 274 + * @phba: pointer to lpfc hba data structure. 275 + * @ctiocb: pointer to lpfc CT command iocb data structure. 276 + * 277 + * This routine is used for processing the IOCB associated with a unsolicited 278 + * CT MIB request. It first determines whether there is an existing ndlp that 279 + * matches the DID from the unsolicited IOCB. If not, it will return. 280 + **/ 281 + static void 282 + lpfc_ct_handle_mibreq(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocbq) 283 + { 284 + struct lpfc_sli_ct_request *ct_req; 285 + struct lpfc_nodelist *ndlp = NULL; 286 + struct lpfc_vport *vport = NULL; 287 + IOCB_t *icmd = &ctiocbq->iocb; 288 + u32 mi_cmd, vpi; 289 + u32 did = 0; 290 + 291 + vpi = ctiocbq->iocb.unsli3.rcvsli3.vpi; 292 + vport = lpfc_find_vport_by_vpid(phba, vpi); 293 + if (!vport) { 294 + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, 295 + "6437 Unsol CT: VPORT NULL vpi : x%x\n", 296 + vpi); 297 + return; 298 + } 299 + 300 + did = ctiocbq->iocb.un.rcvels.remoteID; 301 + if (icmd->ulpStatus) { 302 + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, 303 + "6438 Unsol CT: status:x%x/x%x did : x%x\n", 304 + icmd->ulpStatus, icmd->un.ulpWord[4], did); 305 + return; 306 + } 307 + 308 + /* Ignore traffic received during vport shutdown */ 309 + if (vport->fc_flag & FC_UNLOADING) 310 + return; 311 + 312 + ndlp = lpfc_findnode_did(vport, did); 313 + if (!ndlp) { 314 + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, 315 + "6439 Unsol CT: NDLP Not Found for DID : x%x", 316 + did); 317 + return; 318 + } 319 + 320 + ct_req = ((struct lpfc_sli_ct_request *) 321 + (((struct lpfc_dmabuf *)ctiocbq->context2)->virt)); 322 + 323 + mi_cmd = ct_req->CommandResponse.bits.CmdRsp; 324 + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, 325 + "6442 : MI Cmd : x%x Not Supported\n", mi_cmd); 326 + lpfc_ct_reject_event(ndlp, ct_req, 327 + ctiocbq->iocb.ulpContext, 328 + ctiocbq->iocb.unsli3.rcvsli3.ox_id); 329 + } 330 + 331 + /** 332 + * lpfc_ct_unsol_event - Process an unsolicited event from a ct sli ring 333 + * @phba: pointer to lpfc hba data structure. 334 + * @pring: pointer to a SLI ring. 335 + * @ctiocbq: pointer to lpfc ct iocb data structure. 336 + * 337 + * This routine is used to process an unsolicited event received from a SLI 338 + * (Service Level Interface) ring. The actual processing of the data buffer 339 + * associated with the unsolicited event is done by invoking appropriate routine 340 + * after properly set up the iocb buffer from the SLI ring on which the 341 + * unsolicited event was received. 342 + **/ 102 343 void 103 344 lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, 104 - struct lpfc_iocbq *piocbq) 345 + struct lpfc_iocbq *ctiocbq) 105 346 { 106 347 struct lpfc_dmabuf *mp = NULL; 107 - IOCB_t *icmd = &piocbq->iocb; 348 + IOCB_t *icmd = &ctiocbq->iocb; 108 349 int i; 109 350 struct lpfc_iocbq *iocbq; 110 - dma_addr_t paddr; 351 + dma_addr_t dma_addr; 111 352 uint32_t size; 112 353 struct list_head head; 113 - struct lpfc_dmabuf *bdeBuf; 354 + struct lpfc_sli_ct_request *ct_req; 355 + struct lpfc_dmabuf *bdeBuf1 = ctiocbq->context2; 356 + struct lpfc_dmabuf *bdeBuf2 = ctiocbq->context3; 114 357 115 - if (lpfc_bsg_ct_unsol_event(phba, pring, piocbq) == 0) 116 - return; 358 + ctiocbq->context1 = NULL; 359 + ctiocbq->context2 = NULL; 360 + ctiocbq->context3 = NULL; 117 361 118 362 if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) { 119 363 lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); ··· 371 127 return; 372 128 } 373 129 374 - /* If there are no BDEs associated with this IOCB, 375 - * there is nothing to do. 130 + /* If there are no BDEs associated 131 + * with this IOCB, there is nothing to do. 376 132 */ 377 133 if (icmd->ulpBdeCount == 0) 378 134 return; 379 135 380 136 if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 137 + ctiocbq->context2 = bdeBuf1; 138 + if (icmd->ulpBdeCount == 2) 139 + ctiocbq->context3 = bdeBuf2; 140 + } else { 141 + dma_addr = getPaddr(icmd->un.cont64[0].addrHigh, 142 + icmd->un.cont64[0].addrLow); 143 + ctiocbq->context2 = lpfc_sli_ringpostbuf_get(phba, pring, 144 + dma_addr); 145 + if (icmd->ulpBdeCount == 2) { 146 + dma_addr = getPaddr(icmd->un.cont64[1].addrHigh, 147 + icmd->un.cont64[1].addrLow); 148 + ctiocbq->context3 = lpfc_sli_ringpostbuf_get(phba, 149 + pring, 150 + dma_addr); 151 + } 152 + } 153 + 154 + ct_req = ((struct lpfc_sli_ct_request *) 155 + (((struct lpfc_dmabuf *)ctiocbq->context2)->virt)); 156 + 157 + if (ct_req->FsType == SLI_CT_MANAGEMENT_SERVICE && 158 + ct_req->FsSubType == SLI_CT_MIB_Subtypes) { 159 + lpfc_ct_handle_mibreq(phba, ctiocbq); 160 + } else { 161 + if (!lpfc_bsg_ct_unsol_event(phba, pring, ctiocbq)) 162 + return; 163 + } 164 + 165 + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 381 166 INIT_LIST_HEAD(&head); 382 - list_add_tail(&head, &piocbq->list); 167 + list_add_tail(&head, &ctiocbq->list); 383 168 list_for_each_entry(iocbq, &head, list) { 384 169 icmd = &iocbq->iocb; 385 170 if (icmd->ulpBdeCount == 0) 386 171 continue; 387 - bdeBuf = iocbq->context2; 172 + bdeBuf1 = iocbq->context2; 388 173 iocbq->context2 = NULL; 389 174 size = icmd->un.cont64[0].tus.f.bdeSize; 390 - lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size); 391 - lpfc_in_buf_free(phba, bdeBuf); 175 + lpfc_ct_unsol_buffer(phba, ctiocbq, bdeBuf1, size); 176 + lpfc_in_buf_free(phba, bdeBuf1); 392 177 if (icmd->ulpBdeCount == 2) { 393 - bdeBuf = iocbq->context3; 178 + bdeBuf2 = iocbq->context3; 394 179 iocbq->context3 = NULL; 395 180 size = icmd->unsli3.rcvsli3.bde2.tus.f.bdeSize; 396 - lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, 181 + lpfc_ct_unsol_buffer(phba, ctiocbq, bdeBuf2, 397 182 size); 398 - lpfc_in_buf_free(phba, bdeBuf); 183 + lpfc_in_buf_free(phba, bdeBuf2); 399 184 } 400 185 } 401 186 list_del(&head); 402 187 } else { 403 188 INIT_LIST_HEAD(&head); 404 - list_add_tail(&head, &piocbq->list); 189 + list_add_tail(&head, &ctiocbq->list); 405 190 list_for_each_entry(iocbq, &head, list) { 406 191 icmd = &iocbq->iocb; 407 192 if (icmd->ulpBdeCount == 0) 408 193 lpfc_ct_unsol_buffer(phba, iocbq, NULL, 0); 409 194 for (i = 0; i < icmd->ulpBdeCount; i++) { 410 - paddr = getPaddr(icmd->un.cont64[i].addrHigh, 411 - icmd->un.cont64[i].addrLow); 195 + dma_addr = getPaddr(icmd->un.cont64[i].addrHigh, 196 + icmd->un.cont64[i].addrLow); 412 197 mp = lpfc_sli_ringpostbuf_get(phba, pring, 413 - paddr); 198 + dma_addr); 414 199 size = icmd->un.cont64[i].tus.f.bdeSize; 415 200 lpfc_ct_unsol_buffer(phba, iocbq, mp, size); 416 201 lpfc_in_buf_free(phba, mp);
+3
drivers/scsi/lpfc/lpfc_hw.h
··· 1380 1380 struct lpfc_fdmi_reg_port_list rpl; 1381 1381 }; 1382 1382 1383 + /******** MI MIB ********/ 1384 + #define SLI_CT_MIB_Subtypes 0x11 1385 + 1383 1386 /* 1384 1387 * Register HBA Attributes (RHAT) 1385 1388 */