diff options
| author | Boaz Harrosh <bharrosh@panasas.com> | 2009-11-29 09:26:45 -0500 |
|---|---|---|
| committer | James Bottomley <James.Bottomley@suse.de> | 2009-12-04 13:01:46 -0500 |
| commit | 2cdd6410e5a1665823f2a048fc7f8f6a8384be1d (patch) | |
| tree | 327ae154abd84aea9c18eb24eb87c9d6f8029d26 /drivers/scsi/osd | |
| parent | d6ae4333e648492721a098bdc329bbd82d25eb67 (diff) | |
[SCSI] libosd: osd_dev_info: Unique Identification of an OSD device
Define an osd_dev_info structure that Uniquely identifies an OSD
device lun on the network. The identification is built from unique
target attributes and is the same for all network/SAN machines.
osduld_info_lookup() - NEW
New API that will lookup an osd_dev by its osd_dev_info.
This is used by pNFS-objects for cross network global device
identification. And by exofs multy-device support, the device
info is specified in the on-disk exofs device table.
osduld_device_info() - NEW
Given an osd_dev handle returns its associated osd_dev_info.
The ULD fetches this information at startup and hangs it on
each OSD device. (This is a fast operation that can be called
at any condition)
osduld_device_same() - NEW
With a given osd_dev at one hand and an osd_dev_info
at another, we would like to know if they are the same
device.
Two osd_dev handles can be checked by:
osduld_device_same(od1, osduld_device_info(od2));
osd_auto_detect_ver() - REVISED
Now returns an osd_dev_info structure. Is only called once
by ULD as before. See added comments for how to use.
Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/osd')
| -rw-r--r-- | drivers/scsi/osd/osd_initiator.c | 26 | ||||
| -rw-r--r-- | drivers/scsi/osd/osd_uld.c | 100 |
2 files changed, 117 insertions, 9 deletions
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index 7a117c18114c..60b7ca1e9bc0 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c | |||
| @@ -73,7 +73,8 @@ static const char *_osd_ver_desc(struct osd_request *or) | |||
| 73 | 73 | ||
| 74 | #define ATTR_DEF_RI(id, len) ATTR_DEF(OSD_APAGE_ROOT_INFORMATION, id, len) | 74 | #define ATTR_DEF_RI(id, len) ATTR_DEF(OSD_APAGE_ROOT_INFORMATION, id, len) |
| 75 | 75 | ||
| 76 | static int _osd_print_system_info(struct osd_dev *od, void *caps) | 76 | static int _osd_get_print_system_info(struct osd_dev *od, |
| 77 | void *caps, struct osd_dev_info *odi) | ||
| 77 | { | 78 | { |
| 78 | struct osd_request *or; | 79 | struct osd_request *or; |
| 79 | struct osd_attr get_attrs[] = { | 80 | struct osd_attr get_attrs[] = { |
| @@ -137,8 +138,12 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps) | |||
| 137 | OSD_INFO("PRODUCT_SERIAL_NUMBER [%s]\n", | 138 | OSD_INFO("PRODUCT_SERIAL_NUMBER [%s]\n", |
| 138 | (char *)pFirst); | 139 | (char *)pFirst); |
| 139 | 140 | ||
| 140 | pFirst = get_attrs[a].val_ptr; | 141 | odi->osdname_len = get_attrs[a].len; |
| 141 | OSD_INFO("OSD_NAME [%s]\n", (char *)pFirst); | 142 | /* Avoid NULL for memcmp optimization 0-length is good enough */ |
| 143 | odi->osdname = kzalloc(odi->osdname_len + 1, GFP_KERNEL); | ||
| 144 | if (odi->osdname_len) | ||
| 145 | memcpy(odi->osdname, get_attrs[a].val_ptr, odi->osdname_len); | ||
| 146 | OSD_INFO("OSD_NAME [%s]\n", odi->osdname); | ||
| 142 | a++; | 147 | a++; |
| 143 | 148 | ||
| 144 | pFirst = get_attrs[a++].val_ptr; | 149 | pFirst = get_attrs[a++].val_ptr; |
| @@ -171,6 +176,14 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps) | |||
| 171 | sid_dump, sizeof(sid_dump), true); | 176 | sid_dump, sizeof(sid_dump), true); |
| 172 | OSD_INFO("OSD_SYSTEM_ID(%d)\n" | 177 | OSD_INFO("OSD_SYSTEM_ID(%d)\n" |
| 173 | " [%s]\n", len, sid_dump); | 178 | " [%s]\n", len, sid_dump); |
| 179 | |||
| 180 | if (unlikely(len > sizeof(odi->systemid))) { | ||
| 181 | OSD_ERR("OSD Target error: OSD_SYSTEM_ID too long(%d). " | ||
| 182 | "device idetification might not work\n", len); | ||
| 183 | len = sizeof(odi->systemid); | ||
| 184 | } | ||
| 185 | odi->systemid_len = len; | ||
| 186 | memcpy(odi->systemid, get_attrs[a].val_ptr, len); | ||
| 174 | a++; | 187 | a++; |
| 175 | } | 188 | } |
| 176 | out: | 189 | out: |
| @@ -178,16 +191,17 @@ out: | |||
| 178 | return ret; | 191 | return ret; |
| 179 | } | 192 | } |
| 180 | 193 | ||
| 181 | int osd_auto_detect_ver(struct osd_dev *od, void *caps) | 194 | int osd_auto_detect_ver(struct osd_dev *od, |
| 195 | void *caps, struct osd_dev_info *odi) | ||
| 182 | { | 196 | { |
| 183 | int ret; | 197 | int ret; |
| 184 | 198 | ||
| 185 | /* Auto-detect the osd version */ | 199 | /* Auto-detect the osd version */ |
| 186 | ret = _osd_print_system_info(od, caps); | 200 | ret = _osd_get_print_system_info(od, caps, odi); |
| 187 | if (ret) { | 201 | if (ret) { |
| 188 | osd_dev_set_ver(od, OSD_VER1); | 202 | osd_dev_set_ver(od, OSD_VER1); |
| 189 | OSD_DEBUG("converting to OSD1\n"); | 203 | OSD_DEBUG("converting to OSD1\n"); |
| 190 | ret = _osd_print_system_info(od, caps); | 204 | ret = _osd_get_print_system_info(od, caps, odi); |
| 191 | } | 205 | } |
| 192 | 206 | ||
| 193 | return ret; | 207 | return ret; |
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 | ||
