diff options
Diffstat (limited to 'drivers/scsi/scsi_transport_iscsi.c')
-rw-r--r-- | drivers/scsi/scsi_transport_iscsi.c | 705 |
1 files changed, 500 insertions, 205 deletions
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 2730d507e585..5569fdcfd621 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c | |||
@@ -31,31 +31,26 @@ | |||
31 | #include <scsi/scsi_transport_iscsi.h> | 31 | #include <scsi/scsi_transport_iscsi.h> |
32 | #include <scsi/iscsi_if.h> | 32 | #include <scsi/iscsi_if.h> |
33 | 33 | ||
34 | #define ISCSI_SESSION_ATTRS 8 | 34 | #define ISCSI_SESSION_ATTRS 11 |
35 | #define ISCSI_CONN_ATTRS 6 | 35 | #define ISCSI_CONN_ATTRS 11 |
36 | #define ISCSI_HOST_ATTRS 0 | ||
36 | 37 | ||
37 | struct iscsi_internal { | 38 | struct iscsi_internal { |
39 | int daemon_pid; | ||
38 | struct scsi_transport_template t; | 40 | struct scsi_transport_template t; |
39 | struct iscsi_transport *iscsi_transport; | 41 | struct iscsi_transport *iscsi_transport; |
40 | struct list_head list; | 42 | struct list_head list; |
41 | /* | ||
42 | * based on transport capabilities, at register time we set these | ||
43 | * bits to tell the transport class it wants attributes displayed | ||
44 | * in sysfs or that it can support different iSCSI Data-Path | ||
45 | * capabilities | ||
46 | */ | ||
47 | uint32_t param_mask; | ||
48 | |||
49 | struct class_device cdev; | 43 | struct class_device cdev; |
50 | /* | 44 | |
51 | * We do not have any private or other attrs. | 45 | struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1]; |
52 | */ | ||
53 | struct transport_container conn_cont; | 46 | struct transport_container conn_cont; |
54 | struct class_device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1]; | 47 | struct class_device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1]; |
55 | struct transport_container session_cont; | 48 | struct transport_container session_cont; |
56 | struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1]; | 49 | struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1]; |
57 | }; | 50 | }; |
58 | 51 | ||
52 | static int iscsi_session_nr; /* sysfs session id for next new session */ | ||
53 | |||
59 | /* | 54 | /* |
60 | * list of registered transports and lock that must | 55 | * list of registered transports and lock that must |
61 | * be held while accessing list. The iscsi_transport_lock must | 56 | * be held while accessing list. The iscsi_transport_lock must |
@@ -120,6 +115,24 @@ static struct attribute_group iscsi_transport_group = { | |||
120 | .attrs = iscsi_transport_attrs, | 115 | .attrs = iscsi_transport_attrs, |
121 | }; | 116 | }; |
122 | 117 | ||
118 | static int iscsi_setup_host(struct transport_container *tc, struct device *dev, | ||
119 | struct class_device *cdev) | ||
120 | { | ||
121 | struct Scsi_Host *shost = dev_to_shost(dev); | ||
122 | struct iscsi_host *ihost = shost->shost_data; | ||
123 | |||
124 | memset(ihost, 0, sizeof(*ihost)); | ||
125 | INIT_LIST_HEAD(&ihost->sessions); | ||
126 | mutex_init(&ihost->mutex); | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static DECLARE_TRANSPORT_CLASS(iscsi_host_class, | ||
131 | "iscsi_host", | ||
132 | iscsi_setup_host, | ||
133 | NULL, | ||
134 | NULL); | ||
135 | |||
123 | static DECLARE_TRANSPORT_CLASS(iscsi_session_class, | 136 | static DECLARE_TRANSPORT_CLASS(iscsi_session_class, |
124 | "iscsi_session", | 137 | "iscsi_session", |
125 | NULL, | 138 | NULL, |
@@ -133,7 +146,6 @@ static DECLARE_TRANSPORT_CLASS(iscsi_connection_class, | |||
133 | NULL); | 146 | NULL); |
134 | 147 | ||
135 | static struct sock *nls; | 148 | static struct sock *nls; |
136 | static int daemon_pid; | ||
137 | static DEFINE_MUTEX(rx_queue_mutex); | 149 | static DEFINE_MUTEX(rx_queue_mutex); |
138 | 150 | ||
139 | struct mempool_zone { | 151 | struct mempool_zone { |
@@ -165,14 +177,23 @@ static DEFINE_SPINLOCK(sesslock); | |||
165 | static LIST_HEAD(connlist); | 177 | static LIST_HEAD(connlist); |
166 | static DEFINE_SPINLOCK(connlock); | 178 | static DEFINE_SPINLOCK(connlock); |
167 | 179 | ||
168 | static struct iscsi_cls_session *iscsi_session_lookup(uint64_t handle) | 180 | static uint32_t iscsi_conn_get_sid(struct iscsi_cls_conn *conn) |
181 | { | ||
182 | struct iscsi_cls_session *sess = iscsi_dev_to_session(conn->dev.parent); | ||
183 | return sess->sid; | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * Returns the matching session to a given sid | ||
188 | */ | ||
189 | static struct iscsi_cls_session *iscsi_session_lookup(uint32_t sid) | ||
169 | { | 190 | { |
170 | unsigned long flags; | 191 | unsigned long flags; |
171 | struct iscsi_cls_session *sess; | 192 | struct iscsi_cls_session *sess; |
172 | 193 | ||
173 | spin_lock_irqsave(&sesslock, flags); | 194 | spin_lock_irqsave(&sesslock, flags); |
174 | list_for_each_entry(sess, &sesslist, sess_list) { | 195 | list_for_each_entry(sess, &sesslist, sess_list) { |
175 | if (sess == iscsi_ptr(handle)) { | 196 | if (sess->sid == sid) { |
176 | spin_unlock_irqrestore(&sesslock, flags); | 197 | spin_unlock_irqrestore(&sesslock, flags); |
177 | return sess; | 198 | return sess; |
178 | } | 199 | } |
@@ -181,14 +202,17 @@ static struct iscsi_cls_session *iscsi_session_lookup(uint64_t handle) | |||
181 | return NULL; | 202 | return NULL; |
182 | } | 203 | } |
183 | 204 | ||
184 | static struct iscsi_cls_conn *iscsi_conn_lookup(uint64_t handle) | 205 | /* |
206 | * Returns the matching connection to a given sid / cid tuple | ||
207 | */ | ||
208 | static struct iscsi_cls_conn *iscsi_conn_lookup(uint32_t sid, uint32_t cid) | ||
185 | { | 209 | { |
186 | unsigned long flags; | 210 | unsigned long flags; |
187 | struct iscsi_cls_conn *conn; | 211 | struct iscsi_cls_conn *conn; |
188 | 212 | ||
189 | spin_lock_irqsave(&connlock, flags); | 213 | spin_lock_irqsave(&connlock, flags); |
190 | list_for_each_entry(conn, &connlist, conn_list) { | 214 | list_for_each_entry(conn, &connlist, conn_list) { |
191 | if (conn == iscsi_ptr(handle)) { | 215 | if ((conn->cid == cid) && (iscsi_conn_get_sid(conn) == sid)) { |
192 | spin_unlock_irqrestore(&connlock, flags); | 216 | spin_unlock_irqrestore(&connlock, flags); |
193 | return conn; | 217 | return conn; |
194 | } | 218 | } |
@@ -209,6 +233,7 @@ static void iscsi_session_release(struct device *dev) | |||
209 | 233 | ||
210 | shost = iscsi_session_to_shost(session); | 234 | shost = iscsi_session_to_shost(session); |
211 | scsi_host_put(shost); | 235 | scsi_host_put(shost); |
236 | kfree(session->targetname); | ||
212 | kfree(session); | 237 | kfree(session); |
213 | module_put(transport->owner); | 238 | module_put(transport->owner); |
214 | } | 239 | } |
@@ -218,30 +243,95 @@ static int iscsi_is_session_dev(const struct device *dev) | |||
218 | return dev->release == iscsi_session_release; | 243 | return dev->release == iscsi_session_release; |
219 | } | 244 | } |
220 | 245 | ||
246 | static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, | ||
247 | uint id, uint lun) | ||
248 | { | ||
249 | struct iscsi_host *ihost = shost->shost_data; | ||
250 | struct iscsi_cls_session *session; | ||
251 | |||
252 | mutex_lock(&ihost->mutex); | ||
253 | list_for_each_entry(session, &ihost->sessions, host_list) { | ||
254 | if ((channel == SCAN_WILD_CARD || | ||
255 | channel == session->channel) && | ||
256 | (id == SCAN_WILD_CARD || id == session->target_id)) | ||
257 | scsi_scan_target(&session->dev, session->channel, | ||
258 | session->target_id, lun, 1); | ||
259 | } | ||
260 | mutex_unlock(&ihost->mutex); | ||
261 | |||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static void session_recovery_timedout(void *data) | ||
266 | { | ||
267 | struct iscsi_cls_session *session = data; | ||
268 | |||
269 | dev_printk(KERN_INFO, &session->dev, "iscsi: session recovery timed " | ||
270 | "out after %d secs\n", session->recovery_tmo); | ||
271 | |||
272 | if (session->transport->session_recovery_timedout) | ||
273 | session->transport->session_recovery_timedout(session); | ||
274 | |||
275 | scsi_target_unblock(&session->dev); | ||
276 | } | ||
277 | |||
278 | void iscsi_unblock_session(struct iscsi_cls_session *session) | ||
279 | { | ||
280 | if (!cancel_delayed_work(&session->recovery_work)) | ||
281 | flush_scheduled_work(); | ||
282 | scsi_target_unblock(&session->dev); | ||
283 | } | ||
284 | EXPORT_SYMBOL_GPL(iscsi_unblock_session); | ||
285 | |||
286 | void iscsi_block_session(struct iscsi_cls_session *session) | ||
287 | { | ||
288 | scsi_target_block(&session->dev); | ||
289 | schedule_delayed_work(&session->recovery_work, | ||
290 | session->recovery_tmo * HZ); | ||
291 | } | ||
292 | EXPORT_SYMBOL_GPL(iscsi_block_session); | ||
293 | |||
221 | /** | 294 | /** |
222 | * iscsi_create_session - create iscsi class session | 295 | * iscsi_create_session - create iscsi class session |
223 | * @shost: scsi host | 296 | * @shost: scsi host |
224 | * @transport: iscsi transport | 297 | * @transport: iscsi transport |
225 | * | 298 | * |
226 | * This can be called from a LLD or iscsi_transport | 299 | * This can be called from a LLD or iscsi_transport. |
227 | **/ | 300 | **/ |
228 | struct iscsi_cls_session * | 301 | struct iscsi_cls_session * |
229 | iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport) | 302 | iscsi_create_session(struct Scsi_Host *shost, |
303 | struct iscsi_transport *transport, int channel) | ||
230 | { | 304 | { |
305 | struct iscsi_host *ihost; | ||
231 | struct iscsi_cls_session *session; | 306 | struct iscsi_cls_session *session; |
232 | int err; | 307 | int err; |
233 | 308 | ||
234 | if (!try_module_get(transport->owner)) | 309 | if (!try_module_get(transport->owner)) |
235 | return NULL; | 310 | return NULL; |
236 | 311 | ||
237 | session = kzalloc(sizeof(*session), GFP_KERNEL); | 312 | session = kzalloc(sizeof(*session) + transport->sessiondata_size, |
313 | GFP_KERNEL); | ||
238 | if (!session) | 314 | if (!session) |
239 | goto module_put; | 315 | goto module_put; |
240 | session->transport = transport; | 316 | session->transport = transport; |
317 | session->recovery_tmo = 120; | ||
318 | INIT_WORK(&session->recovery_work, session_recovery_timedout, session); | ||
319 | INIT_LIST_HEAD(&session->host_list); | ||
320 | INIT_LIST_HEAD(&session->sess_list); | ||
321 | |||
322 | if (transport->sessiondata_size) | ||
323 | session->dd_data = &session[1]; | ||
241 | 324 | ||
242 | /* this is released in the dev's release function */ | 325 | /* this is released in the dev's release function */ |
243 | scsi_host_get(shost); | 326 | scsi_host_get(shost); |
244 | snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", shost->host_no); | 327 | ihost = shost->shost_data; |
328 | |||
329 | session->sid = iscsi_session_nr++; | ||
330 | session->channel = channel; | ||
331 | session->target_id = ihost->next_target_id++; | ||
332 | |||
333 | snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", | ||
334 | session->sid); | ||
245 | session->dev.parent = &shost->shost_gendev; | 335 | session->dev.parent = &shost->shost_gendev; |
246 | session->dev.release = iscsi_session_release; | 336 | session->dev.release = iscsi_session_release; |
247 | err = device_register(&session->dev); | 337 | err = device_register(&session->dev); |
@@ -252,6 +342,10 @@ iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport) | |||
252 | } | 342 | } |
253 | transport_register_device(&session->dev); | 343 | transport_register_device(&session->dev); |
254 | 344 | ||
345 | mutex_lock(&ihost->mutex); | ||
346 | list_add(&session->host_list, &ihost->sessions); | ||
347 | mutex_unlock(&ihost->mutex); | ||
348 | |||
255 | return session; | 349 | return session; |
256 | 350 | ||
257 | free_session: | 351 | free_session: |
@@ -272,6 +366,16 @@ EXPORT_SYMBOL_GPL(iscsi_create_session); | |||
272 | **/ | 366 | **/ |
273 | int iscsi_destroy_session(struct iscsi_cls_session *session) | 367 | int iscsi_destroy_session(struct iscsi_cls_session *session) |
274 | { | 368 | { |
369 | struct Scsi_Host *shost = iscsi_session_to_shost(session); | ||
370 | struct iscsi_host *ihost = shost->shost_data; | ||
371 | |||
372 | if (!cancel_delayed_work(&session->recovery_work)) | ||
373 | flush_scheduled_work(); | ||
374 | |||
375 | mutex_lock(&ihost->mutex); | ||
376 | list_del(&session->host_list); | ||
377 | mutex_unlock(&ihost->mutex); | ||
378 | |||
275 | transport_unregister_device(&session->dev); | 379 | transport_unregister_device(&session->dev); |
276 | device_unregister(&session->dev); | 380 | device_unregister(&session->dev); |
277 | return 0; | 381 | return 0; |
@@ -284,6 +388,7 @@ static void iscsi_conn_release(struct device *dev) | |||
284 | struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev); | 388 | struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev); |
285 | struct device *parent = conn->dev.parent; | 389 | struct device *parent = conn->dev.parent; |
286 | 390 | ||
391 | kfree(conn->persistent_address); | ||
287 | kfree(conn); | 392 | kfree(conn); |
288 | put_device(parent); | 393 | put_device(parent); |
289 | } | 394 | } |
@@ -301,12 +406,16 @@ static int iscsi_is_conn_dev(const struct device *dev) | |||
301 | * This can be called from a LLD or iscsi_transport. The connection | 406 | * This can be called from a LLD or iscsi_transport. The connection |
302 | * is child of the session so cid must be unique for all connections | 407 | * is child of the session so cid must be unique for all connections |
303 | * on the session. | 408 | * on the session. |
409 | * | ||
410 | * Since we do not support MCS, cid will normally be zero. In some cases | ||
411 | * for software iscsi we could be trying to preallocate a connection struct | ||
412 | * in which case there could be two connection structs and cid would be | ||
413 | * non-zero. | ||
304 | **/ | 414 | **/ |
305 | struct iscsi_cls_conn * | 415 | struct iscsi_cls_conn * |
306 | iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) | 416 | iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) |
307 | { | 417 | { |
308 | struct iscsi_transport *transport = session->transport; | 418 | struct iscsi_transport *transport = session->transport; |
309 | struct Scsi_Host *shost = iscsi_session_to_shost(session); | ||
310 | struct iscsi_cls_conn *conn; | 419 | struct iscsi_cls_conn *conn; |
311 | int err; | 420 | int err; |
312 | 421 | ||
@@ -319,12 +428,14 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) | |||
319 | 428 | ||
320 | INIT_LIST_HEAD(&conn->conn_list); | 429 | INIT_LIST_HEAD(&conn->conn_list); |
321 | conn->transport = transport; | 430 | conn->transport = transport; |
431 | conn->cid = cid; | ||
322 | 432 | ||
323 | /* this is released in the dev's release function */ | 433 | /* this is released in the dev's release function */ |
324 | if (!get_device(&session->dev)) | 434 | if (!get_device(&session->dev)) |
325 | goto free_conn; | 435 | goto free_conn; |
436 | |||
326 | snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u", | 437 | snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u", |
327 | shost->host_no, cid); | 438 | session->sid, cid); |
328 | conn->dev.parent = &session->dev; | 439 | conn->dev.parent = &session->dev; |
329 | conn->dev.release = iscsi_conn_release; | 440 | conn->dev.release = iscsi_conn_release; |
330 | err = device_register(&conn->dev); | 441 | err = device_register(&conn->dev); |
@@ -361,105 +472,6 @@ int iscsi_destroy_conn(struct iscsi_cls_conn *conn) | |||
361 | EXPORT_SYMBOL_GPL(iscsi_destroy_conn); | 472 | EXPORT_SYMBOL_GPL(iscsi_destroy_conn); |
362 | 473 | ||
363 | /* | 474 | /* |
364 | * These functions are used only by software iscsi_transports | ||
365 | * which do not allocate and more their scsi_hosts since this | ||
366 | * is initiated from userspace. | ||
367 | */ | ||
368 | |||
369 | /* | ||
370 | * iSCSI Session's hostdata organization: | ||
371 | * | ||
372 | * *------------------* <== hostdata_session(host->hostdata) | ||
373 | * | ptr to class sess| | ||
374 | * |------------------| <== iscsi_hostdata(host->hostdata) | ||
375 | * | transport's data | | ||
376 | * *------------------* | ||
377 | */ | ||
378 | |||
379 | #define hostdata_privsize(_t) (sizeof(unsigned long) + _t->hostdata_size + \ | ||
380 | _t->hostdata_size % sizeof(unsigned long)) | ||
381 | |||
382 | #define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata)) | ||
383 | |||
384 | /** | ||
385 | * iscsi_transport_create_session - create iscsi cls session and host | ||
386 | * scsit: scsi transport template | ||
387 | * transport: iscsi transport template | ||
388 | * | ||
389 | * This can be used by software iscsi_transports that allocate | ||
390 | * a session per scsi host. | ||
391 | **/ | ||
392 | struct Scsi_Host * | ||
393 | iscsi_transport_create_session(struct scsi_transport_template *scsit, | ||
394 | struct iscsi_transport *transport) | ||
395 | { | ||
396 | struct iscsi_cls_session *session; | ||
397 | struct Scsi_Host *shost; | ||
398 | unsigned long flags; | ||
399 | |||
400 | shost = scsi_host_alloc(transport->host_template, | ||
401 | hostdata_privsize(transport)); | ||
402 | if (!shost) { | ||
403 | printk(KERN_ERR "iscsi: can not allocate SCSI host for " | ||
404 | "session\n"); | ||
405 | return NULL; | ||
406 | } | ||
407 | |||
408 | shost->max_id = 1; | ||
409 | shost->max_channel = 0; | ||
410 | shost->max_lun = transport->max_lun; | ||
411 | shost->max_cmd_len = transport->max_cmd_len; | ||
412 | shost->transportt = scsit; | ||
413 | shost->transportt->create_work_queue = 1; | ||
414 | |||
415 | if (scsi_add_host(shost, NULL)) | ||
416 | goto free_host; | ||
417 | |||
418 | session = iscsi_create_session(shost, transport); | ||
419 | if (!session) | ||
420 | goto remove_host; | ||
421 | |||
422 | *(unsigned long*)shost->hostdata = (unsigned long)session; | ||
423 | spin_lock_irqsave(&sesslock, flags); | ||
424 | list_add(&session->sess_list, &sesslist); | ||
425 | spin_unlock_irqrestore(&sesslock, flags); | ||
426 | return shost; | ||
427 | |||
428 | remove_host: | ||
429 | scsi_remove_host(shost); | ||
430 | free_host: | ||
431 | scsi_host_put(shost); | ||
432 | return NULL; | ||
433 | } | ||
434 | |||
435 | EXPORT_SYMBOL_GPL(iscsi_transport_create_session); | ||
436 | |||
437 | /** | ||
438 | * iscsi_transport_destroy_session - destroy session and scsi host | ||
439 | * shost: scsi host | ||
440 | * | ||
441 | * This can be used by software iscsi_transports that allocate | ||
442 | * a session per scsi host. | ||
443 | **/ | ||
444 | int iscsi_transport_destroy_session(struct Scsi_Host *shost) | ||
445 | { | ||
446 | struct iscsi_cls_session *session; | ||
447 | unsigned long flags; | ||
448 | |||
449 | scsi_remove_host(shost); | ||
450 | session = hostdata_session(shost->hostdata); | ||
451 | spin_lock_irqsave(&sesslock, flags); | ||
452 | list_del(&session->sess_list); | ||
453 | spin_unlock_irqrestore(&sesslock, flags); | ||
454 | iscsi_destroy_session(session); | ||
455 | /* ref from host alloc */ | ||
456 | scsi_host_put(shost); | ||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | EXPORT_SYMBOL_GPL(iscsi_transport_destroy_session); | ||
461 | |||
462 | /* | ||
463 | * iscsi interface functions | 475 | * iscsi interface functions |
464 | */ | 476 | */ |
465 | static struct iscsi_internal * | 477 | static struct iscsi_internal * |
@@ -560,13 +572,13 @@ mempool_zone_get_skb(struct mempool_zone *zone) | |||
560 | } | 572 | } |
561 | 573 | ||
562 | static int | 574 | static int |
563 | iscsi_unicast_skb(struct mempool_zone *zone, struct sk_buff *skb) | 575 | iscsi_unicast_skb(struct mempool_zone *zone, struct sk_buff *skb, int pid) |
564 | { | 576 | { |
565 | unsigned long flags; | 577 | unsigned long flags; |
566 | int rc; | 578 | int rc; |
567 | 579 | ||
568 | skb_get(skb); | 580 | skb_get(skb); |
569 | rc = netlink_unicast(nls, skb, daemon_pid, MSG_DONTWAIT); | 581 | rc = netlink_unicast(nls, skb, pid, MSG_DONTWAIT); |
570 | if (rc < 0) { | 582 | if (rc < 0) { |
571 | mempool_free(skb, zone->pool); | 583 | mempool_free(skb, zone->pool); |
572 | printk(KERN_ERR "iscsi: can not unicast skb (%d)\n", rc); | 584 | printk(KERN_ERR "iscsi: can not unicast skb (%d)\n", rc); |
@@ -574,6 +586,7 @@ iscsi_unicast_skb(struct mempool_zone *zone, struct sk_buff *skb) | |||
574 | } | 586 | } |
575 | 587 | ||
576 | spin_lock_irqsave(&zone->freelock, flags); | 588 | spin_lock_irqsave(&zone->freelock, flags); |
589 | INIT_LIST_HEAD(skb_to_lh(skb)); | ||
577 | list_add(skb_to_lh(skb), &zone->freequeue); | 590 | list_add(skb_to_lh(skb), &zone->freequeue); |
578 | spin_unlock_irqrestore(&zone->freelock, flags); | 591 | spin_unlock_irqrestore(&zone->freelock, flags); |
579 | 592 | ||
@@ -587,9 +600,14 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, | |||
587 | struct sk_buff *skb; | 600 | struct sk_buff *skb; |
588 | struct iscsi_uevent *ev; | 601 | struct iscsi_uevent *ev; |
589 | char *pdu; | 602 | char *pdu; |
603 | struct iscsi_internal *priv; | ||
590 | int len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct iscsi_hdr) + | 604 | int len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct iscsi_hdr) + |
591 | data_size); | 605 | data_size); |
592 | 606 | ||
607 | priv = iscsi_if_transport_lookup(conn->transport); | ||
608 | if (!priv) | ||
609 | return -EINVAL; | ||
610 | |||
593 | mempool_zone_complete(conn->z_pdu); | 611 | mempool_zone_complete(conn->z_pdu); |
594 | 612 | ||
595 | skb = mempool_zone_get_skb(conn->z_pdu); | 613 | skb = mempool_zone_get_skb(conn->z_pdu); |
@@ -600,19 +618,20 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, | |||
600 | return -ENOMEM; | 618 | return -ENOMEM; |
601 | } | 619 | } |
602 | 620 | ||
603 | nlh = __nlmsg_put(skb, daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); | 621 | nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); |
604 | ev = NLMSG_DATA(nlh); | 622 | ev = NLMSG_DATA(nlh); |
605 | memset(ev, 0, sizeof(*ev)); | 623 | memset(ev, 0, sizeof(*ev)); |
606 | ev->transport_handle = iscsi_handle(conn->transport); | 624 | ev->transport_handle = iscsi_handle(conn->transport); |
607 | ev->type = ISCSI_KEVENT_RECV_PDU; | 625 | ev->type = ISCSI_KEVENT_RECV_PDU; |
608 | if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat) | 626 | if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat) |
609 | ev->iferror = -ENOMEM; | 627 | ev->iferror = -ENOMEM; |
610 | ev->r.recv_req.conn_handle = iscsi_handle(conn); | 628 | ev->r.recv_req.cid = conn->cid; |
629 | ev->r.recv_req.sid = iscsi_conn_get_sid(conn); | ||
611 | pdu = (char*)ev + sizeof(*ev); | 630 | pdu = (char*)ev + sizeof(*ev); |
612 | memcpy(pdu, hdr, sizeof(struct iscsi_hdr)); | 631 | memcpy(pdu, hdr, sizeof(struct iscsi_hdr)); |
613 | memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size); | 632 | memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size); |
614 | 633 | ||
615 | return iscsi_unicast_skb(conn->z_pdu, skb); | 634 | return iscsi_unicast_skb(conn->z_pdu, skb, priv->daemon_pid); |
616 | } | 635 | } |
617 | EXPORT_SYMBOL_GPL(iscsi_recv_pdu); | 636 | EXPORT_SYMBOL_GPL(iscsi_recv_pdu); |
618 | 637 | ||
@@ -621,8 +640,13 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) | |||
621 | struct nlmsghdr *nlh; | 640 | struct nlmsghdr *nlh; |
622 | struct sk_buff *skb; | 641 | struct sk_buff *skb; |
623 | struct iscsi_uevent *ev; | 642 | struct iscsi_uevent *ev; |
643 | struct iscsi_internal *priv; | ||
624 | int len = NLMSG_SPACE(sizeof(*ev)); | 644 | int len = NLMSG_SPACE(sizeof(*ev)); |
625 | 645 | ||
646 | priv = iscsi_if_transport_lookup(conn->transport); | ||
647 | if (!priv) | ||
648 | return; | ||
649 | |||
626 | mempool_zone_complete(conn->z_error); | 650 | mempool_zone_complete(conn->z_error); |
627 | 651 | ||
628 | skb = mempool_zone_get_skb(conn->z_error); | 652 | skb = mempool_zone_get_skb(conn->z_error); |
@@ -632,16 +656,17 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) | |||
632 | return; | 656 | return; |
633 | } | 657 | } |
634 | 658 | ||
635 | nlh = __nlmsg_put(skb, daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); | 659 | nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); |
636 | ev = NLMSG_DATA(nlh); | 660 | ev = NLMSG_DATA(nlh); |
637 | ev->transport_handle = iscsi_handle(conn->transport); | 661 | ev->transport_handle = iscsi_handle(conn->transport); |
638 | ev->type = ISCSI_KEVENT_CONN_ERROR; | 662 | ev->type = ISCSI_KEVENT_CONN_ERROR; |
639 | if (atomic_read(&conn->z_error->allocated) >= conn->z_error->hiwat) | 663 | if (atomic_read(&conn->z_error->allocated) >= conn->z_error->hiwat) |
640 | ev->iferror = -ENOMEM; | 664 | ev->iferror = -ENOMEM; |
641 | ev->r.connerror.error = error; | 665 | ev->r.connerror.error = error; |
642 | ev->r.connerror.conn_handle = iscsi_handle(conn); | 666 | ev->r.connerror.cid = conn->cid; |
667 | ev->r.connerror.sid = iscsi_conn_get_sid(conn); | ||
643 | 668 | ||
644 | iscsi_unicast_skb(conn->z_error, skb); | 669 | iscsi_unicast_skb(conn->z_error, skb, priv->daemon_pid); |
645 | 670 | ||
646 | dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n", | 671 | dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n", |
647 | error); | 672 | error); |
@@ -671,7 +696,7 @@ iscsi_if_send_reply(int pid, int seq, int type, int done, int multi, | |||
671 | nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0); | 696 | nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0); |
672 | nlh->nlmsg_flags = flags; | 697 | nlh->nlmsg_flags = flags; |
673 | memcpy(NLMSG_DATA(nlh), payload, size); | 698 | memcpy(NLMSG_DATA(nlh), payload, size); |
674 | return iscsi_unicast_skb(z_reply, skb); | 699 | return iscsi_unicast_skb(z_reply, skb, pid); |
675 | } | 700 | } |
676 | 701 | ||
677 | static int | 702 | static int |
@@ -683,13 +708,18 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) | |||
683 | struct iscsi_cls_conn *conn; | 708 | struct iscsi_cls_conn *conn; |
684 | struct nlmsghdr *nlhstat; | 709 | struct nlmsghdr *nlhstat; |
685 | struct iscsi_uevent *evstat; | 710 | struct iscsi_uevent *evstat; |
711 | struct iscsi_internal *priv; | ||
686 | int len = NLMSG_SPACE(sizeof(*ev) + | 712 | int len = NLMSG_SPACE(sizeof(*ev) + |
687 | sizeof(struct iscsi_stats) + | 713 | sizeof(struct iscsi_stats) + |
688 | sizeof(struct iscsi_stats_custom) * | 714 | sizeof(struct iscsi_stats_custom) * |
689 | ISCSI_STATS_CUSTOM_MAX); | 715 | ISCSI_STATS_CUSTOM_MAX); |
690 | int err = 0; | 716 | int err = 0; |
691 | 717 | ||
692 | conn = iscsi_conn_lookup(ev->u.get_stats.conn_handle); | 718 | priv = iscsi_if_transport_lookup(transport); |
719 | if (!priv) | ||
720 | return -EINVAL; | ||
721 | |||
722 | conn = iscsi_conn_lookup(ev->u.get_stats.sid, ev->u.get_stats.cid); | ||
693 | if (!conn) | 723 | if (!conn) |
694 | return -EEXIST; | 724 | return -EEXIST; |
695 | 725 | ||
@@ -705,7 +735,7 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) | |||
705 | return -ENOMEM; | 735 | return -ENOMEM; |
706 | } | 736 | } |
707 | 737 | ||
708 | nlhstat = __nlmsg_put(skbstat, daemon_pid, 0, 0, | 738 | nlhstat = __nlmsg_put(skbstat, priv->daemon_pid, 0, 0, |
709 | (len - sizeof(*nlhstat)), 0); | 739 | (len - sizeof(*nlhstat)), 0); |
710 | evstat = NLMSG_DATA(nlhstat); | 740 | evstat = NLMSG_DATA(nlhstat); |
711 | memset(evstat, 0, sizeof(*evstat)); | 741 | memset(evstat, 0, sizeof(*evstat)); |
@@ -713,8 +743,10 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) | |||
713 | evstat->type = nlh->nlmsg_type; | 743 | evstat->type = nlh->nlmsg_type; |
714 | if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat) | 744 | if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat) |
715 | evstat->iferror = -ENOMEM; | 745 | evstat->iferror = -ENOMEM; |
716 | evstat->u.get_stats.conn_handle = | 746 | evstat->u.get_stats.cid = |
717 | ev->u.get_stats.conn_handle; | 747 | ev->u.get_stats.cid; |
748 | evstat->u.get_stats.sid = | ||
749 | ev->u.get_stats.sid; | ||
718 | stats = (struct iscsi_stats *) | 750 | stats = (struct iscsi_stats *) |
719 | ((char*)evstat + sizeof(*evstat)); | 751 | ((char*)evstat + sizeof(*evstat)); |
720 | memset(stats, 0, sizeof(*stats)); | 752 | memset(stats, 0, sizeof(*stats)); |
@@ -729,7 +761,7 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) | |||
729 | skb_trim(skbstat, NLMSG_ALIGN(actual_size)); | 761 | skb_trim(skbstat, NLMSG_ALIGN(actual_size)); |
730 | nlhstat->nlmsg_len = actual_size; | 762 | nlhstat->nlmsg_len = actual_size; |
731 | 763 | ||
732 | err = iscsi_unicast_skb(conn->z_pdu, skbstat); | 764 | err = iscsi_unicast_skb(conn->z_pdu, skbstat, priv->daemon_pid); |
733 | } while (err < 0 && err != -ECONNREFUSED); | 765 | } while (err < 0 && err != -ECONNREFUSED); |
734 | 766 | ||
735 | return err; | 767 | return err; |
@@ -740,16 +772,21 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) | |||
740 | { | 772 | { |
741 | struct iscsi_transport *transport = priv->iscsi_transport; | 773 | struct iscsi_transport *transport = priv->iscsi_transport; |
742 | struct iscsi_cls_session *session; | 774 | struct iscsi_cls_session *session; |
743 | uint32_t sid; | 775 | unsigned long flags; |
776 | uint32_t hostno; | ||
744 | 777 | ||
745 | session = transport->create_session(&priv->t, | 778 | session = transport->create_session(transport, &priv->t, |
746 | ev->u.c_session.initial_cmdsn, | 779 | ev->u.c_session.initial_cmdsn, |
747 | &sid); | 780 | &hostno); |
748 | if (!session) | 781 | if (!session) |
749 | return -ENOMEM; | 782 | return -ENOMEM; |
750 | 783 | ||
751 | ev->r.c_session_ret.session_handle = iscsi_handle(session); | 784 | spin_lock_irqsave(&sesslock, flags); |
752 | ev->r.c_session_ret.sid = sid; | 785 | list_add(&session->sess_list, &sesslist); |
786 | spin_unlock_irqrestore(&sesslock, flags); | ||
787 | |||
788 | ev->r.c_session_ret.host_no = hostno; | ||
789 | ev->r.c_session_ret.sid = session->sid; | ||
753 | return 0; | 790 | return 0; |
754 | } | 791 | } |
755 | 792 | ||
@@ -760,13 +797,20 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) | |||
760 | struct iscsi_cls_session *session; | 797 | struct iscsi_cls_session *session; |
761 | unsigned long flags; | 798 | unsigned long flags; |
762 | 799 | ||
763 | session = iscsi_session_lookup(ev->u.c_conn.session_handle); | 800 | session = iscsi_session_lookup(ev->u.c_conn.sid); |
764 | if (!session) | 801 | if (!session) { |
802 | printk(KERN_ERR "iscsi: invalid session %d\n", | ||
803 | ev->u.c_conn.sid); | ||
765 | return -EINVAL; | 804 | return -EINVAL; |
805 | } | ||
766 | 806 | ||
767 | conn = transport->create_conn(session, ev->u.c_conn.cid); | 807 | conn = transport->create_conn(session, ev->u.c_conn.cid); |
768 | if (!conn) | 808 | if (!conn) { |
809 | printk(KERN_ERR "iscsi: couldn't create a new " | ||
810 | "connection for session %d\n", | ||
811 | session->sid); | ||
769 | return -ENOMEM; | 812 | return -ENOMEM; |
813 | } | ||
770 | 814 | ||
771 | conn->z_pdu = mempool_zone_init(Z_MAX_PDU, | 815 | conn->z_pdu = mempool_zone_init(Z_MAX_PDU, |
772 | NLMSG_SPACE(sizeof(struct iscsi_uevent) + | 816 | NLMSG_SPACE(sizeof(struct iscsi_uevent) + |
@@ -788,7 +832,8 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) | |||
788 | goto free_pdu_pool; | 832 | goto free_pdu_pool; |
789 | } | 833 | } |
790 | 834 | ||
791 | ev->r.handle = iscsi_handle(conn); | 835 | ev->r.c_conn_ret.sid = session->sid; |
836 | ev->r.c_conn_ret.cid = conn->cid; | ||
792 | 837 | ||
793 | spin_lock_irqsave(&connlock, flags); | 838 | spin_lock_irqsave(&connlock, flags); |
794 | list_add(&conn->conn_list, &connlist); | 839 | list_add(&conn->conn_list, &connlist); |
@@ -812,7 +857,7 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev | |||
812 | struct iscsi_cls_conn *conn; | 857 | struct iscsi_cls_conn *conn; |
813 | struct mempool_zone *z_error, *z_pdu; | 858 | struct mempool_zone *z_error, *z_pdu; |
814 | 859 | ||
815 | conn = iscsi_conn_lookup(ev->u.d_conn.conn_handle); | 860 | conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid); |
816 | if (!conn) | 861 | if (!conn) |
817 | return -EINVAL; | 862 | return -EINVAL; |
818 | spin_lock_irqsave(&connlock, flags); | 863 | spin_lock_irqsave(&connlock, flags); |
@@ -832,6 +877,106 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev | |||
832 | return 0; | 877 | return 0; |
833 | } | 878 | } |
834 | 879 | ||
880 | static void | ||
881 | iscsi_copy_param(struct iscsi_uevent *ev, uint32_t *value, char *data) | ||
882 | { | ||
883 | if (ev->u.set_param.len != sizeof(uint32_t)) | ||
884 | BUG(); | ||
885 | memcpy(value, data, min_t(uint32_t, sizeof(uint32_t), | ||
886 | ev->u.set_param.len)); | ||
887 | } | ||
888 | |||
889 | static int | ||
890 | iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) | ||
891 | { | ||
892 | char *data = (char*)ev + sizeof(*ev); | ||
893 | struct iscsi_cls_conn *conn; | ||
894 | struct iscsi_cls_session *session; | ||
895 | int err = 0; | ||
896 | uint32_t value = 0; | ||
897 | |||
898 | session = iscsi_session_lookup(ev->u.set_param.sid); | ||
899 | conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid); | ||
900 | if (!conn || !session) | ||
901 | return -EINVAL; | ||
902 | |||
903 | switch (ev->u.set_param.param) { | ||
904 | case ISCSI_PARAM_SESS_RECOVERY_TMO: | ||
905 | iscsi_copy_param(ev, &value, data); | ||
906 | if (value != 0) | ||
907 | session->recovery_tmo = value; | ||
908 | break; | ||
909 | case ISCSI_PARAM_TARGET_NAME: | ||
910 | /* this should not change between logins */ | ||
911 | if (session->targetname) | ||
912 | return 0; | ||
913 | |||
914 | session->targetname = kstrdup(data, GFP_KERNEL); | ||
915 | if (!session->targetname) | ||
916 | return -ENOMEM; | ||
917 | break; | ||
918 | case ISCSI_PARAM_TPGT: | ||
919 | iscsi_copy_param(ev, &value, data); | ||
920 | session->tpgt = value; | ||
921 | break; | ||
922 | case ISCSI_PARAM_PERSISTENT_PORT: | ||
923 | iscsi_copy_param(ev, &value, data); | ||
924 | conn->persistent_port = value; | ||
925 | break; | ||
926 | case ISCSI_PARAM_PERSISTENT_ADDRESS: | ||
927 | /* | ||
928 | * this is the address returned in discovery so it should | ||
929 | * not change between logins. | ||
930 | */ | ||
931 | if (conn->persistent_address) | ||
932 | return 0; | ||
933 | |||
934 | conn->persistent_address = kstrdup(data, GFP_KERNEL); | ||
935 | if (!conn->persistent_address) | ||
936 | return -ENOMEM; | ||
937 | break; | ||
938 | default: | ||
939 | iscsi_copy_param(ev, &value, data); | ||
940 | err = transport->set_param(conn, ev->u.set_param.param, value); | ||
941 | } | ||
942 | |||
943 | return err; | ||
944 | } | ||
945 | |||
946 | static int | ||
947 | iscsi_if_transport_ep(struct iscsi_transport *transport, | ||
948 | struct iscsi_uevent *ev, int msg_type) | ||
949 | { | ||
950 | struct sockaddr *dst_addr; | ||
951 | int rc = 0; | ||
952 | |||
953 | switch (msg_type) { | ||
954 | case ISCSI_UEVENT_TRANSPORT_EP_CONNECT: | ||
955 | if (!transport->ep_connect) | ||
956 | return -EINVAL; | ||
957 | |||
958 | dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev)); | ||
959 | rc = transport->ep_connect(dst_addr, | ||
960 | ev->u.ep_connect.non_blocking, | ||
961 | &ev->r.ep_connect_ret.handle); | ||
962 | break; | ||
963 | case ISCSI_UEVENT_TRANSPORT_EP_POLL: | ||
964 | if (!transport->ep_poll) | ||
965 | return -EINVAL; | ||
966 | |||
967 | ev->r.retcode = transport->ep_poll(ev->u.ep_poll.ep_handle, | ||
968 | ev->u.ep_poll.timeout_ms); | ||
969 | break; | ||
970 | case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: | ||
971 | if (!transport->ep_disconnect) | ||
972 | return -EINVAL; | ||
973 | |||
974 | transport->ep_disconnect(ev->u.ep_disconnect.ep_handle); | ||
975 | break; | ||
976 | } | ||
977 | return rc; | ||
978 | } | ||
979 | |||
835 | static int | 980 | static int |
836 | iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | 981 | iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
837 | { | 982 | { |
@@ -841,6 +986,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
841 | struct iscsi_internal *priv; | 986 | struct iscsi_internal *priv; |
842 | struct iscsi_cls_session *session; | 987 | struct iscsi_cls_session *session; |
843 | struct iscsi_cls_conn *conn; | 988 | struct iscsi_cls_conn *conn; |
989 | unsigned long flags; | ||
844 | 990 | ||
845 | priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle)); | 991 | priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle)); |
846 | if (!priv) | 992 | if (!priv) |
@@ -850,15 +996,21 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
850 | if (!try_module_get(transport->owner)) | 996 | if (!try_module_get(transport->owner)) |
851 | return -EINVAL; | 997 | return -EINVAL; |
852 | 998 | ||
999 | priv->daemon_pid = NETLINK_CREDS(skb)->pid; | ||
1000 | |||
853 | switch (nlh->nlmsg_type) { | 1001 | switch (nlh->nlmsg_type) { |
854 | case ISCSI_UEVENT_CREATE_SESSION: | 1002 | case ISCSI_UEVENT_CREATE_SESSION: |
855 | err = iscsi_if_create_session(priv, ev); | 1003 | err = iscsi_if_create_session(priv, ev); |
856 | break; | 1004 | break; |
857 | case ISCSI_UEVENT_DESTROY_SESSION: | 1005 | case ISCSI_UEVENT_DESTROY_SESSION: |
858 | session = iscsi_session_lookup(ev->u.d_session.session_handle); | 1006 | session = iscsi_session_lookup(ev->u.d_session.sid); |
859 | if (session) | 1007 | if (session) { |
1008 | spin_lock_irqsave(&sesslock, flags); | ||
1009 | list_del(&session->sess_list); | ||
1010 | spin_unlock_irqrestore(&sesslock, flags); | ||
1011 | |||
860 | transport->destroy_session(session); | 1012 | transport->destroy_session(session); |
861 | else | 1013 | } else |
862 | err = -EINVAL; | 1014 | err = -EINVAL; |
863 | break; | 1015 | break; |
864 | case ISCSI_UEVENT_CREATE_CONN: | 1016 | case ISCSI_UEVENT_CREATE_CONN: |
@@ -868,41 +1020,35 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
868 | err = iscsi_if_destroy_conn(transport, ev); | 1020 | err = iscsi_if_destroy_conn(transport, ev); |
869 | break; | 1021 | break; |
870 | case ISCSI_UEVENT_BIND_CONN: | 1022 | case ISCSI_UEVENT_BIND_CONN: |
871 | session = iscsi_session_lookup(ev->u.b_conn.session_handle); | 1023 | session = iscsi_session_lookup(ev->u.b_conn.sid); |
872 | conn = iscsi_conn_lookup(ev->u.b_conn.conn_handle); | 1024 | conn = iscsi_conn_lookup(ev->u.b_conn.sid, ev->u.b_conn.cid); |
873 | 1025 | ||
874 | if (session && conn) | 1026 | if (session && conn) |
875 | ev->r.retcode = transport->bind_conn(session, conn, | 1027 | ev->r.retcode = transport->bind_conn(session, conn, |
876 | ev->u.b_conn.transport_fd, | 1028 | ev->u.b_conn.transport_eph, |
877 | ev->u.b_conn.is_leading); | 1029 | ev->u.b_conn.is_leading); |
878 | else | 1030 | else |
879 | err = -EINVAL; | 1031 | err = -EINVAL; |
880 | break; | 1032 | break; |
881 | case ISCSI_UEVENT_SET_PARAM: | 1033 | case ISCSI_UEVENT_SET_PARAM: |
882 | conn = iscsi_conn_lookup(ev->u.set_param.conn_handle); | 1034 | err = iscsi_set_param(transport, ev); |
883 | if (conn) | ||
884 | ev->r.retcode = transport->set_param(conn, | ||
885 | ev->u.set_param.param, ev->u.set_param.value); | ||
886 | else | ||
887 | err = -EINVAL; | ||
888 | break; | 1035 | break; |
889 | case ISCSI_UEVENT_START_CONN: | 1036 | case ISCSI_UEVENT_START_CONN: |
890 | conn = iscsi_conn_lookup(ev->u.start_conn.conn_handle); | 1037 | conn = iscsi_conn_lookup(ev->u.start_conn.sid, ev->u.start_conn.cid); |
891 | if (conn) | 1038 | if (conn) |
892 | ev->r.retcode = transport->start_conn(conn); | 1039 | ev->r.retcode = transport->start_conn(conn); |
893 | else | 1040 | else |
894 | err = -EINVAL; | 1041 | err = -EINVAL; |
895 | |||
896 | break; | 1042 | break; |
897 | case ISCSI_UEVENT_STOP_CONN: | 1043 | case ISCSI_UEVENT_STOP_CONN: |
898 | conn = iscsi_conn_lookup(ev->u.stop_conn.conn_handle); | 1044 | conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid); |
899 | if (conn) | 1045 | if (conn) |
900 | transport->stop_conn(conn, ev->u.stop_conn.flag); | 1046 | transport->stop_conn(conn, ev->u.stop_conn.flag); |
901 | else | 1047 | else |
902 | err = -EINVAL; | 1048 | err = -EINVAL; |
903 | break; | 1049 | break; |
904 | case ISCSI_UEVENT_SEND_PDU: | 1050 | case ISCSI_UEVENT_SEND_PDU: |
905 | conn = iscsi_conn_lookup(ev->u.send_pdu.conn_handle); | 1051 | conn = iscsi_conn_lookup(ev->u.send_pdu.sid, ev->u.send_pdu.cid); |
906 | if (conn) | 1052 | if (conn) |
907 | ev->r.retcode = transport->send_pdu(conn, | 1053 | ev->r.retcode = transport->send_pdu(conn, |
908 | (struct iscsi_hdr*)((char*)ev + sizeof(*ev)), | 1054 | (struct iscsi_hdr*)((char*)ev + sizeof(*ev)), |
@@ -914,6 +1060,11 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
914 | case ISCSI_UEVENT_GET_STATS: | 1060 | case ISCSI_UEVENT_GET_STATS: |
915 | err = iscsi_if_get_stats(transport, nlh); | 1061 | err = iscsi_if_get_stats(transport, nlh); |
916 | break; | 1062 | break; |
1063 | case ISCSI_UEVENT_TRANSPORT_EP_CONNECT: | ||
1064 | case ISCSI_UEVENT_TRANSPORT_EP_POLL: | ||
1065 | case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: | ||
1066 | err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type); | ||
1067 | break; | ||
917 | default: | 1068 | default: |
918 | err = -EINVAL; | 1069 | err = -EINVAL; |
919 | break; | 1070 | break; |
@@ -923,9 +1074,11 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
923 | return err; | 1074 | return err; |
924 | } | 1075 | } |
925 | 1076 | ||
926 | /* Get message from skb (based on rtnetlink_rcv_skb). Each message is | 1077 | /* |
927 | * processed by iscsi_if_recv_msg. Malformed skbs with wrong length are | 1078 | * Get message from skb (based on rtnetlink_rcv_skb). Each message is |
928 | * or invalid creds discarded silently. */ | 1079 | * processed by iscsi_if_recv_msg. Malformed skbs with wrong lengths or |
1080 | * invalid creds are discarded silently. | ||
1081 | */ | ||
929 | static void | 1082 | static void |
930 | iscsi_if_rx(struct sock *sk, int len) | 1083 | iscsi_if_rx(struct sock *sk, int len) |
931 | { | 1084 | { |
@@ -937,7 +1090,6 @@ iscsi_if_rx(struct sock *sk, int len) | |||
937 | skb_pull(skb, skb->len); | 1090 | skb_pull(skb, skb->len); |
938 | goto free_skb; | 1091 | goto free_skb; |
939 | } | 1092 | } |
940 | daemon_pid = NETLINK_CREDS(skb)->pid; | ||
941 | 1093 | ||
942 | while (skb->len >= NLMSG_SPACE(0)) { | 1094 | while (skb->len >= NLMSG_SPACE(0)) { |
943 | int err; | 1095 | int err; |
@@ -988,6 +1140,10 @@ free_skb: | |||
988 | #define iscsi_cdev_to_conn(_cdev) \ | 1140 | #define iscsi_cdev_to_conn(_cdev) \ |
989 | iscsi_dev_to_conn(_cdev->dev) | 1141 | iscsi_dev_to_conn(_cdev->dev) |
990 | 1142 | ||
1143 | #define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store) \ | ||
1144 | struct class_device_attribute class_device_attr_##_prefix##_##_name = \ | ||
1145 | __ATTR(_name,_mode,_show,_store) | ||
1146 | |||
991 | /* | 1147 | /* |
992 | * iSCSI connection attrs | 1148 | * iSCSI connection attrs |
993 | */ | 1149 | */ |
@@ -1005,7 +1161,8 @@ show_conn_int_param_##param(struct class_device *cdev, char *buf) \ | |||
1005 | 1161 | ||
1006 | #define iscsi_conn_int_attr(field, param, format) \ | 1162 | #define iscsi_conn_int_attr(field, param, format) \ |
1007 | iscsi_conn_int_attr_show(param, format) \ | 1163 | iscsi_conn_int_attr_show(param, format) \ |
1008 | static CLASS_DEVICE_ATTR(field, S_IRUGO, show_conn_int_param_##param, NULL); | 1164 | static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_int_param_##param, \ |
1165 | NULL); | ||
1009 | 1166 | ||
1010 | iscsi_conn_int_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH, "%u"); | 1167 | iscsi_conn_int_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH, "%u"); |
1011 | iscsi_conn_int_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH, "%u"); | 1168 | iscsi_conn_int_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH, "%u"); |
@@ -1013,6 +1170,26 @@ iscsi_conn_int_attr(header_digest, ISCSI_PARAM_HDRDGST_EN, "%d"); | |||
1013 | iscsi_conn_int_attr(data_digest, ISCSI_PARAM_DATADGST_EN, "%d"); | 1170 | iscsi_conn_int_attr(data_digest, ISCSI_PARAM_DATADGST_EN, "%d"); |
1014 | iscsi_conn_int_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN, "%d"); | 1171 | iscsi_conn_int_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN, "%d"); |
1015 | iscsi_conn_int_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN, "%d"); | 1172 | iscsi_conn_int_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN, "%d"); |
1173 | iscsi_conn_int_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT, "%d"); | ||
1174 | iscsi_conn_int_attr(port, ISCSI_PARAM_CONN_PORT, "%d"); | ||
1175 | iscsi_conn_int_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN, "%u"); | ||
1176 | |||
1177 | #define iscsi_conn_str_attr_show(param) \ | ||
1178 | static ssize_t \ | ||
1179 | show_conn_str_param_##param(struct class_device *cdev, char *buf) \ | ||
1180 | { \ | ||
1181 | struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \ | ||
1182 | struct iscsi_transport *t = conn->transport; \ | ||
1183 | return t->get_conn_str_param(conn, param, buf); \ | ||
1184 | } | ||
1185 | |||
1186 | #define iscsi_conn_str_attr(field, param) \ | ||
1187 | iscsi_conn_str_attr_show(param) \ | ||
1188 | static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_str_param_##param, \ | ||
1189 | NULL); | ||
1190 | |||
1191 | iscsi_conn_str_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS); | ||
1192 | iscsi_conn_str_attr(address, ISCSI_PARAM_CONN_ADDRESS); | ||
1016 | 1193 | ||
1017 | #define iscsi_cdev_to_session(_cdev) \ | 1194 | #define iscsi_cdev_to_session(_cdev) \ |
1018 | iscsi_dev_to_session(_cdev->dev) | 1195 | iscsi_dev_to_session(_cdev->dev) |
@@ -1034,7 +1211,8 @@ show_session_int_param_##param(struct class_device *cdev, char *buf) \ | |||
1034 | 1211 | ||
1035 | #define iscsi_session_int_attr(field, param, format) \ | 1212 | #define iscsi_session_int_attr(field, param, format) \ |
1036 | iscsi_session_int_attr_show(param, format) \ | 1213 | iscsi_session_int_attr_show(param, format) \ |
1037 | static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_int_param_##param, NULL); | 1214 | static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_int_param_##param, \ |
1215 | NULL); | ||
1038 | 1216 | ||
1039 | iscsi_session_int_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, "%d"); | 1217 | iscsi_session_int_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, "%d"); |
1040 | iscsi_session_int_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, "%hu"); | 1218 | iscsi_session_int_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, "%hu"); |
@@ -1044,18 +1222,89 @@ iscsi_session_int_attr(max_burst_len, ISCSI_PARAM_MAX_BURST, "%u"); | |||
1044 | iscsi_session_int_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, "%d"); | 1222 | iscsi_session_int_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, "%d"); |
1045 | iscsi_session_int_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, "%d"); | 1223 | iscsi_session_int_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, "%d"); |
1046 | iscsi_session_int_attr(erl, ISCSI_PARAM_ERL, "%d"); | 1224 | iscsi_session_int_attr(erl, ISCSI_PARAM_ERL, "%d"); |
1225 | iscsi_session_int_attr(tpgt, ISCSI_PARAM_TPGT, "%d"); | ||
1047 | 1226 | ||
1048 | #define SETUP_SESSION_RD_ATTR(field, param) \ | 1227 | #define iscsi_session_str_attr_show(param) \ |
1049 | if (priv->param_mask & (1 << param)) { \ | 1228 | static ssize_t \ |
1050 | priv->session_attrs[count] = &class_device_attr_##field;\ | 1229 | show_session_str_param_##param(struct class_device *cdev, char *buf) \ |
1051 | count++; \ | 1230 | { \ |
1052 | } | 1231 | struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \ |
1232 | struct iscsi_transport *t = session->transport; \ | ||
1233 | return t->get_session_str_param(session, param, buf); \ | ||
1234 | } | ||
1235 | |||
1236 | #define iscsi_session_str_attr(field, param) \ | ||
1237 | iscsi_session_str_attr_show(param) \ | ||
1238 | static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_str_param_##param, \ | ||
1239 | NULL); | ||
1240 | |||
1241 | iscsi_session_str_attr(targetname, ISCSI_PARAM_TARGET_NAME); | ||
1242 | |||
1243 | /* | ||
1244 | * Private session and conn attrs. userspace uses several iscsi values | ||
1245 | * to identify each session between reboots. Some of these values may not | ||
1246 | * be present in the iscsi_transport/LLD driver becuase userspace handles | ||
1247 | * login (and failback for login redirect) so for these type of drivers | ||
1248 | * the class manages the attrs and values for the iscsi_transport/LLD | ||
1249 | */ | ||
1250 | #define iscsi_priv_session_attr_show(field, format) \ | ||
1251 | static ssize_t \ | ||
1252 | show_priv_session_##field(struct class_device *cdev, char *buf) \ | ||
1253 | { \ | ||
1254 | struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \ | ||
1255 | return sprintf(buf, format"\n", session->field); \ | ||
1256 | } | ||
1257 | |||
1258 | #define iscsi_priv_session_attr(field, format) \ | ||
1259 | iscsi_priv_session_attr_show(field, format) \ | ||
1260 | static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \ | ||
1261 | NULL) | ||
1262 | iscsi_priv_session_attr(targetname, "%s"); | ||
1263 | iscsi_priv_session_attr(tpgt, "%d"); | ||
1264 | iscsi_priv_session_attr(recovery_tmo, "%d"); | ||
1265 | |||
1266 | #define iscsi_priv_conn_attr_show(field, format) \ | ||
1267 | static ssize_t \ | ||
1268 | show_priv_conn_##field(struct class_device *cdev, char *buf) \ | ||
1269 | { \ | ||
1270 | struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \ | ||
1271 | return sprintf(buf, format"\n", conn->field); \ | ||
1272 | } | ||
1053 | 1273 | ||
1054 | #define SETUP_CONN_RD_ATTR(field, param) \ | 1274 | #define iscsi_priv_conn_attr(field, format) \ |
1055 | if (priv->param_mask & (1 << param)) { \ | 1275 | iscsi_priv_conn_attr_show(field, format) \ |
1056 | priv->conn_attrs[count] = &class_device_attr_##field; \ | 1276 | static ISCSI_CLASS_ATTR(priv_conn, field, S_IRUGO, show_priv_conn_##field, \ |
1277 | NULL) | ||
1278 | iscsi_priv_conn_attr(persistent_address, "%s"); | ||
1279 | iscsi_priv_conn_attr(persistent_port, "%d"); | ||
1280 | |||
1281 | #define SETUP_PRIV_SESSION_RD_ATTR(field) \ | ||
1282 | do { \ | ||
1283 | priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \ | ||
1284 | count++; \ | ||
1285 | } while (0) | ||
1286 | |||
1287 | #define SETUP_SESSION_RD_ATTR(field, param_flag) \ | ||
1288 | do { \ | ||
1289 | if (tt->param_mask & param_flag) { \ | ||
1290 | priv->session_attrs[count] = &class_device_attr_sess_##field; \ | ||
1057 | count++; \ | 1291 | count++; \ |
1058 | } | 1292 | } \ |
1293 | } while (0) | ||
1294 | |||
1295 | #define SETUP_PRIV_CONN_RD_ATTR(field) \ | ||
1296 | do { \ | ||
1297 | priv->conn_attrs[count] = &class_device_attr_priv_conn_##field; \ | ||
1298 | count++; \ | ||
1299 | } while (0) | ||
1300 | |||
1301 | #define SETUP_CONN_RD_ATTR(field, param_flag) \ | ||
1302 | do { \ | ||
1303 | if (tt->param_mask & param_flag) { \ | ||
1304 | priv->conn_attrs[count] = &class_device_attr_conn_##field; \ | ||
1305 | count++; \ | ||
1306 | } \ | ||
1307 | } while (0) | ||
1059 | 1308 | ||
1060 | static int iscsi_session_match(struct attribute_container *cont, | 1309 | static int iscsi_session_match(struct attribute_container *cont, |
1061 | struct device *dev) | 1310 | struct device *dev) |
@@ -1104,6 +1353,24 @@ static int iscsi_conn_match(struct attribute_container *cont, | |||
1104 | return &priv->conn_cont.ac == cont; | 1353 | return &priv->conn_cont.ac == cont; |
1105 | } | 1354 | } |
1106 | 1355 | ||
1356 | static int iscsi_host_match(struct attribute_container *cont, | ||
1357 | struct device *dev) | ||
1358 | { | ||
1359 | struct Scsi_Host *shost; | ||
1360 | struct iscsi_internal *priv; | ||
1361 | |||
1362 | if (!scsi_is_host_device(dev)) | ||
1363 | return 0; | ||
1364 | |||
1365 | shost = dev_to_shost(dev); | ||
1366 | if (!shost->transportt || | ||
1367 | shost->transportt->host_attrs.ac.class != &iscsi_host_class.class) | ||
1368 | return 0; | ||
1369 | |||
1370 | priv = to_iscsi_internal(shost->transportt); | ||
1371 | return &priv->t.host_attrs.ac == cont; | ||
1372 | } | ||
1373 | |||
1107 | struct scsi_transport_template * | 1374 | struct scsi_transport_template * |
1108 | iscsi_register_transport(struct iscsi_transport *tt) | 1375 | iscsi_register_transport(struct iscsi_transport *tt) |
1109 | { | 1376 | { |
@@ -1122,6 +1389,7 @@ iscsi_register_transport(struct iscsi_transport *tt) | |||
1122 | return NULL; | 1389 | return NULL; |
1123 | INIT_LIST_HEAD(&priv->list); | 1390 | INIT_LIST_HEAD(&priv->list); |
1124 | priv->iscsi_transport = tt; | 1391 | priv->iscsi_transport = tt; |
1392 | priv->t.user_scan = iscsi_user_scan; | ||
1125 | 1393 | ||
1126 | priv->cdev.class = &iscsi_transport_class; | 1394 | priv->cdev.class = &iscsi_transport_class; |
1127 | snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name); | 1395 | snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name); |
@@ -1133,18 +1401,13 @@ iscsi_register_transport(struct iscsi_transport *tt) | |||
1133 | if (err) | 1401 | if (err) |
1134 | goto unregister_cdev; | 1402 | goto unregister_cdev; |
1135 | 1403 | ||
1136 | /* setup parameters mask */ | 1404 | /* host parameters */ |
1137 | priv->param_mask = 0xFFFFFFFF; | 1405 | priv->t.host_attrs.ac.attrs = &priv->host_attrs[0]; |
1138 | if (!(tt->caps & CAP_MULTI_R2T)) | 1406 | priv->t.host_attrs.ac.class = &iscsi_host_class.class; |
1139 | priv->param_mask &= ~(1 << ISCSI_PARAM_MAX_R2T); | 1407 | priv->t.host_attrs.ac.match = iscsi_host_match; |
1140 | if (!(tt->caps & CAP_HDRDGST)) | 1408 | priv->t.host_size = sizeof(struct iscsi_host); |
1141 | priv->param_mask &= ~(1 << ISCSI_PARAM_HDRDGST_EN); | 1409 | priv->host_attrs[0] = NULL; |
1142 | if (!(tt->caps & CAP_DATADGST)) | 1410 | transport_container_register(&priv->t.host_attrs); |
1143 | priv->param_mask &= ~(1 << ISCSI_PARAM_DATADGST_EN); | ||
1144 | if (!(tt->caps & CAP_MARKERS)) { | ||
1145 | priv->param_mask &= ~(1 << ISCSI_PARAM_IFMARKER_EN); | ||
1146 | priv->param_mask &= ~(1 << ISCSI_PARAM_OFMARKER_EN); | ||
1147 | } | ||
1148 | 1411 | ||
1149 | /* connection parameters */ | 1412 | /* connection parameters */ |
1150 | priv->conn_cont.ac.attrs = &priv->conn_attrs[0]; | 1413 | priv->conn_cont.ac.attrs = &priv->conn_attrs[0]; |
@@ -1152,12 +1415,25 @@ iscsi_register_transport(struct iscsi_transport *tt) | |||
1152 | priv->conn_cont.ac.match = iscsi_conn_match; | 1415 | priv->conn_cont.ac.match = iscsi_conn_match; |
1153 | transport_container_register(&priv->conn_cont); | 1416 | transport_container_register(&priv->conn_cont); |
1154 | 1417 | ||
1155 | SETUP_CONN_RD_ATTR(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH); | 1418 | SETUP_CONN_RD_ATTR(max_recv_dlength, ISCSI_MAX_RECV_DLENGTH); |
1156 | SETUP_CONN_RD_ATTR(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH); | 1419 | SETUP_CONN_RD_ATTR(max_xmit_dlength, ISCSI_MAX_XMIT_DLENGTH); |
1157 | SETUP_CONN_RD_ATTR(header_digest, ISCSI_PARAM_HDRDGST_EN); | 1420 | SETUP_CONN_RD_ATTR(header_digest, ISCSI_HDRDGST_EN); |
1158 | SETUP_CONN_RD_ATTR(data_digest, ISCSI_PARAM_DATADGST_EN); | 1421 | SETUP_CONN_RD_ATTR(data_digest, ISCSI_DATADGST_EN); |
1159 | SETUP_CONN_RD_ATTR(ifmarker, ISCSI_PARAM_IFMARKER_EN); | 1422 | SETUP_CONN_RD_ATTR(ifmarker, ISCSI_IFMARKER_EN); |
1160 | SETUP_CONN_RD_ATTR(ofmarker, ISCSI_PARAM_OFMARKER_EN); | 1423 | SETUP_CONN_RD_ATTR(ofmarker, ISCSI_OFMARKER_EN); |
1424 | SETUP_CONN_RD_ATTR(address, ISCSI_CONN_ADDRESS); | ||
1425 | SETUP_CONN_RD_ATTR(port, ISCSI_CONN_PORT); | ||
1426 | SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN); | ||
1427 | |||
1428 | if (tt->param_mask & ISCSI_PERSISTENT_ADDRESS) | ||
1429 | SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS); | ||
1430 | else | ||
1431 | SETUP_PRIV_CONN_RD_ATTR(persistent_address); | ||
1432 | |||
1433 | if (tt->param_mask & ISCSI_PERSISTENT_PORT) | ||
1434 | SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT); | ||
1435 | else | ||
1436 | SETUP_PRIV_CONN_RD_ATTR(persistent_port); | ||
1161 | 1437 | ||
1162 | BUG_ON(count > ISCSI_CONN_ATTRS); | 1438 | BUG_ON(count > ISCSI_CONN_ATTRS); |
1163 | priv->conn_attrs[count] = NULL; | 1439 | priv->conn_attrs[count] = NULL; |
@@ -1169,14 +1445,25 @@ iscsi_register_transport(struct iscsi_transport *tt) | |||
1169 | priv->session_cont.ac.match = iscsi_session_match; | 1445 | priv->session_cont.ac.match = iscsi_session_match; |
1170 | transport_container_register(&priv->session_cont); | 1446 | transport_container_register(&priv->session_cont); |
1171 | 1447 | ||
1172 | SETUP_SESSION_RD_ATTR(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN); | 1448 | SETUP_SESSION_RD_ATTR(initial_r2t, ISCSI_INITIAL_R2T_EN); |
1173 | SETUP_SESSION_RD_ATTR(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T); | 1449 | SETUP_SESSION_RD_ATTR(max_outstanding_r2t, ISCSI_MAX_R2T); |
1174 | SETUP_SESSION_RD_ATTR(immediate_data, ISCSI_PARAM_IMM_DATA_EN); | 1450 | SETUP_SESSION_RD_ATTR(immediate_data, ISCSI_IMM_DATA_EN); |
1175 | SETUP_SESSION_RD_ATTR(first_burst_len, ISCSI_PARAM_FIRST_BURST); | 1451 | SETUP_SESSION_RD_ATTR(first_burst_len, ISCSI_FIRST_BURST); |
1176 | SETUP_SESSION_RD_ATTR(max_burst_len, ISCSI_PARAM_MAX_BURST); | 1452 | SETUP_SESSION_RD_ATTR(max_burst_len, ISCSI_MAX_BURST); |
1177 | SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN); | 1453 | SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PDU_INORDER_EN); |
1178 | SETUP_SESSION_RD_ATTR(data_seq_in_order,ISCSI_PARAM_DATASEQ_INORDER_EN) | 1454 | SETUP_SESSION_RD_ATTR(data_seq_in_order, ISCSI_DATASEQ_INORDER_EN); |
1179 | SETUP_SESSION_RD_ATTR(erl, ISCSI_PARAM_ERL); | 1455 | SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL); |
1456 | SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); | ||
1457 | |||
1458 | if (tt->param_mask & ISCSI_TARGET_NAME) | ||
1459 | SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME); | ||
1460 | else | ||
1461 | SETUP_PRIV_SESSION_RD_ATTR(targetname); | ||
1462 | |||
1463 | if (tt->param_mask & ISCSI_TPGT) | ||
1464 | SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT); | ||
1465 | else | ||
1466 | SETUP_PRIV_SESSION_RD_ATTR(tpgt); | ||
1180 | 1467 | ||
1181 | BUG_ON(count > ISCSI_SESSION_ATTRS); | 1468 | BUG_ON(count > ISCSI_SESSION_ATTRS); |
1182 | priv->session_attrs[count] = NULL; | 1469 | priv->session_attrs[count] = NULL; |
@@ -1214,6 +1501,7 @@ int iscsi_unregister_transport(struct iscsi_transport *tt) | |||
1214 | 1501 | ||
1215 | transport_container_unregister(&priv->conn_cont); | 1502 | transport_container_unregister(&priv->conn_cont); |
1216 | transport_container_unregister(&priv->session_cont); | 1503 | transport_container_unregister(&priv->session_cont); |
1504 | transport_container_unregister(&priv->t.host_attrs); | ||
1217 | 1505 | ||
1218 | sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group); | 1506 | sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group); |
1219 | class_device_unregister(&priv->cdev); | 1507 | class_device_unregister(&priv->cdev); |
@@ -1257,10 +1545,14 @@ static __init int iscsi_transport_init(void) | |||
1257 | if (err) | 1545 | if (err) |
1258 | return err; | 1546 | return err; |
1259 | 1547 | ||
1260 | err = transport_class_register(&iscsi_connection_class); | 1548 | err = transport_class_register(&iscsi_host_class); |
1261 | if (err) | 1549 | if (err) |
1262 | goto unregister_transport_class; | 1550 | goto unregister_transport_class; |
1263 | 1551 | ||
1552 | err = transport_class_register(&iscsi_connection_class); | ||
1553 | if (err) | ||
1554 | goto unregister_host_class; | ||
1555 | |||
1264 | err = transport_class_register(&iscsi_session_class); | 1556 | err = transport_class_register(&iscsi_session_class); |
1265 | if (err) | 1557 | if (err) |
1266 | goto unregister_conn_class; | 1558 | goto unregister_conn_class; |
@@ -1288,6 +1580,8 @@ unregister_session_class: | |||
1288 | transport_class_unregister(&iscsi_session_class); | 1580 | transport_class_unregister(&iscsi_session_class); |
1289 | unregister_conn_class: | 1581 | unregister_conn_class: |
1290 | transport_class_unregister(&iscsi_connection_class); | 1582 | transport_class_unregister(&iscsi_connection_class); |
1583 | unregister_host_class: | ||
1584 | transport_class_unregister(&iscsi_host_class); | ||
1291 | unregister_transport_class: | 1585 | unregister_transport_class: |
1292 | class_unregister(&iscsi_transport_class); | 1586 | class_unregister(&iscsi_transport_class); |
1293 | return err; | 1587 | return err; |
@@ -1300,6 +1594,7 @@ static void __exit iscsi_transport_exit(void) | |||
1300 | netlink_unregister_notifier(&iscsi_nl_notifier); | 1594 | netlink_unregister_notifier(&iscsi_nl_notifier); |
1301 | transport_class_unregister(&iscsi_connection_class); | 1595 | transport_class_unregister(&iscsi_connection_class); |
1302 | transport_class_unregister(&iscsi_session_class); | 1596 | transport_class_unregister(&iscsi_session_class); |
1597 | transport_class_unregister(&iscsi_host_class); | ||
1303 | class_unregister(&iscsi_transport_class); | 1598 | class_unregister(&iscsi_transport_class); |
1304 | } | 1599 | } |
1305 | 1600 | ||