aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/scsi/zfcp_fc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/scsi/zfcp_fc.c')
-rw-r--r--drivers/s390/scsi/zfcp_fc.c131
1 files changed, 66 insertions, 65 deletions
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index 7d6b3cadfb73..e03410043cd7 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -9,20 +9,17 @@
9#define KMSG_COMPONENT "zfcp" 9#define KMSG_COMPONENT "zfcp"
10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11 11
12#include <linux/types.h>
13#include <scsi/fc/fc_els.h>
14#include <scsi/libfc.h>
12#include "zfcp_ext.h" 15#include "zfcp_ext.h"
16#include "zfcp_fc.h"
13 17
14enum rscn_address_format { 18static u32 zfcp_fc_rscn_range_mask[] = {
15 RSCN_PORT_ADDRESS = 0x0, 19 [ELS_ADDR_FMT_PORT] = 0xFFFFFF,
16 RSCN_AREA_ADDRESS = 0x1, 20 [ELS_ADDR_FMT_AREA] = 0xFFFF00,
17 RSCN_DOMAIN_ADDRESS = 0x2, 21 [ELS_ADDR_FMT_DOM] = 0xFF0000,
18 RSCN_FABRIC_ADDRESS = 0x3, 22 [ELS_ADDR_FMT_FAB] = 0x000000,
19};
20
21static u32 rscn_range_mask[] = {
22 [RSCN_PORT_ADDRESS] = 0xFFFFFF,
23 [RSCN_AREA_ADDRESS] = 0xFFFF00,
24 [RSCN_DOMAIN_ADDRESS] = 0xFF0000,
25 [RSCN_FABRIC_ADDRESS] = 0x000000,
26}; 23};
27 24
28struct gpn_ft_resp_acc { 25struct gpn_ft_resp_acc {
@@ -144,7 +141,7 @@ void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *gs)
144} 141}
145 142
146static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, 143static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
147 struct fcp_rscn_element *elem) 144 struct fc_els_rscn_page *page)
148{ 145{
149 unsigned long flags; 146 unsigned long flags;
150 struct zfcp_adapter *adapter = fsf_req->adapter; 147 struct zfcp_adapter *adapter = fsf_req->adapter;
@@ -152,7 +149,7 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
152 149
153 read_lock_irqsave(&adapter->port_list_lock, flags); 150 read_lock_irqsave(&adapter->port_list_lock, flags);
154 list_for_each_entry(port, &adapter->port_list, list) { 151 list_for_each_entry(port, &adapter->port_list, list) {
155 if ((port->d_id & range) == (elem->nport_did & range)) 152 if ((port->d_id & range) == (ntoh24(page->rscn_fid) & range))
156 zfcp_fc_test_link(port); 153 zfcp_fc_test_link(port);
157 if (!port->d_id) 154 if (!port->d_id)
158 zfcp_erp_port_reopen(port, 155 zfcp_erp_port_reopen(port,
@@ -165,24 +162,24 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
165static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) 162static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req)
166{ 163{
167 struct fsf_status_read_buffer *status_buffer = (void *)fsf_req->data; 164 struct fsf_status_read_buffer *status_buffer = (void *)fsf_req->data;
168 struct fcp_rscn_head *fcp_rscn_head; 165 struct fc_els_rscn *head;
169 struct fcp_rscn_element *fcp_rscn_element; 166 struct fc_els_rscn_page *page;
170 u16 i; 167 u16 i;
171 u16 no_entries; 168 u16 no_entries;
172 u32 range_mask; 169 unsigned int afmt;
173 170
174 fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload.data; 171 head = (struct fc_els_rscn *) status_buffer->payload.data;
175 fcp_rscn_element = (struct fcp_rscn_element *) fcp_rscn_head; 172 page = (struct fc_els_rscn_page *) head;
176 173
177 /* see FC-FS */ 174 /* see FC-FS */
178 no_entries = fcp_rscn_head->payload_len / 175 no_entries = head->rscn_plen / sizeof(struct fc_els_rscn_page);
179 sizeof(struct fcp_rscn_element);
180 176
181 for (i = 1; i < no_entries; i++) { 177 for (i = 1; i < no_entries; i++) {
182 /* skip head and start with 1st element */ 178 /* skip head and start with 1st element */
183 fcp_rscn_element++; 179 page++;
184 range_mask = rscn_range_mask[fcp_rscn_element->addr_format]; 180 afmt = page->rscn_page_flags & ELS_RSCN_ADDR_FMT_MASK;
185 _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element); 181 _zfcp_fc_incoming_rscn(fsf_req, zfcp_fc_rscn_range_mask[afmt],
182 page);
186 } 183 }
187 queue_work(fsf_req->adapter->work_queue, &fsf_req->adapter->scan_work); 184 queue_work(fsf_req->adapter->work_queue, &fsf_req->adapter->scan_work);
188} 185}
@@ -204,22 +201,22 @@ static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn)
204 201
205static void zfcp_fc_incoming_plogi(struct zfcp_fsf_req *req) 202static void zfcp_fc_incoming_plogi(struct zfcp_fsf_req *req)
206{ 203{
207 struct fsf_status_read_buffer *status_buffer = 204 struct fsf_status_read_buffer *status_buffer;
208 (struct fsf_status_read_buffer *)req->data; 205 struct fc_els_flogi *plogi;
209 struct fsf_plogi *els_plogi =
210 (struct fsf_plogi *) status_buffer->payload.data;
211 206
212 zfcp_fc_incoming_wwpn(req, els_plogi->serv_param.wwpn); 207 status_buffer = (struct fsf_status_read_buffer *) req->data;
208 plogi = (struct fc_els_flogi *) status_buffer->payload.data;
209 zfcp_fc_incoming_wwpn(req, plogi->fl_wwpn);
213} 210}
214 211
215static void zfcp_fc_incoming_logo(struct zfcp_fsf_req *req) 212static void zfcp_fc_incoming_logo(struct zfcp_fsf_req *req)
216{ 213{
217 struct fsf_status_read_buffer *status_buffer = 214 struct fsf_status_read_buffer *status_buffer =
218 (struct fsf_status_read_buffer *)req->data; 215 (struct fsf_status_read_buffer *)req->data;
219 struct fcp_logo *els_logo = 216 struct fc_els_logo *logo =
220 (struct fcp_logo *) status_buffer->payload.data; 217 (struct fc_els_logo *) status_buffer->payload.data;
221 218
222 zfcp_fc_incoming_wwpn(req, els_logo->nport_wwpn); 219 zfcp_fc_incoming_wwpn(req, logo->fl_n_port_wwn);
223} 220}
224 221
225/** 222/**
@@ -233,11 +230,11 @@ void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req)
233 unsigned int els_type = status_buffer->payload.data[0]; 230 unsigned int els_type = status_buffer->payload.data[0];
234 231
235 zfcp_dbf_san_incoming_els(fsf_req); 232 zfcp_dbf_san_incoming_els(fsf_req);
236 if (els_type == LS_PLOGI) 233 if (els_type == ELS_PLOGI)
237 zfcp_fc_incoming_plogi(fsf_req); 234 zfcp_fc_incoming_plogi(fsf_req);
238 else if (els_type == LS_LOGO) 235 else if (els_type == ELS_LOGO)
239 zfcp_fc_incoming_logo(fsf_req); 236 zfcp_fc_incoming_logo(fsf_req);
240 else if (els_type == LS_RSCN) 237 else if (els_type == ELS_RSCN)
241 zfcp_fc_incoming_rscn(fsf_req); 238 zfcp_fc_incoming_rscn(fsf_req);
242} 239}
243 240
@@ -379,33 +376,36 @@ void zfcp_fc_trigger_did_lookup(struct zfcp_port *port)
379 * 376 *
380 * Evaluate PLOGI playload and copy important fields into zfcp_port structure 377 * Evaluate PLOGI playload and copy important fields into zfcp_port structure
381 */ 378 */
382void zfcp_fc_plogi_evaluate(struct zfcp_port *port, struct fsf_plogi *plogi) 379void zfcp_fc_plogi_evaluate(struct zfcp_port *port, struct fc_els_flogi *plogi)
383{ 380{
384 port->maxframe_size = plogi->serv_param.common_serv_param[7] | 381 if (plogi->fl_wwpn != port->wwpn) {
385 ((plogi->serv_param.common_serv_param[6] & 0x0F) << 8); 382 port->d_id = 0;
386 if (plogi->serv_param.class1_serv_param[0] & 0x80) 383 dev_warn(&port->adapter->ccw_device->dev,
384 "A port opened with WWPN 0x%016Lx returned data that "
385 "identifies it as WWPN 0x%016Lx\n",
386 (unsigned long long) port->wwpn,
387 (unsigned long long) plogi->fl_wwpn);
388 return;
389 }
390
391 port->wwnn = plogi->fl_wwnn;
392 port->maxframe_size = plogi->fl_csp.sp_bb_data;
393
394 if (plogi->fl_cssp[0].cp_class & FC_CPC_VALID)
387 port->supported_classes |= FC_COS_CLASS1; 395 port->supported_classes |= FC_COS_CLASS1;
388 if (plogi->serv_param.class2_serv_param[0] & 0x80) 396 if (plogi->fl_cssp[1].cp_class & FC_CPC_VALID)
389 port->supported_classes |= FC_COS_CLASS2; 397 port->supported_classes |= FC_COS_CLASS2;
390 if (plogi->serv_param.class3_serv_param[0] & 0x80) 398 if (plogi->fl_cssp[2].cp_class & FC_CPC_VALID)
391 port->supported_classes |= FC_COS_CLASS3; 399 port->supported_classes |= FC_COS_CLASS3;
392 if (plogi->serv_param.class4_serv_param[0] & 0x80) 400 if (plogi->fl_cssp[3].cp_class & FC_CPC_VALID)
393 port->supported_classes |= FC_COS_CLASS4; 401 port->supported_classes |= FC_COS_CLASS4;
394} 402}
395 403
396struct zfcp_els_adisc {
397 struct zfcp_send_els els;
398 struct scatterlist req;
399 struct scatterlist resp;
400 struct zfcp_ls_adisc ls_adisc;
401 struct zfcp_ls_adisc ls_adisc_acc;
402};
403
404static void zfcp_fc_adisc_handler(unsigned long data) 404static void zfcp_fc_adisc_handler(unsigned long data)
405{ 405{
406 struct zfcp_els_adisc *adisc = (struct zfcp_els_adisc *) data; 406 struct zfcp_fc_els_adisc *adisc = (struct zfcp_fc_els_adisc *) data;
407 struct zfcp_port *port = adisc->els.port; 407 struct zfcp_port *port = adisc->els.port;
408 struct zfcp_ls_adisc *ls_adisc = &adisc->ls_adisc_acc; 408 struct fc_els_adisc *adisc_resp = &adisc->adisc_resp;
409 409
410 if (adisc->els.status) { 410 if (adisc->els.status) {
411 /* request rejected or timed out */ 411 /* request rejected or timed out */
@@ -415,9 +415,9 @@ static void zfcp_fc_adisc_handler(unsigned long data)
415 } 415 }
416 416
417 if (!port->wwnn) 417 if (!port->wwnn)
418 port->wwnn = ls_adisc->wwnn; 418 port->wwnn = adisc_resp->adisc_wwnn;
419 419
420 if ((port->wwpn != ls_adisc->wwpn) || 420 if ((port->wwpn != adisc_resp->adisc_wwpn) ||
421 !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)) { 421 !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)) {
422 zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, 422 zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED,
423 "fcadh_2", NULL); 423 "fcadh_2", NULL);
@@ -434,32 +434,33 @@ static void zfcp_fc_adisc_handler(unsigned long data)
434 434
435static int zfcp_fc_adisc(struct zfcp_port *port) 435static int zfcp_fc_adisc(struct zfcp_port *port)
436{ 436{
437 struct zfcp_els_adisc *adisc; 437 struct zfcp_fc_els_adisc *adisc;
438 struct zfcp_adapter *adapter = port->adapter; 438 struct zfcp_adapter *adapter = port->adapter;
439 439
440 adisc = kzalloc(sizeof(struct zfcp_els_adisc), GFP_ATOMIC); 440 adisc = kzalloc(sizeof(struct zfcp_fc_els_adisc), GFP_ATOMIC);
441 if (!adisc) 441 if (!adisc)
442 return -ENOMEM; 442 return -ENOMEM;
443 443
444 adisc->els.req = &adisc->req; 444 adisc->els.req = &adisc->req;
445 adisc->els.resp = &adisc->resp; 445 adisc->els.resp = &adisc->resp;
446 sg_init_one(adisc->els.req, &adisc->ls_adisc, 446 sg_init_one(adisc->els.req, &adisc->adisc_req,
447 sizeof(struct zfcp_ls_adisc)); 447 sizeof(struct fc_els_adisc));
448 sg_init_one(adisc->els.resp, &adisc->ls_adisc_acc, 448 sg_init_one(adisc->els.resp, &adisc->adisc_resp,
449 sizeof(struct zfcp_ls_adisc)); 449 sizeof(struct fc_els_adisc));
450 450
451 adisc->els.adapter = adapter; 451 adisc->els.adapter = adapter;
452 adisc->els.port = port; 452 adisc->els.port = port;
453 adisc->els.d_id = port->d_id; 453 adisc->els.d_id = port->d_id;
454 adisc->els.handler = zfcp_fc_adisc_handler; 454 adisc->els.handler = zfcp_fc_adisc_handler;
455 adisc->els.handler_data = (unsigned long) adisc; 455 adisc->els.handler_data = (unsigned long) adisc;
456 adisc->els.ls_code = adisc->ls_adisc.code = ZFCP_LS_ADISC; 456 adisc->els.ls_code = adisc->adisc_req.adisc_cmd = ELS_ADISC;
457 457
458 /* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports 458 /* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports
459 without FC-AL-2 capability, so we don't set it */ 459 without FC-AL-2 capability, so we don't set it */
460 adisc->ls_adisc.wwpn = fc_host_port_name(adapter->scsi_host); 460 adisc->adisc_req.adisc_wwpn = fc_host_port_name(adapter->scsi_host);
461 adisc->ls_adisc.wwnn = fc_host_node_name(adapter->scsi_host); 461 adisc->adisc_req.adisc_wwnn = fc_host_node_name(adapter->scsi_host);
462 adisc->ls_adisc.nport_id = fc_host_port_id(adapter->scsi_host); 462 hton24(adisc->adisc_req.adisc_port_id,
463 fc_host_port_id(adapter->scsi_host));
463 464
464 return zfcp_fsf_send_els(&adisc->els); 465 return zfcp_fsf_send_els(&adisc->els);
465} 466}