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

scsi: fnic: Adding devcmd2 init and posting interfaces

This patch adds fnic devcmd2 interfaces for initialization and posting
commands to fw.

Signed-off-by: Satish Kharat <satishkh@cisco.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Satish Kharat and committed by
Martin K. Petersen
0a2fdd22 9d699c62

+219 -4
+219 -4
drivers/scsi/fnic/vnic_dev.c
··· 316 316 return -ETIMEDOUT; 317 317 } 318 318 319 + int vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, 320 + int wait) 321 + { 322 + struct devcmd2_controller *dc2c = vdev->devcmd2; 323 + struct devcmd2_result *result; 324 + u8 color; 325 + unsigned int i; 326 + int delay; 327 + int err; 328 + u32 fetch_index; 329 + u32 posted; 330 + u32 new_posted; 331 + 332 + posted = ioread32(&dc2c->wq_ctrl->posted_index); 333 + fetch_index = ioread32(&dc2c->wq_ctrl->fetch_index); 334 + 335 + if (posted == 0xFFFFFFFF || fetch_index == 0xFFFFFFFF) { 336 + /* Hardware surprise removal: return error */ 337 + pr_err("%s: devcmd2 invalid posted or fetch index on cmd %d\n", 338 + pci_name(vdev->pdev), _CMD_N(cmd)); 339 + pr_err("%s: fetch index: %u, posted index: %u\n", 340 + pci_name(vdev->pdev), fetch_index, posted); 341 + 342 + return -ENODEV; 343 + 344 + } 345 + 346 + new_posted = (posted + 1) % DEVCMD2_RING_SIZE; 347 + 348 + if (new_posted == fetch_index) { 349 + pr_err("%s: devcmd2 wq full while issuing cmd %d\n", 350 + pci_name(vdev->pdev), _CMD_N(cmd)); 351 + pr_err("%s: fetch index: %u, posted index: %u\n", 352 + pci_name(vdev->pdev), fetch_index, posted); 353 + return -EBUSY; 354 + 355 + } 356 + dc2c->cmd_ring[posted].cmd = cmd; 357 + dc2c->cmd_ring[posted].flags = 0; 358 + 359 + if ((_CMD_FLAGS(cmd) & _CMD_FLAGS_NOWAIT)) 360 + dc2c->cmd_ring[posted].flags |= DEVCMD2_FNORESULT; 361 + if (_CMD_DIR(cmd) & _CMD_DIR_WRITE) { 362 + for (i = 0; i < VNIC_DEVCMD_NARGS; i++) 363 + dc2c->cmd_ring[posted].args[i] = vdev->args[i]; 364 + 365 + } 366 + 367 + /* Adding write memory barrier prevents compiler and/or CPU 368 + * reordering, thus avoiding descriptor posting before 369 + * descriptor is initialized. Otherwise, hardware can read 370 + * stale descriptor fields. 371 + */ 372 + wmb(); 373 + iowrite32(new_posted, &dc2c->wq_ctrl->posted_index); 374 + 375 + if (dc2c->cmd_ring[posted].flags & DEVCMD2_FNORESULT) 376 + return 0; 377 + 378 + result = dc2c->result + dc2c->next_result; 379 + color = dc2c->color; 380 + 381 + dc2c->next_result++; 382 + if (dc2c->next_result == dc2c->result_size) { 383 + dc2c->next_result = 0; 384 + dc2c->color = dc2c->color ? 0 : 1; 385 + } 386 + 387 + for (delay = 0; delay < wait; delay++) { 388 + udelay(100); 389 + if (result->color == color) { 390 + if (result->error) { 391 + err = -(int) result->error; 392 + if (err != ERR_ECMDUNKNOWN || 393 + cmd != CMD_CAPABILITY) 394 + pr_err("%s:Error %d devcmd %d\n", 395 + pci_name(vdev->pdev), 396 + err, _CMD_N(cmd)); 397 + return err; 398 + } 399 + if (_CMD_DIR(cmd) & _CMD_DIR_READ) { 400 + rmb(); /*prevent reorder while reding result*/ 401 + for (i = 0; i < VNIC_DEVCMD_NARGS; i++) 402 + vdev->args[i] = result->results[i]; 403 + } 404 + return 0; 405 + } 406 + } 407 + 408 + pr_err("%s:Timed out devcmd %d\n", pci_name(vdev->pdev), _CMD_N(cmd)); 409 + 410 + return -ETIMEDOUT; 411 + } 412 + 413 + 414 + int vnic_dev_init_devcmd1(struct vnic_dev *vdev) 415 + { 416 + vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0); 417 + if (!vdev->devcmd) 418 + return -ENODEV; 419 + 420 + vdev->devcmd_rtn = &vnic_dev_cmd1; 421 + return 0; 422 + } 423 + 424 + 425 + int vnic_dev_init_devcmd2(struct vnic_dev *vdev) 426 + { 427 + int err; 428 + unsigned int fetch_index; 429 + 430 + if (vdev->devcmd2) 431 + return 0; 432 + 433 + vdev->devcmd2 = kzalloc(sizeof(*vdev->devcmd2), GFP_ATOMIC); 434 + if (!vdev->devcmd2) 435 + return -ENOMEM; 436 + 437 + vdev->devcmd2->color = 1; 438 + vdev->devcmd2->result_size = DEVCMD2_RING_SIZE; 439 + err = vnic_wq_devcmd2_alloc(vdev, &vdev->devcmd2->wq, 440 + DEVCMD2_RING_SIZE, DEVCMD2_DESC_SIZE); 441 + if (err) 442 + goto err_free_devcmd2; 443 + 444 + fetch_index = ioread32(&vdev->devcmd2->wq.ctrl->fetch_index); 445 + if (fetch_index == 0xFFFFFFFF) { /* check for hardware gone */ 446 + pr_err("error in devcmd2 init"); 447 + return -ENODEV; 448 + } 449 + 450 + /* 451 + * Don't change fetch_index ever and 452 + * set posted_index same as fetch_index 453 + * when setting up the WQ for devcmd2. 454 + */ 455 + vnic_wq_init_start(&vdev->devcmd2->wq, 0, fetch_index, 456 + fetch_index, 0, 0); 457 + 458 + vnic_wq_enable(&vdev->devcmd2->wq); 459 + 460 + err = vnic_dev_alloc_desc_ring(vdev, &vdev->devcmd2->results_ring, 461 + DEVCMD2_RING_SIZE, DEVCMD2_DESC_SIZE); 462 + if (err) 463 + goto err_free_wq; 464 + 465 + vdev->devcmd2->result = 466 + (struct devcmd2_result *) vdev->devcmd2->results_ring.descs; 467 + vdev->devcmd2->cmd_ring = 468 + (struct vnic_devcmd2 *) vdev->devcmd2->wq.ring.descs; 469 + vdev->devcmd2->wq_ctrl = vdev->devcmd2->wq.ctrl; 470 + vdev->args[0] = (u64) vdev->devcmd2->results_ring.base_addr | 471 + VNIC_PADDR_TARGET; 472 + vdev->args[1] = DEVCMD2_RING_SIZE; 473 + 474 + err = vnic_dev_cmd2(vdev, CMD_INITIALIZE_DEVCMD2, 1000); 475 + if (err) 476 + goto err_free_desc_ring; 477 + 478 + vdev->devcmd_rtn = &vnic_dev_cmd2; 479 + 480 + return 0; 481 + 482 + err_free_desc_ring: 483 + vnic_dev_free_desc_ring(vdev, &vdev->devcmd2->results_ring); 484 + err_free_wq: 485 + vnic_wq_disable(&vdev->devcmd2->wq); 486 + vnic_wq_free(&vdev->devcmd2->wq); 487 + err_free_devcmd2: 488 + kfree(vdev->devcmd2); 489 + vdev->devcmd2 = NULL; 490 + 491 + return err; 492 + } 493 + 494 + 495 + void vnic_dev_deinit_devcmd2(struct vnic_dev *vdev) 496 + { 497 + vnic_dev_free_desc_ring(vdev, &vdev->devcmd2->results_ring); 498 + vnic_wq_disable(&vdev->devcmd2->wq); 499 + vnic_wq_free(&vdev->devcmd2->wq); 500 + kfree(vdev->devcmd2); 501 + vdev->devcmd2 = NULL; 502 + vdev->devcmd_rtn = &vnic_dev_cmd1; 503 + } 504 + 505 + 506 + int vnic_dev_cmd_no_proxy(struct vnic_dev *vdev, 507 + enum vnic_devcmd_cmd cmd, u64 *a0, u64 *a1, int wait) 508 + { 509 + int err; 510 + 511 + vdev->args[0] = *a0; 512 + vdev->args[1] = *a1; 513 + 514 + err = (*vdev->devcmd_rtn)(vdev, cmd, wait); 515 + 516 + *a0 = vdev->args[0]; 517 + *a1 = vdev->args[1]; 518 + 519 + return err; 520 + } 521 + 522 + 523 + int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, 524 + u64 *a0, u64 *a1, int wait) 525 + { 526 + memset(vdev->args, 0, sizeof(vdev->args)); 527 + 528 + switch (vdev->proxy) { 529 + case PROXY_NONE: 530 + default: 531 + return vnic_dev_cmd_no_proxy(vdev, cmd, a0, a1, wait); 532 + } 533 + } 534 + 535 + 319 536 int vnic_dev_fw_info(struct vnic_dev *vdev, 320 537 struct vnic_devcmd_fw_info **fw_info) 321 538 { ··· 907 690 dma_free_coherent(&vdev->pdev->dev, 908 691 sizeof(struct vnic_devcmd_fw_info), 909 692 vdev->fw_info, vdev->fw_info_pa); 693 + if (vdev->devcmd2) 694 + vnic_dev_deinit_devcmd2(vdev); 910 695 kfree(vdev); 911 696 } 912 697 } ··· 926 707 vdev->pdev = pdev; 927 708 928 709 if (vnic_dev_discover_res(vdev, bar)) 929 - goto err_out; 930 - 931 - vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0); 932 - if (!vdev->devcmd) 933 710 goto err_out; 934 711 935 712 return vdev;