diff options
| -rw-r--r-- | drivers/block/cciss.c | 515 | ||||
| -rw-r--r-- | drivers/block/cciss.h | 8 |
2 files changed, 333 insertions, 190 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 8bcd6c498c60..3c6a6a21d540 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
| @@ -155,15 +155,24 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, | |||
| 155 | 155 | ||
| 156 | static int revalidate_allvol(ctlr_info_t *host); | 156 | static int revalidate_allvol(ctlr_info_t *host); |
| 157 | static int cciss_revalidate(struct gendisk *disk); | 157 | static int cciss_revalidate(struct gendisk *disk); |
| 158 | static int deregister_disk(struct gendisk *disk); | 158 | static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk); |
| 159 | static int register_new_disk(ctlr_info_t *h); | 159 | static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, int clear_all); |
| 160 | 160 | ||
| 161 | static void cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf, | ||
| 162 | int withirq, unsigned int *total_size, unsigned int *block_size); | ||
| 163 | static void cciss_geometry_inquiry(int ctlr, int logvol, | ||
| 164 | int withirq, unsigned int total_size, | ||
| 165 | unsigned int block_size, InquiryData_struct *inq_buff, | ||
| 166 | drive_info_struct *drv); | ||
| 161 | static void cciss_getgeometry(int cntl_num); | 167 | static void cciss_getgeometry(int cntl_num); |
| 162 | 168 | ||
| 163 | static void start_io( ctlr_info_t *h); | 169 | static void start_io( ctlr_info_t *h); |
| 164 | static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size, | 170 | static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size, |
| 165 | unsigned int use_unit_num, unsigned int log_unit, __u8 page_code, | 171 | unsigned int use_unit_num, unsigned int log_unit, __u8 page_code, |
| 166 | unsigned char *scsi3addr, int cmd_type); | 172 | unsigned char *scsi3addr, int cmd_type); |
| 173 | static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size, | ||
| 174 | unsigned int use_unit_num, unsigned int log_unit, __u8 page_code, | ||
| 175 | int cmd_type); | ||
| 167 | 176 | ||
| 168 | #ifdef CONFIG_PROC_FS | 177 | #ifdef CONFIG_PROC_FS |
| 169 | static int cciss_proc_get_info(char *buffer, char **start, off_t offset, | 178 | static int cciss_proc_get_info(char *buffer, char **start, off_t offset, |
| @@ -280,7 +289,7 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset, | |||
| 280 | for(i=0; i<=h->highest_lun; i++) { | 289 | for(i=0; i<=h->highest_lun; i++) { |
| 281 | 290 | ||
| 282 | drv = &h->drv[i]; | 291 | drv = &h->drv[i]; |
| 283 | if (drv->block_size == 0) | 292 | if (drv->heads == 0) |
| 284 | continue; | 293 | continue; |
| 285 | 294 | ||
| 286 | vol_sz = drv->nr_blocks; | 295 | vol_sz = drv->nr_blocks; |
| @@ -471,6 +480,8 @@ static int cciss_open(struct inode *inode, struct file *filep) | |||
| 471 | if (host->busy_initializing) | 480 | if (host->busy_initializing) |
| 472 | return -EBUSY; | 481 | return -EBUSY; |
| 473 | 482 | ||
| 483 | if (host->busy_initializing || drv->busy_configuring) | ||
| 484 | return -EBUSY; | ||
| 474 | /* | 485 | /* |
| 475 | * Root is allowed to open raw volume zero even if it's not configured | 486 | * Root is allowed to open raw volume zero even if it's not configured |
| 476 | * so array config can still work. Root is also allowed to open any | 487 | * so array config can still work. Root is also allowed to open any |
| @@ -814,10 +825,10 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, | |||
| 814 | return(0); | 825 | return(0); |
| 815 | } | 826 | } |
| 816 | case CCISS_DEREGDISK: | 827 | case CCISS_DEREGDISK: |
| 817 | return deregister_disk(disk); | 828 | return rebuild_lun_table(host, disk); |
| 818 | 829 | ||
| 819 | case CCISS_REGNEWD: | 830 | case CCISS_REGNEWD: |
| 820 | return register_new_disk(host); | 831 | return rebuild_lun_table(host, NULL); |
| 821 | 832 | ||
| 822 | case CCISS_PASSTHRU: | 833 | case CCISS_PASSTHRU: |
| 823 | { | 834 | { |
| @@ -1161,48 +1172,323 @@ static int revalidate_allvol(ctlr_info_t *host) | |||
| 1161 | return 0; | 1172 | return 0; |
| 1162 | } | 1173 | } |
| 1163 | 1174 | ||
| 1164 | static int deregister_disk(struct gendisk *disk) | 1175 | /* This function will check the usage_count of the drive to be updated/added. |
| 1176 | * If the usage_count is zero then the drive information will be updated and | ||
| 1177 | * the disk will be re-registered with the kernel. If not then it will be | ||
| 1178 | * left alone for the next reboot. The exception to this is disk 0 which | ||
| 1179 | * will always be left registered with the kernel since it is also the | ||
| 1180 | * controller node. Any changes to disk 0 will show up on the next | ||
| 1181 | * reboot. | ||
| 1182 | */ | ||
| 1183 | static void cciss_update_drive_info(int ctlr, int drv_index) | ||
| 1184 | { | ||
| 1185 | ctlr_info_t *h = hba[ctlr]; | ||
| 1186 | struct gendisk *disk; | ||
| 1187 | ReadCapdata_struct *size_buff = NULL; | ||
| 1188 | InquiryData_struct *inq_buff = NULL; | ||
| 1189 | unsigned int block_size; | ||
| 1190 | unsigned int total_size; | ||
| 1191 | unsigned long flags = 0; | ||
| 1192 | int ret = 0; | ||
| 1193 | |||
| 1194 | /* if the disk already exists then deregister it before proceeding*/ | ||
| 1195 | if (h->drv[drv_index].raid_level != -1){ | ||
| 1196 | spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); | ||
| 1197 | h->drv[drv_index].busy_configuring = 1; | ||
| 1198 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | ||
| 1199 | ret = deregister_disk(h->gendisk[drv_index], | ||
| 1200 | &h->drv[drv_index], 0); | ||
| 1201 | h->drv[drv_index].busy_configuring = 0; | ||
| 1202 | } | ||
| 1203 | |||
| 1204 | /* If the disk is in use return */ | ||
| 1205 | if (ret) | ||
| 1206 | return; | ||
| 1207 | |||
| 1208 | |||
| 1209 | /* Get information about the disk and modify the driver sturcture */ | ||
| 1210 | size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL); | ||
| 1211 | if (size_buff == NULL) | ||
| 1212 | goto mem_msg; | ||
| 1213 | inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL); | ||
| 1214 | if (inq_buff == NULL) | ||
| 1215 | goto mem_msg; | ||
| 1216 | |||
| 1217 | cciss_read_capacity(ctlr, drv_index, size_buff, 1, | ||
| 1218 | &total_size, &block_size); | ||
| 1219 | cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size, | ||
| 1220 | inq_buff, &h->drv[drv_index]); | ||
| 1221 | |||
| 1222 | ++h->num_luns; | ||
| 1223 | disk = h->gendisk[drv_index]; | ||
| 1224 | set_capacity(disk, h->drv[drv_index].nr_blocks); | ||
| 1225 | |||
| 1226 | |||
| 1227 | /* if it's the controller it's already added */ | ||
| 1228 | if (drv_index){ | ||
| 1229 | disk->queue = blk_init_queue(do_cciss_request, &h->lock); | ||
| 1230 | |||
| 1231 | /* Set up queue information */ | ||
| 1232 | disk->queue->backing_dev_info.ra_pages = READ_AHEAD; | ||
| 1233 | blk_queue_bounce_limit(disk->queue, hba[ctlr]->pdev->dma_mask); | ||
| 1234 | |||
| 1235 | /* This is a hardware imposed limit. */ | ||
| 1236 | blk_queue_max_hw_segments(disk->queue, MAXSGENTRIES); | ||
| 1237 | |||
| 1238 | /* This is a limit in the driver and could be eliminated. */ | ||
| 1239 | blk_queue_max_phys_segments(disk->queue, MAXSGENTRIES); | ||
| 1240 | |||
| 1241 | blk_queue_max_sectors(disk->queue, 512); | ||
| 1242 | |||
| 1243 | disk->queue->queuedata = hba[ctlr]; | ||
| 1244 | |||
| 1245 | blk_queue_hardsect_size(disk->queue, | ||
| 1246 | hba[ctlr]->drv[drv_index].block_size); | ||
| 1247 | |||
| 1248 | h->drv[drv_index].queue = disk->queue; | ||
| 1249 | add_disk(disk); | ||
| 1250 | } | ||
| 1251 | |||
| 1252 | freeret: | ||
| 1253 | kfree(size_buff); | ||
| 1254 | kfree(inq_buff); | ||
| 1255 | return; | ||
| 1256 | mem_msg: | ||
| 1257 | printk(KERN_ERR "cciss: out of memory\n"); | ||
| 1258 | goto freeret; | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | /* This function will find the first index of the controllers drive array | ||
| 1262 | * that has a -1 for the raid_level and will return that index. This is | ||
| 1263 | * where new drives will be added. If the index to be returned is greater | ||
| 1264 | * than the highest_lun index for the controller then highest_lun is set | ||
| 1265 | * to this new index. If there are no available indexes then -1 is returned. | ||
| 1266 | */ | ||
| 1267 | static int cciss_find_free_drive_index(int ctlr) | ||
| 1268 | { | ||
| 1269 | int i; | ||
| 1270 | |||
| 1271 | for (i=0; i < CISS_MAX_LUN; i++){ | ||
| 1272 | if (hba[ctlr]->drv[i].raid_level == -1){ | ||
| 1273 | if (i > hba[ctlr]->highest_lun) | ||
| 1274 | hba[ctlr]->highest_lun = i; | ||
| 1275 | return i; | ||
| 1276 | } | ||
| 1277 | } | ||
| 1278 | return -1; | ||
| 1279 | } | ||
| 1280 | |||
| 1281 | /* This function will add and remove logical drives from the Logical | ||
| 1282 | * drive array of the controller and maintain persistancy of ordering | ||
| 1283 | * so that mount points are preserved until the next reboot. This allows | ||
| 1284 | * for the removal of logical drives in the middle of the drive array | ||
| 1285 | * without a re-ordering of those drives. | ||
| 1286 | * INPUT | ||
| 1287 | * h = The controller to perform the operations on | ||
| 1288 | * del_disk = The disk to remove if specified. If the value given | ||
| 1289 | * is NULL then no disk is removed. | ||
| 1290 | */ | ||
| 1291 | static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk) | ||
| 1165 | { | 1292 | { |
| 1293 | int ctlr = h->ctlr; | ||
| 1294 | int num_luns; | ||
| 1295 | ReportLunData_struct *ld_buff = NULL; | ||
| 1296 | drive_info_struct *drv = NULL; | ||
| 1297 | int return_code; | ||
| 1298 | int listlength = 0; | ||
| 1299 | int i; | ||
| 1300 | int drv_found; | ||
| 1301 | int drv_index = 0; | ||
| 1302 | __u32 lunid = 0; | ||
| 1166 | unsigned long flags; | 1303 | unsigned long flags; |
| 1304 | |||
| 1305 | /* Set busy_configuring flag for this operation */ | ||
| 1306 | spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); | ||
| 1307 | if (h->num_luns >= CISS_MAX_LUN){ | ||
| 1308 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | ||
| 1309 | return -EINVAL; | ||
| 1310 | } | ||
| 1311 | |||
| 1312 | if (h->busy_configuring){ | ||
| 1313 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | ||
| 1314 | return -EBUSY; | ||
| 1315 | } | ||
| 1316 | h->busy_configuring = 1; | ||
| 1317 | |||
| 1318 | /* if del_disk is NULL then we are being called to add a new disk | ||
| 1319 | * and update the logical drive table. If it is not NULL then | ||
| 1320 | * we will check if the disk is in use or not. | ||
| 1321 | */ | ||
| 1322 | if (del_disk != NULL){ | ||
| 1323 | drv = get_drv(del_disk); | ||
| 1324 | drv->busy_configuring = 1; | ||
| 1325 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | ||
| 1326 | return_code = deregister_disk(del_disk, drv, 1); | ||
| 1327 | drv->busy_configuring = 0; | ||
| 1328 | h->busy_configuring = 0; | ||
| 1329 | return return_code; | ||
| 1330 | } else { | ||
| 1331 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | ||
| 1332 | if (!capable(CAP_SYS_RAWIO)) | ||
| 1333 | return -EPERM; | ||
| 1334 | |||
| 1335 | ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL); | ||
| 1336 | if (ld_buff == NULL) | ||
| 1337 | goto mem_msg; | ||
| 1338 | |||
| 1339 | return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff, | ||
| 1340 | sizeof(ReportLunData_struct), 0, 0, 0, | ||
| 1341 | TYPE_CMD); | ||
| 1342 | |||
| 1343 | if (return_code == IO_OK){ | ||
| 1344 | listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24; | ||
| 1345 | listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16; | ||
| 1346 | listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8; | ||
| 1347 | listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]); | ||
| 1348 | } else{ /* reading number of logical volumes failed */ | ||
| 1349 | printk(KERN_WARNING "cciss: report logical volume" | ||
| 1350 | " command failed\n"); | ||
| 1351 | listlength = 0; | ||
| 1352 | goto freeret; | ||
| 1353 | } | ||
| 1354 | |||
| 1355 | num_luns = listlength / 8; /* 8 bytes per entry */ | ||
| 1356 | if (num_luns > CISS_MAX_LUN){ | ||
| 1357 | num_luns = CISS_MAX_LUN; | ||
| 1358 | printk(KERN_WARNING "cciss: more luns configured" | ||
| 1359 | " on controller than can be handled by" | ||
| 1360 | " this driver.\n"); | ||
| 1361 | } | ||
| 1362 | |||
| 1363 | /* Compare controller drive array to drivers drive array. | ||
| 1364 | * Check for updates in the drive information and any new drives | ||
| 1365 | * on the controller. | ||
| 1366 | */ | ||
| 1367 | for (i=0; i < num_luns; i++){ | ||
| 1368 | int j; | ||
| 1369 | |||
| 1370 | drv_found = 0; | ||
| 1371 | |||
| 1372 | lunid = (0xff & | ||
| 1373 | (unsigned int)(ld_buff->LUN[i][3])) << 24; | ||
| 1374 | lunid |= (0xff & | ||
| 1375 | (unsigned int)(ld_buff->LUN[i][2])) << 16; | ||
| 1376 | lunid |= (0xff & | ||
| 1377 | (unsigned int)(ld_buff->LUN[i][1])) << 8; | ||
| 1378 | lunid |= 0xff & | ||
| 1379 | (unsigned int)(ld_buff->LUN[i][0]); | ||
| 1380 | |||
| 1381 | /* Find if the LUN is already in the drive array | ||
| 1382 | * of the controller. If so then update its info | ||
| 1383 | * if not is use. If it does not exist then find | ||
| 1384 | * the first free index and add it. | ||
| 1385 | */ | ||
| 1386 | for (j=0; j <= h->highest_lun; j++){ | ||
| 1387 | if (h->drv[j].LunID == lunid){ | ||
| 1388 | drv_index = j; | ||
| 1389 | drv_found = 1; | ||
| 1390 | } | ||
| 1391 | } | ||
| 1392 | |||
| 1393 | /* check if the drive was found already in the array */ | ||
| 1394 | if (!drv_found){ | ||
| 1395 | drv_index = cciss_find_free_drive_index(ctlr); | ||
| 1396 | if (drv_index == -1) | ||
| 1397 | goto freeret; | ||
| 1398 | |||
| 1399 | } | ||
| 1400 | h->drv[drv_index].LunID = lunid; | ||
| 1401 | cciss_update_drive_info(ctlr, drv_index); | ||
| 1402 | } /* end for */ | ||
| 1403 | } /* end else */ | ||
| 1404 | |||
| 1405 | freeret: | ||
| 1406 | kfree(ld_buff); | ||
| 1407 | h->busy_configuring = 0; | ||
| 1408 | /* We return -1 here to tell the ACU that we have registered/updated | ||
| 1409 | * all of the drives that we can and to keep it from calling us | ||
| 1410 | * additional times. | ||
| 1411 | */ | ||
| 1412 | return -1; | ||
| 1413 | mem_msg: | ||
| 1414 | printk(KERN_ERR "cciss: out of memory\n"); | ||
| 1415 | goto freeret; | ||
| 1416 | } | ||
| 1417 | |||
| 1418 | /* This function will deregister the disk and it's queue from the | ||
| 1419 | * kernel. It must be called with the controller lock held and the | ||
| 1420 | * drv structures busy_configuring flag set. It's parameters are: | ||
| 1421 | * | ||
| 1422 | * disk = This is the disk to be deregistered | ||
| 1423 | * drv = This is the drive_info_struct associated with the disk to be | ||
| 1424 | * deregistered. It contains information about the disk used | ||
| 1425 | * by the driver. | ||
| 1426 | * clear_all = This flag determines whether or not the disk information | ||
| 1427 | * is going to be completely cleared out and the highest_lun | ||
| 1428 | * reset. Sometimes we want to clear out information about | ||
| 1429 | * the disk in preperation for re-adding it. In this case | ||
| 1430 | * the highest_lun should be left unchanged and the LunID | ||
| 1431 | * should not be cleared. | ||
| 1432 | */ | ||
| 1433 | static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, | ||
| 1434 | int clear_all) | ||
| 1435 | { | ||
| 1167 | ctlr_info_t *h = get_host(disk); | 1436 | ctlr_info_t *h = get_host(disk); |
| 1168 | drive_info_struct *drv = get_drv(disk); | ||
| 1169 | int ctlr = h->ctlr; | ||
| 1170 | 1437 | ||
| 1171 | if (!capable(CAP_SYS_RAWIO)) | 1438 | if (!capable(CAP_SYS_RAWIO)) |
| 1172 | return -EPERM; | 1439 | return -EPERM; |
| 1173 | 1440 | ||
| 1174 | spin_lock_irqsave(CCISS_LOCK(ctlr), flags); | ||
| 1175 | /* make sure logical volume is NOT is use */ | 1441 | /* make sure logical volume is NOT is use */ |
| 1176 | if( drv->usage_count > 1) { | 1442 | if(clear_all || (h->gendisk[0] == disk)) { |
| 1177 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); | 1443 | if (drv->usage_count > 1) |
| 1178 | return -EBUSY; | 1444 | return -EBUSY; |
| 1179 | } | 1445 | } |
| 1180 | drv->usage_count++; | 1446 | else |
| 1181 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); | 1447 | if( drv->usage_count > 0 ) |
| 1448 | return -EBUSY; | ||
| 1182 | 1449 | ||
| 1183 | /* invalidate the devices and deregister the disk */ | 1450 | /* invalidate the devices and deregister the disk. If it is disk |
| 1184 | if (disk->flags & GENHD_FL_UP) | 1451 | * zero do not deregister it but just zero out it's values. This |
| 1452 | * allows us to delete disk zero but keep the controller registered. | ||
| 1453 | */ | ||
| 1454 | if (h->gendisk[0] != disk){ | ||
| 1455 | if (disk->flags & GENHD_FL_UP){ | ||
| 1456 | blk_cleanup_queue(disk->queue); | ||
| 1185 | del_gendisk(disk); | 1457 | del_gendisk(disk); |
| 1458 | drv->queue = NULL; | ||
| 1459 | } | ||
| 1460 | } | ||
| 1461 | |||
| 1462 | --h->num_luns; | ||
| 1463 | /* zero out the disk size info */ | ||
| 1464 | drv->nr_blocks = 0; | ||
| 1465 | drv->block_size = 0; | ||
| 1466 | drv->heads = 0; | ||
| 1467 | drv->sectors = 0; | ||
| 1468 | drv->cylinders = 0; | ||
| 1469 | drv->raid_level = -1; /* This can be used as a flag variable to | ||
| 1470 | * indicate that this element of the drive | ||
| 1471 | * array is free. | ||
| 1472 | */ | ||
| 1473 | |||
| 1474 | if (clear_all){ | ||
| 1186 | /* check to see if it was the last disk */ | 1475 | /* check to see if it was the last disk */ |
| 1187 | if (drv == h->drv + h->highest_lun) { | 1476 | if (drv == h->drv + h->highest_lun) { |
| 1188 | /* if so, find the new hightest lun */ | 1477 | /* if so, find the new hightest lun */ |
| 1189 | int i, newhighest =-1; | 1478 | int i, newhighest =-1; |
| 1190 | for(i=0; i<h->highest_lun; i++) { | 1479 | for(i=0; i<h->highest_lun; i++) { |
| 1191 | /* if the disk has size > 0, it is available */ | 1480 | /* if the disk has size > 0, it is available */ |
| 1192 | if (h->drv[i].nr_blocks) | 1481 | if (h->drv[i].heads) |
| 1193 | newhighest = i; | 1482 | newhighest = i; |
| 1194 | } | 1483 | } |
| 1195 | h->highest_lun = newhighest; | 1484 | h->highest_lun = newhighest; |
| 1196 | |||
| 1197 | } | 1485 | } |
| 1198 | --h->num_luns; | 1486 | |
| 1199 | /* zero out the disk size info */ | ||
| 1200 | drv->nr_blocks = 0; | ||
| 1201 | drv->block_size = 0; | ||
| 1202 | drv->cylinders = 0; | ||
| 1203 | drv->LunID = 0; | 1487 | drv->LunID = 0; |
| 1488 | } | ||
| 1204 | return(0); | 1489 | return(0); |
| 1205 | } | 1490 | } |
| 1491 | |||
| 1206 | static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, | 1492 | static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, |
| 1207 | size_t size, | 1493 | size_t size, |
| 1208 | unsigned int use_unit_num, /* 0: address the controller, | 1494 | unsigned int use_unit_num, /* 0: address the controller, |
| @@ -1513,164 +1799,6 @@ cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf, | |||
| 1513 | return; | 1799 | return; |
| 1514 | } | 1800 | } |
| 1515 | 1801 | ||
| 1516 | static int register_new_disk(ctlr_info_t *h) | ||
| 1517 | { | ||
| 1518 | struct gendisk *disk; | ||
| 1519 | int ctlr = h->ctlr; | ||
| 1520 | int i; | ||
| 1521 | int num_luns; | ||
| 1522 | int logvol; | ||
| 1523 | int new_lun_found = 0; | ||
| 1524 | int new_lun_index = 0; | ||
| 1525 | int free_index_found = 0; | ||
| 1526 | int free_index = 0; | ||
| 1527 | ReportLunData_struct *ld_buff = NULL; | ||
| 1528 | ReadCapdata_struct *size_buff = NULL; | ||
| 1529 | InquiryData_struct *inq_buff = NULL; | ||
| 1530 | int return_code; | ||
| 1531 | int listlength = 0; | ||
| 1532 | __u32 lunid = 0; | ||
| 1533 | unsigned int block_size; | ||
| 1534 | unsigned int total_size; | ||
| 1535 | |||
| 1536 | if (!capable(CAP_SYS_RAWIO)) | ||
| 1537 | return -EPERM; | ||
| 1538 | /* if we have no space in our disk array left to add anything */ | ||
| 1539 | if( h->num_luns >= CISS_MAX_LUN) | ||
| 1540 | return -EINVAL; | ||
| 1541 | |||
| 1542 | ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL); | ||
| 1543 | if (ld_buff == NULL) | ||
| 1544 | goto mem_msg; | ||
| 1545 | memset(ld_buff, 0, sizeof(ReportLunData_struct)); | ||
| 1546 | size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL); | ||
| 1547 | if (size_buff == NULL) | ||
| 1548 | goto mem_msg; | ||
| 1549 | inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL); | ||
| 1550 | if (inq_buff == NULL) | ||
| 1551 | goto mem_msg; | ||
| 1552 | |||
| 1553 | return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff, | ||
| 1554 | sizeof(ReportLunData_struct), 0, 0, 0, TYPE_CMD); | ||
| 1555 | |||
| 1556 | if( return_code == IO_OK) | ||
| 1557 | { | ||
| 1558 | |||
| 1559 | // printk("LUN Data\n--------------------------\n"); | ||
| 1560 | |||
| 1561 | listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24; | ||
| 1562 | listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16; | ||
| 1563 | listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8; | ||
| 1564 | listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]); | ||
| 1565 | } else /* reading number of logical volumes failed */ | ||
| 1566 | { | ||
| 1567 | printk(KERN_WARNING "cciss: report logical volume" | ||
| 1568 | " command failed\n"); | ||
| 1569 | listlength = 0; | ||
| 1570 | goto free_err; | ||
| 1571 | } | ||
| 1572 | num_luns = listlength / 8; // 8 bytes pre entry | ||
| 1573 | if (num_luns > CISS_MAX_LUN) | ||
| 1574 | { | ||
| 1575 | num_luns = CISS_MAX_LUN; | ||
| 1576 | } | ||
| 1577 | #ifdef CCISS_DEBUG | ||
| 1578 | printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0], | ||
| 1579 | ld_buff->LUNListLength[1], ld_buff->LUNListLength[2], | ||
| 1580 | ld_buff->LUNListLength[3], num_luns); | ||
| 1581 | #endif | ||
| 1582 | for(i=0; i< num_luns; i++) | ||
| 1583 | { | ||
| 1584 | int j; | ||
| 1585 | int lunID_found = 0; | ||
| 1586 | |||
| 1587 | lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24; | ||
| 1588 | lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16; | ||
| 1589 | lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8; | ||
| 1590 | lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]); | ||
| 1591 | |||
| 1592 | /* check to see if this is a new lun */ | ||
| 1593 | for(j=0; j <= h->highest_lun; j++) | ||
| 1594 | { | ||
| 1595 | #ifdef CCISS_DEBUG | ||
| 1596 | printk("Checking %d %x against %x\n", j,h->drv[j].LunID, | ||
| 1597 | lunid); | ||
| 1598 | #endif /* CCISS_DEBUG */ | ||
| 1599 | if (h->drv[j].LunID == lunid) | ||
| 1600 | { | ||
| 1601 | lunID_found = 1; | ||
| 1602 | break; | ||
| 1603 | } | ||
| 1604 | |||
| 1605 | } | ||
| 1606 | if( lunID_found == 1) | ||
| 1607 | continue; | ||
| 1608 | else | ||
| 1609 | { /* It is the new lun we have been looking for */ | ||
| 1610 | #ifdef CCISS_DEBUG | ||
| 1611 | printk("new lun found at %d\n", i); | ||
| 1612 | #endif /* CCISS_DEBUG */ | ||
| 1613 | new_lun_index = i; | ||
| 1614 | new_lun_found = 1; | ||
| 1615 | break; | ||
| 1616 | } | ||
| 1617 | } | ||
| 1618 | if (!new_lun_found) | ||
| 1619 | { | ||
| 1620 | printk(KERN_WARNING "cciss: New Logical Volume not found\n"); | ||
| 1621 | goto free_err; | ||
| 1622 | } | ||
| 1623 | /* Now find the free index */ | ||
| 1624 | for(i=0; i <CISS_MAX_LUN; i++) | ||
| 1625 | { | ||
| 1626 | #ifdef CCISS_DEBUG | ||
| 1627 | printk("Checking Index %d\n", i); | ||
| 1628 | #endif /* CCISS_DEBUG */ | ||
| 1629 | if(h->drv[i].LunID == 0) | ||
| 1630 | { | ||
| 1631 | #ifdef CCISS_DEBUG | ||
| 1632 | printk("free index found at %d\n", i); | ||
| 1633 | #endif /* CCISS_DEBUG */ | ||
| 1634 | free_index_found = 1; | ||
| 1635 | free_index = i; | ||
| 1636 | break; | ||
| 1637 | } | ||
| 1638 | } | ||
| 1639 | if (!free_index_found) | ||
| 1640 | { | ||
| 1641 | printk(KERN_WARNING "cciss: unable to find free slot for disk\n"); | ||
| 1642 | goto free_err; | ||
| 1643 | } | ||
| 1644 | |||
| 1645 | logvol = free_index; | ||
| 1646 | h->drv[logvol].LunID = lunid; | ||
| 1647 | /* there could be gaps in lun numbers, track hightest */ | ||
| 1648 | if(h->highest_lun < lunid) | ||
| 1649 | h->highest_lun = logvol; | ||
| 1650 | cciss_read_capacity(ctlr, logvol, size_buff, 1, | ||
| 1651 | &total_size, &block_size); | ||
| 1652 | cciss_geometry_inquiry(ctlr, logvol, 1, total_size, block_size, | ||
| 1653 | inq_buff, &h->drv[logvol]); | ||
| 1654 | h->drv[logvol].usage_count = 0; | ||
| 1655 | ++h->num_luns; | ||
| 1656 | /* setup partitions per disk */ | ||
| 1657 | disk = h->gendisk[logvol]; | ||
| 1658 | set_capacity(disk, h->drv[logvol].nr_blocks); | ||
| 1659 | /* if it's the controller it's already added */ | ||
| 1660 | if(logvol) | ||
| 1661 | add_disk(disk); | ||
| 1662 | freeret: | ||
| 1663 | kfree(ld_buff); | ||
| 1664 | kfree(size_buff); | ||
| 1665 | kfree(inq_buff); | ||
| 1666 | return (logvol); | ||
| 1667 | mem_msg: | ||
| 1668 | printk(KERN_ERR "cciss: out of memory\n"); | ||
| 1669 | free_err: | ||
| 1670 | logvol = -1; | ||
| 1671 | goto freeret; | ||
| 1672 | } | ||
| 1673 | |||
| 1674 | static int cciss_revalidate(struct gendisk *disk) | 1802 | static int cciss_revalidate(struct gendisk *disk) |
| 1675 | { | 1803 | { |
| 1676 | ctlr_info_t *h = get_host(disk); | 1804 | ctlr_info_t *h = get_host(disk); |
| @@ -2652,12 +2780,16 @@ static void cciss_getgeometry(int cntl_num) | |||
| 2652 | #endif /* CCISS_DEBUG */ | 2780 | #endif /* CCISS_DEBUG */ |
| 2653 | 2781 | ||
| 2654 | hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1; | 2782 | hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1; |
| 2655 | for(i=0; i< hba[cntl_num]->num_luns; i++) | 2783 | // for(i=0; i< hba[cntl_num]->num_luns; i++) |
| 2784 | for(i=0; i < CISS_MAX_LUN; i++) | ||
| 2656 | { | 2785 | { |
| 2657 | 2786 | if (i < hba[cntl_num]->num_luns){ | |
| 2658 | lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24; | 2787 | lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) |
| 2659 | lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16; | 2788 | << 24; |
| 2660 | lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8; | 2789 | lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) |
| 2790 | << 16; | ||
| 2791 | lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) | ||
| 2792 | << 8; | ||
| 2661 | lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]); | 2793 | lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]); |
| 2662 | 2794 | ||
| 2663 | hba[cntl_num]->drv[i].LunID = lunid; | 2795 | hba[cntl_num]->drv[i].LunID = lunid; |
| @@ -2665,13 +2797,18 @@ static void cciss_getgeometry(int cntl_num) | |||
| 2665 | 2797 | ||
| 2666 | #ifdef CCISS_DEBUG | 2798 | #ifdef CCISS_DEBUG |
| 2667 | printk(KERN_DEBUG "LUN[%d]: %x %x %x %x = %x\n", i, | 2799 | printk(KERN_DEBUG "LUN[%d]: %x %x %x %x = %x\n", i, |
| 2668 | ld_buff->LUN[i][0], ld_buff->LUN[i][1],ld_buff->LUN[i][2], | 2800 | ld_buff->LUN[i][0], ld_buff->LUN[i][1], |
| 2669 | ld_buff->LUN[i][3], hba[cntl_num]->drv[i].LunID); | 2801 | ld_buff->LUN[i][2], ld_buff->LUN[i][3], |
| 2802 | hba[cntl_num]->drv[i].LunID); | ||
| 2670 | #endif /* CCISS_DEBUG */ | 2803 | #endif /* CCISS_DEBUG */ |
| 2671 | cciss_read_capacity(cntl_num, i, size_buff, 0, | 2804 | cciss_read_capacity(cntl_num, i, size_buff, 0, |
| 2672 | &total_size, &block_size); | 2805 | &total_size, &block_size); |
| 2673 | cciss_geometry_inquiry(cntl_num, i, 0, total_size, block_size, | 2806 | cciss_geometry_inquiry(cntl_num, i, 0, total_size, |
| 2674 | inq_buff, &hba[cntl_num]->drv[i]); | 2807 | block_size, inq_buff, &hba[cntl_num]->drv[i]); |
| 2808 | } else { | ||
| 2809 | /* initialize raid_level to indicate a free space */ | ||
| 2810 | hba[cntl_num]->drv[i].raid_level = -1; | ||
| 2811 | } | ||
| 2675 | } | 2812 | } |
| 2676 | kfree(ld_buff); | 2813 | kfree(ld_buff); |
| 2677 | kfree(size_buff); | 2814 | kfree(size_buff); |
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 11ee83504b38..dec27a961120 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h | |||
| @@ -35,7 +35,13 @@ typedef struct _drive_info_struct | |||
| 35 | int heads; | 35 | int heads; |
| 36 | int sectors; | 36 | int sectors; |
| 37 | int cylinders; | 37 | int cylinders; |
| 38 | int raid_level; | 38 | int raid_level; /* set to -1 to indicate that |
| 39 | * the drive is not in use/configured | ||
| 40 | */ | ||
| 41 | int busy_configuring; /*This is set when the drive is being removed | ||
| 42 | *to prevent it from being opened or it's queue | ||
| 43 | *from being started. | ||
| 44 | */ | ||
| 39 | } drive_info_struct; | 45 | } drive_info_struct; |
| 40 | 46 | ||
| 41 | struct ctlr_info | 47 | struct ctlr_info |
