aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h21
-rw-r--r--drivers/scsi/qla4xxx/ql4_fw.h20
-rw-r--r--drivers/scsi/qla4xxx/ql4_glbl.h5
-rw-r--r--drivers/scsi/qla4xxx/ql4_init.c5
-rw-r--r--drivers/scsi/qla4xxx/ql4_iocb.c92
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c72
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c113
7 files changed, 328 insertions, 0 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index f91808ce572e..776714d2d70d 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -221,6 +221,15 @@ struct srb {
221 uint16_t reserved2; 221 uint16_t reserved2;
222}; 222};
223 223
224/* Mailbox request block structure */
225struct mrb {
226 struct scsi_qla_host *ha;
227 struct mbox_cmd_iocb *mbox;
228 uint32_t mbox_cmd;
229 uint16_t iocb_cnt; /* Number of used iocbs */
230 uint32_t pid;
231};
232
224/* 233/*
225 * Asynchronous Event Queue structure 234 * Asynchronous Event Queue structure
226 */ 235 */
@@ -303,6 +312,7 @@ struct ql4_tuple_ddb {
303 312
304enum qla4_work_type { 313enum qla4_work_type {
305 QLA4_EVENT_AEN, 314 QLA4_EVENT_AEN,
315 QLA4_EVENT_PING_STATUS,
306}; 316};
307 317
308struct qla4_work_evt { 318struct qla4_work_evt {
@@ -314,6 +324,12 @@ struct qla4_work_evt {
314 uint32_t data_size; 324 uint32_t data_size;
315 uint8_t data[0]; 325 uint8_t data[0];
316 } aen; 326 } aen;
327 struct {
328 uint32_t status;
329 uint32_t pid;
330 uint32_t data_size;
331 uint8_t data[0];
332 } ping;
317 } u; 333 } u;
318}; 334};
319 335
@@ -690,6 +706,11 @@ struct scsi_qla_host {
690 /* event work list */ 706 /* event work list */
691 struct list_head work_list; 707 struct list_head work_list;
692 spinlock_t work_lock; 708 spinlock_t work_lock;
709
710 /* mbox iocb */
711#define MAX_MRB 128
712 struct mrb *active_mrb_array[MAX_MRB];
713 uint32_t mrb_index;
693}; 714};
694 715
695struct ql4_task_data { 716struct ql4_task_data {
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index 5f82b5decd0f..210cd1d64475 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -331,6 +331,10 @@ struct qla_flt_region {
331/* Mailbox command definitions */ 331/* Mailbox command definitions */
332#define MBOX_CMD_ABOUT_FW 0x0009 332#define MBOX_CMD_ABOUT_FW 0x0009
333#define MBOX_CMD_PING 0x000B 333#define MBOX_CMD_PING 0x000B
334#define PING_IPV6_PROTOCOL_ENABLE 0x1
335#define PING_IPV6_LINKLOCAL_ADDR 0x4
336#define PING_IPV6_ADDR0 0x8
337#define PING_IPV6_ADDR1 0xC
334#define MBOX_CMD_ENABLE_INTRS 0x0010 338#define MBOX_CMD_ENABLE_INTRS 0x0010
335#define INTR_DISABLE 0 339#define INTR_DISABLE 0
336#define INTR_ENABLE 1 340#define INTR_ENABLE 1
@@ -922,6 +926,8 @@ struct qla4_header {
922#define ET_CMND_T3 0x19 926#define ET_CMND_T3 0x19
923#define ET_PASSTHRU0 0x3A 927#define ET_PASSTHRU0 0x3A
924#define ET_PASSTHRU_STATUS 0x3C 928#define ET_PASSTHRU_STATUS 0x3C
929#define ET_MBOX_CMD 0x38
930#define ET_MBOX_STATUS 0x39
925 931
926 uint8_t entryStatus; 932 uint8_t entryStatus;
927 uint8_t systemDefined; 933 uint8_t systemDefined;
@@ -1122,6 +1128,20 @@ struct passthru_status {
1122 uint8_t res4[16]; /* 30-3F */ 1128 uint8_t res4[16]; /* 30-3F */
1123}; 1129};
1124 1130
1131struct mbox_cmd_iocb {
1132 struct qla4_header hdr; /* 00-03 */
1133 uint32_t handle; /* 04-07 */
1134 uint32_t in_mbox[8]; /* 08-25 */
1135 uint32_t res1[6]; /* 26-3F */
1136};
1137
1138struct mbox_status_iocb {
1139 struct qla4_header hdr; /* 00-03 */
1140 uint32_t handle; /* 04-07 */
1141 uint32_t out_mbox[8]; /* 08-25 */
1142 uint32_t res1[6]; /* 26-3F */
1143};
1144
1125/* 1145/*
1126 * ISP queue - response queue entry definition. 1146 * ISP queue - response queue entry definition.
1127 */ 1147 */
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index 34cf851978e9..954ba9188256 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -183,6 +183,11 @@ int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index,
183void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset); 183void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset);
184int qla4xxx_post_aen_work(struct scsi_qla_host *ha, uint32_t aen_code, 184int qla4xxx_post_aen_work(struct scsi_qla_host *ha, uint32_t aen_code,
185 uint32_t data_size, uint8_t *data); 185 uint32_t data_size, uint8_t *data);
186int qla4xxx_ping_iocb(struct scsi_qla_host *ha, uint32_t options,
187 uint32_t payload_size, uint32_t pid, uint8_t *ipaddr);
188int qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha,
189 uint32_t status, uint32_t pid,
190 uint32_t data_size, uint8_t *data);
186 191
187/* BSG Functions */ 192/* BSG Functions */
188int qla4xxx_bsg_request(struct bsg_job *bsg_job); 193int qla4xxx_bsg_request(struct bsg_job *bsg_job);
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index 90614f38b55d..90ee5d8fa731 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -86,6 +86,7 @@ static void qla4xxx_init_response_q_entries(struct scsi_qla_host *ha)
86int qla4xxx_init_rings(struct scsi_qla_host *ha) 86int qla4xxx_init_rings(struct scsi_qla_host *ha)
87{ 87{
88 unsigned long flags = 0; 88 unsigned long flags = 0;
89 int i;
89 90
90 /* Initialize request queue. */ 91 /* Initialize request queue. */
91 spin_lock_irqsave(&ha->hardware_lock, flags); 92 spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -125,6 +126,10 @@ int qla4xxx_init_rings(struct scsi_qla_host *ha)
125 126
126 qla4xxx_init_response_q_entries(ha); 127 qla4xxx_init_response_q_entries(ha);
127 128
129 /* Initialize mabilbox active array */
130 for (i = 0; i < MAX_MRB; i++)
131 ha->active_mrb_array[i] = NULL;
132
128 spin_unlock_irqrestore(&ha->hardware_lock, flags); 133 spin_unlock_irqrestore(&ha->hardware_lock, flags);
129 134
130 return QLA_SUCCESS; 135 return QLA_SUCCESS;
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
index 410669351906..c70651ddaf8b 100644
--- a/drivers/scsi/qla4xxx/ql4_iocb.c
+++ b/drivers/scsi/qla4xxx/ql4_iocb.c
@@ -445,3 +445,95 @@ queuing_error:
445 spin_unlock_irqrestore(&ha->hardware_lock, flags); 445 spin_unlock_irqrestore(&ha->hardware_lock, flags);
446 return ret; 446 return ret;
447} 447}
448
449static struct mrb *qla4xxx_get_new_mrb(struct scsi_qla_host *ha)
450{
451 struct mrb *mrb;
452
453 mrb = kzalloc(sizeof(*mrb), GFP_KERNEL);
454 if (!mrb)
455 return mrb;
456
457 mrb->ha = ha;
458 return mrb;
459}
460
461int qla4xxx_send_mbox_iocb(struct scsi_qla_host *ha, struct mrb *mrb,
462 uint32_t *in_mbox)
463{
464 int rval = QLA_SUCCESS;
465 uint32_t i;
466 unsigned long flags;
467 uint32_t index = 0;
468
469 /* Acquire hardware specific lock */
470 spin_lock_irqsave(&ha->hardware_lock, flags);
471
472 /* Get pointer to the queue entry for the marker */
473 rval = qla4xxx_get_req_pkt(ha, (struct queue_entry **) &(mrb->mbox));
474 if (rval != QLA_SUCCESS)
475 goto exit_mbox_iocb;
476
477 index = ha->mrb_index;
478 /* get valid mrb index*/
479 for (i = 0; i < MAX_MRB; i++) {
480 index++;
481 if (index == MAX_MRB)
482 index = 1;
483 if (ha->active_mrb_array[index] == NULL) {
484 ha->mrb_index = index;
485 break;
486 }
487 }
488
489 mrb->iocb_cnt = 1;
490 ha->active_mrb_array[index] = mrb;
491 mrb->mbox->handle = index;
492 mrb->mbox->hdr.entryType = ET_MBOX_CMD;
493 mrb->mbox->hdr.entryCount = mrb->iocb_cnt;
494 memcpy(mrb->mbox->in_mbox, in_mbox, 32);
495 mrb->mbox_cmd = in_mbox[0];
496 wmb();
497
498 ha->isp_ops->queue_iocb(ha);
499exit_mbox_iocb:
500 spin_unlock_irqrestore(&ha->hardware_lock, flags);
501 return rval;
502}
503
504int qla4xxx_ping_iocb(struct scsi_qla_host *ha, uint32_t options,
505 uint32_t payload_size, uint32_t pid, uint8_t *ipaddr)
506{
507 uint32_t in_mbox[8];
508 struct mrb *mrb = NULL;
509 int rval = QLA_SUCCESS;
510
511 memset(in_mbox, 0, sizeof(in_mbox));
512
513 mrb = qla4xxx_get_new_mrb(ha);
514 if (!mrb) {
515 DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: fail to get new mrb\n",
516 __func__));
517 rval = QLA_ERROR;
518 goto exit_ping;
519 }
520
521 in_mbox[0] = MBOX_CMD_PING;
522 in_mbox[1] = options;
523 memcpy(&in_mbox[2], &ipaddr[0], 4);
524 memcpy(&in_mbox[3], &ipaddr[4], 4);
525 memcpy(&in_mbox[4], &ipaddr[8], 4);
526 memcpy(&in_mbox[5], &ipaddr[12], 4);
527 in_mbox[6] = payload_size;
528
529 mrb->pid = pid;
530 rval = qla4xxx_send_mbox_iocb(ha, mrb, in_mbox);
531
532 if (rval != QLA_SUCCESS)
533 goto exit_ping;
534
535 return rval;
536exit_ping:
537 kfree(mrb);
538 return rval;
539}
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 954fe84be575..7c9f28b7da72 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -385,6 +385,71 @@ static void qla4xxx_passthru_status_entry(struct scsi_qla_host *ha,
385 queue_work(ha->task_wq, &task_data->task_work); 385 queue_work(ha->task_wq, &task_data->task_work);
386} 386}
387 387
388static struct mrb *qla4xxx_del_mrb_from_active_array(struct scsi_qla_host *ha,
389 uint32_t index)
390{
391 struct mrb *mrb = NULL;
392
393 /* validate handle and remove from active array */
394 if (index >= MAX_MRB)
395 return mrb;
396
397 mrb = ha->active_mrb_array[index];
398 ha->active_mrb_array[index] = NULL;
399 if (!mrb)
400 return mrb;
401
402 /* update counters */
403 ha->req_q_count += mrb->iocb_cnt;
404 ha->iocb_cnt -= mrb->iocb_cnt;
405
406 return mrb;
407}
408
409static void qla4xxx_mbox_status_entry(struct scsi_qla_host *ha,
410 struct mbox_status_iocb *mbox_sts_entry)
411{
412 struct mrb *mrb;
413 uint32_t status;
414 uint32_t data_size;
415
416 mrb = qla4xxx_del_mrb_from_active_array(ha,
417 le32_to_cpu(mbox_sts_entry->handle));
418
419 if (mrb == NULL) {
420 ql4_printk(KERN_WARNING, ha, "%s: mrb[%d] is null\n", __func__,
421 mbox_sts_entry->handle);
422 return;
423 }
424
425 switch (mrb->mbox_cmd) {
426 case MBOX_CMD_PING:
427 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: mbox_cmd = 0x%x, "
428 "mbox_sts[0] = 0x%x, mbox_sts[6] = 0x%x\n",
429 __func__, mrb->mbox_cmd,
430 mbox_sts_entry->out_mbox[0],
431 mbox_sts_entry->out_mbox[6]));
432
433 if (mbox_sts_entry->out_mbox[0] == MBOX_STS_COMMAND_COMPLETE)
434 status = QLA_SUCCESS;
435 else
436 status = QLA_ERROR;
437
438 data_size = sizeof(mbox_sts_entry->out_mbox);
439
440 qla4xxx_post_ping_evt_work(ha, status, mrb->pid, data_size,
441 (uint8_t *) mbox_sts_entry->out_mbox);
442 break;
443
444 default:
445 DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: invalid mbox_cmd = "
446 "0x%x\n", __func__, mrb->mbox_cmd));
447 }
448
449 kfree(mrb);
450 return;
451}
452
388/** 453/**
389 * qla4xxx_process_response_queue - process response queue completions 454 * qla4xxx_process_response_queue - process response queue completions
390 * @ha: Pointer to host adapter structure. 455 * @ha: Pointer to host adapter structure.
@@ -461,6 +526,13 @@ void qla4xxx_process_response_queue(struct scsi_qla_host *ha)
461 "ignoring\n", ha->host_no, __func__)); 526 "ignoring\n", ha->host_no, __func__));
462 break; 527 break;
463 528
529 case ET_MBOX_STATUS:
530 DEBUG2(ql4_printk(KERN_INFO, ha,
531 "%s: mbox status IOCB\n", __func__));
532 qla4xxx_mbox_status_entry(ha,
533 (struct mbox_status_iocb *)sts_entry);
534 break;
535
464 default: 536 default:
465 /* 537 /*
466 * Invalid entry in response queue, reset RISC 538 * Invalid entry in response queue, reset RISC
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index d423f7afbbd7..877c0e220ac9 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -118,6 +118,10 @@ static void qla4xxx_task_cleanup(struct iscsi_task *);
118static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session); 118static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session);
119static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, 119static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn,
120 struct iscsi_stats *stats); 120 struct iscsi_stats *stats);
121static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num,
122 uint32_t iface_type, uint32_t payload_size,
123 uint32_t pid, struct sockaddr *dst_addr);
124
121/* 125/*
122 * SCSI host template entry points 126 * SCSI host template entry points
123 */ 127 */
@@ -194,10 +198,91 @@ static struct iscsi_transport qla4xxx_iscsi_transport = {
194 .set_iface_param = qla4xxx_iface_set_param, 198 .set_iface_param = qla4xxx_iface_set_param,
195 .get_iface_param = qla4xxx_get_iface_param, 199 .get_iface_param = qla4xxx_get_iface_param,
196 .bsg_request = qla4xxx_bsg_request, 200 .bsg_request = qla4xxx_bsg_request,
201 .send_ping = qla4xxx_send_ping,
197}; 202};
198 203
199static struct scsi_transport_template *qla4xxx_scsi_transport; 204static struct scsi_transport_template *qla4xxx_scsi_transport;
200 205
206static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num,
207 uint32_t iface_type, uint32_t payload_size,
208 uint32_t pid, struct sockaddr *dst_addr)
209{
210 struct scsi_qla_host *ha = to_qla_host(shost);
211 struct sockaddr_in *addr;
212 struct sockaddr_in6 *addr6;
213 uint32_t options = 0;
214 uint8_t ipaddr[IPv6_ADDR_LEN];
215 int rval;
216
217 memset(ipaddr, 0, IPv6_ADDR_LEN);
218 /* IPv4 to IPv4 */
219 if ((iface_type == ISCSI_IFACE_TYPE_IPV4) &&
220 (dst_addr->sa_family == AF_INET)) {
221 addr = (struct sockaddr_in *)dst_addr;
222 memcpy(ipaddr, &addr->sin_addr.s_addr, IP_ADDR_LEN);
223 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv4 Ping src: %pI4 "
224 "dest: %pI4\n", __func__,
225 &ha->ip_config.ip_address, ipaddr));
226 rval = qla4xxx_ping_iocb(ha, options, payload_size, pid,
227 ipaddr);
228 if (rval)
229 rval = -EINVAL;
230 } else if ((iface_type == ISCSI_IFACE_TYPE_IPV6) &&
231 (dst_addr->sa_family == AF_INET6)) {
232 /* IPv6 to IPv6 */
233 addr6 = (struct sockaddr_in6 *)dst_addr;
234 memcpy(ipaddr, &addr6->sin6_addr.in6_u.u6_addr8, IPv6_ADDR_LEN);
235
236 options |= PING_IPV6_PROTOCOL_ENABLE;
237
238 /* Ping using LinkLocal address */
239 if ((iface_num == 0) || (iface_num == 1)) {
240 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: LinkLocal Ping "
241 "src: %pI6 dest: %pI6\n", __func__,
242 &ha->ip_config.ipv6_link_local_addr,
243 ipaddr));
244 options |= PING_IPV6_LINKLOCAL_ADDR;
245 rval = qla4xxx_ping_iocb(ha, options, payload_size,
246 pid, ipaddr);
247 } else {
248 ql4_printk(KERN_WARNING, ha, "%s: iface num = %d "
249 "not supported\n", __func__, iface_num);
250 rval = -ENOSYS;
251 goto exit_send_ping;
252 }
253
254 /*
255 * If ping using LinkLocal address fails, try ping using
256 * IPv6 address
257 */
258 if (rval != QLA_SUCCESS) {
259 options &= ~PING_IPV6_LINKLOCAL_ADDR;
260 if (iface_num == 0) {
261 options |= PING_IPV6_ADDR0;
262 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 "
263 "Ping src: %pI6 "
264 "dest: %pI6\n", __func__,
265 &ha->ip_config.ipv6_addr0,
266 ipaddr));
267 } else if (iface_num == 1) {
268 options |= PING_IPV6_ADDR1;
269 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 "
270 "Ping src: %pI6 "
271 "dest: %pI6\n", __func__,
272 &ha->ip_config.ipv6_addr1,
273 ipaddr));
274 }
275 rval = qla4xxx_ping_iocb(ha, options, payload_size,
276 pid, ipaddr);
277 if (rval)
278 rval = -EINVAL;
279 }
280 } else
281 rval = -ENOSYS;
282exit_send_ping:
283 return rval;
284}
285
201static umode_t ql4_attr_is_visible(int param_type, int param) 286static umode_t ql4_attr_is_visible(int param_type, int param)
202{ 287{
203 switch (param_type) { 288 switch (param_type) {
@@ -2897,6 +2982,26 @@ int qla4xxx_post_aen_work(struct scsi_qla_host *ha,
2897 return QLA_SUCCESS; 2982 return QLA_SUCCESS;
2898} 2983}
2899 2984
2985int qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha,
2986 uint32_t status, uint32_t pid,
2987 uint32_t data_size, uint8_t *data)
2988{
2989 struct qla4_work_evt *e;
2990
2991 e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_PING_STATUS);
2992 if (!e)
2993 return QLA_ERROR;
2994
2995 e->u.ping.status = status;
2996 e->u.ping.pid = pid;
2997 e->u.ping.data_size = data_size;
2998 memcpy(e->u.ping.data, data, data_size);
2999
3000 qla4xxx_post_work(ha, e);
3001
3002 return QLA_SUCCESS;
3003}
3004
2900void qla4xxx_do_work(struct scsi_qla_host *ha) 3005void qla4xxx_do_work(struct scsi_qla_host *ha)
2901{ 3006{
2902 struct qla4_work_evt *e, *tmp; 3007 struct qla4_work_evt *e, *tmp;
@@ -2918,6 +3023,14 @@ void qla4xxx_do_work(struct scsi_qla_host *ha)
2918 e->u.aen.data_size, 3023 e->u.aen.data_size,
2919 e->u.aen.data); 3024 e->u.aen.data);
2920 break; 3025 break;
3026 case QLA4_EVENT_PING_STATUS:
3027 iscsi_ping_comp_event(ha->host_no,
3028 &qla4xxx_iscsi_transport,
3029 e->u.ping.status,
3030 e->u.ping.pid,
3031 e->u.ping.data_size,
3032 e->u.ping.data);
3033 break;
2921 default: 3034 default:
2922 ql4_printk(KERN_WARNING, ha, "event type: 0x%x not " 3035 ql4_printk(KERN_WARNING, ha, "event type: 0x%x not "
2923 "supported", e->type); 3036 "supported", e->type);