diff options
Diffstat (limited to 'drivers/scsi/qla4xxx/ql4_mbx.c')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_mbx.c | 930 |
1 files changed, 930 insertions, 0 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c new file mode 100644 index 00000000000..ed977f70b2d --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_mbx.c | |||
@@ -0,0 +1,930 @@ | |||
1 | /* | ||
2 | * QLogic iSCSI HBA Driver | ||
3 | * Copyright (c) 2003-2006 QLogic Corporation | ||
4 | * | ||
5 | * See LICENSE.qla4xxx for copyright and licensing details. | ||
6 | */ | ||
7 | |||
8 | #include "ql4_def.h" | ||
9 | |||
10 | |||
11 | /** | ||
12 | * qla4xxx_mailbox_command - issues mailbox commands | ||
13 | * @ha: Pointer to host adapter structure. | ||
14 | * @inCount: number of mailbox registers to load. | ||
15 | * @outCount: number of mailbox registers to return. | ||
16 | * @mbx_cmd: data pointer for mailbox in registers. | ||
17 | * @mbx_sts: data pointer for mailbox out registers. | ||
18 | * | ||
19 | * This routine sssue mailbox commands and waits for completion. | ||
20 | * If outCount is 0, this routine completes successfully WITHOUT waiting | ||
21 | * for the mailbox command to complete. | ||
22 | **/ | ||
23 | int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, | ||
24 | uint8_t outCount, uint32_t *mbx_cmd, | ||
25 | uint32_t *mbx_sts) | ||
26 | { | ||
27 | int status = QLA_ERROR; | ||
28 | uint8_t i; | ||
29 | u_long wait_count; | ||
30 | uint32_t intr_status; | ||
31 | unsigned long flags = 0; | ||
32 | DECLARE_WAITQUEUE(wait, current); | ||
33 | |||
34 | mutex_lock(&ha->mbox_sem); | ||
35 | |||
36 | /* Mailbox code active */ | ||
37 | set_bit(AF_MBOX_COMMAND, &ha->flags); | ||
38 | |||
39 | /* Make sure that pointers are valid */ | ||
40 | if (!mbx_cmd || !mbx_sts) { | ||
41 | DEBUG2(printk("scsi%ld: %s: Invalid mbx_cmd or mbx_sts " | ||
42 | "pointer\n", ha->host_no, __func__)); | ||
43 | goto mbox_exit; | ||
44 | } | ||
45 | |||
46 | /* To prevent overwriting mailbox registers for a command that has | ||
47 | * not yet been serviced, check to see if a previously issued | ||
48 | * mailbox command is interrupting. | ||
49 | * ----------------------------------------------------------------- | ||
50 | */ | ||
51 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
52 | intr_status = readl(&ha->reg->ctrl_status); | ||
53 | if (intr_status & CSR_SCSI_PROCESSOR_INTR) { | ||
54 | /* Service existing interrupt */ | ||
55 | qla4xxx_interrupt_service_routine(ha, intr_status); | ||
56 | clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags); | ||
57 | } | ||
58 | |||
59 | /* Send the mailbox command to the firmware */ | ||
60 | ha->mbox_status_count = outCount; | ||
61 | for (i = 0; i < outCount; i++) | ||
62 | ha->mbox_status[i] = 0; | ||
63 | |||
64 | /* Load all mailbox registers, except mailbox 0. */ | ||
65 | for (i = 1; i < inCount; i++) | ||
66 | writel(mbx_cmd[i], &ha->reg->mailbox[i]); | ||
67 | |||
68 | /* Wakeup firmware */ | ||
69 | writel(mbx_cmd[0], &ha->reg->mailbox[0]); | ||
70 | readl(&ha->reg->mailbox[0]); | ||
71 | writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status); | ||
72 | readl(&ha->reg->ctrl_status); | ||
73 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
74 | |||
75 | /* Wait for completion */ | ||
76 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
77 | add_wait_queue(&ha->mailbox_wait_queue, &wait); | ||
78 | |||
79 | /* | ||
80 | * If we don't want status, don't wait for the mailbox command to | ||
81 | * complete. For example, MBOX_CMD_RESET_FW doesn't return status, | ||
82 | * you must poll the inbound Interrupt Mask for completion. | ||
83 | */ | ||
84 | if (outCount == 0) { | ||
85 | status = QLA_SUCCESS; | ||
86 | set_current_state(TASK_RUNNING); | ||
87 | remove_wait_queue(&ha->mailbox_wait_queue, &wait); | ||
88 | goto mbox_exit; | ||
89 | } | ||
90 | /* Wait for command to complete */ | ||
91 | wait_count = jiffies + MBOX_TOV * HZ; | ||
92 | while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) { | ||
93 | if (time_after_eq(jiffies, wait_count)) | ||
94 | break; | ||
95 | |||
96 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
97 | intr_status = readl(&ha->reg->ctrl_status); | ||
98 | if (intr_status & INTR_PENDING) { | ||
99 | /* | ||
100 | * Service the interrupt. | ||
101 | * The ISR will save the mailbox status registers | ||
102 | * to a temporary storage location in the adapter | ||
103 | * structure. | ||
104 | */ | ||
105 | ha->mbox_status_count = outCount; | ||
106 | qla4xxx_interrupt_service_routine(ha, intr_status); | ||
107 | } | ||
108 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
109 | msleep(10); | ||
110 | } | ||
111 | set_current_state(TASK_RUNNING); | ||
112 | remove_wait_queue(&ha->mailbox_wait_queue, &wait); | ||
113 | |||
114 | /* Check for mailbox timeout. */ | ||
115 | if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) { | ||
116 | DEBUG2(printk("scsi%ld: Mailbox Cmd 0x%08X timed out ...," | ||
117 | " Scheduling Adapter Reset\n", ha->host_no, | ||
118 | mbx_cmd[0])); | ||
119 | ha->mailbox_timeout_count++; | ||
120 | mbx_sts[0] = (-1); | ||
121 | set_bit(DPC_RESET_HA, &ha->dpc_flags); | ||
122 | goto mbox_exit; | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * Copy the mailbox out registers to the caller's mailbox in/out | ||
127 | * structure. | ||
128 | */ | ||
129 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
130 | for (i = 0; i < outCount; i++) | ||
131 | mbx_sts[i] = ha->mbox_status[i]; | ||
132 | |||
133 | /* Set return status and error flags (if applicable). */ | ||
134 | switch (ha->mbox_status[0]) { | ||
135 | case MBOX_STS_COMMAND_COMPLETE: | ||
136 | status = QLA_SUCCESS; | ||
137 | break; | ||
138 | |||
139 | case MBOX_STS_INTERMEDIATE_COMPLETION: | ||
140 | status = QLA_SUCCESS; | ||
141 | break; | ||
142 | |||
143 | case MBOX_STS_BUSY: | ||
144 | DEBUG2( printk("scsi%ld: %s: Cmd = %08X, ISP BUSY\n", | ||
145 | ha->host_no, __func__, mbx_cmd[0])); | ||
146 | ha->mailbox_timeout_count++; | ||
147 | break; | ||
148 | |||
149 | default: | ||
150 | DEBUG2(printk("scsi%ld: %s: **** FAILED, cmd = %08X, " | ||
151 | "sts = %08X ****\n", ha->host_no, __func__, | ||
152 | mbx_cmd[0], mbx_sts[0])); | ||
153 | break; | ||
154 | } | ||
155 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
156 | |||
157 | mbox_exit: | ||
158 | clear_bit(AF_MBOX_COMMAND, &ha->flags); | ||
159 | clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags); | ||
160 | mutex_unlock(&ha->mbox_sem); | ||
161 | |||
162 | return status; | ||
163 | } | ||
164 | |||
165 | |||
166 | /** | ||
167 | * qla4xxx_issue_iocb - issue mailbox iocb command | ||
168 | * @ha: adapter state pointer. | ||
169 | * @buffer: buffer pointer. | ||
170 | * @phys_addr: physical address of buffer. | ||
171 | * @size: size of buffer. | ||
172 | * | ||
173 | * Issues iocbs via mailbox commands. | ||
174 | * TARGET_QUEUE_LOCK must be released. | ||
175 | * ADAPTER_STATE_LOCK must be released. | ||
176 | **/ | ||
177 | int | ||
178 | qla4xxx_issue_iocb(struct scsi_qla_host * ha, void *buffer, | ||
179 | dma_addr_t phys_addr, size_t size) | ||
180 | { | ||
181 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
182 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
183 | int status; | ||
184 | |||
185 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
186 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
187 | mbox_cmd[0] = MBOX_CMD_EXECUTE_IOCB_A64; | ||
188 | mbox_cmd[1] = 0; | ||
189 | mbox_cmd[2] = LSDW(phys_addr); | ||
190 | mbox_cmd[3] = MSDW(phys_addr); | ||
191 | status = qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]); | ||
192 | return status; | ||
193 | } | ||
194 | |||
195 | int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha, | ||
196 | uint16_t fw_ddb_index, | ||
197 | uint16_t connection_id, | ||
198 | uint16_t option) | ||
199 | { | ||
200 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
201 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
202 | |||
203 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
204 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
205 | mbox_cmd[0] = MBOX_CMD_CONN_CLOSE_SESS_LOGOUT; | ||
206 | mbox_cmd[1] = fw_ddb_index; | ||
207 | mbox_cmd[2] = connection_id; | ||
208 | mbox_cmd[3] = LOGOUT_OPTION_RELOGIN; | ||
209 | if (qla4xxx_mailbox_command(ha, 4, 2, &mbox_cmd[0], &mbox_sts[0]) != | ||
210 | QLA_SUCCESS) { | ||
211 | DEBUG2(printk("scsi%ld: %s: MBOX_CMD_CONN_CLOSE_SESS_LOGOUT " | ||
212 | "option %04x failed sts %04X %04X", | ||
213 | ha->host_no, __func__, | ||
214 | option, mbox_sts[0], mbox_sts[1])); | ||
215 | if (mbox_sts[0] == 0x4005) | ||
216 | DEBUG2(printk("%s reason %04X\n", __func__, | ||
217 | mbox_sts[1])); | ||
218 | } | ||
219 | return QLA_SUCCESS; | ||
220 | } | ||
221 | |||
222 | int qla4xxx_clear_database_entry(struct scsi_qla_host * ha, | ||
223 | uint16_t fw_ddb_index) | ||
224 | { | ||
225 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
226 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
227 | |||
228 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
229 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
230 | mbox_cmd[0] = MBOX_CMD_CLEAR_DATABASE_ENTRY; | ||
231 | mbox_cmd[1] = fw_ddb_index; | ||
232 | if (qla4xxx_mailbox_command(ha, 2, 5, &mbox_cmd[0], &mbox_sts[0]) != | ||
233 | QLA_SUCCESS) | ||
234 | return QLA_ERROR; | ||
235 | |||
236 | return QLA_SUCCESS; | ||
237 | } | ||
238 | |||
239 | /** | ||
240 | * qla4xxx_initialize_fw_cb - initializes firmware control block. | ||
241 | * @ha: Pointer to host adapter structure. | ||
242 | **/ | ||
243 | int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha) | ||
244 | { | ||
245 | struct init_fw_ctrl_blk *init_fw_cb; | ||
246 | dma_addr_t init_fw_cb_dma; | ||
247 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
248 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
249 | int status = QLA_ERROR; | ||
250 | |||
251 | init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, | ||
252 | sizeof(struct init_fw_ctrl_blk), | ||
253 | &init_fw_cb_dma, GFP_KERNEL); | ||
254 | if (init_fw_cb == NULL) { | ||
255 | DEBUG2(printk("scsi%ld: %s: Unable to alloc init_cb\n", | ||
256 | ha->host_no, __func__)); | ||
257 | return 10; | ||
258 | } | ||
259 | memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk)); | ||
260 | |||
261 | /* Get Initialize Firmware Control Block. */ | ||
262 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
263 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
264 | mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK; | ||
265 | mbox_cmd[2] = LSDW(init_fw_cb_dma); | ||
266 | mbox_cmd[3] = MSDW(init_fw_cb_dma); | ||
267 | if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) != | ||
268 | QLA_SUCCESS) { | ||
269 | dma_free_coherent(&ha->pdev->dev, | ||
270 | sizeof(struct init_fw_ctrl_blk), | ||
271 | init_fw_cb, init_fw_cb_dma); | ||
272 | return status; | ||
273 | } | ||
274 | |||
275 | /* Initialize request and response queues. */ | ||
276 | qla4xxx_init_rings(ha); | ||
277 | |||
278 | /* Fill in the request and response queue information. */ | ||
279 | init_fw_cb->ReqQConsumerIndex = cpu_to_le16(ha->request_out); | ||
280 | init_fw_cb->ComplQProducerIndex = cpu_to_le16(ha->response_in); | ||
281 | init_fw_cb->ReqQLen = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH); | ||
282 | init_fw_cb->ComplQLen = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH); | ||
283 | init_fw_cb->ReqQAddrLo = cpu_to_le32(LSDW(ha->request_dma)); | ||
284 | init_fw_cb->ReqQAddrHi = cpu_to_le32(MSDW(ha->request_dma)); | ||
285 | init_fw_cb->ComplQAddrLo = cpu_to_le32(LSDW(ha->response_dma)); | ||
286 | init_fw_cb->ComplQAddrHi = cpu_to_le32(MSDW(ha->response_dma)); | ||
287 | init_fw_cb->ShadowRegBufAddrLo = | ||
288 | cpu_to_le32(LSDW(ha->shadow_regs_dma)); | ||
289 | init_fw_cb->ShadowRegBufAddrHi = | ||
290 | cpu_to_le32(MSDW(ha->shadow_regs_dma)); | ||
291 | |||
292 | /* Set up required options. */ | ||
293 | init_fw_cb->FwOptions |= | ||
294 | __constant_cpu_to_le16(FWOPT_SESSION_MODE | | ||
295 | FWOPT_INITIATOR_MODE); | ||
296 | init_fw_cb->FwOptions &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE); | ||
297 | |||
298 | /* Save some info in adapter structure. */ | ||
299 | ha->firmware_options = le16_to_cpu(init_fw_cb->FwOptions); | ||
300 | ha->tcp_options = le16_to_cpu(init_fw_cb->TCPOptions); | ||
301 | ha->heartbeat_interval = init_fw_cb->HeartbeatInterval; | ||
302 | memcpy(ha->ip_address, init_fw_cb->IPAddr, | ||
303 | min(sizeof(ha->ip_address), sizeof(init_fw_cb->IPAddr))); | ||
304 | memcpy(ha->subnet_mask, init_fw_cb->SubnetMask, | ||
305 | min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->SubnetMask))); | ||
306 | memcpy(ha->gateway, init_fw_cb->GatewayIPAddr, | ||
307 | min(sizeof(ha->gateway), sizeof(init_fw_cb->GatewayIPAddr))); | ||
308 | memcpy(ha->name_string, init_fw_cb->iSCSINameString, | ||
309 | min(sizeof(ha->name_string), | ||
310 | sizeof(init_fw_cb->iSCSINameString))); | ||
311 | memcpy(ha->alias, init_fw_cb->Alias, | ||
312 | min(sizeof(ha->alias), sizeof(init_fw_cb->Alias))); | ||
313 | |||
314 | /* Save Command Line Paramater info */ | ||
315 | ha->port_down_retry_count = le16_to_cpu(init_fw_cb->KeepAliveTimeout); | ||
316 | ha->discovery_wait = ql4xdiscoverywait; | ||
317 | |||
318 | /* Send Initialize Firmware Control Block. */ | ||
319 | mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE; | ||
320 | mbox_cmd[1] = 0; | ||
321 | mbox_cmd[2] = LSDW(init_fw_cb_dma); | ||
322 | mbox_cmd[3] = MSDW(init_fw_cb_dma); | ||
323 | if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) == | ||
324 | QLA_SUCCESS) | ||
325 | status = QLA_SUCCESS; | ||
326 | else { | ||
327 | DEBUG2(printk("scsi%ld: %s: MBOX_CMD_INITIALIZE_FIRMWARE " | ||
328 | "failed w/ status %04X\n", ha->host_no, __func__, | ||
329 | mbox_sts[0])); | ||
330 | } | ||
331 | dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk), | ||
332 | init_fw_cb, init_fw_cb_dma); | ||
333 | |||
334 | return status; | ||
335 | } | ||
336 | |||
337 | /** | ||
338 | * qla4xxx_get_dhcp_ip_address - gets HBA ip address via DHCP | ||
339 | * @ha: Pointer to host adapter structure. | ||
340 | **/ | ||
341 | int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha) | ||
342 | { | ||
343 | struct init_fw_ctrl_blk *init_fw_cb; | ||
344 | dma_addr_t init_fw_cb_dma; | ||
345 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
346 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
347 | |||
348 | init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, | ||
349 | sizeof(struct init_fw_ctrl_blk), | ||
350 | &init_fw_cb_dma, GFP_KERNEL); | ||
351 | if (init_fw_cb == NULL) { | ||
352 | printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no, | ||
353 | __func__); | ||
354 | return 10; | ||
355 | } | ||
356 | |||
357 | /* Get Initialize Firmware Control Block. */ | ||
358 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
359 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
360 | memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk)); | ||
361 | mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK; | ||
362 | mbox_cmd[2] = LSDW(init_fw_cb_dma); | ||
363 | mbox_cmd[3] = MSDW(init_fw_cb_dma); | ||
364 | |||
365 | if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) != | ||
366 | QLA_SUCCESS) { | ||
367 | DEBUG2(printk("scsi%ld: %s: Failed to get init_fw_ctrl_blk\n", | ||
368 | ha->host_no, __func__)); | ||
369 | dma_free_coherent(&ha->pdev->dev, | ||
370 | sizeof(struct init_fw_ctrl_blk), | ||
371 | init_fw_cb, init_fw_cb_dma); | ||
372 | return QLA_ERROR; | ||
373 | } | ||
374 | |||
375 | /* Save IP Address. */ | ||
376 | memcpy(ha->ip_address, init_fw_cb->IPAddr, | ||
377 | min(sizeof(ha->ip_address), sizeof(init_fw_cb->IPAddr))); | ||
378 | memcpy(ha->subnet_mask, init_fw_cb->SubnetMask, | ||
379 | min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->SubnetMask))); | ||
380 | memcpy(ha->gateway, init_fw_cb->GatewayIPAddr, | ||
381 | min(sizeof(ha->gateway), sizeof(init_fw_cb->GatewayIPAddr))); | ||
382 | |||
383 | dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk), | ||
384 | init_fw_cb, init_fw_cb_dma); | ||
385 | |||
386 | return QLA_SUCCESS; | ||
387 | } | ||
388 | |||
389 | /** | ||
390 | * qla4xxx_get_firmware_state - gets firmware state of HBA | ||
391 | * @ha: Pointer to host adapter structure. | ||
392 | **/ | ||
393 | int qla4xxx_get_firmware_state(struct scsi_qla_host * ha) | ||
394 | { | ||
395 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
396 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
397 | |||
398 | /* Get firmware version */ | ||
399 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
400 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
401 | mbox_cmd[0] = MBOX_CMD_GET_FW_STATE; | ||
402 | if (qla4xxx_mailbox_command(ha, 1, 4, &mbox_cmd[0], &mbox_sts[0]) != | ||
403 | QLA_SUCCESS) { | ||
404 | DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATE failed w/ " | ||
405 | "status %04X\n", ha->host_no, __func__, | ||
406 | mbox_sts[0])); | ||
407 | return QLA_ERROR; | ||
408 | } | ||
409 | ha->firmware_state = mbox_sts[1]; | ||
410 | ha->board_id = mbox_sts[2]; | ||
411 | ha->addl_fw_state = mbox_sts[3]; | ||
412 | DEBUG2(printk("scsi%ld: %s firmware_state=0x%x\n", | ||
413 | ha->host_no, __func__, ha->firmware_state);) | ||
414 | |||
415 | return QLA_SUCCESS; | ||
416 | } | ||
417 | |||
418 | /** | ||
419 | * qla4xxx_get_firmware_status - retrieves firmware status | ||
420 | * @ha: Pointer to host adapter structure. | ||
421 | **/ | ||
422 | int qla4xxx_get_firmware_status(struct scsi_qla_host * ha) | ||
423 | { | ||
424 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
425 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
426 | |||
427 | /* Get firmware version */ | ||
428 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
429 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
430 | mbox_cmd[0] = MBOX_CMD_GET_FW_STATUS; | ||
431 | if (qla4xxx_mailbox_command(ha, 1, 3, &mbox_cmd[0], &mbox_sts[0]) != | ||
432 | QLA_SUCCESS) { | ||
433 | DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATUS failed w/ " | ||
434 | "status %04X\n", ha->host_no, __func__, | ||
435 | mbox_sts[0])); | ||
436 | return QLA_ERROR; | ||
437 | } | ||
438 | |||
439 | /* High-water mark of IOCBs */ | ||
440 | ha->iocb_hiwat = mbox_sts[2]; | ||
441 | if (ha->iocb_hiwat > IOCB_HIWAT_CUSHION) | ||
442 | ha->iocb_hiwat -= IOCB_HIWAT_CUSHION; | ||
443 | else | ||
444 | dev_info(&ha->pdev->dev, "WARNING!!! You have less than %d " | ||
445 | "firmare IOCBs available (%d).\n", | ||
446 | IOCB_HIWAT_CUSHION, ha->iocb_hiwat); | ||
447 | |||
448 | return QLA_SUCCESS; | ||
449 | } | ||
450 | |||
451 | /** | ||
452 | * qla4xxx_get_fwddb_entry - retrieves firmware ddb entry | ||
453 | * @ha: Pointer to host adapter structure. | ||
454 | * @fw_ddb_index: Firmware's device database index | ||
455 | * @fw_ddb_entry: Pointer to firmware's device database entry structure | ||
456 | * @num_valid_ddb_entries: Pointer to number of valid ddb entries | ||
457 | * @next_ddb_index: Pointer to next valid device database index | ||
458 | * @fw_ddb_device_state: Pointer to device state | ||
459 | **/ | ||
460 | int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, | ||
461 | uint16_t fw_ddb_index, | ||
462 | struct dev_db_entry *fw_ddb_entry, | ||
463 | dma_addr_t fw_ddb_entry_dma, | ||
464 | uint32_t *num_valid_ddb_entries, | ||
465 | uint32_t *next_ddb_index, | ||
466 | uint32_t *fw_ddb_device_state, | ||
467 | uint32_t *conn_err_detail, | ||
468 | uint16_t *tcp_source_port_num, | ||
469 | uint16_t *connection_id) | ||
470 | { | ||
471 | int status = QLA_ERROR; | ||
472 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
473 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
474 | |||
475 | /* Make sure the device index is valid */ | ||
476 | if (fw_ddb_index >= MAX_DDB_ENTRIES) { | ||
477 | DEBUG2(printk("scsi%ld: %s: index [%d] out of range.\n", | ||
478 | ha->host_no, __func__, fw_ddb_index)); | ||
479 | goto exit_get_fwddb; | ||
480 | } | ||
481 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
482 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
483 | mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY; | ||
484 | mbox_cmd[1] = (uint32_t) fw_ddb_index; | ||
485 | mbox_cmd[2] = LSDW(fw_ddb_entry_dma); | ||
486 | mbox_cmd[3] = MSDW(fw_ddb_entry_dma); | ||
487 | if (qla4xxx_mailbox_command(ha, 4, 7, &mbox_cmd[0], &mbox_sts[0]) == | ||
488 | QLA_ERROR) { | ||
489 | DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_DATABASE_ENTRY failed" | ||
490 | " with status 0x%04X\n", ha->host_no, __func__, | ||
491 | mbox_sts[0])); | ||
492 | goto exit_get_fwddb; | ||
493 | } | ||
494 | if (fw_ddb_index != mbox_sts[1]) { | ||
495 | DEBUG2(printk("scsi%ld: %s: index mismatch [%d] != [%d].\n", | ||
496 | ha->host_no, __func__, fw_ddb_index, | ||
497 | mbox_sts[1])); | ||
498 | goto exit_get_fwddb; | ||
499 | } | ||
500 | if (fw_ddb_entry) { | ||
501 | dev_info(&ha->pdev->dev, "DDB[%d] MB0 %04x Tot %d Next %d " | ||
502 | "State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n", | ||
503 | fw_ddb_index, mbox_sts[0], mbox_sts[2], mbox_sts[3], | ||
504 | mbox_sts[4], mbox_sts[5], fw_ddb_entry->ipAddr[0], | ||
505 | fw_ddb_entry->ipAddr[1], fw_ddb_entry->ipAddr[2], | ||
506 | fw_ddb_entry->ipAddr[3], | ||
507 | le16_to_cpu(fw_ddb_entry->portNumber), | ||
508 | fw_ddb_entry->iscsiName); | ||
509 | } | ||
510 | if (num_valid_ddb_entries) | ||
511 | *num_valid_ddb_entries = mbox_sts[2]; | ||
512 | if (next_ddb_index) | ||
513 | *next_ddb_index = mbox_sts[3]; | ||
514 | if (fw_ddb_device_state) | ||
515 | *fw_ddb_device_state = mbox_sts[4]; | ||
516 | |||
517 | /* | ||
518 | * RA: This mailbox has been changed to pass connection error and | ||
519 | * details. Its true for ISP4010 as per Version E - Not sure when it | ||
520 | * was changed. Get the time2wait from the fw_dd_entry field : | ||
521 | * default_time2wait which we call it as minTime2Wait DEV_DB_ENTRY | ||
522 | * struct. | ||
523 | */ | ||
524 | if (conn_err_detail) | ||
525 | *conn_err_detail = mbox_sts[5]; | ||
526 | if (tcp_source_port_num) | ||
527 | *tcp_source_port_num = (uint16_t) mbox_sts[6] >> 16; | ||
528 | if (connection_id) | ||
529 | *connection_id = (uint16_t) mbox_sts[6] & 0x00FF; | ||
530 | status = QLA_SUCCESS; | ||
531 | |||
532 | exit_get_fwddb: | ||
533 | return status; | ||
534 | } | ||
535 | |||
536 | /** | ||
537 | * qla4xxx_set_fwddb_entry - sets a ddb entry. | ||
538 | * @ha: Pointer to host adapter structure. | ||
539 | * @fw_ddb_index: Firmware's device database index | ||
540 | * @fw_ddb_entry: Pointer to firmware's ddb entry structure, or NULL. | ||
541 | * | ||
542 | * This routine initializes or updates the adapter's device database | ||
543 | * entry for the specified device. It also triggers a login for the | ||
544 | * specified device. Therefore, it may also be used as a secondary | ||
545 | * login routine when a NULL pointer is specified for the fw_ddb_entry. | ||
546 | **/ | ||
547 | int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, | ||
548 | dma_addr_t fw_ddb_entry_dma) | ||
549 | { | ||
550 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
551 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
552 | |||
553 | /* Do not wait for completion. The firmware will send us an | ||
554 | * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status. | ||
555 | */ | ||
556 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
557 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
558 | |||
559 | mbox_cmd[0] = MBOX_CMD_SET_DATABASE_ENTRY; | ||
560 | mbox_cmd[1] = (uint32_t) fw_ddb_index; | ||
561 | mbox_cmd[2] = LSDW(fw_ddb_entry_dma); | ||
562 | mbox_cmd[3] = MSDW(fw_ddb_entry_dma); | ||
563 | return qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]); | ||
564 | } | ||
565 | |||
566 | int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha, | ||
567 | uint16_t fw_ddb_index) | ||
568 | { | ||
569 | int status = QLA_ERROR; | ||
570 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
571 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
572 | |||
573 | /* Do not wait for completion. The firmware will send us an | ||
574 | * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status. | ||
575 | */ | ||
576 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
577 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
578 | mbox_cmd[0] = MBOX_CMD_CONN_OPEN_SESS_LOGIN; | ||
579 | mbox_cmd[1] = (uint32_t) fw_ddb_index; | ||
580 | mbox_cmd[2] = 0; | ||
581 | mbox_cmd[3] = 0; | ||
582 | mbox_cmd[4] = 0; | ||
583 | status = qla4xxx_mailbox_command(ha, 4, 0, &mbox_cmd[0], &mbox_sts[0]); | ||
584 | DEBUG2(printk("%s fw_ddb_index=%d status=%d mbx0_1=0x%x :0x%x\n", | ||
585 | __func__, fw_ddb_index, status, mbox_sts[0], | ||
586 | mbox_sts[1]);) | ||
587 | |||
588 | return status; | ||
589 | } | ||
590 | |||
591 | /** | ||
592 | * qla4xxx_get_crash_record - retrieves crash record. | ||
593 | * @ha: Pointer to host adapter structure. | ||
594 | * | ||
595 | * This routine retrieves a crash record from the QLA4010 after an 8002h aen. | ||
596 | **/ | ||
597 | void qla4xxx_get_crash_record(struct scsi_qla_host * ha) | ||
598 | { | ||
599 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
600 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
601 | struct crash_record *crash_record = NULL; | ||
602 | dma_addr_t crash_record_dma = 0; | ||
603 | uint32_t crash_record_size = 0; | ||
604 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
605 | memset(&mbox_sts, 0, sizeof(mbox_cmd)); | ||
606 | |||
607 | /* Get size of crash record. */ | ||
608 | mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD; | ||
609 | if (qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]) != | ||
610 | QLA_SUCCESS) { | ||
611 | DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve size!\n", | ||
612 | ha->host_no, __func__)); | ||
613 | goto exit_get_crash_record; | ||
614 | } | ||
615 | crash_record_size = mbox_sts[4]; | ||
616 | if (crash_record_size == 0) { | ||
617 | DEBUG2(printk("scsi%ld: %s: ERROR: Crash record size is 0!\n", | ||
618 | ha->host_no, __func__)); | ||
619 | goto exit_get_crash_record; | ||
620 | } | ||
621 | |||
622 | /* Alloc Memory for Crash Record. */ | ||
623 | crash_record = dma_alloc_coherent(&ha->pdev->dev, crash_record_size, | ||
624 | &crash_record_dma, GFP_KERNEL); | ||
625 | if (crash_record == NULL) | ||
626 | goto exit_get_crash_record; | ||
627 | |||
628 | /* Get Crash Record. */ | ||
629 | mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD; | ||
630 | mbox_cmd[2] = LSDW(crash_record_dma); | ||
631 | mbox_cmd[3] = MSDW(crash_record_dma); | ||
632 | mbox_cmd[4] = crash_record_size; | ||
633 | if (qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]) != | ||
634 | QLA_SUCCESS) | ||
635 | goto exit_get_crash_record; | ||
636 | |||
637 | /* Dump Crash Record. */ | ||
638 | |||
639 | exit_get_crash_record: | ||
640 | if (crash_record) | ||
641 | dma_free_coherent(&ha->pdev->dev, crash_record_size, | ||
642 | crash_record, crash_record_dma); | ||
643 | } | ||
644 | |||
645 | /** | ||
646 | * qla4xxx_get_conn_event_log - retrieves connection event log | ||
647 | * @ha: Pointer to host adapter structure. | ||
648 | **/ | ||
649 | void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha) | ||
650 | { | ||
651 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
652 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
653 | struct conn_event_log_entry *event_log = NULL; | ||
654 | dma_addr_t event_log_dma = 0; | ||
655 | uint32_t event_log_size = 0; | ||
656 | uint32_t num_valid_entries; | ||
657 | uint32_t oldest_entry = 0; | ||
658 | uint32_t max_event_log_entries; | ||
659 | uint8_t i; | ||
660 | |||
661 | |||
662 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
663 | memset(&mbox_sts, 0, sizeof(mbox_cmd)); | ||
664 | |||
665 | /* Get size of crash record. */ | ||
666 | mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG; | ||
667 | if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) != | ||
668 | QLA_SUCCESS) | ||
669 | goto exit_get_event_log; | ||
670 | |||
671 | event_log_size = mbox_sts[4]; | ||
672 | if (event_log_size == 0) | ||
673 | goto exit_get_event_log; | ||
674 | |||
675 | /* Alloc Memory for Crash Record. */ | ||
676 | event_log = dma_alloc_coherent(&ha->pdev->dev, event_log_size, | ||
677 | &event_log_dma, GFP_KERNEL); | ||
678 | if (event_log == NULL) | ||
679 | goto exit_get_event_log; | ||
680 | |||
681 | /* Get Crash Record. */ | ||
682 | mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG; | ||
683 | mbox_cmd[2] = LSDW(event_log_dma); | ||
684 | mbox_cmd[3] = MSDW(event_log_dma); | ||
685 | if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) != | ||
686 | QLA_SUCCESS) { | ||
687 | DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve event " | ||
688 | "log!\n", ha->host_no, __func__)); | ||
689 | goto exit_get_event_log; | ||
690 | } | ||
691 | |||
692 | /* Dump Event Log. */ | ||
693 | num_valid_entries = mbox_sts[1]; | ||
694 | |||
695 | max_event_log_entries = event_log_size / | ||
696 | sizeof(struct conn_event_log_entry); | ||
697 | |||
698 | if (num_valid_entries > max_event_log_entries) | ||
699 | oldest_entry = num_valid_entries % max_event_log_entries; | ||
700 | |||
701 | DEBUG3(printk("scsi%ld: Connection Event Log Dump (%d entries):\n", | ||
702 | ha->host_no, num_valid_entries)); | ||
703 | |||
704 | if (extended_error_logging == 3) { | ||
705 | if (oldest_entry == 0) { | ||
706 | /* Circular Buffer has not wrapped around */ | ||
707 | for (i=0; i < num_valid_entries; i++) { | ||
708 | qla4xxx_dump_buffer((uint8_t *)event_log+ | ||
709 | (i*sizeof(*event_log)), | ||
710 | sizeof(*event_log)); | ||
711 | } | ||
712 | } | ||
713 | else { | ||
714 | /* Circular Buffer has wrapped around - | ||
715 | * display accordingly*/ | ||
716 | for (i=oldest_entry; i < max_event_log_entries; i++) { | ||
717 | qla4xxx_dump_buffer((uint8_t *)event_log+ | ||
718 | (i*sizeof(*event_log)), | ||
719 | sizeof(*event_log)); | ||
720 | } | ||
721 | for (i=0; i < oldest_entry; i++) { | ||
722 | qla4xxx_dump_buffer((uint8_t *)event_log+ | ||
723 | (i*sizeof(*event_log)), | ||
724 | sizeof(*event_log)); | ||
725 | } | ||
726 | } | ||
727 | } | ||
728 | |||
729 | exit_get_event_log: | ||
730 | if (event_log) | ||
731 | dma_free_coherent(&ha->pdev->dev, event_log_size, event_log, | ||
732 | event_log_dma); | ||
733 | } | ||
734 | |||
735 | /** | ||
736 | * qla4xxx_reset_lun - issues LUN Reset | ||
737 | * @ha: Pointer to host adapter structure. | ||
738 | * @db_entry: Pointer to device database entry | ||
739 | * @un_entry: Pointer to lun entry structure | ||
740 | * | ||
741 | * This routine performs a LUN RESET on the specified target/lun. | ||
742 | * The caller must ensure that the ddb_entry and lun_entry pointers | ||
743 | * are valid before calling this routine. | ||
744 | **/ | ||
745 | int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, | ||
746 | int lun) | ||
747 | { | ||
748 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
749 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
750 | int status = QLA_SUCCESS; | ||
751 | |||
752 | DEBUG2(printk("scsi%ld:%d:%d: lun reset issued\n", ha->host_no, | ||
753 | ddb_entry->os_target_id, lun)); | ||
754 | |||
755 | /* | ||
756 | * Send lun reset command to ISP, so that the ISP will return all | ||
757 | * outstanding requests with RESET status | ||
758 | */ | ||
759 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
760 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
761 | mbox_cmd[0] = MBOX_CMD_LUN_RESET; | ||
762 | mbox_cmd[1] = ddb_entry->fw_ddb_index; | ||
763 | mbox_cmd[2] = lun << 8; | ||
764 | mbox_cmd[5] = 0x01; /* Immediate Command Enable */ | ||
765 | qla4xxx_mailbox_command(ha, 6, 1, &mbox_cmd[0], &mbox_sts[0]); | ||
766 | if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE && | ||
767 | mbox_sts[0] != MBOX_STS_COMMAND_ERROR) | ||
768 | status = QLA_ERROR; | ||
769 | |||
770 | return status; | ||
771 | } | ||
772 | |||
773 | |||
774 | int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, | ||
775 | uint32_t offset, uint32_t len) | ||
776 | { | ||
777 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
778 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
779 | |||
780 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
781 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
782 | mbox_cmd[0] = MBOX_CMD_READ_FLASH; | ||
783 | mbox_cmd[1] = LSDW(dma_addr); | ||
784 | mbox_cmd[2] = MSDW(dma_addr); | ||
785 | mbox_cmd[3] = offset; | ||
786 | mbox_cmd[4] = len; | ||
787 | if (qla4xxx_mailbox_command(ha, 5, 2, &mbox_cmd[0], &mbox_sts[0]) != | ||
788 | QLA_SUCCESS) { | ||
789 | DEBUG2(printk("scsi%ld: %s: MBOX_CMD_READ_FLASH, failed w/ " | ||
790 | "status %04X %04X, offset %08x, len %08x\n", ha->host_no, | ||
791 | __func__, mbox_sts[0], mbox_sts[1], offset, len)); | ||
792 | return QLA_ERROR; | ||
793 | } | ||
794 | return QLA_SUCCESS; | ||
795 | } | ||
796 | |||
797 | /** | ||
798 | * qla4xxx_get_fw_version - gets firmware version | ||
799 | * @ha: Pointer to host adapter structure. | ||
800 | * | ||
801 | * Retrieves the firmware version on HBA. In QLA4010, mailboxes 2 & 3 may | ||
802 | * hold an address for data. Make sure that we write 0 to those mailboxes, | ||
803 | * if unused. | ||
804 | **/ | ||
805 | int qla4xxx_get_fw_version(struct scsi_qla_host * ha) | ||
806 | { | ||
807 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
808 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
809 | |||
810 | /* Get firmware version. */ | ||
811 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
812 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
813 | mbox_cmd[0] = MBOX_CMD_ABOUT_FW; | ||
814 | if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) != | ||
815 | QLA_SUCCESS) { | ||
816 | DEBUG2(printk("scsi%ld: %s: MBOX_CMD_ABOUT_FW failed w/ " | ||
817 | "status %04X\n", ha->host_no, __func__, mbox_sts[0])); | ||
818 | return QLA_ERROR; | ||
819 | } | ||
820 | |||
821 | /* Save firmware version information. */ | ||
822 | ha->firmware_version[0] = mbox_sts[1]; | ||
823 | ha->firmware_version[1] = mbox_sts[2]; | ||
824 | ha->patch_number = mbox_sts[3]; | ||
825 | ha->build_number = mbox_sts[4]; | ||
826 | |||
827 | return QLA_SUCCESS; | ||
828 | } | ||
829 | |||
830 | int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, dma_addr_t dma_addr) | ||
831 | { | ||
832 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
833 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
834 | |||
835 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
836 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
837 | |||
838 | mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS; | ||
839 | mbox_cmd[2] = LSDW(dma_addr); | ||
840 | mbox_cmd[3] = MSDW(dma_addr); | ||
841 | |||
842 | if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) != | ||
843 | QLA_SUCCESS) { | ||
844 | DEBUG2(printk("scsi%ld: %s: failed status %04X\n", | ||
845 | ha->host_no, __func__, mbox_sts[0])); | ||
846 | return QLA_ERROR; | ||
847 | } | ||
848 | return QLA_SUCCESS; | ||
849 | } | ||
850 | |||
851 | int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index) | ||
852 | { | ||
853 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
854 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
855 | |||
856 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
857 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
858 | |||
859 | mbox_cmd[0] = MBOX_CMD_REQUEST_DATABASE_ENTRY; | ||
860 | mbox_cmd[1] = MAX_PRST_DEV_DB_ENTRIES; | ||
861 | |||
862 | if (qla4xxx_mailbox_command(ha, 2, 3, &mbox_cmd[0], &mbox_sts[0]) != | ||
863 | QLA_SUCCESS) { | ||
864 | if (mbox_sts[0] == MBOX_STS_COMMAND_ERROR) { | ||
865 | *ddb_index = mbox_sts[2]; | ||
866 | } else { | ||
867 | DEBUG2(printk("scsi%ld: %s: failed status %04X\n", | ||
868 | ha->host_no, __func__, mbox_sts[0])); | ||
869 | return QLA_ERROR; | ||
870 | } | ||
871 | } else { | ||
872 | *ddb_index = MAX_PRST_DEV_DB_ENTRIES; | ||
873 | } | ||
874 | |||
875 | return QLA_SUCCESS; | ||
876 | } | ||
877 | |||
878 | |||
879 | int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port) | ||
880 | { | ||
881 | struct dev_db_entry *fw_ddb_entry; | ||
882 | dma_addr_t fw_ddb_entry_dma; | ||
883 | uint32_t ddb_index; | ||
884 | int ret_val = QLA_SUCCESS; | ||
885 | |||
886 | |||
887 | fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, | ||
888 | sizeof(*fw_ddb_entry), | ||
889 | &fw_ddb_entry_dma, GFP_KERNEL); | ||
890 | if (!fw_ddb_entry) { | ||
891 | DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", | ||
892 | ha->host_no, __func__)); | ||
893 | ret_val = QLA_ERROR; | ||
894 | goto qla4xxx_send_tgts_exit; | ||
895 | } | ||
896 | |||
897 | ret_val = qla4xxx_get_default_ddb(ha, fw_ddb_entry_dma); | ||
898 | if (ret_val != QLA_SUCCESS) | ||
899 | goto qla4xxx_send_tgts_exit; | ||
900 | |||
901 | ret_val = qla4xxx_req_ddb_entry(ha, &ddb_index); | ||
902 | if (ret_val != QLA_SUCCESS) | ||
903 | goto qla4xxx_send_tgts_exit; | ||
904 | |||
905 | memset((void *)fw_ddb_entry->iSCSIAlias, 0, | ||
906 | sizeof(fw_ddb_entry->iSCSIAlias)); | ||
907 | |||
908 | memset((void *)fw_ddb_entry->iscsiName, 0, | ||
909 | sizeof(fw_ddb_entry->iscsiName)); | ||
910 | |||
911 | memset((void *)fw_ddb_entry->ipAddr, 0, sizeof(fw_ddb_entry->ipAddr)); | ||
912 | memset((void *)fw_ddb_entry->targetAddr, 0, | ||
913 | sizeof(fw_ddb_entry->targetAddr)); | ||
914 | |||
915 | fw_ddb_entry->options = (DDB_OPT_DISC_SESSION | DDB_OPT_TARGET); | ||
916 | fw_ddb_entry->portNumber = cpu_to_le16(ntohs(port)); | ||
917 | |||
918 | fw_ddb_entry->ipAddr[0] = *ip; | ||
919 | fw_ddb_entry->ipAddr[1] = *(ip + 1); | ||
920 | fw_ddb_entry->ipAddr[2] = *(ip + 2); | ||
921 | fw_ddb_entry->ipAddr[3] = *(ip + 3); | ||
922 | |||
923 | ret_val = qla4xxx_set_ddb_entry(ha, ddb_index, fw_ddb_entry_dma); | ||
924 | |||
925 | qla4xxx_send_tgts_exit: | ||
926 | dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), | ||
927 | fw_ddb_entry, fw_ddb_entry_dma); | ||
928 | return ret_val; | ||
929 | } | ||
930 | |||