diff options
author | Christof Schmitt <christof.schmitt@de.ibm.com> | 2008-06-10 12:20:54 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-07-12 09:22:25 -0400 |
commit | 24073b475d6d2bad8880434a16343ee1da816ea5 (patch) | |
tree | 27cf64817f5aa9020692b88366a46743b11db6d3 /drivers/s390/scsi | |
parent | 6362abd3e00d3161affad996fa53cc69a01fc6d1 (diff) |
[SCSI] zfcp: Move FC code to new file
Move all Fibre Channel related code to new file and cleanup the code
while doing so.
Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com>
Signed-off-by: Swen Schillig <swen@vnet.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/s390/scsi')
-rw-r--r-- | drivers/s390/scsi/Makefile | 2 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 518 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_dbf.c | 4 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 8 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 188 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 12 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 305 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 8 |
8 files changed, 319 insertions, 726 deletions
diff --git a/drivers/s390/scsi/Makefile b/drivers/s390/scsi/Makefile index d6a78f1a2f1..f775f9e6030 100644 --- a/drivers/s390/scsi/Makefile +++ b/drivers/s390/scsi/Makefile | |||
@@ -4,6 +4,6 @@ | |||
4 | 4 | ||
5 | zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \ | 5 | zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \ |
6 | zfcp_fsf.o zfcp_dbf.o zfcp_sysfs_adapter.o zfcp_sysfs_port.o \ | 6 | zfcp_fsf.o zfcp_dbf.o zfcp_sysfs_adapter.o zfcp_sysfs_port.o \ |
7 | zfcp_sysfs_unit.o zfcp_sysfs_driver.o | 7 | zfcp_sysfs_unit.o zfcp_sysfs_driver.o zfcp_fc.o |
8 | 8 | ||
9 | obj-$(CONFIG_ZFCP) += zfcp.o | 9 | obj-$(CONFIG_ZFCP) += zfcp.o |
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 9a3c138ec50..9eb8827e19e 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -43,9 +43,6 @@ static char *device; | |||
43 | /* written against the module interface */ | 43 | /* written against the module interface */ |
44 | static int __init zfcp_module_init(void); | 44 | static int __init zfcp_module_init(void); |
45 | 45 | ||
46 | /* FCP related */ | ||
47 | static void zfcp_ns_gid_pn_handler(unsigned long); | ||
48 | |||
49 | /* miscellaneous */ | 46 | /* miscellaneous */ |
50 | static int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t); | 47 | static int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t); |
51 | static void zfcp_sg_list_free(struct zfcp_sg_list *); | 48 | static void zfcp_sg_list_free(struct zfcp_sg_list *); |
@@ -1349,518 +1346,3 @@ zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) | |||
1349 | } | 1346 | } |
1350 | 1347 | ||
1351 | #undef ZFCP_LOG_AREA | 1348 | #undef ZFCP_LOG_AREA |
1352 | |||
1353 | /****************************************************************/ | ||
1354 | /******* Fibre Channel Standard related Functions **************/ | ||
1355 | /****************************************************************/ | ||
1356 | |||
1357 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_FC | ||
1358 | |||
1359 | static void zfcp_fsf_incoming_els_rscn(struct zfcp_fsf_req *fsf_req) | ||
1360 | { | ||
1361 | struct fsf_status_read_buffer *status_buffer = (void*)fsf_req->data; | ||
1362 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
1363 | struct fcp_rscn_head *fcp_rscn_head; | ||
1364 | struct fcp_rscn_element *fcp_rscn_element; | ||
1365 | struct zfcp_port *port; | ||
1366 | u16 i; | ||
1367 | u16 no_entries; | ||
1368 | u32 range_mask; | ||
1369 | unsigned long flags; | ||
1370 | |||
1371 | fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload; | ||
1372 | fcp_rscn_element = (struct fcp_rscn_element *) status_buffer->payload; | ||
1373 | |||
1374 | /* see FC-FS */ | ||
1375 | no_entries = (fcp_rscn_head->payload_len / 4); | ||
1376 | |||
1377 | for (i = 1; i < no_entries; i++) { | ||
1378 | /* skip head and start with 1st element */ | ||
1379 | fcp_rscn_element++; | ||
1380 | switch (fcp_rscn_element->addr_format) { | ||
1381 | case ZFCP_PORT_ADDRESS: | ||
1382 | range_mask = ZFCP_PORTS_RANGE_PORT; | ||
1383 | break; | ||
1384 | case ZFCP_AREA_ADDRESS: | ||
1385 | range_mask = ZFCP_PORTS_RANGE_AREA; | ||
1386 | break; | ||
1387 | case ZFCP_DOMAIN_ADDRESS: | ||
1388 | range_mask = ZFCP_PORTS_RANGE_DOMAIN; | ||
1389 | break; | ||
1390 | case ZFCP_FABRIC_ADDRESS: | ||
1391 | range_mask = ZFCP_PORTS_RANGE_FABRIC; | ||
1392 | break; | ||
1393 | default: | ||
1394 | ZFCP_LOG_INFO("incoming RSCN with unknown " | ||
1395 | "address format\n"); | ||
1396 | continue; | ||
1397 | } | ||
1398 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1399 | list_for_each_entry(port, &adapter->port_list_head, list) { | ||
1400 | if (atomic_test_mask | ||
1401 | (ZFCP_STATUS_PORT_WKA, &port->status)) | ||
1402 | continue; | ||
1403 | /* Do we know this port? If not skip it. */ | ||
1404 | if (!atomic_test_mask | ||
1405 | (ZFCP_STATUS_PORT_DID_DID, &port->status)) { | ||
1406 | ZFCP_LOG_INFO("incoming RSCN, trying to open " | ||
1407 | "port 0x%016Lx\n", port->wwpn); | ||
1408 | zfcp_erp_port_reopen(port, | ||
1409 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
1410 | 82, fsf_req); | ||
1411 | continue; | ||
1412 | } | ||
1413 | |||
1414 | /* | ||
1415 | * FIXME: race: d_id might being invalidated | ||
1416 | * (...DID_DID reset) | ||
1417 | */ | ||
1418 | if ((port->d_id & range_mask) | ||
1419 | == (fcp_rscn_element->nport_did & range_mask)) { | ||
1420 | ZFCP_LOG_TRACE("reopen did 0x%08x\n", | ||
1421 | fcp_rscn_element->nport_did); | ||
1422 | /* | ||
1423 | * Unfortunately, an RSCN does not specify the | ||
1424 | * type of change a target underwent. We assume | ||
1425 | * that it makes sense to reopen the link. | ||
1426 | * FIXME: Shall we try to find out more about | ||
1427 | * the target and link state before closing it? | ||
1428 | * How to accomplish this? (nameserver?) | ||
1429 | * Where would such code be put in? | ||
1430 | * (inside or outside erp) | ||
1431 | */ | ||
1432 | ZFCP_LOG_INFO("incoming RSCN, trying to open " | ||
1433 | "port 0x%016Lx\n", port->wwpn); | ||
1434 | zfcp_test_link(port); | ||
1435 | } | ||
1436 | } | ||
1437 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1438 | } | ||
1439 | } | ||
1440 | |||
1441 | static void zfcp_fsf_incoming_els_plogi(struct zfcp_fsf_req *fsf_req) | ||
1442 | { | ||
1443 | struct fsf_status_read_buffer *status_buffer = (void*)fsf_req->data; | ||
1444 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
1445 | struct fsf_plogi *els_plogi; | ||
1446 | struct zfcp_port *port; | ||
1447 | unsigned long flags; | ||
1448 | |||
1449 | els_plogi = (struct fsf_plogi *) status_buffer->payload; | ||
1450 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1451 | list_for_each_entry(port, &adapter->port_list_head, list) { | ||
1452 | if (port->wwpn == (*(wwn_t *) &els_plogi->serv_param.wwpn)) | ||
1453 | break; | ||
1454 | } | ||
1455 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1456 | |||
1457 | if (!port || (port->wwpn != (*(wwn_t *) &els_plogi->serv_param.wwpn))) { | ||
1458 | ZFCP_LOG_DEBUG("ignored incoming PLOGI for nonexisting port " | ||
1459 | "with d_id 0x%06x on adapter %s\n", | ||
1460 | status_buffer->d_id, | ||
1461 | zfcp_get_busid_by_adapter(adapter)); | ||
1462 | } else { | ||
1463 | zfcp_erp_port_forced_reopen(port, 0, 83, fsf_req); | ||
1464 | } | ||
1465 | } | ||
1466 | |||
1467 | static void zfcp_fsf_incoming_els_logo(struct zfcp_fsf_req *fsf_req) | ||
1468 | { | ||
1469 | struct fsf_status_read_buffer *status_buffer = (void*)fsf_req->data; | ||
1470 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
1471 | struct fcp_logo *els_logo = (struct fcp_logo *) status_buffer->payload; | ||
1472 | struct zfcp_port *port; | ||
1473 | unsigned long flags; | ||
1474 | |||
1475 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1476 | list_for_each_entry(port, &adapter->port_list_head, list) { | ||
1477 | if (port->wwpn == els_logo->nport_wwpn) | ||
1478 | break; | ||
1479 | } | ||
1480 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1481 | |||
1482 | if (!port || (port->wwpn != els_logo->nport_wwpn)) { | ||
1483 | ZFCP_LOG_DEBUG("ignored incoming LOGO for nonexisting port " | ||
1484 | "with d_id 0x%06x on adapter %s\n", | ||
1485 | status_buffer->d_id, | ||
1486 | zfcp_get_busid_by_adapter(adapter)); | ||
1487 | } else { | ||
1488 | zfcp_erp_port_forced_reopen(port, 0, 84, fsf_req); | ||
1489 | } | ||
1490 | } | ||
1491 | |||
1492 | static void | ||
1493 | zfcp_fsf_incoming_els_unknown(struct zfcp_adapter *adapter, | ||
1494 | struct fsf_status_read_buffer *status_buffer) | ||
1495 | { | ||
1496 | ZFCP_LOG_NORMAL("warning: unknown incoming ELS 0x%08x " | ||
1497 | "for adapter %s\n", *(u32 *) (status_buffer->payload), | ||
1498 | zfcp_get_busid_by_adapter(adapter)); | ||
1499 | |||
1500 | } | ||
1501 | |||
1502 | void | ||
1503 | zfcp_fsf_incoming_els(struct zfcp_fsf_req *fsf_req) | ||
1504 | { | ||
1505 | struct fsf_status_read_buffer *status_buffer; | ||
1506 | u32 els_type; | ||
1507 | struct zfcp_adapter *adapter; | ||
1508 | |||
1509 | status_buffer = (struct fsf_status_read_buffer *) fsf_req->data; | ||
1510 | els_type = *(u32 *) (status_buffer->payload); | ||
1511 | adapter = fsf_req->adapter; | ||
1512 | |||
1513 | zfcp_san_dbf_event_incoming_els(fsf_req); | ||
1514 | if (els_type == LS_PLOGI) | ||
1515 | zfcp_fsf_incoming_els_plogi(fsf_req); | ||
1516 | else if (els_type == LS_LOGO) | ||
1517 | zfcp_fsf_incoming_els_logo(fsf_req); | ||
1518 | else if ((els_type & 0xffff0000) == LS_RSCN) | ||
1519 | /* we are only concerned with the command, not the length */ | ||
1520 | zfcp_fsf_incoming_els_rscn(fsf_req); | ||
1521 | else | ||
1522 | zfcp_fsf_incoming_els_unknown(adapter, status_buffer); | ||
1523 | } | ||
1524 | |||
1525 | |||
1526 | /** | ||
1527 | * zfcp_gid_pn_buffers_alloc - allocate buffers for GID_PN nameserver request | ||
1528 | * @gid_pn: pointer to return pointer to struct zfcp_gid_pn_data | ||
1529 | * @pool: pointer to mempool_t if non-null memory pool is used for allocation | ||
1530 | */ | ||
1531 | static int | ||
1532 | zfcp_gid_pn_buffers_alloc(struct zfcp_gid_pn_data **gid_pn, mempool_t *pool) | ||
1533 | { | ||
1534 | struct zfcp_gid_pn_data *data; | ||
1535 | |||
1536 | if (pool) | ||
1537 | data = mempool_alloc(pool, GFP_ATOMIC); | ||
1538 | else | ||
1539 | data = kmem_cache_alloc(zfcp_data.gid_pn_cache, GFP_ATOMIC); | ||
1540 | |||
1541 | if (NULL == data) | ||
1542 | return -ENOMEM; | ||
1543 | |||
1544 | memset(data, 0, sizeof(*data)); | ||
1545 | data->ct.pool = pool; | ||
1546 | sg_init_table(&data->req , 1); | ||
1547 | sg_init_table(&data->resp , 1); | ||
1548 | data->ct.req = &data->req; | ||
1549 | data->ct.resp = &data->resp; | ||
1550 | data->ct.req_count = data->ct.resp_count = 1; | ||
1551 | zfcp_address_to_sg(&data->ct_iu_req, &data->req, sizeof(struct ct_iu_gid_pn_req)); | ||
1552 | zfcp_address_to_sg(&data->ct_iu_resp, &data->resp, sizeof(struct ct_iu_gid_pn_resp)); | ||
1553 | |||
1554 | *gid_pn = data; | ||
1555 | return 0; | ||
1556 | } | ||
1557 | |||
1558 | /** | ||
1559 | * zfcp_gid_pn_buffers_free - free buffers for GID_PN nameserver request | ||
1560 | * @gid_pn: pointer to struct zfcp_gid_pn_data which has to be freed | ||
1561 | */ | ||
1562 | static void zfcp_gid_pn_buffers_free(struct zfcp_gid_pn_data *gid_pn) | ||
1563 | { | ||
1564 | if (gid_pn->ct.pool) | ||
1565 | mempool_free(gid_pn, gid_pn->ct.pool); | ||
1566 | else | ||
1567 | kmem_cache_free(zfcp_data.gid_pn_cache, gid_pn); | ||
1568 | } | ||
1569 | |||
1570 | /** | ||
1571 | * zfcp_ns_gid_pn_request - initiate GID_PN nameserver request | ||
1572 | * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed | ||
1573 | */ | ||
1574 | int | ||
1575 | zfcp_ns_gid_pn_request(struct zfcp_erp_action *erp_action) | ||
1576 | { | ||
1577 | int ret; | ||
1578 | struct ct_iu_gid_pn_req *ct_iu_req; | ||
1579 | struct zfcp_gid_pn_data *gid_pn; | ||
1580 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1581 | |||
1582 | ret = zfcp_gid_pn_buffers_alloc(&gid_pn, adapter->pool.data_gid_pn); | ||
1583 | if (ret < 0) { | ||
1584 | ZFCP_LOG_INFO("error: buffer allocation for gid_pn nameserver " | ||
1585 | "request failed for adapter %s\n", | ||
1586 | zfcp_get_busid_by_adapter(adapter)); | ||
1587 | goto out; | ||
1588 | } | ||
1589 | |||
1590 | /* setup nameserver request */ | ||
1591 | ct_iu_req = zfcp_sg_to_address(gid_pn->ct.req); | ||
1592 | ct_iu_req->header.revision = ZFCP_CT_REVISION; | ||
1593 | ct_iu_req->header.gs_type = ZFCP_CT_DIRECTORY_SERVICE; | ||
1594 | ct_iu_req->header.gs_subtype = ZFCP_CT_NAME_SERVER; | ||
1595 | ct_iu_req->header.options = ZFCP_CT_SYNCHRONOUS; | ||
1596 | ct_iu_req->header.cmd_rsp_code = ZFCP_CT_GID_PN; | ||
1597 | ct_iu_req->header.max_res_size = ZFCP_CT_MAX_SIZE; | ||
1598 | ct_iu_req->wwpn = erp_action->port->wwpn; | ||
1599 | |||
1600 | /* setup parameters for send generic command */ | ||
1601 | gid_pn->ct.port = adapter->nameserver_port; | ||
1602 | gid_pn->ct.handler = zfcp_ns_gid_pn_handler; | ||
1603 | gid_pn->ct.handler_data = (unsigned long) gid_pn; | ||
1604 | gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; | ||
1605 | gid_pn->port = erp_action->port; | ||
1606 | |||
1607 | ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp, | ||
1608 | erp_action); | ||
1609 | if (ret) { | ||
1610 | ZFCP_LOG_INFO("error: initiation of gid_pn nameserver request " | ||
1611 | "failed for adapter %s\n", | ||
1612 | zfcp_get_busid_by_adapter(adapter)); | ||
1613 | |||
1614 | zfcp_gid_pn_buffers_free(gid_pn); | ||
1615 | } | ||
1616 | |||
1617 | out: | ||
1618 | return ret; | ||
1619 | } | ||
1620 | |||
1621 | /** | ||
1622 | * zfcp_ns_gid_pn_handler - handler for GID_PN nameserver request | ||
1623 | * @data: unsigned long, contains pointer to struct zfcp_gid_pn_data | ||
1624 | */ | ||
1625 | static void zfcp_ns_gid_pn_handler(unsigned long data) | ||
1626 | { | ||
1627 | struct zfcp_port *port; | ||
1628 | struct zfcp_send_ct *ct; | ||
1629 | struct ct_iu_gid_pn_req *ct_iu_req; | ||
1630 | struct ct_iu_gid_pn_resp *ct_iu_resp; | ||
1631 | struct zfcp_gid_pn_data *gid_pn; | ||
1632 | |||
1633 | |||
1634 | gid_pn = (struct zfcp_gid_pn_data *) data; | ||
1635 | port = gid_pn->port; | ||
1636 | ct = &gid_pn->ct; | ||
1637 | ct_iu_req = zfcp_sg_to_address(ct->req); | ||
1638 | ct_iu_resp = zfcp_sg_to_address(ct->resp); | ||
1639 | |||
1640 | if (ct->status != 0) | ||
1641 | goto failed; | ||
1642 | |||
1643 | if (zfcp_check_ct_response(&ct_iu_resp->header)) { | ||
1644 | /* FIXME: do we need some specific erp entry points */ | ||
1645 | atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status); | ||
1646 | goto failed; | ||
1647 | } | ||
1648 | /* paranoia */ | ||
1649 | if (ct_iu_req->wwpn != port->wwpn) { | ||
1650 | ZFCP_LOG_NORMAL("bug: wwpn 0x%016Lx returned by nameserver " | ||
1651 | "lookup does not match expected wwpn 0x%016Lx " | ||
1652 | "for adapter %s\n", ct_iu_req->wwpn, port->wwpn, | ||
1653 | zfcp_get_busid_by_port(port)); | ||
1654 | goto mismatch; | ||
1655 | } | ||
1656 | |||
1657 | /* looks like a valid d_id */ | ||
1658 | port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; | ||
1659 | atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); | ||
1660 | ZFCP_LOG_DEBUG("adapter %s: wwpn=0x%016Lx ---> d_id=0x%06x\n", | ||
1661 | zfcp_get_busid_by_port(port), port->wwpn, port->d_id); | ||
1662 | goto out; | ||
1663 | |||
1664 | mismatch: | ||
1665 | ZFCP_LOG_DEBUG("CT IUs do not match:\n"); | ||
1666 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_req, | ||
1667 | sizeof(struct ct_iu_gid_pn_req)); | ||
1668 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_resp, | ||
1669 | sizeof(struct ct_iu_gid_pn_resp)); | ||
1670 | |||
1671 | failed: | ||
1672 | ZFCP_LOG_NORMAL("warning: failed gid_pn nameserver request for wwpn " | ||
1673 | "0x%016Lx for adapter %s\n", | ||
1674 | port->wwpn, zfcp_get_busid_by_port(port)); | ||
1675 | out: | ||
1676 | zfcp_gid_pn_buffers_free(gid_pn); | ||
1677 | return; | ||
1678 | } | ||
1679 | |||
1680 | /* reject CT_IU reason codes acc. to FC-GS-4 */ | ||
1681 | static const struct zfcp_rc_entry zfcp_ct_rc[] = { | ||
1682 | {0x01, "invalid command code"}, | ||
1683 | {0x02, "invalid version level"}, | ||
1684 | {0x03, "logical error"}, | ||
1685 | {0x04, "invalid CT_IU size"}, | ||
1686 | {0x05, "logical busy"}, | ||
1687 | {0x07, "protocol error"}, | ||
1688 | {0x09, "unable to perform command request"}, | ||
1689 | {0x0b, "command not supported"}, | ||
1690 | {0x0d, "server not available"}, | ||
1691 | {0x0e, "session could not be established"}, | ||
1692 | {0xff, "vendor specific error"}, | ||
1693 | {0, NULL}, | ||
1694 | }; | ||
1695 | |||
1696 | /* LS_RJT reason codes acc. to FC-FS */ | ||
1697 | static const struct zfcp_rc_entry zfcp_ls_rjt_rc[] = { | ||
1698 | {0x01, "invalid LS_Command code"}, | ||
1699 | {0x03, "logical error"}, | ||
1700 | {0x05, "logical busy"}, | ||
1701 | {0x07, "protocol error"}, | ||
1702 | {0x09, "unable to perform command request"}, | ||
1703 | {0x0b, "command not supported"}, | ||
1704 | {0x0e, "command already in progress"}, | ||
1705 | {0xff, "vendor specific error"}, | ||
1706 | {0, NULL}, | ||
1707 | }; | ||
1708 | |||
1709 | /* reject reason codes according to FC-PH/FC-FS */ | ||
1710 | static const struct zfcp_rc_entry zfcp_p_rjt_rc[] = { | ||
1711 | {0x01, "invalid D_ID"}, | ||
1712 | {0x02, "invalid S_ID"}, | ||
1713 | {0x03, "Nx_Port not available, temporary"}, | ||
1714 | {0x04, "Nx_Port not available, permament"}, | ||
1715 | {0x05, "class not supported"}, | ||
1716 | {0x06, "delimiter usage error"}, | ||
1717 | {0x07, "TYPE not supported"}, | ||
1718 | {0x08, "invalid Link_Control"}, | ||
1719 | {0x09, "invalid R_CTL field"}, | ||
1720 | {0x0a, "invalid F_CTL field"}, | ||
1721 | {0x0b, "invalid OX_ID"}, | ||
1722 | {0x0c, "invalid RX_ID"}, | ||
1723 | {0x0d, "invalid SEQ_ID"}, | ||
1724 | {0x0e, "invalid DF_CTL"}, | ||
1725 | {0x0f, "invalid SEQ_CNT"}, | ||
1726 | {0x10, "invalid parameter field"}, | ||
1727 | {0x11, "exchange error"}, | ||
1728 | {0x12, "protocol error"}, | ||
1729 | {0x13, "incorrect length"}, | ||
1730 | {0x14, "unsupported ACK"}, | ||
1731 | {0x15, "class of service not supported by entity at FFFFFE"}, | ||
1732 | {0x16, "login required"}, | ||
1733 | {0x17, "excessive sequences attempted"}, | ||
1734 | {0x18, "unable to establish exchange"}, | ||
1735 | {0x1a, "fabric path not available"}, | ||
1736 | {0x1b, "invalid VC_ID (class 4)"}, | ||
1737 | {0x1c, "invalid CS_CTL field"}, | ||
1738 | {0x1d, "insufficient resources for VC (class 4)"}, | ||
1739 | {0x1f, "invalid class of service"}, | ||
1740 | {0x20, "preemption request rejected"}, | ||
1741 | {0x21, "preemption not enabled"}, | ||
1742 | {0x22, "multicast error"}, | ||
1743 | {0x23, "multicast error terminate"}, | ||
1744 | {0x24, "process login required"}, | ||
1745 | {0xff, "vendor specific reject"}, | ||
1746 | {0, NULL}, | ||
1747 | }; | ||
1748 | |||
1749 | /** | ||
1750 | * zfcp_rc_description - return description for given reaon code | ||
1751 | * @code: reason code | ||
1752 | * @rc_table: table of reason codes and descriptions | ||
1753 | */ | ||
1754 | static const char * | ||
1755 | zfcp_rc_description(u8 code, const struct zfcp_rc_entry *rc_table) | ||
1756 | { | ||
1757 | const char *descr = "unknown reason code"; | ||
1758 | |||
1759 | do { | ||
1760 | if (code == rc_table->code) { | ||
1761 | descr = rc_table->description; | ||
1762 | break; | ||
1763 | } | ||
1764 | rc_table++; | ||
1765 | } while (rc_table->code && rc_table->description); | ||
1766 | |||
1767 | return descr; | ||
1768 | } | ||
1769 | |||
1770 | /** | ||
1771 | * zfcp_check_ct_response - evaluate reason code for CT_IU | ||
1772 | * @rjt: response payload to an CT_IU request | ||
1773 | * Return: 0 for accept CT_IU, 1 for reject CT_IU or invlid response code | ||
1774 | */ | ||
1775 | int | ||
1776 | zfcp_check_ct_response(struct ct_hdr *rjt) | ||
1777 | { | ||
1778 | if (rjt->cmd_rsp_code == ZFCP_CT_ACCEPT) | ||
1779 | return 0; | ||
1780 | |||
1781 | if (rjt->cmd_rsp_code != ZFCP_CT_REJECT) { | ||
1782 | ZFCP_LOG_NORMAL("error: invalid Generic Service command/" | ||
1783 | "response code (0x%04hx)\n", | ||
1784 | rjt->cmd_rsp_code); | ||
1785 | return 1; | ||
1786 | } | ||
1787 | |||
1788 | ZFCP_LOG_INFO("Generic Service command rejected\n"); | ||
1789 | ZFCP_LOG_INFO("%s (0x%02x, 0x%02x, 0x%02x)\n", | ||
1790 | zfcp_rc_description(rjt->reason_code, zfcp_ct_rc), | ||
1791 | (u32) rjt->reason_code, (u32) rjt->reason_code_expl, | ||
1792 | (u32) rjt->vendor_unique); | ||
1793 | |||
1794 | return 1; | ||
1795 | } | ||
1796 | |||
1797 | /** | ||
1798 | * zfcp_print_els_rjt - print reject parameter and description for ELS reject | ||
1799 | * @rjt_par: reject parameter acc. to FC-PH/FC-FS | ||
1800 | * @rc_table: table of reason codes and descriptions | ||
1801 | */ | ||
1802 | static void | ||
1803 | zfcp_print_els_rjt(struct zfcp_ls_rjt_par *rjt_par, | ||
1804 | const struct zfcp_rc_entry *rc_table) | ||
1805 | { | ||
1806 | ZFCP_LOG_INFO("%s (%02x %02x %02x %02x)\n", | ||
1807 | zfcp_rc_description(rjt_par->reason_code, rc_table), | ||
1808 | (u32) rjt_par->action, (u32) rjt_par->reason_code, | ||
1809 | (u32) rjt_par->reason_expl, (u32) rjt_par->vendor_unique); | ||
1810 | } | ||
1811 | |||
1812 | /** | ||
1813 | * zfcp_fsf_handle_els_rjt - evaluate status qualifier/reason code on ELS reject | ||
1814 | * @sq: status qualifier word | ||
1815 | * @rjt_par: reject parameter as described in FC-PH and FC-FS | ||
1816 | * Return: -EROMTEIO for LS_RJT, -EREMCHG for invalid D_ID, -EIO else | ||
1817 | */ | ||
1818 | int | ||
1819 | zfcp_handle_els_rjt(u32 sq, struct zfcp_ls_rjt_par *rjt_par) | ||
1820 | { | ||
1821 | int ret = -EIO; | ||
1822 | |||
1823 | if (sq == FSF_IOSTAT_NPORT_RJT) { | ||
1824 | ZFCP_LOG_INFO("ELS rejected (P_RJT)\n"); | ||
1825 | zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc); | ||
1826 | /* invalid d_id */ | ||
1827 | if (rjt_par->reason_code == 0x01) | ||
1828 | ret = -EREMCHG; | ||
1829 | } else if (sq == FSF_IOSTAT_FABRIC_RJT) { | ||
1830 | ZFCP_LOG_INFO("ELS rejected (F_RJT)\n"); | ||
1831 | zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc); | ||
1832 | /* invalid d_id */ | ||
1833 | if (rjt_par->reason_code == 0x01) | ||
1834 | ret = -EREMCHG; | ||
1835 | } else if (sq == FSF_IOSTAT_LS_RJT) { | ||
1836 | ZFCP_LOG_INFO("ELS rejected (LS_RJT)\n"); | ||
1837 | zfcp_print_els_rjt(rjt_par, zfcp_ls_rjt_rc); | ||
1838 | ret = -EREMOTEIO; | ||
1839 | } else | ||
1840 | ZFCP_LOG_INFO("unexpected SQ: 0x%02x\n", sq); | ||
1841 | |||
1842 | return ret; | ||
1843 | } | ||
1844 | |||
1845 | /** | ||
1846 | * zfcp_plogi_evaluate - evaluate PLOGI playload and copy important fields | ||
1847 | * into zfcp_port structure | ||
1848 | * @port: zfcp_port structure | ||
1849 | * @plogi: plogi payload | ||
1850 | */ | ||
1851 | void | ||
1852 | zfcp_plogi_evaluate(struct zfcp_port *port, struct fsf_plogi *plogi) | ||
1853 | { | ||
1854 | port->maxframe_size = plogi->serv_param.common_serv_param[7] | | ||
1855 | ((plogi->serv_param.common_serv_param[6] & 0x0F) << 8); | ||
1856 | if (plogi->serv_param.class1_serv_param[0] & 0x80) | ||
1857 | port->supported_classes |= FC_COS_CLASS1; | ||
1858 | if (plogi->serv_param.class2_serv_param[0] & 0x80) | ||
1859 | port->supported_classes |= FC_COS_CLASS2; | ||
1860 | if (plogi->serv_param.class3_serv_param[0] & 0x80) | ||
1861 | port->supported_classes |= FC_COS_CLASS3; | ||
1862 | if (plogi->serv_param.class4_serv_param[0] & 0x80) | ||
1863 | port->supported_classes |= FC_COS_CLASS4; | ||
1864 | } | ||
1865 | |||
1866 | #undef ZFCP_LOG_AREA | ||
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 558dae9639f..01e817abe0a 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c | |||
@@ -546,8 +546,8 @@ static const char *zfcp_rec_dbf_ids[] = { | |||
546 | [80] = "exclusive read-only unit access unsupported", | 546 | [80] = "exclusive read-only unit access unsupported", |
547 | [81] = "shared read-write unit access unsupported", | 547 | [81] = "shared read-write unit access unsupported", |
548 | [82] = "incoming rscn", | 548 | [82] = "incoming rscn", |
549 | [83] = "incoming plogi", | 549 | [83] = "incoming wwpn", |
550 | [84] = "incoming logo", | 550 | [84] = "", |
551 | [85] = "online", | 551 | [85] = "online", |
552 | [86] = "offline", | 552 | [86] = "offline", |
553 | [87] = "ccw device gone", | 553 | [87] = "ccw device gone", |
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index fc61a8ed52d..d23c3b9b283 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
@@ -223,9 +223,9 @@ struct fcp_rsp_iu { | |||
223 | #define RSP_CODE_TASKMAN_FAILED 5 | 223 | #define RSP_CODE_TASKMAN_FAILED 5 |
224 | 224 | ||
225 | /* see fc-fs */ | 225 | /* see fc-fs */ |
226 | #define LS_RSCN 0x61040000 | 226 | #define LS_RSCN 0x61 |
227 | #define LS_LOGO 0x05000000 | 227 | #define LS_LOGO 0x05 |
228 | #define LS_PLOGI 0x03000000 | 228 | #define LS_PLOGI 0x03 |
229 | 229 | ||
230 | struct fcp_rscn_head { | 230 | struct fcp_rscn_head { |
231 | u8 command; | 231 | u8 command; |
@@ -622,7 +622,6 @@ typedef void (*zfcp_send_ct_handler_t)(unsigned long); | |||
622 | * @resp_count: number of elements in response scatter-gather list | 622 | * @resp_count: number of elements in response scatter-gather list |
623 | * @handler: handler function (called for response to the request) | 623 | * @handler: handler function (called for response to the request) |
624 | * @handler_data: data passed to handler function | 624 | * @handler_data: data passed to handler function |
625 | * @pool: pointer to memory pool for ct request structure | ||
626 | * @timeout: FSF timeout for this request | 625 | * @timeout: FSF timeout for this request |
627 | * @completion: completion for synchronization purposes | 626 | * @completion: completion for synchronization purposes |
628 | * @status: used to pass error status to calling function | 627 | * @status: used to pass error status to calling function |
@@ -635,7 +634,6 @@ struct zfcp_send_ct { | |||
635 | unsigned int resp_count; | 634 | unsigned int resp_count; |
636 | zfcp_send_ct_handler_t handler; | 635 | zfcp_send_ct_handler_t handler; |
637 | unsigned long handler_data; | 636 | unsigned long handler_data; |
638 | mempool_t *pool; | ||
639 | int timeout; | 637 | int timeout; |
640 | struct completion *completion; | 638 | struct completion *completion; |
641 | int status; | 639 | int status; |
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index d05b3705489..ee19be13e70 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c | |||
@@ -23,9 +23,6 @@ | |||
23 | 23 | ||
24 | #include "zfcp_ext.h" | 24 | #include "zfcp_ext.h" |
25 | 25 | ||
26 | static int zfcp_erp_adisc(struct zfcp_port *); | ||
27 | static void zfcp_erp_adisc_handler(unsigned long); | ||
28 | |||
29 | static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *, int, u8, | 26 | static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *, int, u8, |
30 | void *); | 27 | void *); |
31 | static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *, int, u8, | 28 | static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *, int, u8, |
@@ -292,189 +289,6 @@ int zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear_mask, u8 id, | |||
292 | return retval; | 289 | return retval; |
293 | } | 290 | } |
294 | 291 | ||
295 | |||
296 | /** | ||
297 | * zfcp_erp_adisc - send ADISC ELS command | ||
298 | * @port: port structure | ||
299 | */ | ||
300 | static int | ||
301 | zfcp_erp_adisc(struct zfcp_port *port) | ||
302 | { | ||
303 | struct zfcp_adapter *adapter = port->adapter; | ||
304 | struct zfcp_send_els *send_els; | ||
305 | struct zfcp_ls_adisc *adisc; | ||
306 | void *address = NULL; | ||
307 | int retval = 0; | ||
308 | |||
309 | send_els = kzalloc(sizeof(struct zfcp_send_els), GFP_ATOMIC); | ||
310 | if (send_els == NULL) | ||
311 | goto nomem; | ||
312 | |||
313 | send_els->req = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC); | ||
314 | if (send_els->req == NULL) | ||
315 | goto nomem; | ||
316 | sg_init_table(send_els->req, 1); | ||
317 | |||
318 | send_els->resp = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC); | ||
319 | if (send_els->resp == NULL) | ||
320 | goto nomem; | ||
321 | sg_init_table(send_els->resp, 1); | ||
322 | |||
323 | address = (void *) get_zeroed_page(GFP_ATOMIC); | ||
324 | if (address == NULL) | ||
325 | goto nomem; | ||
326 | |||
327 | zfcp_address_to_sg(address, send_els->req, sizeof(struct zfcp_ls_adisc)); | ||
328 | address += PAGE_SIZE >> 1; | ||
329 | zfcp_address_to_sg(address, send_els->resp, sizeof(struct zfcp_ls_adisc_acc)); | ||
330 | send_els->req_count = send_els->resp_count = 1; | ||
331 | |||
332 | send_els->adapter = adapter; | ||
333 | send_els->port = port; | ||
334 | send_els->d_id = port->d_id; | ||
335 | send_els->handler = zfcp_erp_adisc_handler; | ||
336 | send_els->handler_data = (unsigned long) send_els; | ||
337 | |||
338 | adisc = zfcp_sg_to_address(send_els->req); | ||
339 | send_els->ls_code = adisc->code = ZFCP_LS_ADISC; | ||
340 | |||
341 | /* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports | ||
342 | without FC-AL-2 capability, so we don't set it */ | ||
343 | adisc->wwpn = fc_host_port_name(adapter->scsi_host); | ||
344 | adisc->wwnn = fc_host_node_name(adapter->scsi_host); | ||
345 | adisc->nport_id = fc_host_port_id(adapter->scsi_host); | ||
346 | ZFCP_LOG_INFO("ADISC request from s_id 0x%06x to d_id 0x%06x " | ||
347 | "(wwpn=0x%016Lx, wwnn=0x%016Lx, " | ||
348 | "hard_nport_id=0x%06x, nport_id=0x%06x)\n", | ||
349 | adisc->nport_id, send_els->d_id, (wwn_t) adisc->wwpn, | ||
350 | (wwn_t) adisc->wwnn, adisc->hard_nport_id, | ||
351 | adisc->nport_id); | ||
352 | |||
353 | retval = zfcp_fsf_send_els(send_els); | ||
354 | if (retval != 0) { | ||
355 | ZFCP_LOG_NORMAL("error: initiation of Send ELS failed for port " | ||
356 | "0x%06x on adapter %s\n", send_els->d_id, | ||
357 | zfcp_get_busid_by_adapter(adapter)); | ||
358 | goto freemem; | ||
359 | } | ||
360 | |||
361 | goto out; | ||
362 | |||
363 | nomem: | ||
364 | retval = -ENOMEM; | ||
365 | freemem: | ||
366 | if (address != NULL) | ||
367 | __free_pages(sg_page(send_els->req), 0); | ||
368 | if (send_els != NULL) { | ||
369 | kfree(send_els->req); | ||
370 | kfree(send_els->resp); | ||
371 | kfree(send_els); | ||
372 | } | ||
373 | out: | ||
374 | return retval; | ||
375 | } | ||
376 | |||
377 | |||
378 | /** | ||
379 | * zfcp_erp_adisc_handler - handler for ADISC ELS command | ||
380 | * @data: pointer to struct zfcp_send_els | ||
381 | * | ||
382 | * If ADISC failed (LS_RJT or timed out) forced reopen of the port is triggered. | ||
383 | */ | ||
384 | static void | ||
385 | zfcp_erp_adisc_handler(unsigned long data) | ||
386 | { | ||
387 | struct zfcp_send_els *send_els; | ||
388 | struct zfcp_port *port; | ||
389 | struct zfcp_adapter *adapter; | ||
390 | u32 d_id; | ||
391 | struct zfcp_ls_adisc_acc *adisc; | ||
392 | |||
393 | send_els = (struct zfcp_send_els *) data; | ||
394 | adapter = send_els->adapter; | ||
395 | port = send_els->port; | ||
396 | d_id = send_els->d_id; | ||
397 | |||
398 | /* request rejected or timed out */ | ||
399 | if (send_els->status != 0) { | ||
400 | ZFCP_LOG_NORMAL("ELS request rejected/timed out, " | ||
401 | "force physical port reopen " | ||
402 | "(adapter %s, port d_id=0x%06x)\n", | ||
403 | zfcp_get_busid_by_adapter(adapter), d_id); | ||
404 | if (zfcp_erp_port_forced_reopen(port, 0, 63, NULL)) | ||
405 | ZFCP_LOG_NORMAL("failed reopen of port " | ||
406 | "(adapter %s, wwpn=0x%016Lx)\n", | ||
407 | zfcp_get_busid_by_port(port), | ||
408 | port->wwpn); | ||
409 | goto out; | ||
410 | } | ||
411 | |||
412 | adisc = zfcp_sg_to_address(send_els->resp); | ||
413 | |||
414 | ZFCP_LOG_INFO("ADISC response from d_id 0x%06x to s_id " | ||
415 | "0x%06x (wwpn=0x%016Lx, wwnn=0x%016Lx, " | ||
416 | "hard_nport_id=0x%06x, nport_id=0x%06x)\n", | ||
417 | d_id, fc_host_port_id(adapter->scsi_host), | ||
418 | (wwn_t) adisc->wwpn, (wwn_t) adisc->wwnn, | ||
419 | adisc->hard_nport_id, adisc->nport_id); | ||
420 | |||
421 | /* set wwnn for port */ | ||
422 | if (port->wwnn == 0) | ||
423 | port->wwnn = adisc->wwnn; | ||
424 | |||
425 | if (port->wwpn != adisc->wwpn) { | ||
426 | ZFCP_LOG_NORMAL("d_id assignment changed, reopening " | ||
427 | "port (adapter %s, wwpn=0x%016Lx, " | ||
428 | "adisc_resp_wwpn=0x%016Lx)\n", | ||
429 | zfcp_get_busid_by_port(port), | ||
430 | port->wwpn, (wwn_t) adisc->wwpn); | ||
431 | if (zfcp_erp_port_reopen(port, 0, 64, NULL)) | ||
432 | ZFCP_LOG_NORMAL("failed reopen of port " | ||
433 | "(adapter %s, wwpn=0x%016Lx)\n", | ||
434 | zfcp_get_busid_by_port(port), | ||
435 | port->wwpn); | ||
436 | } | ||
437 | |||
438 | out: | ||
439 | zfcp_port_put(port); | ||
440 | __free_pages(sg_page(send_els->req), 0); | ||
441 | kfree(send_els->req); | ||
442 | kfree(send_els->resp); | ||
443 | kfree(send_els); | ||
444 | } | ||
445 | |||
446 | |||
447 | /** | ||
448 | * zfcp_test_link - lightweight link test procedure | ||
449 | * @port: port to be tested | ||
450 | * | ||
451 | * Test status of a link to a remote port using the ELS command ADISC. | ||
452 | */ | ||
453 | int | ||
454 | zfcp_test_link(struct zfcp_port *port) | ||
455 | { | ||
456 | int retval; | ||
457 | |||
458 | zfcp_port_get(port); | ||
459 | retval = zfcp_erp_adisc(port); | ||
460 | if (retval != 0 && retval != -EBUSY) { | ||
461 | zfcp_port_put(port); | ||
462 | ZFCP_LOG_NORMAL("reopen needed for port 0x%016Lx " | ||
463 | "on adapter %s\n ", port->wwpn, | ||
464 | zfcp_get_busid_by_port(port)); | ||
465 | retval = zfcp_erp_port_forced_reopen(port, 0, 65, NULL); | ||
466 | if (retval != 0) { | ||
467 | ZFCP_LOG_NORMAL("reopen of remote port 0x%016Lx " | ||
468 | "on adapter %s failed\n", port->wwpn, | ||
469 | zfcp_get_busid_by_port(port)); | ||
470 | retval = -EPERM; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | return retval; | ||
475 | } | ||
476 | |||
477 | |||
478 | /* | 292 | /* |
479 | * function: | 293 | * function: |
480 | * | 294 | * |
@@ -2564,7 +2378,7 @@ zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *erp_action) | |||
2564 | { | 2378 | { |
2565 | int retval; | 2379 | int retval; |
2566 | 2380 | ||
2567 | retval = zfcp_ns_gid_pn_request(erp_action); | 2381 | retval = zfcp_fc_ns_gid_pn_request(erp_action); |
2568 | if (retval == -ENOMEM) { | 2382 | if (retval == -ENOMEM) { |
2569 | retval = ZFCP_ERP_NOMEM; | 2383 | retval = ZFCP_ERP_NOMEM; |
2570 | goto out; | 2384 | goto out; |
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index e47ab8d05b6..91d58843205 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -103,7 +103,6 @@ extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *, | |||
103 | struct zfcp_unit *, | 103 | struct zfcp_unit *, |
104 | struct scsi_cmnd *, int, int); | 104 | struct scsi_cmnd *, int, int); |
105 | extern int zfcp_fsf_req_complete(struct zfcp_fsf_req *); | 105 | extern int zfcp_fsf_req_complete(struct zfcp_fsf_req *); |
106 | extern void zfcp_fsf_incoming_els(struct zfcp_fsf_req *); | ||
107 | extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); | 106 | extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); |
108 | extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_command_task_management( | 107 | extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_command_task_management( |
109 | struct zfcp_adapter *, struct zfcp_unit *, u8, int); | 108 | struct zfcp_adapter *, struct zfcp_unit *, u8, int); |
@@ -111,11 +110,12 @@ extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command( | |||
111 | unsigned long, struct zfcp_adapter *, struct zfcp_unit *, int); | 110 | unsigned long, struct zfcp_adapter *, struct zfcp_unit *, int); |
112 | 111 | ||
113 | /******************************* FC/FCP **************************************/ | 112 | /******************************* FC/FCP **************************************/ |
113 | extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *); | ||
114 | extern int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *); | ||
115 | extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); | ||
116 | extern void zfcp_test_link(struct zfcp_port *); | ||
117 | |||
114 | extern int zfcp_nameserver_enqueue(struct zfcp_adapter *); | 118 | extern int zfcp_nameserver_enqueue(struct zfcp_adapter *); |
115 | extern int zfcp_ns_gid_pn_request(struct zfcp_erp_action *); | ||
116 | extern int zfcp_check_ct_response(struct ct_hdr *); | ||
117 | extern int zfcp_handle_els_rjt(u32, struct zfcp_ls_rjt_par *); | ||
118 | extern void zfcp_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); | ||
119 | 119 | ||
120 | /******************************* SCSI ****************************************/ | 120 | /******************************* SCSI ****************************************/ |
121 | extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); | 121 | extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); |
@@ -158,8 +158,6 @@ extern int zfcp_erp_thread_kill(struct zfcp_adapter *); | |||
158 | extern int zfcp_erp_wait(struct zfcp_adapter *); | 158 | extern int zfcp_erp_wait(struct zfcp_adapter *); |
159 | extern void zfcp_erp_async_handler(struct zfcp_erp_action *, unsigned long); | 159 | extern void zfcp_erp_async_handler(struct zfcp_erp_action *, unsigned long); |
160 | 160 | ||
161 | extern int zfcp_test_link(struct zfcp_port *); | ||
162 | |||
163 | extern void zfcp_erp_port_boxed(struct zfcp_port *, u8 id, void *ref); | 161 | extern void zfcp_erp_port_boxed(struct zfcp_port *, u8 id, void *ref); |
164 | extern void zfcp_erp_unit_boxed(struct zfcp_unit *, u8 id, void *ref); | 162 | extern void zfcp_erp_unit_boxed(struct zfcp_unit *, u8 id, void *ref); |
165 | extern void zfcp_erp_port_access_denied(struct zfcp_port *, u8 id, void *ref); | 163 | extern void zfcp_erp_port_access_denied(struct zfcp_port *, u8 id, void *ref); |
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c new file mode 100644 index 00000000000..bb07c3bf225 --- /dev/null +++ b/drivers/s390/scsi/zfcp_fc.c | |||
@@ -0,0 +1,305 @@ | |||
1 | /* | ||
2 | * zfcp device driver | ||
3 | * | ||
4 | * Fibre Channel related functions for the zfcp device driver. | ||
5 | * | ||
6 | * Copyright IBM Corporation 2008 | ||
7 | */ | ||
8 | |||
9 | #include "zfcp_ext.h" | ||
10 | |||
11 | static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, | ||
12 | struct fcp_rscn_element *elem) | ||
13 | { | ||
14 | unsigned long flags; | ||
15 | struct zfcp_port *port; | ||
16 | |||
17 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
18 | list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) { | ||
19 | if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) | ||
20 | continue; | ||
21 | /* FIXME: ZFCP_STATUS_PORT_DID_DID check is racy */ | ||
22 | if (!atomic_test_mask(ZFCP_STATUS_PORT_DID_DID, &port->status)) | ||
23 | /* Try to connect to unused ports anyway. */ | ||
24 | zfcp_erp_port_reopen(port, | ||
25 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
26 | 82, fsf_req); | ||
27 | else if ((port->d_id & range) == (elem->nport_did & range)) | ||
28 | /* Check connection status for connected ports */ | ||
29 | zfcp_test_link(port); | ||
30 | } | ||
31 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
32 | } | ||
33 | |||
34 | static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) | ||
35 | { | ||
36 | struct fsf_status_read_buffer *status_buffer = (void *)fsf_req->data; | ||
37 | struct fcp_rscn_head *fcp_rscn_head; | ||
38 | struct fcp_rscn_element *fcp_rscn_element; | ||
39 | u16 i; | ||
40 | u16 no_entries; | ||
41 | u32 range_mask; | ||
42 | |||
43 | fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload; | ||
44 | fcp_rscn_element = (struct fcp_rscn_element *) status_buffer->payload; | ||
45 | |||
46 | /* see FC-FS */ | ||
47 | no_entries = fcp_rscn_head->payload_len / | ||
48 | sizeof(struct fcp_rscn_element); | ||
49 | |||
50 | for (i = 1; i < no_entries; i++) { | ||
51 | /* skip head and start with 1st element */ | ||
52 | fcp_rscn_element++; | ||
53 | switch (fcp_rscn_element->addr_format) { | ||
54 | case ZFCP_PORT_ADDRESS: | ||
55 | range_mask = ZFCP_PORTS_RANGE_PORT; | ||
56 | break; | ||
57 | case ZFCP_AREA_ADDRESS: | ||
58 | range_mask = ZFCP_PORTS_RANGE_AREA; | ||
59 | break; | ||
60 | case ZFCP_DOMAIN_ADDRESS: | ||
61 | range_mask = ZFCP_PORTS_RANGE_DOMAIN; | ||
62 | break; | ||
63 | case ZFCP_FABRIC_ADDRESS: | ||
64 | range_mask = ZFCP_PORTS_RANGE_FABRIC; | ||
65 | break; | ||
66 | default: | ||
67 | continue; | ||
68 | } | ||
69 | _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, wwn_t wwpn) | ||
74 | { | ||
75 | struct zfcp_adapter *adapter = req->adapter; | ||
76 | struct zfcp_port *port; | ||
77 | unsigned long flags; | ||
78 | |||
79 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
80 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
81 | if (port->wwpn == wwpn) | ||
82 | break; | ||
83 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
84 | |||
85 | if (port && (port->wwpn == wwpn)) | ||
86 | zfcp_erp_port_forced_reopen(port, 0, 83, req); | ||
87 | } | ||
88 | |||
89 | static void zfcp_fc_incoming_plogi(struct zfcp_fsf_req *req) | ||
90 | { | ||
91 | struct fsf_status_read_buffer *status_buffer = | ||
92 | (struct fsf_status_read_buffer *)req->data; | ||
93 | struct fsf_plogi *els_plogi = | ||
94 | (struct fsf_plogi *) status_buffer->payload; | ||
95 | |||
96 | zfcp_fc_incoming_wwpn(req, els_plogi->serv_param.wwpn); | ||
97 | } | ||
98 | |||
99 | static void zfcp_fc_incoming_logo(struct zfcp_fsf_req *req) | ||
100 | { | ||
101 | struct fsf_status_read_buffer *status_buffer = | ||
102 | (struct fsf_status_read_buffer *)req->data; | ||
103 | struct fcp_logo *els_logo = (struct fcp_logo *) status_buffer->payload; | ||
104 | |||
105 | zfcp_fc_incoming_wwpn(req, els_logo->nport_wwpn); | ||
106 | } | ||
107 | |||
108 | /** | ||
109 | * zfcp_fc_incoming_els - handle incoming ELS | ||
110 | * @fsf_req - request which contains incoming ELS | ||
111 | */ | ||
112 | void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req) | ||
113 | { | ||
114 | struct fsf_status_read_buffer *status_buffer = | ||
115 | (struct fsf_status_read_buffer *) fsf_req->data; | ||
116 | unsigned int els_type = status_buffer->payload[0]; | ||
117 | |||
118 | zfcp_san_dbf_event_incoming_els(fsf_req); | ||
119 | if (els_type == LS_PLOGI) | ||
120 | zfcp_fc_incoming_plogi(fsf_req); | ||
121 | else if (els_type == LS_LOGO) | ||
122 | zfcp_fc_incoming_logo(fsf_req); | ||
123 | else if (els_type == LS_RSCN) | ||
124 | zfcp_fc_incoming_rscn(fsf_req); | ||
125 | } | ||
126 | |||
127 | static void zfcp_ns_gid_pn_handler(unsigned long data) | ||
128 | { | ||
129 | struct zfcp_gid_pn_data *gid_pn = (struct zfcp_gid_pn_data *) data; | ||
130 | struct zfcp_send_ct *ct = &gid_pn->ct; | ||
131 | struct ct_iu_gid_pn_req *ct_iu_req = sg_virt(ct->req); | ||
132 | struct ct_iu_gid_pn_resp *ct_iu_resp = sg_virt(ct->resp); | ||
133 | struct zfcp_port *port = gid_pn->port; | ||
134 | |||
135 | if (ct->status) | ||
136 | goto out; | ||
137 | if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT) { | ||
138 | atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status); | ||
139 | goto out; | ||
140 | } | ||
141 | /* paranoia */ | ||
142 | if (ct_iu_req->wwpn != port->wwpn) | ||
143 | goto out; | ||
144 | /* looks like a valid d_id */ | ||
145 | port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; | ||
146 | atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); | ||
147 | out: | ||
148 | mempool_free(gid_pn, port->adapter->pool.data_gid_pn); | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * zfcp_fc_ns_gid_pn_request - initiate GID_PN nameserver request | ||
153 | * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed | ||
154 | * return: -ENOMEM on error, 0 otherwise | ||
155 | */ | ||
156 | int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action) | ||
157 | { | ||
158 | int ret; | ||
159 | struct zfcp_gid_pn_data *gid_pn; | ||
160 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
161 | |||
162 | gid_pn = mempool_alloc(adapter->pool.data_gid_pn, GFP_ATOMIC); | ||
163 | if (!gid_pn) | ||
164 | return -ENOMEM; | ||
165 | |||
166 | memset(gid_pn, 0, sizeof(*gid_pn)); | ||
167 | |||
168 | /* setup parameters for send generic command */ | ||
169 | gid_pn->port = erp_action->port; | ||
170 | gid_pn->ct.port = adapter->nameserver_port; | ||
171 | gid_pn->ct.handler = zfcp_ns_gid_pn_handler; | ||
172 | gid_pn->ct.handler_data = (unsigned long) gid_pn; | ||
173 | gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; | ||
174 | gid_pn->ct.req = &gid_pn->req; | ||
175 | gid_pn->ct.resp = &gid_pn->resp; | ||
176 | gid_pn->ct.req_count = 1; | ||
177 | gid_pn->ct.resp_count = 1; | ||
178 | sg_init_one(&gid_pn->req, &gid_pn->ct_iu_req, | ||
179 | sizeof(struct ct_iu_gid_pn_req)); | ||
180 | sg_init_one(&gid_pn->resp, &gid_pn->ct_iu_resp, | ||
181 | sizeof(struct ct_iu_gid_pn_resp)); | ||
182 | |||
183 | /* setup nameserver request */ | ||
184 | gid_pn->ct_iu_req.header.revision = ZFCP_CT_REVISION; | ||
185 | gid_pn->ct_iu_req.header.gs_type = ZFCP_CT_DIRECTORY_SERVICE; | ||
186 | gid_pn->ct_iu_req.header.gs_subtype = ZFCP_CT_NAME_SERVER; | ||
187 | gid_pn->ct_iu_req.header.options = ZFCP_CT_SYNCHRONOUS; | ||
188 | gid_pn->ct_iu_req.header.cmd_rsp_code = ZFCP_CT_GID_PN; | ||
189 | gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_MAX_SIZE; | ||
190 | gid_pn->ct_iu_req.wwpn = erp_action->port->wwpn; | ||
191 | |||
192 | ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp, | ||
193 | erp_action); | ||
194 | if (ret) | ||
195 | mempool_free(gid_pn, adapter->pool.data_gid_pn); | ||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | /** | ||
200 | * zfcp_fc_plogi_evaluate - evaluate PLOGI playload | ||
201 | * @port: zfcp_port structure | ||
202 | * @plogi: plogi payload | ||
203 | * | ||
204 | * Evaluate PLOGI playload and copy important fields into zfcp_port structure | ||
205 | */ | ||
206 | void zfcp_fc_plogi_evaluate(struct zfcp_port *port, struct fsf_plogi *plogi) | ||
207 | { | ||
208 | port->maxframe_size = plogi->serv_param.common_serv_param[7] | | ||
209 | ((plogi->serv_param.common_serv_param[6] & 0x0F) << 8); | ||
210 | if (plogi->serv_param.class1_serv_param[0] & 0x80) | ||
211 | port->supported_classes |= FC_COS_CLASS1; | ||
212 | if (plogi->serv_param.class2_serv_param[0] & 0x80) | ||
213 | port->supported_classes |= FC_COS_CLASS2; | ||
214 | if (plogi->serv_param.class3_serv_param[0] & 0x80) | ||
215 | port->supported_classes |= FC_COS_CLASS3; | ||
216 | if (plogi->serv_param.class4_serv_param[0] & 0x80) | ||
217 | port->supported_classes |= FC_COS_CLASS4; | ||
218 | } | ||
219 | |||
220 | struct zfcp_els_adisc { | ||
221 | struct zfcp_send_els els; | ||
222 | struct scatterlist req; | ||
223 | struct scatterlist resp; | ||
224 | struct zfcp_ls_adisc ls_adisc; | ||
225 | struct zfcp_ls_adisc_acc ls_adisc_acc; | ||
226 | }; | ||
227 | |||
228 | static void zfcp_fc_adisc_handler(unsigned long data) | ||
229 | { | ||
230 | struct zfcp_els_adisc *adisc = (struct zfcp_els_adisc *) data; | ||
231 | struct zfcp_port *port = adisc->els.port; | ||
232 | struct zfcp_ls_adisc_acc *ls_adisc = &adisc->ls_adisc_acc; | ||
233 | |||
234 | if (!adisc->els.status) { | ||
235 | /* request rejected or timed out */ | ||
236 | zfcp_erp_port_forced_reopen(port, 0, 63, NULL); | ||
237 | goto out; | ||
238 | } | ||
239 | |||
240 | if (!port->wwnn) | ||
241 | port->wwnn = ls_adisc->wwnn; | ||
242 | |||
243 | if (port->wwpn != ls_adisc->wwpn) | ||
244 | zfcp_erp_port_reopen(port, 0, 64, NULL); | ||
245 | |||
246 | out: | ||
247 | zfcp_port_put(port); | ||
248 | kfree(adisc); | ||
249 | } | ||
250 | |||
251 | static int zfcp_fc_adisc(struct zfcp_port *port) | ||
252 | { | ||
253 | struct zfcp_els_adisc *adisc; | ||
254 | struct zfcp_adapter *adapter = port->adapter; | ||
255 | |||
256 | adisc = kzalloc(sizeof(struct zfcp_els_adisc), GFP_ATOMIC); | ||
257 | if (!adisc) | ||
258 | return -ENOMEM; | ||
259 | |||
260 | adisc->els.req = &adisc->req; | ||
261 | adisc->els.resp = &adisc->resp; | ||
262 | sg_init_one(adisc->els.req, &adisc->ls_adisc, | ||
263 | sizeof(struct zfcp_ls_adisc)); | ||
264 | sg_init_one(adisc->els.resp, &adisc->ls_adisc_acc, | ||
265 | sizeof(struct zfcp_ls_adisc_acc)); | ||
266 | |||
267 | adisc->els.req_count = 1; | ||
268 | adisc->els.resp_count = 1; | ||
269 | adisc->els.adapter = adapter; | ||
270 | adisc->els.port = port; | ||
271 | adisc->els.d_id = port->d_id; | ||
272 | adisc->els.handler = zfcp_fc_adisc_handler; | ||
273 | adisc->els.handler_data = (unsigned long) adisc; | ||
274 | adisc->els.ls_code = adisc->ls_adisc.code = ZFCP_LS_ADISC; | ||
275 | |||
276 | /* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports | ||
277 | without FC-AL-2 capability, so we don't set it */ | ||
278 | adisc->ls_adisc.wwpn = fc_host_port_name(adapter->scsi_host); | ||
279 | adisc->ls_adisc.wwnn = fc_host_node_name(adapter->scsi_host); | ||
280 | adisc->ls_adisc.nport_id = fc_host_port_id(adapter->scsi_host); | ||
281 | |||
282 | return zfcp_fsf_send_els(&adisc->els); | ||
283 | } | ||
284 | |||
285 | /** | ||
286 | * zfcp_test_link - lightweight link test procedure | ||
287 | * @port: port to be tested | ||
288 | * | ||
289 | * Test status of a link to a remote port using the ELS command ADISC. | ||
290 | * If there is a problem with the remote port, error recovery steps | ||
291 | * will be triggered. | ||
292 | */ | ||
293 | void zfcp_test_link(struct zfcp_port *port) | ||
294 | { | ||
295 | int retval; | ||
296 | |||
297 | zfcp_port_get(port); | ||
298 | retval = zfcp_fc_adisc(port); | ||
299 | if (retval == 0 || retval == -EBUSY) | ||
300 | return; | ||
301 | |||
302 | /* send of ADISC was not possible */ | ||
303 | zfcp_port_put(port); | ||
304 | zfcp_erp_port_forced_reopen(port, 0, 65, NULL); | ||
305 | } | ||
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 01f9b27daa8..8568b6f3f27 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -848,7 +848,7 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) | |||
848 | break; | 848 | break; |
849 | 849 | ||
850 | case FSF_STATUS_READ_INCOMING_ELS: | 850 | case FSF_STATUS_READ_INCOMING_ELS: |
851 | zfcp_fsf_incoming_els(fsf_req); | 851 | zfcp_fc_incoming_els(fsf_req); |
852 | break; | 852 | break; |
853 | 853 | ||
854 | case FSF_STATUS_READ_SENSE_DATA_AVAIL: | 854 | case FSF_STATUS_READ_SENSE_DATA_AVAIL: |
@@ -1742,10 +1742,6 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) | |||
1742 | break; | 1742 | break; |
1743 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 1743 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: |
1744 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1744 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
1745 | retval = | ||
1746 | zfcp_handle_els_rjt(header->fsf_status_qual.word[1], | ||
1747 | (struct zfcp_ls_rjt_par *) | ||
1748 | &header->fsf_status_qual.word[2]); | ||
1749 | break; | 1745 | break; |
1750 | case FSF_SQ_RETRY_IF_POSSIBLE: | 1746 | case FSF_SQ_RETRY_IF_POSSIBLE: |
1751 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1747 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
@@ -2534,7 +2530,7 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) | |||
2534 | &port->status); | 2530 | &port->status); |
2535 | } else { | 2531 | } else { |
2536 | port->wwnn = plogi->serv_param.wwnn; | 2532 | port->wwnn = plogi->serv_param.wwnn; |
2537 | zfcp_plogi_evaluate(port, plogi); | 2533 | zfcp_fc_plogi_evaluate(port, plogi); |
2538 | } | 2534 | } |
2539 | } | 2535 | } |
2540 | } | 2536 | } |