diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_fc.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 131 |
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 | ||
14 | enum rscn_address_format { | 18 | static 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 | |||
21 | static 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 | ||
28 | struct gpn_ft_resp_acc { | 25 | struct gpn_ft_resp_acc { |
@@ -144,7 +141,7 @@ void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *gs) | |||
144 | } | 141 | } |
145 | 142 | ||
146 | static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, | 143 | static 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, | |||
165 | static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) | 162 | static 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 | ||
205 | static void zfcp_fc_incoming_plogi(struct zfcp_fsf_req *req) | 202 | static 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 | ||
215 | static void zfcp_fc_incoming_logo(struct zfcp_fsf_req *req) | 212 | static 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 | */ |
382 | void zfcp_fc_plogi_evaluate(struct zfcp_port *port, struct fsf_plogi *plogi) | 379 | void 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 | ||
396 | struct 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 | |||
404 | static void zfcp_fc_adisc_handler(unsigned long data) | 404 | static 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 | ||
435 | static int zfcp_fc_adisc(struct zfcp_port *port) | 435 | static 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 | } |