diff options
Diffstat (limited to 'drivers/scsi/megaraid/megaraid_sas_base.c')
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_base.c | 106 |
1 files changed, 97 insertions, 9 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 1f0ca68409d4..9f7c4a169222 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c | |||
@@ -92,6 +92,8 @@ MODULE_DESCRIPTION("LSI MegaRAID SAS Driver"); | |||
92 | 92 | ||
93 | int megasas_transition_to_ready(struct megasas_instance *instance, int ocr); | 93 | int megasas_transition_to_ready(struct megasas_instance *instance, int ocr); |
94 | static int megasas_get_pd_list(struct megasas_instance *instance); | 94 | static int megasas_get_pd_list(struct megasas_instance *instance); |
95 | static int megasas_ld_list_query(struct megasas_instance *instance, | ||
96 | u8 query_type); | ||
95 | static int megasas_issue_init_mfi(struct megasas_instance *instance); | 97 | static int megasas_issue_init_mfi(struct megasas_instance *instance); |
96 | static int megasas_register_aen(struct megasas_instance *instance, | 98 | static int megasas_register_aen(struct megasas_instance *instance, |
97 | u32 seq_num, u32 class_locale_word); | 99 | u32 seq_num, u32 class_locale_word); |
@@ -3271,6 +3273,84 @@ megasas_get_ld_list(struct megasas_instance *instance) | |||
3271 | } | 3273 | } |
3272 | 3274 | ||
3273 | /** | 3275 | /** |
3276 | * megasas_ld_list_query - Returns FW's ld_list structure | ||
3277 | * @instance: Adapter soft state | ||
3278 | * @ld_list: ld_list structure | ||
3279 | * | ||
3280 | * Issues an internal command (DCMD) to get the FW's controller PD | ||
3281 | * list structure. This information is mainly used to find out SYSTEM | ||
3282 | * supported by the FW. | ||
3283 | */ | ||
3284 | static int | ||
3285 | megasas_ld_list_query(struct megasas_instance *instance, u8 query_type) | ||
3286 | { | ||
3287 | int ret = 0, ld_index = 0, ids = 0; | ||
3288 | struct megasas_cmd *cmd; | ||
3289 | struct megasas_dcmd_frame *dcmd; | ||
3290 | struct MR_LD_TARGETID_LIST *ci; | ||
3291 | dma_addr_t ci_h = 0; | ||
3292 | |||
3293 | cmd = megasas_get_cmd(instance); | ||
3294 | |||
3295 | if (!cmd) { | ||
3296 | printk(KERN_WARNING | ||
3297 | "megasas:(megasas_ld_list_query): Failed to get cmd\n"); | ||
3298 | return -ENOMEM; | ||
3299 | } | ||
3300 | |||
3301 | dcmd = &cmd->frame->dcmd; | ||
3302 | |||
3303 | ci = pci_alloc_consistent(instance->pdev, | ||
3304 | sizeof(struct MR_LD_TARGETID_LIST), &ci_h); | ||
3305 | |||
3306 | if (!ci) { | ||
3307 | printk(KERN_WARNING | ||
3308 | "megasas: Failed to alloc mem for ld_list_query\n"); | ||
3309 | megasas_return_cmd(instance, cmd); | ||
3310 | return -ENOMEM; | ||
3311 | } | ||
3312 | |||
3313 | memset(ci, 0, sizeof(*ci)); | ||
3314 | memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); | ||
3315 | |||
3316 | dcmd->mbox.b[0] = query_type; | ||
3317 | |||
3318 | dcmd->cmd = MFI_CMD_DCMD; | ||
3319 | dcmd->cmd_status = 0xFF; | ||
3320 | dcmd->sge_count = 1; | ||
3321 | dcmd->flags = MFI_FRAME_DIR_READ; | ||
3322 | dcmd->timeout = 0; | ||
3323 | dcmd->data_xfer_len = sizeof(struct MR_LD_TARGETID_LIST); | ||
3324 | dcmd->opcode = MR_DCMD_LD_LIST_QUERY; | ||
3325 | dcmd->sgl.sge32[0].phys_addr = ci_h; | ||
3326 | dcmd->sgl.sge32[0].length = sizeof(struct MR_LD_TARGETID_LIST); | ||
3327 | dcmd->pad_0 = 0; | ||
3328 | |||
3329 | if (!megasas_issue_polled(instance, cmd) && !dcmd->cmd_status) { | ||
3330 | ret = 0; | ||
3331 | } else { | ||
3332 | /* On failure, call older LD list DCMD */ | ||
3333 | ret = 1; | ||
3334 | } | ||
3335 | |||
3336 | if ((ret == 0) && (ci->count <= (MAX_LOGICAL_DRIVES))) { | ||
3337 | memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS); | ||
3338 | for (ld_index = 0; ld_index < ci->count; ld_index++) { | ||
3339 | ids = ci->targetId[ld_index]; | ||
3340 | instance->ld_ids[ids] = ci->targetId[ld_index]; | ||
3341 | } | ||
3342 | |||
3343 | } | ||
3344 | |||
3345 | pci_free_consistent(instance->pdev, sizeof(struct MR_LD_TARGETID_LIST), | ||
3346 | ci, ci_h); | ||
3347 | |||
3348 | megasas_return_cmd(instance, cmd); | ||
3349 | |||
3350 | return ret; | ||
3351 | } | ||
3352 | |||
3353 | /** | ||
3274 | * megasas_get_controller_info - Returns FW's controller structure | 3354 | * megasas_get_controller_info - Returns FW's controller structure |
3275 | * @instance: Adapter soft state | 3355 | * @instance: Adapter soft state |
3276 | * @ctrl_info: Controller information structure | 3356 | * @ctrl_info: Controller information structure |
@@ -3648,7 +3728,9 @@ static int megasas_init_fw(struct megasas_instance *instance) | |||
3648 | megasas_get_pd_list(instance); | 3728 | megasas_get_pd_list(instance); |
3649 | 3729 | ||
3650 | memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS); | 3730 | memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS); |
3651 | megasas_get_ld_list(instance); | 3731 | if (megasas_ld_list_query(instance, |
3732 | MR_LD_QUERY_TYPE_EXPOSED_TO_HOST)) | ||
3733 | megasas_get_ld_list(instance); | ||
3652 | 3734 | ||
3653 | ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL); | 3735 | ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL); |
3654 | 3736 | ||
@@ -5389,7 +5471,9 @@ megasas_aen_polling(struct work_struct *work) | |||
5389 | case MR_EVT_LD_OFFLINE: | 5471 | case MR_EVT_LD_OFFLINE: |
5390 | case MR_EVT_CFG_CLEARED: | 5472 | case MR_EVT_CFG_CLEARED: |
5391 | case MR_EVT_LD_DELETED: | 5473 | case MR_EVT_LD_DELETED: |
5392 | megasas_get_ld_list(instance); | 5474 | if (megasas_ld_list_query(instance, |
5475 | MR_LD_QUERY_TYPE_EXPOSED_TO_HOST)) | ||
5476 | megasas_get_ld_list(instance); | ||
5393 | for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) { | 5477 | for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) { |
5394 | for (j = 0; | 5478 | for (j = 0; |
5395 | j < MEGASAS_MAX_DEV_PER_CHANNEL; | 5479 | j < MEGASAS_MAX_DEV_PER_CHANNEL; |
@@ -5399,7 +5483,7 @@ megasas_aen_polling(struct work_struct *work) | |||
5399 | (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j; | 5483 | (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j; |
5400 | 5484 | ||
5401 | sdev1 = scsi_device_lookup(host, | 5485 | sdev1 = scsi_device_lookup(host, |
5402 | i + MEGASAS_MAX_LD_CHANNELS, | 5486 | MEGASAS_MAX_PD_CHANNELS + i, |
5403 | j, | 5487 | j, |
5404 | 0); | 5488 | 0); |
5405 | 5489 | ||
@@ -5418,7 +5502,9 @@ megasas_aen_polling(struct work_struct *work) | |||
5418 | doscan = 0; | 5502 | doscan = 0; |
5419 | break; | 5503 | break; |
5420 | case MR_EVT_LD_CREATED: | 5504 | case MR_EVT_LD_CREATED: |
5421 | megasas_get_ld_list(instance); | 5505 | if (megasas_ld_list_query(instance, |
5506 | MR_LD_QUERY_TYPE_EXPOSED_TO_HOST)) | ||
5507 | megasas_get_ld_list(instance); | ||
5422 | for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) { | 5508 | for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) { |
5423 | for (j = 0; | 5509 | for (j = 0; |
5424 | j < MEGASAS_MAX_DEV_PER_CHANNEL; | 5510 | j < MEGASAS_MAX_DEV_PER_CHANNEL; |
@@ -5427,14 +5513,14 @@ megasas_aen_polling(struct work_struct *work) | |||
5427 | (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j; | 5513 | (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j; |
5428 | 5514 | ||
5429 | sdev1 = scsi_device_lookup(host, | 5515 | sdev1 = scsi_device_lookup(host, |
5430 | i+MEGASAS_MAX_LD_CHANNELS, | 5516 | MEGASAS_MAX_PD_CHANNELS + i, |
5431 | j, 0); | 5517 | j, 0); |
5432 | 5518 | ||
5433 | if (instance->ld_ids[ld_index] != | 5519 | if (instance->ld_ids[ld_index] != |
5434 | 0xff) { | 5520 | 0xff) { |
5435 | if (!sdev1) { | 5521 | if (!sdev1) { |
5436 | scsi_add_device(host, | 5522 | scsi_add_device(host, |
5437 | i + 2, | 5523 | MEGASAS_MAX_PD_CHANNELS + i, |
5438 | j, 0); | 5524 | j, 0); |
5439 | } | 5525 | } |
5440 | } | 5526 | } |
@@ -5483,18 +5569,20 @@ megasas_aen_polling(struct work_struct *work) | |||
5483 | } | 5569 | } |
5484 | } | 5570 | } |
5485 | 5571 | ||
5486 | megasas_get_ld_list(instance); | 5572 | if (megasas_ld_list_query(instance, |
5573 | MR_LD_QUERY_TYPE_EXPOSED_TO_HOST)) | ||
5574 | megasas_get_ld_list(instance); | ||
5487 | for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) { | 5575 | for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) { |
5488 | for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) { | 5576 | for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) { |
5489 | ld_index = | 5577 | ld_index = |
5490 | (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j; | 5578 | (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j; |
5491 | 5579 | ||
5492 | sdev1 = scsi_device_lookup(host, | 5580 | sdev1 = scsi_device_lookup(host, |
5493 | i+MEGASAS_MAX_LD_CHANNELS, j, 0); | 5581 | MEGASAS_MAX_PD_CHANNELS + i, j, 0); |
5494 | if (instance->ld_ids[ld_index] != 0xff) { | 5582 | if (instance->ld_ids[ld_index] != 0xff) { |
5495 | if (!sdev1) { | 5583 | if (!sdev1) { |
5496 | scsi_add_device(host, | 5584 | scsi_add_device(host, |
5497 | i+2, | 5585 | MEGASAS_MAX_PD_CHANNELS + i, |
5498 | j, 0); | 5586 | j, 0); |
5499 | } else { | 5587 | } else { |
5500 | scsi_device_put(sdev1); | 5588 | scsi_device_put(sdev1); |