diff options
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas.c | 125 | ||||
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas.h | 17 |
2 files changed, 141 insertions, 1 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 6d998e050338..b0d6991cb6f3 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c | |||
@@ -1520,6 +1520,8 @@ megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev, | |||
1520 | return 0; | 1520 | return 0; |
1521 | } | 1521 | } |
1522 | 1522 | ||
1523 | static void megasas_aen_polling(struct work_struct *work); | ||
1524 | |||
1523 | /** | 1525 | /** |
1524 | * megasas_service_aen - Processes an event notification | 1526 | * megasas_service_aen - Processes an event notification |
1525 | * @instance: Adapter soft state | 1527 | * @instance: Adapter soft state |
@@ -1551,6 +1553,20 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd) | |||
1551 | 1553 | ||
1552 | instance->aen_cmd = NULL; | 1554 | instance->aen_cmd = NULL; |
1553 | megasas_return_cmd(instance, cmd); | 1555 | megasas_return_cmd(instance, cmd); |
1556 | |||
1557 | if (instance->unload == 0) { | ||
1558 | struct megasas_aen_event *ev; | ||
1559 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); | ||
1560 | if (!ev) { | ||
1561 | printk(KERN_ERR "megasas_service_aen: out of memory\n"); | ||
1562 | } else { | ||
1563 | ev->instance = instance; | ||
1564 | instance->ev = ev; | ||
1565 | INIT_WORK(&ev->hotplug_work, megasas_aen_polling); | ||
1566 | schedule_delayed_work( | ||
1567 | (struct delayed_work *)&ev->hotplug_work, 0); | ||
1568 | } | ||
1569 | } | ||
1554 | } | 1570 | } |
1555 | 1571 | ||
1556 | /* | 1572 | /* |
@@ -2075,6 +2091,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) | |||
2075 | } | 2091 | } |
2076 | 2092 | ||
2077 | cmd->frame->io.context = cmd->index; | 2093 | cmd->frame->io.context = cmd->index; |
2094 | cmd->frame->io.pad_0 = 0; | ||
2078 | } | 2095 | } |
2079 | 2096 | ||
2080 | return 0; | 2097 | return 0; |
@@ -2271,7 +2288,6 @@ megasas_get_pd_list(struct megasas_instance *instance) | |||
2271 | return ret; | 2288 | return ret; |
2272 | } | 2289 | } |
2273 | 2290 | ||
2274 | |||
2275 | /** | 2291 | /** |
2276 | * megasas_get_controller_info - Returns FW's controller structure | 2292 | * megasas_get_controller_info - Returns FW's controller structure |
2277 | * @instance: Adapter soft state | 2293 | * @instance: Adapter soft state |
@@ -2986,6 +3002,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
2986 | *instance->consumer = 0; | 3002 | *instance->consumer = 0; |
2987 | megasas_poll_wait_aen = 0; | 3003 | megasas_poll_wait_aen = 0; |
2988 | instance->flag_ieee = 0; | 3004 | instance->flag_ieee = 0; |
3005 | instance->ev = NULL; | ||
2989 | 3006 | ||
2990 | instance->evt_detail = pci_alloc_consistent(pdev, | 3007 | instance->evt_detail = pci_alloc_consistent(pdev, |
2991 | sizeof(struct | 3008 | sizeof(struct |
@@ -3209,6 +3226,16 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state) | |||
3209 | 3226 | ||
3210 | megasas_flush_cache(instance); | 3227 | megasas_flush_cache(instance); |
3211 | megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN); | 3228 | megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN); |
3229 | |||
3230 | /* cancel the delayed work if this work still in queue */ | ||
3231 | if (instance->ev != NULL) { | ||
3232 | struct megasas_aen_event *ev = instance->ev; | ||
3233 | cancel_delayed_work( | ||
3234 | (struct delayed_work *)&ev->hotplug_work); | ||
3235 | flush_scheduled_work(); | ||
3236 | instance->ev = NULL; | ||
3237 | } | ||
3238 | |||
3212 | tasklet_kill(&instance->isr_tasklet); | 3239 | tasklet_kill(&instance->isr_tasklet); |
3213 | 3240 | ||
3214 | pci_set_drvdata(instance->pdev, instance); | 3241 | pci_set_drvdata(instance->pdev, instance); |
@@ -3349,6 +3376,16 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev) | |||
3349 | scsi_remove_host(instance->host); | 3376 | scsi_remove_host(instance->host); |
3350 | megasas_flush_cache(instance); | 3377 | megasas_flush_cache(instance); |
3351 | megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN); | 3378 | megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN); |
3379 | |||
3380 | /* cancel the delayed work if this work still in queue*/ | ||
3381 | if (instance->ev != NULL) { | ||
3382 | struct megasas_aen_event *ev = instance->ev; | ||
3383 | cancel_delayed_work( | ||
3384 | (struct delayed_work *)&ev->hotplug_work); | ||
3385 | flush_scheduled_work(); | ||
3386 | instance->ev = NULL; | ||
3387 | } | ||
3388 | |||
3352 | tasklet_kill(&instance->isr_tasklet); | 3389 | tasklet_kill(&instance->isr_tasklet); |
3353 | 3390 | ||
3354 | /* | 3391 | /* |
@@ -3913,6 +3950,92 @@ out: | |||
3913 | return retval; | 3950 | return retval; |
3914 | } | 3951 | } |
3915 | 3952 | ||
3953 | static void | ||
3954 | megasas_aen_polling(struct work_struct *work) | ||
3955 | { | ||
3956 | struct megasas_aen_event *ev = | ||
3957 | container_of(work, struct megasas_aen_event, hotplug_work); | ||
3958 | struct megasas_instance *instance = ev->instance; | ||
3959 | union megasas_evt_class_locale class_locale; | ||
3960 | struct Scsi_Host *host; | ||
3961 | struct scsi_device *sdev1; | ||
3962 | u16 pd_index = 0; | ||
3963 | int i, j, doscan = 0; | ||
3964 | u32 seq_num; | ||
3965 | int error; | ||
3966 | |||
3967 | if (!instance) { | ||
3968 | printk(KERN_ERR "invalid instance!\n"); | ||
3969 | kfree(ev); | ||
3970 | return; | ||
3971 | } | ||
3972 | instance->ev = NULL; | ||
3973 | host = instance->host; | ||
3974 | if (instance->evt_detail) { | ||
3975 | |||
3976 | switch (instance->evt_detail->code) { | ||
3977 | case MR_EVT_PD_INSERTED: | ||
3978 | case MR_EVT_PD_REMOVED: | ||
3979 | case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED: | ||
3980 | doscan = 1; | ||
3981 | break; | ||
3982 | default: | ||
3983 | doscan = 0; | ||
3984 | break; | ||
3985 | } | ||
3986 | } else { | ||
3987 | printk(KERN_ERR "invalid evt_detail!\n"); | ||
3988 | kfree(ev); | ||
3989 | return; | ||
3990 | } | ||
3991 | |||
3992 | if (doscan) { | ||
3993 | printk(KERN_INFO "scanning ...\n"); | ||
3994 | megasas_get_pd_list(instance); | ||
3995 | for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) { | ||
3996 | for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) { | ||
3997 | pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j; | ||
3998 | sdev1 = scsi_device_lookup(host, i, j, 0); | ||
3999 | if (instance->pd_list[pd_index].driveState == | ||
4000 | MR_PD_STATE_SYSTEM) { | ||
4001 | if (!sdev1) { | ||
4002 | scsi_add_device(host, i, j, 0); | ||
4003 | } | ||
4004 | if (sdev1) | ||
4005 | scsi_device_put(sdev1); | ||
4006 | } else { | ||
4007 | if (sdev1) { | ||
4008 | scsi_remove_device(sdev1); | ||
4009 | scsi_device_put(sdev1); | ||
4010 | } | ||
4011 | } | ||
4012 | } | ||
4013 | } | ||
4014 | } | ||
4015 | |||
4016 | if ( instance->aen_cmd != NULL ) { | ||
4017 | kfree(ev); | ||
4018 | return ; | ||
4019 | } | ||
4020 | |||
4021 | seq_num = instance->evt_detail->seq_num + 1; | ||
4022 | |||
4023 | /* Register AEN with FW for latest sequence number plus 1 */ | ||
4024 | class_locale.members.reserved = 0; | ||
4025 | class_locale.members.locale = MR_EVT_LOCALE_ALL; | ||
4026 | class_locale.members.class = MR_EVT_CLASS_DEBUG; | ||
4027 | mutex_lock(&instance->aen_mutex); | ||
4028 | error = megasas_register_aen(instance, seq_num, | ||
4029 | class_locale.word); | ||
4030 | mutex_unlock(&instance->aen_mutex); | ||
4031 | |||
4032 | if (error) | ||
4033 | printk(KERN_ERR "register aen failed error %x\n", error); | ||
4034 | |||
4035 | kfree(ev); | ||
4036 | } | ||
4037 | |||
4038 | |||
3916 | static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUGO, | 4039 | static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUGO, |
3917 | megasas_sysfs_show_poll_mode_io, | 4040 | megasas_sysfs_show_poll_mode_io, |
3918 | megasas_sysfs_set_poll_mode_io); | 4041 | megasas_sysfs_set_poll_mode_io); |
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 13ac37e80075..cd1c008f9ab8 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h | |||
@@ -285,6 +285,17 @@ enum MR_PD_QUERY_TYPE { | |||
285 | MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5, | 285 | MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5, |
286 | }; | 286 | }; |
287 | 287 | ||
288 | #define MR_EVT_CFG_CLEARED 0x0004 | ||
289 | #define MR_EVT_LD_STATE_CHANGE 0x0051 | ||
290 | #define MR_EVT_PD_INSERTED 0x005b | ||
291 | #define MR_EVT_PD_REMOVED 0x0070 | ||
292 | #define MR_EVT_LD_CREATED 0x008a | ||
293 | #define MR_EVT_LD_DELETED 0x008b | ||
294 | #define MR_EVT_FOREIGN_CFG_IMPORTED 0x00db | ||
295 | #define MR_EVT_LD_OFFLINE 0x00fc | ||
296 | #define MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED 0x0152 | ||
297 | #define MAX_LOGICAL_DRIVES 64 | ||
298 | |||
288 | enum MR_PD_STATE { | 299 | enum MR_PD_STATE { |
289 | MR_PD_STATE_UNCONFIGURED_GOOD = 0x00, | 300 | MR_PD_STATE_UNCONFIGURED_GOOD = 0x00, |
290 | MR_PD_STATE_UNCONFIGURED_BAD = 0x01, | 301 | MR_PD_STATE_UNCONFIGURED_BAD = 0x01, |
@@ -1157,6 +1168,11 @@ struct megasas_evt_detail { | |||
1157 | 1168 | ||
1158 | } __attribute__ ((packed)); | 1169 | } __attribute__ ((packed)); |
1159 | 1170 | ||
1171 | struct megasas_aen_event { | ||
1172 | struct work_struct hotplug_work; | ||
1173 | struct megasas_instance *instance; | ||
1174 | }; | ||
1175 | |||
1160 | struct megasas_instance { | 1176 | struct megasas_instance { |
1161 | 1177 | ||
1162 | u32 *producer; | 1178 | u32 *producer; |
@@ -1176,6 +1192,7 @@ struct megasas_instance { | |||
1176 | u16 max_num_sge; | 1192 | u16 max_num_sge; |
1177 | u16 max_fw_cmds; | 1193 | u16 max_fw_cmds; |
1178 | u32 max_sectors_per_req; | 1194 | u32 max_sectors_per_req; |
1195 | struct megasas_aen_event *ev; | ||
1179 | 1196 | ||
1180 | struct megasas_cmd **cmd_list; | 1197 | struct megasas_cmd **cmd_list; |
1181 | struct list_head cmd_pool; | 1198 | struct list_head cmd_pool; |