aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/megaraid
diff options
context:
space:
mode:
authorYang, Bo <Bo.Yang@lsi.com>2009-10-06 16:50:17 -0400
committerJames Bottomley <James.Bottomley@suse.de>2009-10-29 13:03:21 -0400
commit7e8a75f4dfbff173977b2f58799c3eceb7b09afd (patch)
tree3ef74557eaa6cf0ceb6a68e71b0dfb068bb52cb4 /drivers/scsi/megaraid
parent0c79e681eef10810a5ed41a2eb1dce244ab1c37d (diff)
[SCSI] megaraid_sas: Add the support for updating the OS after adding/removing the devices from FW
Driver will update the OS devices after adding and deleting the device from FW. When driver receive add or delete AEN from FW, driver will send the DCMD cmd to get the System PD list from FW. Then driver will check if this device already in the OS: If add event and OS don't have the device (but it is in the list), driver add the device to OS, otherwise driver will not add. If remove event, driver will check the list, if is not in the list, but OS have the device, driver will remove the device. Signed-off-by Bo Yang<bo.yang@lsi.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/megaraid')
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c125
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h17
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
1523static 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
3953static void
3954megasas_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
3916static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUGO, 4039static 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
288enum MR_PD_STATE { 299enum 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
1171struct megasas_aen_event {
1172 struct work_struct hotplug_work;
1173 struct megasas_instance *instance;
1174};
1175
1160struct megasas_instance { 1176struct 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;