diff options
Diffstat (limited to 'drivers/scsi/osd/osd_uld.c')
-rw-r--r-- | drivers/scsi/osd/osd_uld.c | 100 |
1 files changed, 97 insertions, 3 deletions
diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c index fc6fc1c4d4d1..0a90702b3d71 100644 --- a/drivers/scsi/osd/osd_uld.c +++ b/drivers/scsi/osd/osd_uld.c | |||
@@ -84,6 +84,7 @@ struct osd_uld_device { | |||
84 | struct device class_dev; | 84 | struct device class_dev; |
85 | struct cdev cdev; | 85 | struct cdev cdev; |
86 | struct osd_dev od; | 86 | struct osd_dev od; |
87 | struct osd_dev_info odi; | ||
87 | struct gendisk *disk; | 88 | struct gendisk *disk; |
88 | }; | 89 | }; |
89 | 90 | ||
@@ -225,6 +226,72 @@ free_od: | |||
225 | } | 226 | } |
226 | EXPORT_SYMBOL(osduld_path_lookup); | 227 | EXPORT_SYMBOL(osduld_path_lookup); |
227 | 228 | ||
229 | static inline bool _the_same_or_null(const u8 *a1, unsigned a1_len, | ||
230 | const u8 *a2, unsigned a2_len) | ||
231 | { | ||
232 | if (!a2_len) /* User string is Empty means don't care */ | ||
233 | return true; | ||
234 | |||
235 | if (a1_len != a2_len) | ||
236 | return false; | ||
237 | |||
238 | return 0 == memcmp(a1, a2, a1_len); | ||
239 | } | ||
240 | |||
241 | struct find_oud_t { | ||
242 | const struct osd_dev_info *odi; | ||
243 | struct device *dev; | ||
244 | struct osd_uld_device *oud; | ||
245 | } ; | ||
246 | |||
247 | int _mach_odi(struct device *dev, void *find_data) | ||
248 | { | ||
249 | struct osd_uld_device *oud = container_of(dev, struct osd_uld_device, | ||
250 | class_dev); | ||
251 | struct find_oud_t *fot = find_data; | ||
252 | const struct osd_dev_info *odi = fot->odi; | ||
253 | |||
254 | if (_the_same_or_null(oud->odi.systemid, oud->odi.systemid_len, | ||
255 | odi->systemid, odi->systemid_len) && | ||
256 | _the_same_or_null(oud->odi.osdname, oud->odi.osdname_len, | ||
257 | odi->osdname, odi->osdname_len)) { | ||
258 | OSD_DEBUG("found device sysid_len=%d osdname=%d\n", | ||
259 | odi->systemid_len, odi->osdname_len); | ||
260 | fot->oud = oud; | ||
261 | return 1; | ||
262 | } else { | ||
263 | return 0; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | /* osduld_info_lookup - Loop through all devices, return the requested osd_dev. | ||
268 | * | ||
269 | * if @odi->systemid_len and/or @odi->osdname_len are zero, they act as a don't | ||
270 | * care. .e.g if they're both zero /dev/osd0 is returned. | ||
271 | */ | ||
272 | struct osd_dev *osduld_info_lookup(const struct osd_dev_info *odi) | ||
273 | { | ||
274 | struct find_oud_t find = {.odi = odi}; | ||
275 | |||
276 | find.dev = class_find_device(&osd_uld_class, NULL, &find, _mach_odi); | ||
277 | if (likely(find.dev)) { | ||
278 | struct osd_dev_handle *odh = kzalloc(sizeof(*odh), GFP_KERNEL); | ||
279 | |||
280 | if (unlikely(!odh)) { | ||
281 | put_device(find.dev); | ||
282 | return ERR_PTR(-ENOMEM); | ||
283 | } | ||
284 | |||
285 | odh->od = find.oud->od; | ||
286 | odh->oud = find.oud; | ||
287 | |||
288 | return &odh->od; | ||
289 | } | ||
290 | |||
291 | return ERR_PTR(-ENODEV); | ||
292 | } | ||
293 | EXPORT_SYMBOL(osduld_info_lookup); | ||
294 | |||
228 | void osduld_put_device(struct osd_dev *od) | 295 | void osduld_put_device(struct osd_dev *od) |
229 | { | 296 | { |
230 | if (od && !IS_ERR(od)) { | 297 | if (od && !IS_ERR(od)) { |
@@ -240,14 +307,39 @@ void osduld_put_device(struct osd_dev *od) | |||
240 | * is called after the fops->release. A get_/put_ pair makes | 307 | * is called after the fops->release. A get_/put_ pair makes |
241 | * sure we have a cdev for the duration of fput | 308 | * sure we have a cdev for the duration of fput |
242 | */ | 309 | */ |
243 | get_device(&oud->class_dev); | 310 | if (odh->file) { |
244 | fput(odh->file); | 311 | get_device(&oud->class_dev); |
312 | fput(odh->file); | ||
313 | } | ||
245 | put_device(&oud->class_dev); | 314 | put_device(&oud->class_dev); |
246 | kfree(odh); | 315 | kfree(odh); |
247 | } | 316 | } |
248 | } | 317 | } |
249 | EXPORT_SYMBOL(osduld_put_device); | 318 | EXPORT_SYMBOL(osduld_put_device); |
250 | 319 | ||
320 | const struct osd_dev_info *osduld_device_info(struct osd_dev *od) | ||
321 | { | ||
322 | struct osd_dev_handle *odh = | ||
323 | container_of(od, struct osd_dev_handle, od); | ||
324 | return &odh->oud->odi; | ||
325 | } | ||
326 | EXPORT_SYMBOL(osduld_device_info); | ||
327 | |||
328 | bool osduld_device_same(struct osd_dev *od, const struct osd_dev_info *odi) | ||
329 | { | ||
330 | struct osd_dev_handle *odh = | ||
331 | container_of(od, struct osd_dev_handle, od); | ||
332 | struct osd_uld_device *oud = odh->oud; | ||
333 | |||
334 | return (oud->odi.systemid_len == odi->systemid_len) && | ||
335 | _the_same_or_null(oud->odi.systemid, oud->odi.systemid_len, | ||
336 | odi->systemid, odi->systemid_len) && | ||
337 | (oud->odi.osdname_len == odi->osdname_len) && | ||
338 | _the_same_or_null(oud->odi.osdname, oud->odi.osdname_len, | ||
339 | odi->osdname, odi->osdname_len); | ||
340 | } | ||
341 | EXPORT_SYMBOL(osduld_device_same); | ||
342 | |||
251 | /* | 343 | /* |
252 | * Scsi Device operations | 344 | * Scsi Device operations |
253 | */ | 345 | */ |
@@ -268,7 +360,7 @@ static int __detect_osd(struct osd_uld_device *oud) | |||
268 | OSD_ERR("warning: scsi_test_unit_ready failed\n"); | 360 | OSD_ERR("warning: scsi_test_unit_ready failed\n"); |
269 | 361 | ||
270 | osd_sec_init_nosec_doall_caps(caps, &osd_root_object, false, true); | 362 | osd_sec_init_nosec_doall_caps(caps, &osd_root_object, false, true); |
271 | if (osd_auto_detect_ver(&oud->od, caps)) | 363 | if (osd_auto_detect_ver(&oud->od, caps, &oud->odi)) |
272 | return -ENODEV; | 364 | return -ENODEV; |
273 | 365 | ||
274 | return 0; | 366 | return 0; |
@@ -280,6 +372,8 @@ static void __remove(struct device *dev) | |||
280 | class_dev); | 372 | class_dev); |
281 | struct scsi_device *scsi_device = oud->od.scsi_device; | 373 | struct scsi_device *scsi_device = oud->od.scsi_device; |
282 | 374 | ||
375 | kfree(oud->odi.osdname); | ||
376 | |||
283 | if (oud->cdev.owner) | 377 | if (oud->cdev.owner) |
284 | cdev_del(&oud->cdev); | 378 | cdev_del(&oud->cdev); |
285 | 379 | ||