Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 1 | // MegaRAID SAS boot support. |
| 2 | // |
| 3 | // Copyright (C) 2012 Hannes Reinecke, SUSE Linux Products GmbH |
| 4 | // |
| 5 | // Authors: |
| 6 | // Hannes Reinecke <hare@suse.de> |
| 7 | // |
| 8 | // based on virtio-scsi.c which is written by: |
| 9 | // Paolo Bonzini <pbonzini@redhat.com> |
| 10 | // |
| 11 | // This file may be distributed under the terms of the GNU LGPLv3 license. |
| 12 | |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 13 | #include "biosvar.h" // GET_GLOBALFLAT |
Kevin O'Connor | 135f3f6 | 2013-09-14 23:57:26 -0400 | [diff] [blame] | 14 | #include "block.h" // struct drive_s |
Kevin O'Connor | d83c87b | 2013-01-21 01:14:12 -0500 | [diff] [blame] | 15 | #include "blockcmd.h" // scsi_drive_setup |
Kevin O'Connor | 2d2fa31 | 2013-09-14 21:55:26 -0400 | [diff] [blame] | 16 | #include "config.h" // CONFIG_* |
Kevin O'Connor | 9dea590 | 2013-09-14 20:23:54 -0400 | [diff] [blame] | 17 | #include "malloc.h" // free |
Kevin O'Connor | 2d2fa31 | 2013-09-14 21:55:26 -0400 | [diff] [blame] | 18 | #include "output.h" // dprintf |
Kevin O'Connor | 4d8510c | 2016-02-03 01:28:20 -0500 | [diff] [blame] | 19 | #include "pci.h" // pci_config_readl |
| 20 | #include "pcidevice.h" // foreachpci |
Kevin O'Connor | 2d2fa31 | 2013-09-14 21:55:26 -0400 | [diff] [blame] | 21 | #include "pci_ids.h" // PCI_DEVICE_ID_XXX |
| 22 | #include "pci_regs.h" // PCI_VENDOR_ID |
Kevin O'Connor | 3df600b | 2013-09-14 19:28:55 -0400 | [diff] [blame] | 23 | #include "stacks.h" // yield |
Kevin O'Connor | 135f3f6 | 2013-09-14 23:57:26 -0400 | [diff] [blame] | 24 | #include "std/disk.h" // DISK_RET_SUCCESS |
Kevin O'Connor | fa9c66a | 2013-09-14 19:10:40 -0400 | [diff] [blame] | 25 | #include "string.h" // memset |
Kevin O'Connor | 2d2fa31 | 2013-09-14 21:55:26 -0400 | [diff] [blame] | 26 | #include "util.h" // timer_calc |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 27 | |
| 28 | #define MFI_DB 0x0 // Doorbell |
| 29 | #define MFI_OMSG0 0x18 // Outbound message 0 |
| 30 | #define MFI_IDB 0x20 // Inbound doorbell |
| 31 | #define MFI_ODB 0x2c // Outbound doorbell |
| 32 | #define MFI_IQP 0x40 // Inbound queue port |
| 33 | #define MFI_OSP0 0xb0 // Outbound scratch pad0 |
| 34 | #define MFI_IQPL 0xc0 // Inbound queue port (low bytes) |
| 35 | #define MFI_IQPH 0xc4 // Inbound queue port (high bytes) |
| 36 | |
| 37 | #define MFI_STATE_MASK 0xf0000000 |
| 38 | #define MFI_STATE_WAIT_HANDSHAKE 0x60000000 |
| 39 | #define MFI_STATE_BOOT_MESSAGE_PENDING 0x90000000 |
| 40 | #define MFI_STATE_READY 0xb0000000 |
| 41 | #define MFI_STATE_OPERATIONAL 0xc0000000 |
| 42 | #define MFI_STATE_FAULT 0xf0000000 |
| 43 | |
| 44 | /* MFI Commands */ |
| 45 | typedef enum { |
| 46 | MFI_CMD_INIT = 0x00, |
| 47 | MFI_CMD_LD_READ, |
| 48 | MFI_CMD_LD_WRITE, |
| 49 | MFI_CMD_LD_SCSI_IO, |
| 50 | MFI_CMD_PD_SCSI_IO, |
| 51 | MFI_CMD_DCMD, |
| 52 | MFI_CMD_ABORT, |
| 53 | MFI_CMD_SMP, |
| 54 | MFI_CMD_STP |
| 55 | } mfi_cmd_t; |
| 56 | |
| 57 | struct megasas_cmd_frame { |
| 58 | u8 cmd; /*00h */ |
| 59 | u8 sense_len; /*01h */ |
| 60 | u8 cmd_status; /*02h */ |
| 61 | u8 scsi_status; /*03h */ |
| 62 | |
| 63 | u8 target_id; /*04h */ |
| 64 | u8 lun; /*05h */ |
| 65 | u8 cdb_len; /*06h */ |
| 66 | u8 sge_count; /*07h */ |
| 67 | |
| 68 | u32 context; /*08h */ |
| 69 | u32 context_64; /*0Ch */ |
| 70 | |
| 71 | u16 flags; /*10h */ |
| 72 | u16 timeout; /*12h */ |
| 73 | u32 data_xfer_len; /*14h */ |
| 74 | |
| 75 | union { |
| 76 | struct { |
| 77 | u32 opcode; /*18h */ |
| 78 | u8 mbox[12]; /*1Ch */ |
| 79 | u32 sgl_addr; /*28h */ |
| 80 | u32 sgl_len; /*32h */ |
| 81 | u32 pad; /*34h */ |
| 82 | } dcmd; |
| 83 | struct { |
| 84 | u32 sense_buf_lo; /*18h */ |
| 85 | u32 sense_buf_hi; /*1Ch */ |
| 86 | u8 cdb[16]; /*20h */ |
| 87 | u32 sgl_addr; /*30h */ |
| 88 | u32 sgl_len; /*34h */ |
| 89 | } pthru; |
| 90 | struct { |
| 91 | u8 pad[22]; /*18h */ |
| 92 | } gen; |
| 93 | }; |
| 94 | } __attribute__ ((packed)); |
| 95 | |
| 96 | struct mfi_ld_list_s { |
| 97 | u32 count; |
| 98 | u32 reserved_0; |
| 99 | struct { |
| 100 | u8 target; |
| 101 | u8 lun; |
| 102 | u16 seq; |
| 103 | u8 state; |
| 104 | u8 reserved_1[3]; |
| 105 | u64 size; |
| 106 | } lds[64]; |
| 107 | } __attribute__ ((packed)); |
| 108 | |
| 109 | #define MEGASAS_POLL_TIMEOUT 60000 // 60 seconds polling timeout |
| 110 | |
| 111 | struct megasas_lun_s { |
| 112 | struct drive_s drive; |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 113 | struct megasas_cmd_frame *frame; |
| 114 | u32 iobase; |
Kevin O'Connor | 051275b | 2013-10-26 11:53:38 -0400 | [diff] [blame] | 115 | u16 pci_id; |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 116 | u8 target; |
| 117 | u8 lun; |
| 118 | }; |
| 119 | |
| 120 | static int megasas_fire_cmd(u16 pci_id, u32 ioaddr, |
| 121 | struct megasas_cmd_frame *frame) |
| 122 | { |
| 123 | u32 frame_addr = (u32)frame; |
| 124 | int frame_count = 1; |
| 125 | u8 cmd_state; |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 126 | |
| 127 | dprintf(2, "Frame 0x%x\n", frame_addr); |
| 128 | if (pci_id == PCI_DEVICE_ID_LSI_SAS2004 || |
| 129 | pci_id == PCI_DEVICE_ID_LSI_SAS2008) { |
| 130 | outl(0, ioaddr + MFI_IQPH); |
| 131 | outl(frame_addr | frame_count << 1 | 1, ioaddr + MFI_IQPL); |
| 132 | } else if (pci_id == PCI_DEVICE_ID_DELL_PERC5 || |
| 133 | pci_id == PCI_DEVICE_ID_LSI_SAS1064R || |
| 134 | pci_id == PCI_DEVICE_ID_LSI_VERDE_ZCR) { |
| 135 | outl(frame_addr >> 3 | frame_count, ioaddr + MFI_IQP); |
| 136 | } else { |
| 137 | outl(frame_addr | frame_count << 1 | 1, ioaddr + MFI_IQP); |
| 138 | } |
| 139 | |
Kevin O'Connor | 018bdd7 | 2013-07-20 18:22:57 -0400 | [diff] [blame] | 140 | u32 end = timer_calc(MEGASAS_POLL_TIMEOUT); |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 141 | do { |
| 142 | for (;;) { |
| 143 | cmd_state = GET_LOWFLAT(frame->cmd_status); |
| 144 | if (cmd_state != 0xff) |
| 145 | break; |
Kevin O'Connor | 018bdd7 | 2013-07-20 18:22:57 -0400 | [diff] [blame] | 146 | if (timer_check(end)) { |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 147 | warn_timeout(); |
| 148 | return -1; |
| 149 | } |
| 150 | yield(); |
| 151 | } |
| 152 | } while (cmd_state == 0xff); |
| 153 | |
| 154 | if (cmd_state == 0 || cmd_state == 0x2d) |
| 155 | return 0; |
| 156 | dprintf(1, "ERROR: Frame 0x%x, status 0x%x\n", frame_addr, cmd_state); |
| 157 | return -1; |
| 158 | } |
| 159 | |
| 160 | int |
Kevin O'Connor | 0429a9e | 2015-07-07 12:06:01 -0400 | [diff] [blame] | 161 | megasas_process_op(struct disk_op_s *op) |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 162 | { |
Kevin O'Connor | 0429a9e | 2015-07-07 12:06:01 -0400 | [diff] [blame] | 163 | if (!CONFIG_MEGASAS) |
| 164 | return DISK_RET_EBADTRACK; |
| 165 | u8 cdb[16]; |
| 166 | int blocksize = scsi_fill_cmd(op, cdb, sizeof(cdb)); |
| 167 | if (blocksize < 0) |
| 168 | return default_process_op(op); |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 169 | struct megasas_lun_s *mlun_gf = |
Kevin O'Connor | e5a0b61 | 2017-07-11 12:24:50 -0400 | [diff] [blame] | 170 | container_of(op->drive_fl, struct megasas_lun_s, drive); |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 171 | struct megasas_cmd_frame *frame = GET_GLOBALFLAT(mlun_gf->frame); |
Kevin O'Connor | 051275b | 2013-10-26 11:53:38 -0400 | [diff] [blame] | 172 | u16 pci_id = GET_GLOBALFLAT(mlun_gf->pci_id); |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 173 | int i; |
| 174 | |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 175 | memset_fl(frame, 0, sizeof(*frame)); |
| 176 | SET_LOWFLAT(frame->cmd, MFI_CMD_LD_SCSI_IO); |
| 177 | SET_LOWFLAT(frame->cmd_status, 0xFF); |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 178 | SET_LOWFLAT(frame->target_id, GET_GLOBALFLAT(mlun_gf->target)); |
| 179 | SET_LOWFLAT(frame->lun, GET_GLOBALFLAT(mlun_gf->lun)); |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 180 | SET_LOWFLAT(frame->flags, 0x0001); |
| 181 | SET_LOWFLAT(frame->data_xfer_len, op->count * blocksize); |
| 182 | SET_LOWFLAT(frame->cdb_len, 16); |
| 183 | |
| 184 | for (i = 0; i < 16; i++) { |
| 185 | SET_LOWFLAT(frame->pthru.cdb[i], cdb[i]); |
| 186 | } |
| 187 | dprintf(2, "pthru cmd 0x%x count %d bs %d\n", |
| 188 | cdb[0], op->count, blocksize); |
| 189 | |
| 190 | if (op->count) { |
| 191 | SET_LOWFLAT(frame->pthru.sgl_addr, (u32)op->buf_fl); |
| 192 | SET_LOWFLAT(frame->pthru.sgl_len, op->count * blocksize); |
| 193 | SET_LOWFLAT(frame->sge_count, 1); |
| 194 | } |
| 195 | SET_LOWFLAT(frame->context, (u32)frame); |
| 196 | |
Kevin O'Connor | 1902c94 | 2013-10-26 11:48:06 -0400 | [diff] [blame] | 197 | if (megasas_fire_cmd(pci_id, GET_GLOBALFLAT(mlun_gf->iobase), frame) == 0) |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 198 | return DISK_RET_SUCCESS; |
| 199 | |
| 200 | dprintf(2, "pthru cmd 0x%x failed\n", cdb[0]); |
| 201 | return DISK_RET_EBADTRACK; |
| 202 | } |
| 203 | |
| 204 | static int |
| 205 | megasas_add_lun(struct pci_device *pci, u32 iobase, u8 target, u8 lun) |
| 206 | { |
| 207 | struct megasas_lun_s *mlun = malloc_fseg(sizeof(*mlun)); |
| 208 | char *name; |
| 209 | int prio, ret = 0; |
| 210 | |
| 211 | if (!mlun) { |
| 212 | warn_noalloc(); |
| 213 | return -1; |
| 214 | } |
| 215 | memset(mlun, 0, sizeof(*mlun)); |
| 216 | mlun->drive.type = DTYPE_MEGASAS; |
| 217 | mlun->drive.cntl_id = pci->bdf; |
Kevin O'Connor | 051275b | 2013-10-26 11:53:38 -0400 | [diff] [blame] | 218 | mlun->pci_id = pci->device; |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 219 | mlun->target = target; |
| 220 | mlun->lun = lun; |
| 221 | mlun->iobase = iobase; |
| 222 | mlun->frame = memalign_low(256, sizeof(struct megasas_cmd_frame)); |
| 223 | if (!mlun->frame) { |
| 224 | warn_noalloc(); |
| 225 | free(mlun); |
| 226 | return -1; |
| 227 | } |
Kevin O'Connor | 937ca6f | 2016-02-03 03:27:36 -0500 | [diff] [blame] | 228 | name = znprintf(MAXDESCSIZE, "MegaRAID SAS (PCI %pP) LD %d:%d" |
| 229 | , pci, target, lun); |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 230 | prio = bootprio_find_scsi_device(pci, target, lun); |
Kevin O'Connor | d83c87b | 2013-01-21 01:14:12 -0500 | [diff] [blame] | 231 | ret = scsi_drive_setup(&mlun->drive, name, prio); |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 232 | free(name); |
| 233 | if (ret) { |
| 234 | free(mlun->frame); |
| 235 | free(mlun); |
| 236 | ret = -1; |
| 237 | } |
| 238 | |
| 239 | return ret; |
| 240 | } |
| 241 | |
| 242 | static void megasas_scan_target(struct pci_device *pci, u32 iobase) |
| 243 | { |
| 244 | struct mfi_ld_list_s ld_list; |
| 245 | struct megasas_cmd_frame *frame = memalign_tmp(256, sizeof(*frame)); |
Kevin O'Connor | 3abdc7c | 2015-06-30 11:10:41 -0400 | [diff] [blame] | 246 | if (!frame) { |
| 247 | warn_noalloc(); |
| 248 | return; |
| 249 | } |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 250 | |
| 251 | memset(&ld_list, 0, sizeof(ld_list)); |
| 252 | memset_fl(frame, 0, sizeof(*frame)); |
| 253 | |
| 254 | frame->cmd = MFI_CMD_DCMD; |
| 255 | frame->cmd_status = 0xFF; |
| 256 | frame->sge_count = 1; |
| 257 | frame->flags = 0x0011; |
| 258 | frame->data_xfer_len = sizeof(ld_list); |
| 259 | frame->dcmd.opcode = 0x03010000; |
| 260 | frame->dcmd.sgl_addr = (u32)MAKE_FLATPTR(GET_SEG(SS), &ld_list); |
| 261 | frame->dcmd.sgl_len = sizeof(ld_list); |
| 262 | frame->context = (u32)frame; |
| 263 | |
| 264 | if (megasas_fire_cmd(pci->device, iobase, frame) == 0) { |
| 265 | dprintf(2, "%d LD found\n", ld_list.count); |
Kevin O'Connor | 3abdc7c | 2015-06-30 11:10:41 -0400 | [diff] [blame] | 266 | int i; |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 267 | for (i = 0; i < ld_list.count; i++) { |
| 268 | dprintf(2, "LD %d:%d state 0x%x\n", |
| 269 | ld_list.lds[i].target, ld_list.lds[i].lun, |
| 270 | ld_list.lds[i].state); |
| 271 | if (ld_list.lds[i].state != 0) { |
| 272 | megasas_add_lun(pci, iobase, |
| 273 | ld_list.lds[i].target, ld_list.lds[i].lun); |
| 274 | } |
| 275 | } |
| 276 | } |
| 277 | } |
| 278 | |
| 279 | static int megasas_transition_to_ready(struct pci_device *pci, u32 ioaddr) |
| 280 | { |
| 281 | u32 fw_state = 0, new_state, mfi_flags = 0; |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 282 | |
| 283 | if (pci->device == PCI_DEVICE_ID_LSI_SAS1064R || |
| 284 | pci->device == PCI_DEVICE_ID_DELL_PERC5) |
| 285 | new_state = inl(ioaddr + MFI_OMSG0) & MFI_STATE_MASK; |
| 286 | else |
| 287 | new_state = inl(ioaddr + MFI_OSP0) & MFI_STATE_MASK; |
| 288 | |
| 289 | while (fw_state != new_state) { |
| 290 | switch (new_state) { |
| 291 | case MFI_STATE_FAULT: |
| 292 | dprintf(1, "ERROR: fw in fault state\n"); |
| 293 | return -1; |
| 294 | break; |
| 295 | case MFI_STATE_WAIT_HANDSHAKE: |
| 296 | mfi_flags = 0x08; |
| 297 | /* fallthrough */ |
| 298 | case MFI_STATE_BOOT_MESSAGE_PENDING: |
| 299 | mfi_flags |= 0x10; |
| 300 | if (pci->device == PCI_DEVICE_ID_LSI_SAS2004 || |
| 301 | pci->device == PCI_DEVICE_ID_LSI_SAS2008 || |
| 302 | pci->device == PCI_DEVICE_ID_LSI_SAS2208 || |
| 303 | pci->device == PCI_DEVICE_ID_LSI_SAS3108) { |
Stefan Weil | a8c72ee | 2015-08-29 08:02:38 +0200 | [diff] [blame] | 304 | outl(mfi_flags, ioaddr + MFI_DB); |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 305 | } else { |
Stefan Weil | a8c72ee | 2015-08-29 08:02:38 +0200 | [diff] [blame] | 306 | outl(mfi_flags, ioaddr + MFI_IDB); |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 307 | } |
| 308 | break; |
| 309 | case MFI_STATE_OPERATIONAL: |
| 310 | mfi_flags = 0x07; |
| 311 | if (pci->device == PCI_DEVICE_ID_LSI_SAS2004 || |
| 312 | pci->device == PCI_DEVICE_ID_LSI_SAS2008 || |
| 313 | pci->device == PCI_DEVICE_ID_LSI_SAS2208 || |
| 314 | pci->device == PCI_DEVICE_ID_LSI_SAS3108) { |
Stefan Weil | a8c72ee | 2015-08-29 08:02:38 +0200 | [diff] [blame] | 315 | outl(mfi_flags, ioaddr + MFI_DB); |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 316 | if (pci->device == PCI_DEVICE_ID_LSI_SAS2208 || |
| 317 | pci->device == PCI_DEVICE_ID_LSI_SAS3108) { |
| 318 | int j = 0; |
| 319 | u32 doorbell; |
| 320 | |
| 321 | while (j < MEGASAS_POLL_TIMEOUT) { |
| 322 | doorbell = inl(ioaddr + MFI_DB) & 1; |
| 323 | if (!doorbell) |
| 324 | break; |
| 325 | msleep(20); |
| 326 | j++; |
| 327 | } |
| 328 | } |
| 329 | } else { |
Kevin O'Connor | ff28e3b | 2015-09-03 10:00:57 -0400 | [diff] [blame] | 330 | outl(mfi_flags, ioaddr + MFI_IDB); |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 331 | } |
| 332 | break; |
| 333 | case MFI_STATE_READY: |
| 334 | dprintf(2, "MegaRAID SAS fw ready\n"); |
| 335 | return 0; |
| 336 | } |
| 337 | // The current state should not last longer than poll timeout |
Kevin O'Connor | 018bdd7 | 2013-07-20 18:22:57 -0400 | [diff] [blame] | 338 | u32 end = timer_calc(MEGASAS_POLL_TIMEOUT); |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 339 | for (;;) { |
Kevin O'Connor | 018bdd7 | 2013-07-20 18:22:57 -0400 | [diff] [blame] | 340 | if (timer_check(end)) { |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 341 | break; |
| 342 | } |
| 343 | yield(); |
| 344 | fw_state = new_state; |
| 345 | if (pci->device == PCI_DEVICE_ID_LSI_SAS1064R || |
| 346 | pci->device == PCI_DEVICE_ID_DELL_PERC5) |
| 347 | new_state = inl(ioaddr + MFI_OMSG0) & MFI_STATE_MASK; |
| 348 | else |
| 349 | new_state = inl(ioaddr + MFI_OSP0) & MFI_STATE_MASK; |
| 350 | if (new_state != fw_state) { |
| 351 | break; |
| 352 | } |
| 353 | } |
| 354 | } |
| 355 | dprintf(1, "ERROR: fw in state %x\n", new_state & MFI_STATE_MASK); |
| 356 | return -1; |
| 357 | } |
| 358 | |
| 359 | static void |
Kevin O'Connor | 79bafa1 | 2016-04-05 13:04:07 -0400 | [diff] [blame] | 360 | init_megasas(void *data) |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 361 | { |
Kevin O'Connor | 79bafa1 | 2016-04-05 13:04:07 -0400 | [diff] [blame] | 362 | struct pci_device *pci = data; |
Kevin O'Connor | 71f4844 | 2016-02-02 22:19:35 -0500 | [diff] [blame] | 363 | u32 bar = PCI_BASE_ADDRESS_2; |
| 364 | if (!(pci_config_readl(pci->bdf, bar) & PCI_BASE_ADDRESS_IO_MASK)) |
| 365 | bar = PCI_BASE_ADDRESS_0; |
| 366 | u32 iobase = pci_enable_iobar(pci, bar); |
Hannes Reinecke | 09f876f | 2014-11-06 14:31:56 +0100 | [diff] [blame] | 367 | if (!iobase) |
Kevin O'Connor | 71f4844 | 2016-02-02 22:19:35 -0500 | [diff] [blame] | 368 | return; |
| 369 | pci_enable_busmaster(pci); |
Hannes Reinecke | 09f876f | 2014-11-06 14:31:56 +0100 | [diff] [blame] | 370 | |
Kevin O'Connor | 7b67300 | 2016-02-03 03:03:15 -0500 | [diff] [blame] | 371 | dprintf(1, "found MegaRAID SAS at %pP, io @ %x\n", pci, iobase); |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 372 | |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 373 | // reset |
| 374 | if (megasas_transition_to_ready(pci, iobase) == 0) |
| 375 | megasas_scan_target(pci, iobase); |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 376 | } |
| 377 | |
| 378 | void |
| 379 | megasas_setup(void) |
| 380 | { |
| 381 | ASSERT32FLAT(); |
| 382 | if (!CONFIG_MEGASAS) |
| 383 | return; |
| 384 | |
| 385 | dprintf(3, "init megasas\n"); |
| 386 | |
| 387 | struct pci_device *pci; |
| 388 | foreachpci(pci) { |
| 389 | if (pci->vendor != PCI_VENDOR_ID_LSI_LOGIC && |
| 390 | pci->vendor != PCI_VENDOR_ID_DELL) |
| 391 | continue; |
Hannes Reinecke | 261e870 | 2012-12-19 15:12:47 +0100 | [diff] [blame] | 392 | if (pci->device == PCI_DEVICE_ID_LSI_SAS1064R || |
| 393 | pci->device == PCI_DEVICE_ID_LSI_SAS1078 || |
| 394 | pci->device == PCI_DEVICE_ID_LSI_SAS1078DE || |
| 395 | pci->device == PCI_DEVICE_ID_LSI_SAS2108 || |
| 396 | pci->device == PCI_DEVICE_ID_LSI_SAS2108E || |
| 397 | pci->device == PCI_DEVICE_ID_LSI_SAS2004 || |
| 398 | pci->device == PCI_DEVICE_ID_LSI_SAS2008 || |
| 399 | pci->device == PCI_DEVICE_ID_LSI_VERDE_ZCR || |
| 400 | pci->device == PCI_DEVICE_ID_DELL_PERC5 || |
| 401 | pci->device == PCI_DEVICE_ID_LSI_SAS2208 || |
| 402 | pci->device == PCI_DEVICE_ID_LSI_SAS3108) |
Kevin O'Connor | 79bafa1 | 2016-04-05 13:04:07 -0400 | [diff] [blame] | 403 | run_thread(init_megasas, pci); |
Hannes Reinecke | 2df70bf | 2012-11-13 15:03:31 +0100 | [diff] [blame] | 404 | } |
| 405 | } |