diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/scsi/qla2xxx/qla_gs.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_gs.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gs.c | 1059 |
1 files changed, 1059 insertions, 0 deletions
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c new file mode 100644 index 000000000000..531dad95896c --- /dev/null +++ b/drivers/scsi/qla2xxx/qla_gs.c | |||
@@ -0,0 +1,1059 @@ | |||
1 | /* | ||
2 | * QLOGIC LINUX SOFTWARE | ||
3 | * | ||
4 | * QLogic ISP2x00 device driver for Linux 2.6.x | ||
5 | * Copyright (C) 2003-2004 QLogic Corporation | ||
6 | * (www.qlogic.com) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2, or (at your option) any | ||
11 | * later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | */ | ||
19 | #include "qla_def.h" | ||
20 | |||
21 | static inline ms_iocb_entry_t * | ||
22 | qla2x00_prep_ms_iocb(scsi_qla_host_t *, uint32_t, uint32_t); | ||
23 | |||
24 | static inline struct ct_sns_req * | ||
25 | qla2x00_prep_ct_req(struct ct_sns_req *, uint16_t, uint16_t); | ||
26 | |||
27 | static inline struct sns_cmd_pkt * | ||
28 | qla2x00_prep_sns_cmd(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t); | ||
29 | |||
30 | static int qla2x00_sns_ga_nxt(scsi_qla_host_t *, fc_port_t *); | ||
31 | static int qla2x00_sns_gid_pt(scsi_qla_host_t *, sw_info_t *); | ||
32 | static int qla2x00_sns_gpn_id(scsi_qla_host_t *, sw_info_t *); | ||
33 | static int qla2x00_sns_gnn_id(scsi_qla_host_t *, sw_info_t *); | ||
34 | static int qla2x00_sns_rft_id(scsi_qla_host_t *); | ||
35 | static int qla2x00_sns_rnn_id(scsi_qla_host_t *); | ||
36 | |||
37 | /** | ||
38 | * qla2x00_prep_ms_iocb() - Prepare common MS IOCB fields for SNS CT query. | ||
39 | * @ha: HA context | ||
40 | * @req_size: request size in bytes | ||
41 | * @rsp_size: response size in bytes | ||
42 | * | ||
43 | * Returns a pointer to the @ha's ms_iocb. | ||
44 | */ | ||
45 | static inline ms_iocb_entry_t * | ||
46 | qla2x00_prep_ms_iocb(scsi_qla_host_t *ha, uint32_t req_size, uint32_t rsp_size) | ||
47 | { | ||
48 | ms_iocb_entry_t *ms_pkt; | ||
49 | |||
50 | ms_pkt = ha->ms_iocb; | ||
51 | memset(ms_pkt, 0, sizeof(ms_iocb_entry_t)); | ||
52 | |||
53 | ms_pkt->entry_type = MS_IOCB_TYPE; | ||
54 | ms_pkt->entry_count = 1; | ||
55 | SET_TARGET_ID(ha, ms_pkt->loop_id, SIMPLE_NAME_SERVER); | ||
56 | ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG); | ||
57 | ms_pkt->timeout = __constant_cpu_to_le16(25); | ||
58 | ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); | ||
59 | ms_pkt->total_dsd_count = __constant_cpu_to_le16(2); | ||
60 | ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size); | ||
61 | ms_pkt->req_bytecount = cpu_to_le32(req_size); | ||
62 | |||
63 | ms_pkt->dseg_req_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); | ||
64 | ms_pkt->dseg_req_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); | ||
65 | ms_pkt->dseg_req_length = ms_pkt->req_bytecount; | ||
66 | |||
67 | ms_pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); | ||
68 | ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); | ||
69 | ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount; | ||
70 | |||
71 | return (ms_pkt); | ||
72 | } | ||
73 | |||
74 | /** | ||
75 | * qla2x00_prep_ct_req() - Prepare common CT request fields for SNS query. | ||
76 | * @ct_req: CT request buffer | ||
77 | * @cmd: GS command | ||
78 | * @rsp_size: response size in bytes | ||
79 | * | ||
80 | * Returns a pointer to the intitialized @ct_req. | ||
81 | */ | ||
82 | static inline struct ct_sns_req * | ||
83 | qla2x00_prep_ct_req(struct ct_sns_req *ct_req, uint16_t cmd, uint16_t rsp_size) | ||
84 | { | ||
85 | memset(ct_req, 0, sizeof(struct ct_sns_pkt)); | ||
86 | |||
87 | ct_req->header.revision = 0x01; | ||
88 | ct_req->header.gs_type = 0xFC; | ||
89 | ct_req->header.gs_subtype = 0x02; | ||
90 | ct_req->command = cpu_to_be16(cmd); | ||
91 | ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4); | ||
92 | |||
93 | return (ct_req); | ||
94 | } | ||
95 | |||
96 | |||
97 | /** | ||
98 | * qla2x00_ga_nxt() - SNS scan for fabric devices via GA_NXT command. | ||
99 | * @ha: HA context | ||
100 | * @fcport: fcport entry to updated | ||
101 | * | ||
102 | * Returns 0 on success. | ||
103 | */ | ||
104 | int | ||
105 | qla2x00_ga_nxt(scsi_qla_host_t *ha, fc_port_t *fcport) | ||
106 | { | ||
107 | int rval; | ||
108 | |||
109 | ms_iocb_entry_t *ms_pkt; | ||
110 | struct ct_sns_req *ct_req; | ||
111 | struct ct_sns_rsp *ct_rsp; | ||
112 | |||
113 | if (IS_QLA2100(ha) || IS_QLA2200(ha)) { | ||
114 | return (qla2x00_sns_ga_nxt(ha, fcport)); | ||
115 | } | ||
116 | |||
117 | /* Issue GA_NXT */ | ||
118 | /* Prepare common MS IOCB */ | ||
119 | ms_pkt = qla2x00_prep_ms_iocb(ha, GA_NXT_REQ_SIZE, GA_NXT_RSP_SIZE); | ||
120 | |||
121 | /* Prepare CT request */ | ||
122 | ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GA_NXT_CMD, | ||
123 | GA_NXT_RSP_SIZE); | ||
124 | ct_rsp = &ha->ct_sns->p.rsp; | ||
125 | |||
126 | /* Prepare CT arguments -- port_id */ | ||
127 | ct_req->req.port_id.port_id[0] = fcport->d_id.b.domain; | ||
128 | ct_req->req.port_id.port_id[1] = fcport->d_id.b.area; | ||
129 | ct_req->req.port_id.port_id[2] = fcport->d_id.b.al_pa; | ||
130 | |||
131 | /* Execute MS IOCB */ | ||
132 | rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, | ||
133 | sizeof(ms_iocb_entry_t)); | ||
134 | if (rval != QLA_SUCCESS) { | ||
135 | /*EMPTY*/ | ||
136 | DEBUG2_3(printk("scsi(%ld): GA_NXT issue IOCB failed (%d).\n", | ||
137 | ha->host_no, rval)); | ||
138 | } else if (ct_rsp->header.response != | ||
139 | __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { | ||
140 | DEBUG2_3(printk("scsi(%ld): GA_NXT failed, rejected request, " | ||
141 | "ga_nxt_rsp:\n", ha->host_no)); | ||
142 | DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header, | ||
143 | sizeof(struct ct_rsp_hdr))); | ||
144 | rval = QLA_FUNCTION_FAILED; | ||
145 | } else { | ||
146 | /* Populate fc_port_t entry. */ | ||
147 | fcport->d_id.b.domain = ct_rsp->rsp.ga_nxt.port_id[0]; | ||
148 | fcport->d_id.b.area = ct_rsp->rsp.ga_nxt.port_id[1]; | ||
149 | fcport->d_id.b.al_pa = ct_rsp->rsp.ga_nxt.port_id[2]; | ||
150 | |||
151 | memcpy(fcport->node_name, ct_rsp->rsp.ga_nxt.node_name, | ||
152 | WWN_SIZE); | ||
153 | memcpy(fcport->port_name, ct_rsp->rsp.ga_nxt.port_name, | ||
154 | WWN_SIZE); | ||
155 | |||
156 | if (ct_rsp->rsp.ga_nxt.port_type != NS_N_PORT_TYPE && | ||
157 | ct_rsp->rsp.ga_nxt.port_type != NS_NL_PORT_TYPE) | ||
158 | fcport->d_id.b.domain = 0xf0; | ||
159 | |||
160 | DEBUG2_3(printk("scsi(%ld): GA_NXT entry - " | ||
161 | "nn %02x%02x%02x%02x%02x%02x%02x%02x " | ||
162 | "pn %02x%02x%02x%02x%02x%02x%02x%02x " | ||
163 | "portid=%02x%02x%02x.\n", | ||
164 | ha->host_no, | ||
165 | fcport->node_name[0], fcport->node_name[1], | ||
166 | fcport->node_name[2], fcport->node_name[3], | ||
167 | fcport->node_name[4], fcport->node_name[5], | ||
168 | fcport->node_name[6], fcport->node_name[7], | ||
169 | fcport->port_name[0], fcport->port_name[1], | ||
170 | fcport->port_name[2], fcport->port_name[3], | ||
171 | fcport->port_name[4], fcport->port_name[5], | ||
172 | fcport->port_name[6], fcport->port_name[7], | ||
173 | fcport->d_id.b.domain, fcport->d_id.b.area, | ||
174 | fcport->d_id.b.al_pa)); | ||
175 | } | ||
176 | |||
177 | return (rval); | ||
178 | } | ||
179 | |||
180 | /** | ||
181 | * qla2x00_gid_pt() - SNS scan for fabric devices via GID_PT command. | ||
182 | * @ha: HA context | ||
183 | * @list: switch info entries to populate | ||
184 | * | ||
185 | * NOTE: Non-Nx_Ports are not requested. | ||
186 | * | ||
187 | * Returns 0 on success. | ||
188 | */ | ||
189 | int | ||
190 | qla2x00_gid_pt(scsi_qla_host_t *ha, sw_info_t *list) | ||
191 | { | ||
192 | int rval; | ||
193 | uint16_t i; | ||
194 | |||
195 | ms_iocb_entry_t *ms_pkt; | ||
196 | struct ct_sns_req *ct_req; | ||
197 | struct ct_sns_rsp *ct_rsp; | ||
198 | |||
199 | struct ct_sns_gid_pt_data *gid_data; | ||
200 | |||
201 | if (IS_QLA2100(ha) || IS_QLA2200(ha)) { | ||
202 | return (qla2x00_sns_gid_pt(ha, list)); | ||
203 | } | ||
204 | |||
205 | gid_data = NULL; | ||
206 | |||
207 | /* Issue GID_PT */ | ||
208 | /* Prepare common MS IOCB */ | ||
209 | ms_pkt = qla2x00_prep_ms_iocb(ha, GID_PT_REQ_SIZE, GID_PT_RSP_SIZE); | ||
210 | |||
211 | /* Prepare CT request */ | ||
212 | ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GID_PT_CMD, | ||
213 | GID_PT_RSP_SIZE); | ||
214 | ct_rsp = &ha->ct_sns->p.rsp; | ||
215 | |||
216 | /* Prepare CT arguments -- port_type */ | ||
217 | ct_req->req.gid_pt.port_type = NS_NX_PORT_TYPE; | ||
218 | |||
219 | /* Execute MS IOCB */ | ||
220 | rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, | ||
221 | sizeof(ms_iocb_entry_t)); | ||
222 | if (rval != QLA_SUCCESS) { | ||
223 | /*EMPTY*/ | ||
224 | DEBUG2_3(printk("scsi(%ld): GID_PT issue IOCB failed (%d).\n", | ||
225 | ha->host_no, rval)); | ||
226 | } else if (ct_rsp->header.response != | ||
227 | __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { | ||
228 | DEBUG2_3(printk("scsi(%ld): GID_PT failed, rejected request, " | ||
229 | "gid_pt_rsp:\n", ha->host_no)); | ||
230 | DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header, | ||
231 | sizeof(struct ct_rsp_hdr))); | ||
232 | rval = QLA_FUNCTION_FAILED; | ||
233 | } else { | ||
234 | /* Set port IDs in switch info list. */ | ||
235 | for (i = 0; i < MAX_FIBRE_DEVICES; i++) { | ||
236 | gid_data = &ct_rsp->rsp.gid_pt.entries[i]; | ||
237 | list[i].d_id.b.domain = gid_data->port_id[0]; | ||
238 | list[i].d_id.b.area = gid_data->port_id[1]; | ||
239 | list[i].d_id.b.al_pa = gid_data->port_id[2]; | ||
240 | |||
241 | /* Last one exit. */ | ||
242 | if (gid_data->control_byte & BIT_7) { | ||
243 | list[i].d_id.b.rsvd_1 = gid_data->control_byte; | ||
244 | break; | ||
245 | } | ||
246 | } | ||
247 | |||
248 | /* | ||
249 | * If we've used all available slots, then the switch is | ||
250 | * reporting back more devices than we can handle with this | ||
251 | * single call. Return a failed status, and let GA_NXT handle | ||
252 | * the overload. | ||
253 | */ | ||
254 | if (i == MAX_FIBRE_DEVICES) | ||
255 | rval = QLA_FUNCTION_FAILED; | ||
256 | } | ||
257 | |||
258 | return (rval); | ||
259 | } | ||
260 | |||
261 | /** | ||
262 | * qla2x00_gpn_id() - SNS Get Port Name (GPN_ID) query. | ||
263 | * @ha: HA context | ||
264 | * @list: switch info entries to populate | ||
265 | * | ||
266 | * Returns 0 on success. | ||
267 | */ | ||
268 | int | ||
269 | qla2x00_gpn_id(scsi_qla_host_t *ha, sw_info_t *list) | ||
270 | { | ||
271 | int rval; | ||
272 | uint16_t i; | ||
273 | |||
274 | ms_iocb_entry_t *ms_pkt; | ||
275 | struct ct_sns_req *ct_req; | ||
276 | struct ct_sns_rsp *ct_rsp; | ||
277 | |||
278 | if (IS_QLA2100(ha) || IS_QLA2200(ha)) { | ||
279 | return (qla2x00_sns_gpn_id(ha, list)); | ||
280 | } | ||
281 | |||
282 | for (i = 0; i < MAX_FIBRE_DEVICES; i++) { | ||
283 | /* Issue GPN_ID */ | ||
284 | /* Prepare common MS IOCB */ | ||
285 | ms_pkt = qla2x00_prep_ms_iocb(ha, GPN_ID_REQ_SIZE, | ||
286 | GPN_ID_RSP_SIZE); | ||
287 | |||
288 | /* Prepare CT request */ | ||
289 | ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GPN_ID_CMD, | ||
290 | GPN_ID_RSP_SIZE); | ||
291 | ct_rsp = &ha->ct_sns->p.rsp; | ||
292 | |||
293 | /* Prepare CT arguments -- port_id */ | ||
294 | ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain; | ||
295 | ct_req->req.port_id.port_id[1] = list[i].d_id.b.area; | ||
296 | ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa; | ||
297 | |||
298 | /* Execute MS IOCB */ | ||
299 | rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, | ||
300 | sizeof(ms_iocb_entry_t)); | ||
301 | if (rval != QLA_SUCCESS) { | ||
302 | /*EMPTY*/ | ||
303 | DEBUG2_3(printk("scsi(%ld): GPN_ID issue IOCB failed " | ||
304 | "(%d).\n", ha->host_no, rval)); | ||
305 | } else if (ct_rsp->header.response != | ||
306 | __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { | ||
307 | DEBUG2_3(printk("scsi(%ld): GPN_ID failed, rejected " | ||
308 | "request, gpn_id_rsp:\n", ha->host_no)); | ||
309 | DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header, | ||
310 | sizeof(struct ct_rsp_hdr))); | ||
311 | rval = QLA_FUNCTION_FAILED; | ||
312 | } else { | ||
313 | /* Save portname */ | ||
314 | memcpy(list[i].port_name, | ||
315 | ct_rsp->rsp.gpn_id.port_name, WWN_SIZE); | ||
316 | } | ||
317 | |||
318 | /* Last device exit. */ | ||
319 | if (list[i].d_id.b.rsvd_1 != 0) | ||
320 | break; | ||
321 | } | ||
322 | |||
323 | return (rval); | ||
324 | } | ||
325 | |||
326 | /** | ||
327 | * qla2x00_gnn_id() - SNS Get Node Name (GNN_ID) query. | ||
328 | * @ha: HA context | ||
329 | * @list: switch info entries to populate | ||
330 | * | ||
331 | * Returns 0 on success. | ||
332 | */ | ||
333 | int | ||
334 | qla2x00_gnn_id(scsi_qla_host_t *ha, sw_info_t *list) | ||
335 | { | ||
336 | int rval; | ||
337 | uint16_t i; | ||
338 | |||
339 | ms_iocb_entry_t *ms_pkt; | ||
340 | struct ct_sns_req *ct_req; | ||
341 | struct ct_sns_rsp *ct_rsp; | ||
342 | |||
343 | if (IS_QLA2100(ha) || IS_QLA2200(ha)) { | ||
344 | return (qla2x00_sns_gnn_id(ha, list)); | ||
345 | } | ||
346 | |||
347 | for (i = 0; i < MAX_FIBRE_DEVICES; i++) { | ||
348 | /* Issue GNN_ID */ | ||
349 | /* Prepare common MS IOCB */ | ||
350 | ms_pkt = qla2x00_prep_ms_iocb(ha, GNN_ID_REQ_SIZE, | ||
351 | GNN_ID_RSP_SIZE); | ||
352 | |||
353 | /* Prepare CT request */ | ||
354 | ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GNN_ID_CMD, | ||
355 | GNN_ID_RSP_SIZE); | ||
356 | ct_rsp = &ha->ct_sns->p.rsp; | ||
357 | |||
358 | /* Prepare CT arguments -- port_id */ | ||
359 | ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain; | ||
360 | ct_req->req.port_id.port_id[1] = list[i].d_id.b.area; | ||
361 | ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa; | ||
362 | |||
363 | /* Execute MS IOCB */ | ||
364 | rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, | ||
365 | sizeof(ms_iocb_entry_t)); | ||
366 | if (rval != QLA_SUCCESS) { | ||
367 | /*EMPTY*/ | ||
368 | DEBUG2_3(printk("scsi(%ld): GNN_ID issue IOCB failed " | ||
369 | "(%d).\n", ha->host_no, rval)); | ||
370 | } else if (ct_rsp->header.response != | ||
371 | __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { | ||
372 | DEBUG2_3(printk("scsi(%ld): GNN_ID failed, rejected " | ||
373 | "request, gnn_id_rsp:\n", ha->host_no)); | ||
374 | DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header, | ||
375 | sizeof(struct ct_rsp_hdr))); | ||
376 | rval = QLA_FUNCTION_FAILED; | ||
377 | } else { | ||
378 | /* Save nodename */ | ||
379 | memcpy(list[i].node_name, | ||
380 | ct_rsp->rsp.gnn_id.node_name, WWN_SIZE); | ||
381 | |||
382 | DEBUG2_3(printk("scsi(%ld): GID_PT entry - " | ||
383 | "nn %02x%02x%02x%02x%02x%02x%02x%02x " | ||
384 | "pn %02x%02x%02x%02x%02x%02x%02x%02x " | ||
385 | "portid=%02x%02x%02x.\n", | ||
386 | ha->host_no, | ||
387 | list[i].node_name[0], list[i].node_name[1], | ||
388 | list[i].node_name[2], list[i].node_name[3], | ||
389 | list[i].node_name[4], list[i].node_name[5], | ||
390 | list[i].node_name[6], list[i].node_name[7], | ||
391 | list[i].port_name[0], list[i].port_name[1], | ||
392 | list[i].port_name[2], list[i].port_name[3], | ||
393 | list[i].port_name[4], list[i].port_name[5], | ||
394 | list[i].port_name[6], list[i].port_name[7], | ||
395 | list[i].d_id.b.domain, list[i].d_id.b.area, | ||
396 | list[i].d_id.b.al_pa)); | ||
397 | } | ||
398 | |||
399 | /* Last device exit. */ | ||
400 | if (list[i].d_id.b.rsvd_1 != 0) | ||
401 | break; | ||
402 | } | ||
403 | |||
404 | return (rval); | ||
405 | } | ||
406 | |||
407 | /** | ||
408 | * qla2x00_rft_id() - SNS Register FC-4 TYPEs (RFT_ID) supported by the HBA. | ||
409 | * @ha: HA context | ||
410 | * | ||
411 | * Returns 0 on success. | ||
412 | */ | ||
413 | int | ||
414 | qla2x00_rft_id(scsi_qla_host_t *ha) | ||
415 | { | ||
416 | int rval; | ||
417 | |||
418 | ms_iocb_entry_t *ms_pkt; | ||
419 | struct ct_sns_req *ct_req; | ||
420 | struct ct_sns_rsp *ct_rsp; | ||
421 | |||
422 | if (IS_QLA2100(ha) || IS_QLA2200(ha)) { | ||
423 | return (qla2x00_sns_rft_id(ha)); | ||
424 | } | ||
425 | |||
426 | /* Issue RFT_ID */ | ||
427 | /* Prepare common MS IOCB */ | ||
428 | ms_pkt = qla2x00_prep_ms_iocb(ha, RFT_ID_REQ_SIZE, RFT_ID_RSP_SIZE); | ||
429 | |||
430 | /* Prepare CT request */ | ||
431 | ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFT_ID_CMD, | ||
432 | RFT_ID_RSP_SIZE); | ||
433 | ct_rsp = &ha->ct_sns->p.rsp; | ||
434 | |||
435 | /* Prepare CT arguments -- port_id, FC-4 types */ | ||
436 | ct_req->req.rft_id.port_id[0] = ha->d_id.b.domain; | ||
437 | ct_req->req.rft_id.port_id[1] = ha->d_id.b.area; | ||
438 | ct_req->req.rft_id.port_id[2] = ha->d_id.b.al_pa; | ||
439 | |||
440 | ct_req->req.rft_id.fc4_types[2] = 0x01; /* FCP-3 */ | ||
441 | |||
442 | /* Execute MS IOCB */ | ||
443 | rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, | ||
444 | sizeof(ms_iocb_entry_t)); | ||
445 | if (rval != QLA_SUCCESS) { | ||
446 | /*EMPTY*/ | ||
447 | DEBUG2_3(printk("scsi(%ld): RFT_ID issue IOCB failed (%d).\n", | ||
448 | ha->host_no, rval)); | ||
449 | } else if (ct_rsp->header.response != | ||
450 | __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { | ||
451 | DEBUG2_3(printk("scsi(%ld): RFT_ID failed, rejected " | ||
452 | "request, rft_id_rsp:\n", ha->host_no)); | ||
453 | DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header, | ||
454 | sizeof(struct ct_rsp_hdr))); | ||
455 | rval = QLA_FUNCTION_FAILED; | ||
456 | } else { | ||
457 | DEBUG2(printk("scsi(%ld): RFT_ID exiting normally.\n", | ||
458 | ha->host_no)); | ||
459 | } | ||
460 | |||
461 | return (rval); | ||
462 | } | ||
463 | |||
464 | /** | ||
465 | * qla2x00_rff_id() - SNS Register FC-4 Features (RFF_ID) supported by the HBA. | ||
466 | * @ha: HA context | ||
467 | * | ||
468 | * Returns 0 on success. | ||
469 | */ | ||
470 | int | ||
471 | qla2x00_rff_id(scsi_qla_host_t *ha) | ||
472 | { | ||
473 | int rval; | ||
474 | |||
475 | ms_iocb_entry_t *ms_pkt; | ||
476 | struct ct_sns_req *ct_req; | ||
477 | struct ct_sns_rsp *ct_rsp; | ||
478 | |||
479 | if (IS_QLA2100(ha) || IS_QLA2200(ha)) { | ||
480 | DEBUG2(printk("scsi(%ld): RFF_ID call unsupported on " | ||
481 | "ISP2100/ISP2200.\n", ha->host_no)); | ||
482 | return (QLA_SUCCESS); | ||
483 | } | ||
484 | |||
485 | /* Issue RFF_ID */ | ||
486 | /* Prepare common MS IOCB */ | ||
487 | ms_pkt = qla2x00_prep_ms_iocb(ha, RFF_ID_REQ_SIZE, RFF_ID_RSP_SIZE); | ||
488 | |||
489 | /* Prepare CT request */ | ||
490 | ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFF_ID_CMD, | ||
491 | RFF_ID_RSP_SIZE); | ||
492 | ct_rsp = &ha->ct_sns->p.rsp; | ||
493 | |||
494 | /* Prepare CT arguments -- port_id, FC-4 feature, FC-4 type */ | ||
495 | ct_req->req.rff_id.port_id[0] = ha->d_id.b.domain; | ||
496 | ct_req->req.rff_id.port_id[1] = ha->d_id.b.area; | ||
497 | ct_req->req.rff_id.port_id[2] = ha->d_id.b.al_pa; | ||
498 | |||
499 | ct_req->req.rff_id.fc4_type = 0x08; /* SCSI - FCP */ | ||
500 | |||
501 | /* Execute MS IOCB */ | ||
502 | rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, | ||
503 | sizeof(ms_iocb_entry_t)); | ||
504 | if (rval != QLA_SUCCESS) { | ||
505 | /*EMPTY*/ | ||
506 | DEBUG2_3(printk("scsi(%ld): RFF_ID issue IOCB failed (%d).\n", | ||
507 | ha->host_no, rval)); | ||
508 | } else if (ct_rsp->header.response != | ||
509 | __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { | ||
510 | DEBUG2_3(printk("scsi(%ld): RFF_ID failed, rejected " | ||
511 | "request, rff_id_rsp:\n", ha->host_no)); | ||
512 | DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header, | ||
513 | sizeof(struct ct_rsp_hdr))); | ||
514 | rval = QLA_FUNCTION_FAILED; | ||
515 | } else { | ||
516 | DEBUG2(printk("scsi(%ld): RFF_ID exiting normally.\n", | ||
517 | ha->host_no)); | ||
518 | } | ||
519 | |||
520 | return (rval); | ||
521 | } | ||
522 | |||
523 | /** | ||
524 | * qla2x00_rnn_id() - SNS Register Node Name (RNN_ID) of the HBA. | ||
525 | * @ha: HA context | ||
526 | * | ||
527 | * Returns 0 on success. | ||
528 | */ | ||
529 | int | ||
530 | qla2x00_rnn_id(scsi_qla_host_t *ha) | ||
531 | { | ||
532 | int rval; | ||
533 | |||
534 | ms_iocb_entry_t *ms_pkt; | ||
535 | struct ct_sns_req *ct_req; | ||
536 | struct ct_sns_rsp *ct_rsp; | ||
537 | |||
538 | if (IS_QLA2100(ha) || IS_QLA2200(ha)) { | ||
539 | return (qla2x00_sns_rnn_id(ha)); | ||
540 | } | ||
541 | |||
542 | /* Issue RNN_ID */ | ||
543 | /* Prepare common MS IOCB */ | ||
544 | ms_pkt = qla2x00_prep_ms_iocb(ha, RNN_ID_REQ_SIZE, RNN_ID_RSP_SIZE); | ||
545 | |||
546 | /* Prepare CT request */ | ||
547 | ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RNN_ID_CMD, | ||
548 | RNN_ID_RSP_SIZE); | ||
549 | ct_rsp = &ha->ct_sns->p.rsp; | ||
550 | |||
551 | /* Prepare CT arguments -- port_id, node_name */ | ||
552 | ct_req->req.rnn_id.port_id[0] = ha->d_id.b.domain; | ||
553 | ct_req->req.rnn_id.port_id[1] = ha->d_id.b.area; | ||
554 | ct_req->req.rnn_id.port_id[2] = ha->d_id.b.al_pa; | ||
555 | |||
556 | memcpy(ct_req->req.rnn_id.node_name, ha->init_cb->node_name, WWN_SIZE); | ||
557 | |||
558 | /* Execute MS IOCB */ | ||
559 | rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, | ||
560 | sizeof(ms_iocb_entry_t)); | ||
561 | if (rval != QLA_SUCCESS) { | ||
562 | /*EMPTY*/ | ||
563 | DEBUG2_3(printk("scsi(%ld): RNN_ID issue IOCB failed (%d).\n", | ||
564 | ha->host_no, rval)); | ||
565 | } else if (ct_rsp->header.response != | ||
566 | __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { | ||
567 | DEBUG2_3(printk("scsi(%ld): RNN_ID failed, rejected " | ||
568 | "request, rnn_id_rsp:\n", ha->host_no)); | ||
569 | DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header, | ||
570 | sizeof(struct ct_rsp_hdr))); | ||
571 | rval = QLA_FUNCTION_FAILED; | ||
572 | } else { | ||
573 | DEBUG2(printk("scsi(%ld): RNN_ID exiting normally.\n", | ||
574 | ha->host_no)); | ||
575 | } | ||
576 | |||
577 | return (rval); | ||
578 | } | ||
579 | |||
580 | /** | ||
581 | * qla2x00_rsnn_nn() - SNS Register Symbolic Node Name (RSNN_NN) of the HBA. | ||
582 | * @ha: HA context | ||
583 | * | ||
584 | * Returns 0 on success. | ||
585 | */ | ||
586 | int | ||
587 | qla2x00_rsnn_nn(scsi_qla_host_t *ha) | ||
588 | { | ||
589 | int rval; | ||
590 | uint8_t *snn; | ||
591 | uint8_t version[20]; | ||
592 | |||
593 | ms_iocb_entry_t *ms_pkt; | ||
594 | struct ct_sns_req *ct_req; | ||
595 | struct ct_sns_rsp *ct_rsp; | ||
596 | |||
597 | if (IS_QLA2100(ha) || IS_QLA2200(ha)) { | ||
598 | DEBUG2(printk("scsi(%ld): RSNN_ID call unsupported on " | ||
599 | "ISP2100/ISP2200.\n", ha->host_no)); | ||
600 | return (QLA_SUCCESS); | ||
601 | } | ||
602 | |||
603 | /* Issue RSNN_NN */ | ||
604 | /* Prepare common MS IOCB */ | ||
605 | /* Request size adjusted after CT preparation */ | ||
606 | ms_pkt = qla2x00_prep_ms_iocb(ha, 0, RSNN_NN_RSP_SIZE); | ||
607 | |||
608 | /* Prepare CT request */ | ||
609 | ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RSNN_NN_CMD, | ||
610 | RSNN_NN_RSP_SIZE); | ||
611 | ct_rsp = &ha->ct_sns->p.rsp; | ||
612 | |||
613 | /* Prepare CT arguments -- node_name, symbolic node_name, size */ | ||
614 | memcpy(ct_req->req.rsnn_nn.node_name, ha->init_cb->node_name, WWN_SIZE); | ||
615 | |||
616 | /* Prepare the Symbolic Node Name */ | ||
617 | /* Board type */ | ||
618 | snn = ct_req->req.rsnn_nn.sym_node_name; | ||
619 | strcpy(snn, ha->model_number); | ||
620 | /* Firmware version */ | ||
621 | strcat(snn, " FW:v"); | ||
622 | sprintf(version, "%d.%02d.%02d", ha->fw_major_version, | ||
623 | ha->fw_minor_version, ha->fw_subminor_version); | ||
624 | strcat(snn, version); | ||
625 | /* Driver version */ | ||
626 | strcat(snn, " DVR:v"); | ||
627 | strcat(snn, qla2x00_version_str); | ||
628 | |||
629 | /* Calculate SNN length */ | ||
630 | ct_req->req.rsnn_nn.name_len = (uint8_t)strlen(snn); | ||
631 | |||
632 | /* Update MS IOCB request */ | ||
633 | ms_pkt->req_bytecount = | ||
634 | cpu_to_le32(24 + 1 + ct_req->req.rsnn_nn.name_len); | ||
635 | ms_pkt->dseg_req_length = ms_pkt->req_bytecount; | ||
636 | |||
637 | /* Execute MS IOCB */ | ||
638 | rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, | ||
639 | sizeof(ms_iocb_entry_t)); | ||
640 | if (rval != QLA_SUCCESS) { | ||
641 | /*EMPTY*/ | ||
642 | DEBUG2_3(printk("scsi(%ld): RSNN_NN issue IOCB failed (%d).\n", | ||
643 | ha->host_no, rval)); | ||
644 | } else if (ct_rsp->header.response != | ||
645 | __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { | ||
646 | DEBUG2_3(printk("scsi(%ld): RSNN_NN failed, rejected " | ||
647 | "request, rsnn_id_rsp:\n", ha->host_no)); | ||
648 | DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header, | ||
649 | sizeof(struct ct_rsp_hdr))); | ||
650 | rval = QLA_FUNCTION_FAILED; | ||
651 | } else { | ||
652 | DEBUG2(printk("scsi(%ld): RSNN_NN exiting normally.\n", | ||
653 | ha->host_no)); | ||
654 | } | ||
655 | |||
656 | return (rval); | ||
657 | } | ||
658 | |||
659 | |||
660 | /** | ||
661 | * qla2x00_prep_sns_cmd() - Prepare common SNS command request fields for query. | ||
662 | * @ha: HA context | ||
663 | * @cmd: GS command | ||
664 | * @scmd_len: Subcommand length | ||
665 | * @data_size: response size in bytes | ||
666 | * | ||
667 | * Returns a pointer to the @ha's sns_cmd. | ||
668 | */ | ||
669 | static inline struct sns_cmd_pkt * | ||
670 | qla2x00_prep_sns_cmd(scsi_qla_host_t *ha, uint16_t cmd, uint16_t scmd_len, | ||
671 | uint16_t data_size) | ||
672 | { | ||
673 | uint16_t wc; | ||
674 | struct sns_cmd_pkt *sns_cmd; | ||
675 | |||
676 | sns_cmd = ha->sns_cmd; | ||
677 | memset(sns_cmd, 0, sizeof(struct sns_cmd_pkt)); | ||
678 | wc = data_size / 2; /* Size in 16bit words. */ | ||
679 | sns_cmd->p.cmd.buffer_length = cpu_to_le16(wc); | ||
680 | sns_cmd->p.cmd.buffer_address[0] = cpu_to_le32(LSD(ha->sns_cmd_dma)); | ||
681 | sns_cmd->p.cmd.buffer_address[1] = cpu_to_le32(MSD(ha->sns_cmd_dma)); | ||
682 | sns_cmd->p.cmd.subcommand_length = cpu_to_le16(scmd_len); | ||
683 | sns_cmd->p.cmd.subcommand = cpu_to_le16(cmd); | ||
684 | wc = (data_size - 16) / 4; /* Size in 32bit words. */ | ||
685 | sns_cmd->p.cmd.size = cpu_to_le16(wc); | ||
686 | |||
687 | return (sns_cmd); | ||
688 | } | ||
689 | |||
690 | /** | ||
691 | * qla2x00_sns_ga_nxt() - SNS scan for fabric devices via GA_NXT command. | ||
692 | * @ha: HA context | ||
693 | * @fcport: fcport entry to updated | ||
694 | * | ||
695 | * This command uses the old Exectute SNS Command mailbox routine. | ||
696 | * | ||
697 | * Returns 0 on success. | ||
698 | */ | ||
699 | static int | ||
700 | qla2x00_sns_ga_nxt(scsi_qla_host_t *ha, fc_port_t *fcport) | ||
701 | { | ||
702 | int rval; | ||
703 | |||
704 | struct sns_cmd_pkt *sns_cmd; | ||
705 | |||
706 | /* Issue GA_NXT. */ | ||
707 | /* Prepare SNS command request. */ | ||
708 | sns_cmd = qla2x00_prep_sns_cmd(ha, GA_NXT_CMD, GA_NXT_SNS_SCMD_LEN, | ||
709 | GA_NXT_SNS_DATA_SIZE); | ||
710 | |||
711 | /* Prepare SNS command arguments -- port_id. */ | ||
712 | sns_cmd->p.cmd.param[0] = fcport->d_id.b.al_pa; | ||
713 | sns_cmd->p.cmd.param[1] = fcport->d_id.b.area; | ||
714 | sns_cmd->p.cmd.param[2] = fcport->d_id.b.domain; | ||
715 | |||
716 | /* Execute SNS command. */ | ||
717 | rval = qla2x00_send_sns(ha, ha->sns_cmd_dma, GA_NXT_SNS_CMD_SIZE / 2, | ||
718 | sizeof(struct sns_cmd_pkt)); | ||
719 | if (rval != QLA_SUCCESS) { | ||
720 | /*EMPTY*/ | ||
721 | DEBUG2_3(printk("scsi(%ld): GA_NXT Send SNS failed (%d).\n", | ||
722 | ha->host_no, rval)); | ||
723 | } else if (sns_cmd->p.gan_data[8] != 0x80 || | ||
724 | sns_cmd->p.gan_data[9] != 0x02) { | ||
725 | DEBUG2_3(printk("scsi(%ld): GA_NXT failed, rejected request, " | ||
726 | "ga_nxt_rsp:\n", ha->host_no)); | ||
727 | DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.gan_data, 16)); | ||
728 | rval = QLA_FUNCTION_FAILED; | ||
729 | } else { | ||
730 | /* Populate fc_port_t entry. */ | ||
731 | fcport->d_id.b.domain = sns_cmd->p.gan_data[17]; | ||
732 | fcport->d_id.b.area = sns_cmd->p.gan_data[18]; | ||
733 | fcport->d_id.b.al_pa = sns_cmd->p.gan_data[19]; | ||
734 | |||
735 | memcpy(fcport->node_name, &sns_cmd->p.gan_data[284], WWN_SIZE); | ||
736 | memcpy(fcport->port_name, &sns_cmd->p.gan_data[20], WWN_SIZE); | ||
737 | |||
738 | if (sns_cmd->p.gan_data[16] != NS_N_PORT_TYPE && | ||
739 | sns_cmd->p.gan_data[16] != NS_NL_PORT_TYPE) | ||
740 | fcport->d_id.b.domain = 0xf0; | ||
741 | |||
742 | DEBUG2_3(printk("scsi(%ld): GA_NXT entry - " | ||
743 | "nn %02x%02x%02x%02x%02x%02x%02x%02x " | ||
744 | "pn %02x%02x%02x%02x%02x%02x%02x%02x " | ||
745 | "portid=%02x%02x%02x.\n", | ||
746 | ha->host_no, | ||
747 | fcport->node_name[0], fcport->node_name[1], | ||
748 | fcport->node_name[2], fcport->node_name[3], | ||
749 | fcport->node_name[4], fcport->node_name[5], | ||
750 | fcport->node_name[6], fcport->node_name[7], | ||
751 | fcport->port_name[0], fcport->port_name[1], | ||
752 | fcport->port_name[2], fcport->port_name[3], | ||
753 | fcport->port_name[4], fcport->port_name[5], | ||
754 | fcport->port_name[6], fcport->port_name[7], | ||
755 | fcport->d_id.b.domain, fcport->d_id.b.area, | ||
756 | fcport->d_id.b.al_pa)); | ||
757 | } | ||
758 | |||
759 | return (rval); | ||
760 | } | ||
761 | |||
762 | /** | ||
763 | * qla2x00_sns_gid_pt() - SNS scan for fabric devices via GID_PT command. | ||
764 | * @ha: HA context | ||
765 | * @list: switch info entries to populate | ||
766 | * | ||
767 | * This command uses the old Exectute SNS Command mailbox routine. | ||
768 | * | ||
769 | * NOTE: Non-Nx_Ports are not requested. | ||
770 | * | ||
771 | * Returns 0 on success. | ||
772 | */ | ||
773 | static int | ||
774 | qla2x00_sns_gid_pt(scsi_qla_host_t *ha, sw_info_t *list) | ||
775 | { | ||
776 | int rval; | ||
777 | |||
778 | uint16_t i; | ||
779 | uint8_t *entry; | ||
780 | struct sns_cmd_pkt *sns_cmd; | ||
781 | |||
782 | /* Issue GID_PT. */ | ||
783 | /* Prepare SNS command request. */ | ||
784 | sns_cmd = qla2x00_prep_sns_cmd(ha, GID_PT_CMD, GID_PT_SNS_SCMD_LEN, | ||
785 | GID_PT_SNS_DATA_SIZE); | ||
786 | |||
787 | /* Prepare SNS command arguments -- port_type. */ | ||
788 | sns_cmd->p.cmd.param[0] = NS_NX_PORT_TYPE; | ||
789 | |||
790 | /* Execute SNS command. */ | ||
791 | rval = qla2x00_send_sns(ha, ha->sns_cmd_dma, GID_PT_SNS_CMD_SIZE / 2, | ||
792 | sizeof(struct sns_cmd_pkt)); | ||
793 | if (rval != QLA_SUCCESS) { | ||
794 | /*EMPTY*/ | ||
795 | DEBUG2_3(printk("scsi(%ld): GID_PT Send SNS failed (%d).\n", | ||
796 | ha->host_no, rval)); | ||
797 | } else if (sns_cmd->p.gid_data[8] != 0x80 || | ||
798 | sns_cmd->p.gid_data[9] != 0x02) { | ||
799 | DEBUG2_3(printk("scsi(%ld): GID_PT failed, rejected request, " | ||
800 | "gid_rsp:\n", ha->host_no)); | ||
801 | DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.gid_data, 16)); | ||
802 | rval = QLA_FUNCTION_FAILED; | ||
803 | } else { | ||
804 | /* Set port IDs in switch info list. */ | ||
805 | for (i = 0; i < MAX_FIBRE_DEVICES; i++) { | ||
806 | entry = &sns_cmd->p.gid_data[(i * 4) + 16]; | ||
807 | list[i].d_id.b.domain = entry[1]; | ||
808 | list[i].d_id.b.area = entry[2]; | ||
809 | list[i].d_id.b.al_pa = entry[3]; | ||
810 | |||
811 | /* Last one exit. */ | ||
812 | if (entry[0] & BIT_7) { | ||
813 | list[i].d_id.b.rsvd_1 = entry[0]; | ||
814 | break; | ||
815 | } | ||
816 | } | ||
817 | |||
818 | /* | ||
819 | * If we've used all available slots, then the switch is | ||
820 | * reporting back more devices that we can handle with this | ||
821 | * single call. Return a failed status, and let GA_NXT handle | ||
822 | * the overload. | ||
823 | */ | ||
824 | if (i == MAX_FIBRE_DEVICES) | ||
825 | rval = QLA_FUNCTION_FAILED; | ||
826 | } | ||
827 | |||
828 | return (rval); | ||
829 | } | ||
830 | |||
831 | /** | ||
832 | * qla2x00_sns_gpn_id() - SNS Get Port Name (GPN_ID) query. | ||
833 | * @ha: HA context | ||
834 | * @list: switch info entries to populate | ||
835 | * | ||
836 | * This command uses the old Exectute SNS Command mailbox routine. | ||
837 | * | ||
838 | * Returns 0 on success. | ||
839 | */ | ||
840 | static int | ||
841 | qla2x00_sns_gpn_id(scsi_qla_host_t *ha, sw_info_t *list) | ||
842 | { | ||
843 | int rval; | ||
844 | |||
845 | uint16_t i; | ||
846 | struct sns_cmd_pkt *sns_cmd; | ||
847 | |||
848 | for (i = 0; i < MAX_FIBRE_DEVICES; i++) { | ||
849 | /* Issue GPN_ID */ | ||
850 | /* Prepare SNS command request. */ | ||
851 | sns_cmd = qla2x00_prep_sns_cmd(ha, GPN_ID_CMD, | ||
852 | GPN_ID_SNS_SCMD_LEN, GPN_ID_SNS_DATA_SIZE); | ||
853 | |||
854 | /* Prepare SNS command arguments -- port_id. */ | ||
855 | sns_cmd->p.cmd.param[0] = list[i].d_id.b.al_pa; | ||
856 | sns_cmd->p.cmd.param[1] = list[i].d_id.b.area; | ||
857 | sns_cmd->p.cmd.param[2] = list[i].d_id.b.domain; | ||
858 | |||
859 | /* Execute SNS command. */ | ||
860 | rval = qla2x00_send_sns(ha, ha->sns_cmd_dma, | ||
861 | GPN_ID_SNS_CMD_SIZE / 2, sizeof(struct sns_cmd_pkt)); | ||
862 | if (rval != QLA_SUCCESS) { | ||
863 | /*EMPTY*/ | ||
864 | DEBUG2_3(printk("scsi(%ld): GPN_ID Send SNS failed " | ||
865 | "(%d).\n", ha->host_no, rval)); | ||
866 | } else if (sns_cmd->p.gpn_data[8] != 0x80 || | ||
867 | sns_cmd->p.gpn_data[9] != 0x02) { | ||
868 | DEBUG2_3(printk("scsi(%ld): GPN_ID failed, rejected " | ||
869 | "request, gpn_rsp:\n", ha->host_no)); | ||
870 | DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.gpn_data, 16)); | ||
871 | rval = QLA_FUNCTION_FAILED; | ||
872 | } else { | ||
873 | /* Save portname */ | ||
874 | memcpy(list[i].port_name, &sns_cmd->p.gpn_data[16], | ||
875 | WWN_SIZE); | ||
876 | } | ||
877 | |||
878 | /* Last device exit. */ | ||
879 | if (list[i].d_id.b.rsvd_1 != 0) | ||
880 | break; | ||
881 | } | ||
882 | |||
883 | return (rval); | ||
884 | } | ||
885 | |||
886 | /** | ||
887 | * qla2x00_sns_gnn_id() - SNS Get Node Name (GNN_ID) query. | ||
888 | * @ha: HA context | ||
889 | * @list: switch info entries to populate | ||
890 | * | ||
891 | * This command uses the old Exectute SNS Command mailbox routine. | ||
892 | * | ||
893 | * Returns 0 on success. | ||
894 | */ | ||
895 | static int | ||
896 | qla2x00_sns_gnn_id(scsi_qla_host_t *ha, sw_info_t *list) | ||
897 | { | ||
898 | int rval; | ||
899 | |||
900 | uint16_t i; | ||
901 | struct sns_cmd_pkt *sns_cmd; | ||
902 | |||
903 | for (i = 0; i < MAX_FIBRE_DEVICES; i++) { | ||
904 | /* Issue GNN_ID */ | ||
905 | /* Prepare SNS command request. */ | ||
906 | sns_cmd = qla2x00_prep_sns_cmd(ha, GNN_ID_CMD, | ||
907 | GNN_ID_SNS_SCMD_LEN, GNN_ID_SNS_DATA_SIZE); | ||
908 | |||
909 | /* Prepare SNS command arguments -- port_id. */ | ||
910 | sns_cmd->p.cmd.param[0] = list[i].d_id.b.al_pa; | ||
911 | sns_cmd->p.cmd.param[1] = list[i].d_id.b.area; | ||
912 | sns_cmd->p.cmd.param[2] = list[i].d_id.b.domain; | ||
913 | |||
914 | /* Execute SNS command. */ | ||
915 | rval = qla2x00_send_sns(ha, ha->sns_cmd_dma, | ||
916 | GNN_ID_SNS_CMD_SIZE / 2, sizeof(struct sns_cmd_pkt)); | ||
917 | if (rval != QLA_SUCCESS) { | ||
918 | /*EMPTY*/ | ||
919 | DEBUG2_3(printk("scsi(%ld): GNN_ID Send SNS failed " | ||
920 | "(%d).\n", ha->host_no, rval)); | ||
921 | } else if (sns_cmd->p.gnn_data[8] != 0x80 || | ||
922 | sns_cmd->p.gnn_data[9] != 0x02) { | ||
923 | DEBUG2_3(printk("scsi(%ld): GNN_ID failed, rejected " | ||
924 | "request, gnn_rsp:\n", ha->host_no)); | ||
925 | DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.gnn_data, 16)); | ||
926 | rval = QLA_FUNCTION_FAILED; | ||
927 | } else { | ||
928 | /* Save nodename */ | ||
929 | memcpy(list[i].node_name, &sns_cmd->p.gnn_data[16], | ||
930 | WWN_SIZE); | ||
931 | |||
932 | DEBUG2_3(printk("scsi(%ld): GID_PT entry - " | ||
933 | "nn %02x%02x%02x%02x%02x%02x%02x%02x " | ||
934 | "pn %02x%02x%02x%02x%02x%02x%02x%02x " | ||
935 | "portid=%02x%02x%02x.\n", | ||
936 | ha->host_no, | ||
937 | list[i].node_name[0], list[i].node_name[1], | ||
938 | list[i].node_name[2], list[i].node_name[3], | ||
939 | list[i].node_name[4], list[i].node_name[5], | ||
940 | list[i].node_name[6], list[i].node_name[7], | ||
941 | list[i].port_name[0], list[i].port_name[1], | ||
942 | list[i].port_name[2], list[i].port_name[3], | ||
943 | list[i].port_name[4], list[i].port_name[5], | ||
944 | list[i].port_name[6], list[i].port_name[7], | ||
945 | list[i].d_id.b.domain, list[i].d_id.b.area, | ||
946 | list[i].d_id.b.al_pa)); | ||
947 | } | ||
948 | |||
949 | /* Last device exit. */ | ||
950 | if (list[i].d_id.b.rsvd_1 != 0) | ||
951 | break; | ||
952 | } | ||
953 | |||
954 | return (rval); | ||
955 | } | ||
956 | |||
957 | /** | ||
958 | * qla2x00_snd_rft_id() - SNS Register FC-4 TYPEs (RFT_ID) supported by the HBA. | ||
959 | * @ha: HA context | ||
960 | * | ||
961 | * This command uses the old Exectute SNS Command mailbox routine. | ||
962 | * | ||
963 | * Returns 0 on success. | ||
964 | */ | ||
965 | static int | ||
966 | qla2x00_sns_rft_id(scsi_qla_host_t *ha) | ||
967 | { | ||
968 | int rval; | ||
969 | |||
970 | struct sns_cmd_pkt *sns_cmd; | ||
971 | |||
972 | /* Issue RFT_ID. */ | ||
973 | /* Prepare SNS command request. */ | ||
974 | sns_cmd = qla2x00_prep_sns_cmd(ha, RFT_ID_CMD, RFT_ID_SNS_SCMD_LEN, | ||
975 | RFT_ID_SNS_DATA_SIZE); | ||
976 | |||
977 | /* Prepare SNS command arguments -- port_id, FC-4 types */ | ||
978 | sns_cmd->p.cmd.param[0] = ha->d_id.b.al_pa; | ||
979 | sns_cmd->p.cmd.param[1] = ha->d_id.b.area; | ||
980 | sns_cmd->p.cmd.param[2] = ha->d_id.b.domain; | ||
981 | |||
982 | sns_cmd->p.cmd.param[5] = 0x01; /* FCP-3 */ | ||
983 | |||
984 | /* Execute SNS command. */ | ||
985 | rval = qla2x00_send_sns(ha, ha->sns_cmd_dma, RFT_ID_SNS_CMD_SIZE / 2, | ||
986 | sizeof(struct sns_cmd_pkt)); | ||
987 | if (rval != QLA_SUCCESS) { | ||
988 | /*EMPTY*/ | ||
989 | DEBUG2_3(printk("scsi(%ld): RFT_ID Send SNS failed (%d).\n", | ||
990 | ha->host_no, rval)); | ||
991 | } else if (sns_cmd->p.rft_data[8] != 0x80 || | ||
992 | sns_cmd->p.rft_data[9] != 0x02) { | ||
993 | DEBUG2_3(printk("scsi(%ld): RFT_ID failed, rejected request, " | ||
994 | "rft_rsp:\n", ha->host_no)); | ||
995 | DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.rft_data, 16)); | ||
996 | rval = QLA_FUNCTION_FAILED; | ||
997 | } else { | ||
998 | DEBUG2(printk("scsi(%ld): RFT_ID exiting normally.\n", | ||
999 | ha->host_no)); | ||
1000 | } | ||
1001 | |||
1002 | return (rval); | ||
1003 | } | ||
1004 | |||
1005 | /** | ||
1006 | * qla2x00_sns_rnn_id() - SNS Register Node Name (RNN_ID) of the HBA. | ||
1007 | * HBA. | ||
1008 | * @ha: HA context | ||
1009 | * | ||
1010 | * This command uses the old Exectute SNS Command mailbox routine. | ||
1011 | * | ||
1012 | * Returns 0 on success. | ||
1013 | */ | ||
1014 | static int | ||
1015 | qla2x00_sns_rnn_id(scsi_qla_host_t *ha) | ||
1016 | { | ||
1017 | int rval; | ||
1018 | |||
1019 | struct sns_cmd_pkt *sns_cmd; | ||
1020 | |||
1021 | /* Issue RNN_ID. */ | ||
1022 | /* Prepare SNS command request. */ | ||
1023 | sns_cmd = qla2x00_prep_sns_cmd(ha, RNN_ID_CMD, RNN_ID_SNS_SCMD_LEN, | ||
1024 | RNN_ID_SNS_DATA_SIZE); | ||
1025 | |||
1026 | /* Prepare SNS command arguments -- port_id, nodename. */ | ||
1027 | sns_cmd->p.cmd.param[0] = ha->d_id.b.al_pa; | ||
1028 | sns_cmd->p.cmd.param[1] = ha->d_id.b.area; | ||
1029 | sns_cmd->p.cmd.param[2] = ha->d_id.b.domain; | ||
1030 | |||
1031 | sns_cmd->p.cmd.param[4] = ha->init_cb->node_name[7]; | ||
1032 | sns_cmd->p.cmd.param[5] = ha->init_cb->node_name[6]; | ||
1033 | sns_cmd->p.cmd.param[6] = ha->init_cb->node_name[5]; | ||
1034 | sns_cmd->p.cmd.param[7] = ha->init_cb->node_name[4]; | ||
1035 | sns_cmd->p.cmd.param[8] = ha->init_cb->node_name[3]; | ||
1036 | sns_cmd->p.cmd.param[9] = ha->init_cb->node_name[2]; | ||
1037 | sns_cmd->p.cmd.param[10] = ha->init_cb->node_name[1]; | ||
1038 | sns_cmd->p.cmd.param[11] = ha->init_cb->node_name[0]; | ||
1039 | |||
1040 | /* Execute SNS command. */ | ||
1041 | rval = qla2x00_send_sns(ha, ha->sns_cmd_dma, RNN_ID_SNS_CMD_SIZE / 2, | ||
1042 | sizeof(struct sns_cmd_pkt)); | ||
1043 | if (rval != QLA_SUCCESS) { | ||
1044 | /*EMPTY*/ | ||
1045 | DEBUG2_3(printk("scsi(%ld): RNN_ID Send SNS failed (%d).\n", | ||
1046 | ha->host_no, rval)); | ||
1047 | } else if (sns_cmd->p.rnn_data[8] != 0x80 || | ||
1048 | sns_cmd->p.rnn_data[9] != 0x02) { | ||
1049 | DEBUG2_3(printk("scsi(%ld): RNN_ID failed, rejected request, " | ||
1050 | "rnn_rsp:\n", ha->host_no)); | ||
1051 | DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.rnn_data, 16)); | ||
1052 | rval = QLA_FUNCTION_FAILED; | ||
1053 | } else { | ||
1054 | DEBUG2(printk("scsi(%ld): RNN_ID exiting normally.\n", | ||
1055 | ha->host_no)); | ||
1056 | } | ||
1057 | |||
1058 | return (rval); | ||
1059 | } | ||