diff options
author | Andrew Vasquez <andrew.vasquez@qlogic.com> | 2009-08-20 14:06:05 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-09-05 10:41:57 -0400 |
commit | ac280b670e6d6666667aba02324e2fc50bd96ae7 (patch) | |
tree | 4d0d9187b26513ef9f820ab140f29a4f49f678b8 /drivers/scsi/qla2xxx/qla_init.c | |
parent | cf53b069f52ae3f83dec1acd339e3c3a2e979478 (diff) |
[SCSI] qla2xxx: Add asynchronous-login support.
ISPs which support this feature include 23xx and above.
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_init.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_init.c | 215 |
1 files changed, 212 insertions, 3 deletions
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 0cbe39e92506..37c99a27874c 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c | |||
@@ -40,6 +40,210 @@ static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *); | |||
40 | static int qla84xx_init_chip(scsi_qla_host_t *); | 40 | static int qla84xx_init_chip(scsi_qla_host_t *); |
41 | static int qla25xx_init_queues(struct qla_hw_data *); | 41 | static int qla25xx_init_queues(struct qla_hw_data *); |
42 | 42 | ||
43 | /* SRB Extensions ---------------------------------------------------------- */ | ||
44 | |||
45 | static void | ||
46 | qla2x00_ctx_sp_timeout(unsigned long __data) | ||
47 | { | ||
48 | srb_t *sp = (srb_t *)__data; | ||
49 | struct srb_ctx *ctx; | ||
50 | fc_port_t *fcport = sp->fcport; | ||
51 | struct qla_hw_data *ha = fcport->vha->hw; | ||
52 | struct req_que *req; | ||
53 | unsigned long flags; | ||
54 | |||
55 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
56 | req = ha->req_q_map[0]; | ||
57 | req->outstanding_cmds[sp->handle] = NULL; | ||
58 | ctx = sp->ctx; | ||
59 | ctx->timeout(sp); | ||
60 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
61 | |||
62 | ctx->free(sp); | ||
63 | } | ||
64 | |||
65 | static void | ||
66 | qla2x00_ctx_sp_free(srb_t *sp) | ||
67 | { | ||
68 | struct srb_ctx *ctx = sp->ctx; | ||
69 | |||
70 | kfree(ctx); | ||
71 | mempool_free(sp, sp->fcport->vha->hw->srb_mempool); | ||
72 | } | ||
73 | |||
74 | inline srb_t * | ||
75 | qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size, | ||
76 | unsigned long tmo) | ||
77 | { | ||
78 | srb_t *sp; | ||
79 | struct qla_hw_data *ha = vha->hw; | ||
80 | struct srb_ctx *ctx; | ||
81 | |||
82 | sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL); | ||
83 | if (!sp) | ||
84 | goto done; | ||
85 | ctx = kzalloc(size, GFP_KERNEL); | ||
86 | if (!ctx) { | ||
87 | mempool_free(sp, ha->srb_mempool); | ||
88 | goto done; | ||
89 | } | ||
90 | |||
91 | memset(sp, 0, sizeof(*sp)); | ||
92 | sp->fcport = fcport; | ||
93 | sp->ctx = ctx; | ||
94 | ctx->free = qla2x00_ctx_sp_free; | ||
95 | |||
96 | init_timer(&ctx->timer); | ||
97 | if (!tmo) | ||
98 | goto done; | ||
99 | ctx->timer.expires = jiffies + tmo * HZ; | ||
100 | ctx->timer.data = (unsigned long)sp; | ||
101 | ctx->timer.function = qla2x00_ctx_sp_timeout; | ||
102 | add_timer(&ctx->timer); | ||
103 | done: | ||
104 | return sp; | ||
105 | } | ||
106 | |||
107 | /* Asynchronous Login/Logout Routines -------------------------------------- */ | ||
108 | |||
109 | #define ELS_TMO_2_RATOV(ha) ((ha)->r_a_tov / 10 * 2) | ||
110 | |||
111 | static void | ||
112 | qla2x00_async_logio_timeout(srb_t *sp) | ||
113 | { | ||
114 | fc_port_t *fcport = sp->fcport; | ||
115 | struct srb_logio *lio = sp->ctx; | ||
116 | |||
117 | DEBUG2(printk(KERN_WARNING | ||
118 | "scsi(%ld:%x): Async-%s timeout.\n", | ||
119 | fcport->vha->host_no, sp->handle, | ||
120 | lio->ctx.type == SRB_LOGIN_CMD ? "login": "logout")); | ||
121 | |||
122 | if (lio->ctx.type == SRB_LOGIN_CMD) | ||
123 | qla2x00_post_async_logout_work(fcport->vha, fcport, NULL); | ||
124 | } | ||
125 | |||
126 | int | ||
127 | qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, | ||
128 | uint16_t *data) | ||
129 | { | ||
130 | struct qla_hw_data *ha = vha->hw; | ||
131 | srb_t *sp; | ||
132 | struct srb_logio *lio; | ||
133 | int rval; | ||
134 | |||
135 | rval = QLA_FUNCTION_FAILED; | ||
136 | sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio), | ||
137 | ELS_TMO_2_RATOV(ha) + 2); | ||
138 | if (!sp) | ||
139 | goto done; | ||
140 | |||
141 | lio = sp->ctx; | ||
142 | lio->ctx.type = SRB_LOGIN_CMD; | ||
143 | lio->ctx.timeout = qla2x00_async_logio_timeout; | ||
144 | lio->flags |= SRB_LOGIN_COND_PLOGI; | ||
145 | if (data[1] & QLA_LOGIO_LOGIN_RETRIED) | ||
146 | lio->flags |= SRB_LOGIN_RETRIED; | ||
147 | rval = qla2x00_start_sp(sp); | ||
148 | if (rval != QLA_SUCCESS) | ||
149 | goto done_free_sp; | ||
150 | |||
151 | DEBUG2(printk(KERN_DEBUG | ||
152 | "scsi(%ld:%x): Async-login - loop-id=%x portid=%02x%02x%02x " | ||
153 | "retries=%d.\n", fcport->vha->host_no, sp->handle, fcport->loop_id, | ||
154 | fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, | ||
155 | fcport->login_retry)); | ||
156 | return rval; | ||
157 | |||
158 | done_free_sp: | ||
159 | del_timer_sync(&lio->ctx.timer); | ||
160 | lio->ctx.free(sp); | ||
161 | done: | ||
162 | return rval; | ||
163 | } | ||
164 | |||
165 | int | ||
166 | qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport) | ||
167 | { | ||
168 | struct qla_hw_data *ha = vha->hw; | ||
169 | srb_t *sp; | ||
170 | struct srb_logio *lio; | ||
171 | int rval; | ||
172 | |||
173 | rval = QLA_FUNCTION_FAILED; | ||
174 | sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio), | ||
175 | ELS_TMO_2_RATOV(ha) + 2); | ||
176 | if (!sp) | ||
177 | goto done; | ||
178 | |||
179 | lio = sp->ctx; | ||
180 | lio->ctx.type = SRB_LOGOUT_CMD; | ||
181 | lio->ctx.timeout = qla2x00_async_logio_timeout; | ||
182 | rval = qla2x00_start_sp(sp); | ||
183 | if (rval != QLA_SUCCESS) | ||
184 | goto done_free_sp; | ||
185 | |||
186 | DEBUG2(printk(KERN_DEBUG | ||
187 | "scsi(%ld:%x): Async-logout - loop-id=%x portid=%02x%02x%02x.\n", | ||
188 | fcport->vha->host_no, sp->handle, fcport->loop_id, | ||
189 | fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa)); | ||
190 | return rval; | ||
191 | |||
192 | done_free_sp: | ||
193 | del_timer_sync(&lio->ctx.timer); | ||
194 | lio->ctx.free(sp); | ||
195 | done: | ||
196 | return rval; | ||
197 | } | ||
198 | |||
199 | int | ||
200 | qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, | ||
201 | uint16_t *data) | ||
202 | { | ||
203 | int rval; | ||
204 | uint8_t opts = 0; | ||
205 | |||
206 | switch (data[0]) { | ||
207 | case MBS_COMMAND_COMPLETE: | ||
208 | if (fcport->flags & FCF_TAPE_PRESENT) | ||
209 | opts |= BIT_1; | ||
210 | rval = qla2x00_get_port_database(vha, fcport, opts); | ||
211 | if (rval != QLA_SUCCESS) | ||
212 | qla2x00_mark_device_lost(vha, fcport, 1, 0); | ||
213 | else | ||
214 | qla2x00_update_fcport(vha, fcport); | ||
215 | break; | ||
216 | case MBS_COMMAND_ERROR: | ||
217 | if (data[1] & QLA_LOGIO_LOGIN_RETRIED) | ||
218 | set_bit(RELOGIN_NEEDED, &vha->dpc_flags); | ||
219 | else | ||
220 | qla2x00_mark_device_lost(vha, fcport, 1, 0); | ||
221 | break; | ||
222 | case MBS_PORT_ID_USED: | ||
223 | fcport->loop_id = data[1]; | ||
224 | qla2x00_post_async_login_work(vha, fcport, NULL); | ||
225 | break; | ||
226 | case MBS_LOOP_ID_USED: | ||
227 | fcport->loop_id++; | ||
228 | rval = qla2x00_find_new_loop_id(vha, fcport); | ||
229 | if (rval != QLA_SUCCESS) { | ||
230 | qla2x00_mark_device_lost(vha, fcport, 1, 0); | ||
231 | break; | ||
232 | } | ||
233 | qla2x00_post_async_login_work(vha, fcport, NULL); | ||
234 | break; | ||
235 | } | ||
236 | return QLA_SUCCESS; | ||
237 | } | ||
238 | |||
239 | int | ||
240 | qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport, | ||
241 | uint16_t *data) | ||
242 | { | ||
243 | qla2x00_mark_device_lost(vha, fcport, 1, 0); | ||
244 | return QLA_SUCCESS; | ||
245 | } | ||
246 | |||
43 | /****************************************************************************/ | 247 | /****************************************************************************/ |
44 | /* QLogic ISP2x00 Hardware Support Functions. */ | 248 | /* QLogic ISP2x00 Hardware Support Functions. */ |
45 | /****************************************************************************/ | 249 | /****************************************************************************/ |
@@ -1977,7 +2181,7 @@ qla2x00_rport_del(void *data) | |||
1977 | struct fc_rport *rport; | 2181 | struct fc_rport *rport; |
1978 | 2182 | ||
1979 | spin_lock_irq(fcport->vha->host->host_lock); | 2183 | spin_lock_irq(fcport->vha->host->host_lock); |
1980 | rport = fcport->drport; | 2184 | rport = fcport->drport ? fcport->drport: fcport->rport; |
1981 | fcport->drport = NULL; | 2185 | fcport->drport = NULL; |
1982 | spin_unlock_irq(fcport->vha->host->host_lock); | 2186 | spin_unlock_irq(fcport->vha->host->host_lock); |
1983 | if (rport) | 2187 | if (rport) |
@@ -2344,8 +2548,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) | |||
2344 | struct fc_rport *rport; | 2548 | struct fc_rport *rport; |
2345 | struct qla_hw_data *ha = vha->hw; | 2549 | struct qla_hw_data *ha = vha->hw; |
2346 | 2550 | ||
2347 | if (fcport->drport) | 2551 | qla2x00_rport_del(fcport); |
2348 | qla2x00_rport_del(fcport); | ||
2349 | 2552 | ||
2350 | rport_ids.node_name = wwn_to_u64(fcport->node_name); | 2553 | rport_ids.node_name = wwn_to_u64(fcport->node_name); |
2351 | rport_ids.port_name = wwn_to_u64(fcport->port_name); | 2554 | rport_ids.port_name = wwn_to_u64(fcport->port_name); |
@@ -3038,6 +3241,12 @@ qla2x00_fabric_dev_login(scsi_qla_host_t *vha, fc_port_t *fcport, | |||
3038 | rval = QLA_SUCCESS; | 3241 | rval = QLA_SUCCESS; |
3039 | retry = 0; | 3242 | retry = 0; |
3040 | 3243 | ||
3244 | if (IS_ALOGIO_CAPABLE(ha)) { | ||
3245 | rval = qla2x00_post_async_login_work(vha, fcport, NULL); | ||
3246 | if (!rval) | ||
3247 | return rval; | ||
3248 | } | ||
3249 | |||
3041 | rval = qla2x00_fabric_login(vha, fcport, next_loopid); | 3250 | rval = qla2x00_fabric_login(vha, fcport, next_loopid); |
3042 | if (rval == QLA_SUCCESS) { | 3251 | if (rval == QLA_SUCCESS) { |
3043 | /* Send an ADISC to tape devices.*/ | 3252 | /* Send an ADISC to tape devices.*/ |