11e66f787SSean Bruno /*-
27ea28254SJohn Hall * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries.
31e66f787SSean Bruno *
41e66f787SSean Bruno * Redistribution and use in source and binary forms, with or without
51e66f787SSean Bruno * modification, are permitted provided that the following conditions
61e66f787SSean Bruno * are met:
71e66f787SSean Bruno * 1. Redistributions of source code must retain the above copyright
81e66f787SSean Bruno * notice, this list of conditions and the following disclaimer.
91e66f787SSean Bruno * 2. Redistributions in binary form must reproduce the above copyright
101e66f787SSean Bruno * notice, this list of conditions and the following disclaimer in the
111e66f787SSean Bruno * documentation and/or other materials provided with the distribution.
121e66f787SSean Bruno *
131e66f787SSean Bruno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
141e66f787SSean Bruno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
151e66f787SSean Bruno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
161e66f787SSean Bruno * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
171e66f787SSean Bruno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
181e66f787SSean Bruno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
191e66f787SSean Bruno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
201e66f787SSean Bruno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
211e66f787SSean Bruno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
221e66f787SSean Bruno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
231e66f787SSean Bruno * SUCH DAMAGE.
241e66f787SSean Bruno */
251e66f787SSean Bruno
261e66f787SSean Bruno
271e66f787SSean Bruno #include "smartpqi_includes.h"
281e66f787SSean Bruno
297ea28254SJohn Hall /*
307ea28254SJohn Hall * Populate the controller's advanced aio features via BMIC cmd.
317ea28254SJohn Hall */
327ea28254SJohn Hall int
pqisrc_QuerySenseFeatures(pqisrc_softstate_t * softs)337ea28254SJohn Hall pqisrc_QuerySenseFeatures(pqisrc_softstate_t *softs)
341e66f787SSean Bruno {
357ea28254SJohn Hall bmic_sense_feature_aio_buffer_t *features;
367ea28254SJohn Hall int ret;
377ea28254SJohn Hall pqisrc_raid_req_t request;
381e66f787SSean Bruno
397ea28254SJohn Hall /* Initializing defaults for AIO support subpage */
407ea28254SJohn Hall softs->max_aio_write_raid5_6 =
417ea28254SJohn Hall PQISRC_MAX_AIO_RAID5_OR_6_WRITE;
427ea28254SJohn Hall softs->max_aio_write_raid1_10_2drv =
437ea28254SJohn Hall PQISRC_MAX_AIO_RAID1_OR_10_WRITE_2DRV;
447ea28254SJohn Hall softs->max_aio_write_raid1_10_3drv =
457ea28254SJohn Hall PQISRC_MAX_AIO_RAID1_OR_10_WRITE_3DRV;
467ea28254SJohn Hall softs->max_aio_rw_xfer_crypto_nvme =
477ea28254SJohn Hall PQISRC_MAX_AIO_RW_XFER_NVME_CRYPTO;
487ea28254SJohn Hall softs->max_aio_rw_xfer_crypto_sas_sata =
497ea28254SJohn Hall PQISRC_MAX_AIO_RW_XFER_SAS_SATA_CRYPTO;
501e66f787SSean Bruno
517ea28254SJohn Hall #ifdef DEVICE_HINT
527ea28254SJohn Hall softs->enable_stream_detection = softs->hint.stream_status;
537ea28254SJohn Hall #endif
541e66f787SSean Bruno
557ea28254SJohn Hall /* Implement SENSE_FEATURE BMIC to populate AIO limits */
567ea28254SJohn Hall features = os_mem_alloc(softs, sizeof(*features));
577ea28254SJohn Hall if (!features) {
587ea28254SJohn Hall DBG_ERR("Failed to allocate memory for sense aio features.\n");
597ea28254SJohn Hall goto err;
607ea28254SJohn Hall }
617ea28254SJohn Hall memset(features, 0, sizeof(*features));
627ea28254SJohn Hall
637ea28254SJohn Hall memset(&request, 0, sizeof(request));
647ea28254SJohn Hall request.data_direction = SOP_DATA_DIR_TO_DEVICE;
657ea28254SJohn Hall request.cmd.bmic_cdb.op_code = BMIC_READ;
667ea28254SJohn Hall request.cmd.cdb[2] = IO_SENSE_FEATURES_PAGE;
677ea28254SJohn Hall request.cmd.cdb[3] = SENSE_FEATURES_AIO_SUBPAGE;
687ea28254SJohn Hall request.cmd.bmic_cdb.cmd = BMIC_SENSE_FEATURE;
697ea28254SJohn Hall request.cmd.bmic_cdb.xfer_len = BE_16(sizeof(*features));
707ea28254SJohn Hall ret = pqisrc_prepare_send_ctrlr_request(softs, &request,
717ea28254SJohn Hall features, sizeof(*features));
727ea28254SJohn Hall
737ea28254SJohn Hall if (ret)
747ea28254SJohn Hall goto free_err;
757ea28254SJohn Hall
767ea28254SJohn Hall /* If AIO subpage was valid, use values from that page */
777ea28254SJohn Hall if (features->aio_subpage.header.total_length >=
787ea28254SJohn Hall MINIMUM_AIO_SUBPAGE_LENGTH) {
797ea28254SJohn Hall DBG_INIT("AIO support subpage valid. total_length = 0x%0x.\n",
807ea28254SJohn Hall features->aio_subpage.header.total_length);
817ea28254SJohn Hall softs->adv_aio_capable = true;
827ea28254SJohn Hall
837ea28254SJohn Hall /* AIO transfer limits are reported in kbytes, so x 1024.
847ea28254SJohn Hall * Values of 0 mean 'no limit'.
857ea28254SJohn Hall */
867ea28254SJohn Hall
877ea28254SJohn Hall softs->max_aio_write_raid5_6 =
887ea28254SJohn Hall (features->aio_subpage.max_aio_write_raid5_6 == 0) ?
897ea28254SJohn Hall PQISRC_MAX_AIO_NO_LIMIT :
907ea28254SJohn Hall features->aio_subpage.max_aio_write_raid5_6 * 1024;
917ea28254SJohn Hall softs->max_aio_write_raid1_10_2drv =
927ea28254SJohn Hall (features->aio_subpage.max_aio_write_raid1_10_2drv
937ea28254SJohn Hall == 0) ? PQISRC_MAX_AIO_NO_LIMIT :
947ea28254SJohn Hall features->aio_subpage.max_aio_write_raid1_10_2drv
957ea28254SJohn Hall * 1024;
967ea28254SJohn Hall softs->max_aio_write_raid1_10_3drv =
977ea28254SJohn Hall (features->aio_subpage.max_aio_write_raid1_10_3drv
987ea28254SJohn Hall == 0) ? PQISRC_MAX_AIO_NO_LIMIT :
997ea28254SJohn Hall features->aio_subpage.max_aio_write_raid1_10_3drv
1007ea28254SJohn Hall * 1024;
1017ea28254SJohn Hall softs->max_aio_rw_xfer_crypto_nvme =
1027ea28254SJohn Hall (features->aio_subpage.max_aio_rw_xfer_crypto_nvme
1037ea28254SJohn Hall == 0) ? PQISRC_MAX_AIO_NO_LIMIT :
1047ea28254SJohn Hall features->aio_subpage.max_aio_rw_xfer_crypto_nvme
1057ea28254SJohn Hall * 1024;
1067ea28254SJohn Hall softs->max_aio_rw_xfer_crypto_sas_sata =
1077ea28254SJohn Hall (features->aio_subpage.max_aio_rw_xfer_crypto_sas_sata
1087ea28254SJohn Hall == 0) ? PQISRC_MAX_AIO_NO_LIMIT :
1097ea28254SJohn Hall features->aio_subpage.max_aio_rw_xfer_crypto_sas_sata
1107ea28254SJohn Hall * 1024;
1117ea28254SJohn Hall
1127ea28254SJohn Hall DBG_INIT("softs->max_aio_write_raid5_6: 0x%x\n",
1137ea28254SJohn Hall softs->max_aio_write_raid5_6);
1147ea28254SJohn Hall DBG_INIT("softs->max_aio_write_raid1_10_2drv: 0x%x\n",
1157ea28254SJohn Hall softs->max_aio_write_raid1_10_2drv);
1167ea28254SJohn Hall DBG_INIT("softs->max_aio_write_raid1_10_3drv: 0x%x\n",
1177ea28254SJohn Hall softs->max_aio_write_raid1_10_3drv);
1187ea28254SJohn Hall DBG_INIT("softs->max_aio_rw_xfer_crypto_nvme: 0x%x\n",
1197ea28254SJohn Hall softs->max_aio_rw_xfer_crypto_nvme);
1207ea28254SJohn Hall DBG_INIT("softs->max_aio_rw_xfer_crypto_sas_sata: 0x%x\n",
1217ea28254SJohn Hall softs->max_aio_rw_xfer_crypto_sas_sata);
1227ea28254SJohn Hall
1237ea28254SJohn Hall } else {
1247ea28254SJohn Hall DBG_WARN("Problem getting AIO support subpage settings. "
1257ea28254SJohn Hall "Disabling advanced AIO writes.\n");
1267ea28254SJohn Hall softs->adv_aio_capable = false;
1277ea28254SJohn Hall }
1287ea28254SJohn Hall
1297ea28254SJohn Hall
1307ea28254SJohn Hall os_mem_free(softs, features, sizeof(*features));
1317ea28254SJohn Hall return ret;
1327ea28254SJohn Hall free_err:
1337ea28254SJohn Hall os_mem_free(softs, features, sizeof(*features));
1347ea28254SJohn Hall err:
1357ea28254SJohn Hall return PQI_STATUS_FAILURE;
1361e66f787SSean Bruno }
1371e66f787SSean Bruno
1389fac68fcSPAPANI SRIKANTH /*
1397ea28254SJohn Hall * Initialize target ID pool for exposed physical devices .
1409fac68fcSPAPANI SRIKANTH */
1419fac68fcSPAPANI SRIKANTH void
pqisrc_init_bitmap(pqisrc_softstate_t * softs)1427ea28254SJohn Hall pqisrc_init_bitmap(pqisrc_softstate_t *softs)
143b17f4335SSean Bruno {
1447ea28254SJohn Hall memset(&softs->bit_map, SLOT_AVAILABLE, sizeof(softs->bit_map));
145b17f4335SSean Bruno }
146b17f4335SSean Bruno
1477ea28254SJohn Hall void
pqisrc_remove_target_bit(pqisrc_softstate_t * softs,int target)1487ea28254SJohn Hall pqisrc_remove_target_bit(pqisrc_softstate_t *softs, int target)
1497ea28254SJohn Hall {
1507ea28254SJohn Hall if((target == PQI_CTLR_INDEX) || (target == INVALID_ELEM)) {
1517ea28254SJohn Hall DBG_ERR("Invalid target ID\n");
1527ea28254SJohn Hall return;
1537ea28254SJohn Hall }
1547ea28254SJohn Hall DBG_DISC("Giving back target %d\n", target);
1557ea28254SJohn Hall softs->bit_map.bit_vector[target] = SLOT_AVAILABLE;
1567ea28254SJohn Hall }
1577ea28254SJohn Hall
1587ea28254SJohn Hall /* Use bit map to find availible targets */
1599fac68fcSPAPANI SRIKANTH int
pqisrc_find_avail_target(pqisrc_softstate_t * softs)1607ea28254SJohn Hall pqisrc_find_avail_target(pqisrc_softstate_t *softs)
161b17f4335SSean Bruno {
1629fac68fcSPAPANI SRIKANTH
1637ea28254SJohn Hall int avail_target;
1647ea28254SJohn Hall for(avail_target = 1; avail_target < MAX_TARGET_BIT; avail_target++) {
1657ea28254SJohn Hall if(softs->bit_map.bit_vector[avail_target] == SLOT_AVAILABLE){
1667ea28254SJohn Hall softs->bit_map.bit_vector[avail_target] = SLOT_TAKEN;
1677ea28254SJohn Hall DBG_DISC("Avail_target is %d\n", avail_target);
1687ea28254SJohn Hall return avail_target;
1697ea28254SJohn Hall }
1707ea28254SJohn Hall }
1717ea28254SJohn Hall DBG_ERR("No available targets\n");
172b17f4335SSean Bruno return INVALID_ELEM;
173b17f4335SSean Bruno }
174b17f4335SSean Bruno
1757ea28254SJohn Hall /* Subroutine used to set Bus-Target-Lun for the requested device */
1767ea28254SJohn Hall static inline void
pqisrc_set_btl(pqi_scsi_dev_t * device,int bus,int target,int lun)1777ea28254SJohn Hall pqisrc_set_btl(pqi_scsi_dev_t *device, int bus, int target, int lun)
178b17f4335SSean Bruno {
1791e66f787SSean Bruno DBG_FUNC("IN\n");
1801e66f787SSean Bruno
1817ea28254SJohn Hall device->bus = bus;
1827ea28254SJohn Hall device->target = target;
1837ea28254SJohn Hall device->lun = lun;
1841e66f787SSean Bruno
1851e66f787SSean Bruno DBG_FUNC("OUT\n");
1867ea28254SJohn Hall }
1871e66f787SSean Bruno
1887ea28254SJohn Hall /* Add all exposed physical devices, logical devices, controller devices, PT RAID
1897ea28254SJohn Hall * devices and multi-lun devices */
1907ea28254SJohn Hall boolean_t
pqisrc_add_softs_entry(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device,uint8_t * scsi3addr)1917ea28254SJohn Hall pqisrc_add_softs_entry(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device,
1927ea28254SJohn Hall uint8_t *scsi3addr)
1937ea28254SJohn Hall {
1947ea28254SJohn Hall /* Add physical devices with targets that need
1957ea28254SJohn Hall * targets */
1967ea28254SJohn Hall int j;
1977ea28254SJohn Hall int tid = 0;
1987ea28254SJohn Hall unsigned char addr1[8], addr2[8];
1997ea28254SJohn Hall pqi_scsi_dev_t *temp_device;
2007ea28254SJohn Hall
2017ea28254SJohn Hall /* If controller device, add it to list because its lun/bus/target
2027ea28254SJohn Hall * values are already set */
2037ea28254SJohn Hall if(pqisrc_is_hba_lunid(scsi3addr))
2047ea28254SJohn Hall goto add_device_to_dev_list;
2057ea28254SJohn Hall
2067ea28254SJohn Hall /* If exposed physical device give it a target then add it
2077ea28254SJohn Hall * to the dev list */
2087ea28254SJohn Hall if(!pqisrc_is_logical_device(device)) {
2097ea28254SJohn Hall tid = pqisrc_find_avail_target(softs);
2107ea28254SJohn Hall if(INVALID_ELEM != tid){
2117ea28254SJohn Hall pqisrc_set_btl(device, PQI_PHYSICAL_DEVICE_BUS, tid, 0);
2127ea28254SJohn Hall goto add_device_to_dev_list;
2137ea28254SJohn Hall }
2147ea28254SJohn Hall }
2157ea28254SJohn Hall
2167ea28254SJohn Hall /* If external raid device , assign target from the target pool.
2177ea28254SJohn Hall * If a non-zero lun device, search through the list & find the
2187ea28254SJohn Hall * device which has same target (byte 2 of LUN address).
2197ea28254SJohn Hall * Assign the same target for this new lun. */
2207ea28254SJohn Hall if (pqisrc_is_external_raid_device(device)) {
2217ea28254SJohn Hall memcpy(addr1, device->scsi3addr, 8);
2227ea28254SJohn Hall for(j = 0; j < PQI_MAX_DEVICES; j++) {
2237ea28254SJohn Hall if(softs->dev_list[j] == NULL)
2247ea28254SJohn Hall continue;
2257ea28254SJohn Hall temp_device = softs->dev_list[j];
2267ea28254SJohn Hall memcpy(addr2, temp_device->scsi3addr, 8);
2277ea28254SJohn Hall if (addr1[2] == addr2[2]) {
2287ea28254SJohn Hall pqisrc_set_btl(device, PQI_EXTERNAL_RAID_VOLUME_BUS,
2297ea28254SJohn Hall temp_device->target,device->scsi3addr[0]);
2307ea28254SJohn Hall goto add_device_to_dev_list;
2317ea28254SJohn Hall }
2327ea28254SJohn Hall }
2337ea28254SJohn Hall tid = pqisrc_find_avail_target(softs);
2347ea28254SJohn Hall if(INVALID_ELEM != tid){
2357ea28254SJohn Hall pqisrc_set_btl(device, PQI_EXTERNAL_RAID_VOLUME_BUS, tid, device->scsi3addr[0]);
2367ea28254SJohn Hall goto add_device_to_dev_list;
2377ea28254SJohn Hall }
2387ea28254SJohn Hall }
2397ea28254SJohn Hall
2407ea28254SJohn Hall /* If logical device, add it to list because its lun/bus/target
2417ea28254SJohn Hall * values are already set */
2427ea28254SJohn Hall if(pqisrc_is_logical_device(device) && !pqisrc_is_external_raid_device(device))
2437ea28254SJohn Hall goto add_device_to_dev_list;
2447ea28254SJohn Hall
2457ea28254SJohn Hall /* This is a non-zero lun of a multi-lun device.
2467ea28254SJohn Hall * Search through our list and find the device which
2477ea28254SJohn Hall * has the same 8 byte LUN address, except with bytes 4 and 5.
2487ea28254SJohn Hall * Assign the same bus and target for this new LUN.
2497ea28254SJohn Hall * Use the logical unit number from the firmware. */
2507ea28254SJohn Hall memcpy(addr1, device->scsi3addr, 8);
2517ea28254SJohn Hall addr1[4] = 0;
2527ea28254SJohn Hall addr1[5] = 0;
2537ea28254SJohn Hall for(j = 0; j < PQI_MAX_DEVICES; j++) {
2547ea28254SJohn Hall if(softs->dev_list[j] == NULL)
2557ea28254SJohn Hall continue;
2567ea28254SJohn Hall temp_device = softs->dev_list[j];
2577ea28254SJohn Hall memcpy(addr2, temp_device->scsi3addr, 8);
2587ea28254SJohn Hall addr2[4] = 0;
2597ea28254SJohn Hall addr2[5] = 0;
2607ea28254SJohn Hall /* If addresses are the same, except for bytes 4 and 5
2617ea28254SJohn Hall * then the passed-in device is an additional lun of a
2627ea28254SJohn Hall * previously added multi-lun device. Use the same target
2637ea28254SJohn Hall * id as that previous device. Otherwise, use the new
2647ea28254SJohn Hall * target id */
2657ea28254SJohn Hall if(memcmp(addr1, addr2, 8) == 0) {
2667ea28254SJohn Hall pqisrc_set_btl(device, temp_device->bus,
2677ea28254SJohn Hall temp_device->target, temp_device->scsi3addr[4]);
2687ea28254SJohn Hall goto add_device_to_dev_list;
2697ea28254SJohn Hall }
2707ea28254SJohn Hall }
2717ea28254SJohn Hall DBG_ERR("The device is not a physical, lun or ptraid device"
2727ea28254SJohn Hall "B %d: T %d: L %d\n", device->bus, device->target,
2737ea28254SJohn Hall device->lun );
2747ea28254SJohn Hall return false;
2757ea28254SJohn Hall
2767ea28254SJohn Hall add_device_to_dev_list:
2777ea28254SJohn Hall /* Actually add the device to the driver list
2787ea28254SJohn Hall * softs->dev_list */
2797ea28254SJohn Hall softs->num_devs++;
2807ea28254SJohn Hall for(j = 0; j < PQI_MAX_DEVICES; j++) {
2817ea28254SJohn Hall if(softs->dev_list[j])
2827ea28254SJohn Hall continue;
2837ea28254SJohn Hall softs->dev_list[j] = device;
2847ea28254SJohn Hall break;
2857ea28254SJohn Hall }
2867ea28254SJohn Hall DBG_NOTE("Added device [%d of %d]: B %d: T %d: L %d\n",
2877ea28254SJohn Hall j, softs->num_devs, device->bus, device->target,
2887ea28254SJohn Hall device->lun);
2891e66f787SSean Bruno return true;
2901e66f787SSean Bruno }
2911e66f787SSean Bruno
2927ea28254SJohn Hall /* Return a given index for a specific bus, target, lun within the
2937ea28254SJohn Hall * softs dev_list (This function is specifically for freebsd)*/
2949fac68fcSPAPANI SRIKANTH int
pqisrc_find_btl_list_index(pqisrc_softstate_t * softs,int bus,int target,int lun)2957ea28254SJohn Hall pqisrc_find_btl_list_index(pqisrc_softstate_t *softs,
2967ea28254SJohn Hall int bus, int target, int lun)
2971e66f787SSean Bruno {
2981e66f787SSean Bruno
2997ea28254SJohn Hall int index;
3007ea28254SJohn Hall pqi_scsi_dev_t *temp_device;
3017ea28254SJohn Hall for(index = 0; index < PQI_MAX_DEVICES; index++) {
3027ea28254SJohn Hall if(softs->dev_list[index] == NULL)
3037ea28254SJohn Hall continue;
3047ea28254SJohn Hall temp_device = softs->dev_list[index];
3057ea28254SJohn Hall /* Match the devices then return the location
3067ea28254SJohn Hall * of that device for further use*/
3077ea28254SJohn Hall if(bus == softs->bus_id &&
3087ea28254SJohn Hall target == temp_device->target &&
3097ea28254SJohn Hall lun == temp_device->lun){
3107ea28254SJohn Hall DBG_DISC("Returning device list index %d\n", index);
3117ea28254SJohn Hall return index;
3127ea28254SJohn Hall
3137ea28254SJohn Hall }
3147ea28254SJohn Hall if ((temp_device->is_physical_device) && (target == temp_device->target)
3157ea28254SJohn Hall && (temp_device->is_multi_lun)) {
3167ea28254SJohn Hall return index;
3177ea28254SJohn Hall }
3187ea28254SJohn Hall }
3197ea28254SJohn Hall return INVALID_ELEM;
3207ea28254SJohn Hall }
3217ea28254SJohn Hall
3227ea28254SJohn Hall /* Return a given index for a specific device within the
3237ea28254SJohn Hall * softs dev_list */
3247ea28254SJohn Hall int
pqisrc_find_device_list_index(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)3257ea28254SJohn Hall pqisrc_find_device_list_index(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
3267ea28254SJohn Hall {
3277ea28254SJohn Hall
3287ea28254SJohn Hall int index;
3297ea28254SJohn Hall pqi_scsi_dev_t *temp_device;
3307ea28254SJohn Hall for(index = 0; index < PQI_MAX_DEVICES; index++) {
3317ea28254SJohn Hall if(softs->dev_list[index] == NULL)
3327ea28254SJohn Hall continue;
3337ea28254SJohn Hall temp_device = softs->dev_list[index];
3347ea28254SJohn Hall /* Match the devices then return the location
3357ea28254SJohn Hall * of that device for further use*/
3367ea28254SJohn Hall if(device->bus == temp_device->bus &&
3377ea28254SJohn Hall device->target == temp_device->target
3387ea28254SJohn Hall && device->lun == temp_device->lun){
3397ea28254SJohn Hall DBG_DISC("Returning device list index %d\n", index);
3407ea28254SJohn Hall return index;
3417ea28254SJohn Hall
3427ea28254SJohn Hall }
3437ea28254SJohn Hall }
3447ea28254SJohn Hall return INVALID_ELEM;
3457ea28254SJohn Hall }
3467ea28254SJohn Hall
3477ea28254SJohn Hall /* Delete a given device from the softs dev_list*/
3487ea28254SJohn Hall int
pqisrc_delete_softs_entry(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)3497ea28254SJohn Hall pqisrc_delete_softs_entry(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
3507ea28254SJohn Hall {
3517ea28254SJohn Hall
3527ea28254SJohn Hall int index;
3537ea28254SJohn Hall index = pqisrc_find_device_list_index(softs, device);
3547ea28254SJohn Hall if (0 <= index && index < MAX_TARGET_BIT) {
3557ea28254SJohn Hall softs->dev_list[index] = NULL;
3567ea28254SJohn Hall softs->num_devs--;
3577ea28254SJohn Hall DBG_NOTE("Removing device : B %d: T %d: L %d positioned at %d\n",
3587ea28254SJohn Hall device->bus, device->target, device->lun, softs->num_devs);
3597ea28254SJohn Hall return PQI_STATUS_SUCCESS;
3607ea28254SJohn Hall }
3617ea28254SJohn Hall if (index == INVALID_ELEM) {
3627ea28254SJohn Hall DBG_NOTE("Invalid device, either it was already removed "
3637ea28254SJohn Hall "or never added\n");
3647ea28254SJohn Hall return PQI_STATUS_FAILURE;
3657ea28254SJohn Hall }
3667ea28254SJohn Hall DBG_ERR("This is a bogus device\n");
3677ea28254SJohn Hall return PQI_STATUS_FAILURE;
3687ea28254SJohn Hall }
3697ea28254SJohn Hall
3707ea28254SJohn Hall int
pqisrc_simple_dma_alloc(pqisrc_softstate_t * softs,struct dma_mem * device_mem,size_t datasize,sgt_t * sgd)3717ea28254SJohn Hall pqisrc_simple_dma_alloc(pqisrc_softstate_t *softs, struct dma_mem *device_mem,
3727ea28254SJohn Hall size_t datasize, sgt_t *sgd)
3737ea28254SJohn Hall {
3741e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
3751e66f787SSean Bruno
3767ea28254SJohn Hall memset(device_mem, 0, sizeof(struct dma_mem));
3771e66f787SSean Bruno
3781e66f787SSean Bruno /* for TUR datasize: 0 buff: NULL */
3791e66f787SSean Bruno if (datasize) {
3801e66f787SSean Bruno
3817ea28254SJohn Hall os_strlcpy(device_mem->tag, "device_mem", sizeof(device_mem->tag));
3827ea28254SJohn Hall device_mem->size = datasize;
3837ea28254SJohn Hall device_mem->align = PQISRC_DEFAULT_DMA_ALIGN;
3847ea28254SJohn Hall
3857ea28254SJohn Hall ret = os_dma_mem_alloc(softs, device_mem);
3861e66f787SSean Bruno
3871e66f787SSean Bruno if (ret) {
3881e66f787SSean Bruno DBG_ERR("failed to allocate dma memory for device_mem return code %d\n", ret);
3891e66f787SSean Bruno return ret;
3901e66f787SSean Bruno }
3911e66f787SSean Bruno
3927ea28254SJohn Hall ASSERT(device_mem->size == datasize);
3931e66f787SSean Bruno
3947ea28254SJohn Hall sgd->addr = device_mem->dma_addr;
3951e66f787SSean Bruno sgd->len = datasize;
3961e66f787SSean Bruno sgd->flags = SG_FLAG_LAST;
3979fac68fcSPAPANI SRIKANTH
3981e66f787SSean Bruno }
3991e66f787SSean Bruno
4007ea28254SJohn Hall return ret;
4017ea28254SJohn Hall }
4027ea28254SJohn Hall
4037ea28254SJohn Hall /*
4047ea28254SJohn Hall * Function used to build the internal raid request and analyze the response
4057ea28254SJohn Hall */
4067ea28254SJohn Hall static int
pqisrc_build_send_raid_request(pqisrc_softstate_t * softs,struct dma_mem device_mem,pqisrc_raid_req_t * request,void * buff,size_t datasize,uint8_t cmd,uint8_t * scsi3addr,raid_path_error_info_elem_t * error_info)4077ea28254SJohn Hall pqisrc_build_send_raid_request(pqisrc_softstate_t *softs, struct dma_mem device_mem,
4087ea28254SJohn Hall pqisrc_raid_req_t *request, void *buff,
4097ea28254SJohn Hall size_t datasize, uint8_t cmd, uint8_t *scsi3addr,
4107ea28254SJohn Hall raid_path_error_info_elem_t *error_info)
4117ea28254SJohn Hall {
4127ea28254SJohn Hall
4137ea28254SJohn Hall uint32_t tag = 0;
4147ea28254SJohn Hall int ret = PQI_STATUS_SUCCESS;
4157ea28254SJohn Hall
4167ea28254SJohn Hall ib_queue_t *ib_q = &softs->op_raid_ib_q[PQI_DEFAULT_IB_QUEUE];
4177ea28254SJohn Hall ob_queue_t *ob_q = &softs->op_ob_q[PQI_DEFAULT_IB_QUEUE];
4187ea28254SJohn Hall
4197ea28254SJohn Hall rcb_t *rcb = NULL;
4207ea28254SJohn Hall
4211e66f787SSean Bruno /* Build raid path request */
4221e66f787SSean Bruno request->header.iu_type = PQI_IU_TYPE_RAID_PATH_IO_REQUEST;
4231e66f787SSean Bruno
4241e66f787SSean Bruno request->header.iu_length = LE_16(offsetof(pqisrc_raid_req_t,
4251e66f787SSean Bruno sg_descriptors[1]) - PQI_REQUEST_HEADER_LENGTH);
4261e66f787SSean Bruno request->buffer_length = LE_32(datasize);
4271e66f787SSean Bruno memcpy(request->lun_number, scsi3addr, sizeof(request->lun_number));
4281e66f787SSean Bruno request->task_attribute = SOP_TASK_ATTRIBUTE_SIMPLE;
4291e66f787SSean Bruno request->additional_cdb_bytes_usage = PQI_ADDITIONAL_CDB_BYTES_0;
4301e66f787SSean Bruno
4311e66f787SSean Bruno tag = pqisrc_get_tag(&softs->taglist);
4321e66f787SSean Bruno if (INVALID_ELEM == tag) {
4331e66f787SSean Bruno DBG_ERR("Tag not available\n");
4341e66f787SSean Bruno ret = PQI_STATUS_FAILURE;
4351e66f787SSean Bruno goto err_notag;
4361e66f787SSean Bruno }
4371e66f787SSean Bruno
4381e66f787SSean Bruno ((pqisrc_raid_req_t *)request)->request_id = tag;
4391e66f787SSean Bruno ((pqisrc_raid_req_t *)request)->error_index = ((pqisrc_raid_req_t *)request)->request_id;
4401e66f787SSean Bruno ((pqisrc_raid_req_t *)request)->response_queue_id = ob_q->q_id;
4411e66f787SSean Bruno rcb = &softs->rcb[tag];
4421e66f787SSean Bruno rcb->success_cmp_callback = pqisrc_process_internal_raid_response_success;
4431e66f787SSean Bruno rcb->error_cmp_callback = pqisrc_process_internal_raid_response_error;
4441e66f787SSean Bruno
4451e66f787SSean Bruno rcb->req_pending = true;
4461e66f787SSean Bruno rcb->tag = tag;
4471e66f787SSean Bruno /* Submit Command */
4481e66f787SSean Bruno ret = pqisrc_submit_cmnd(softs, ib_q, request);
4491e66f787SSean Bruno
4501e66f787SSean Bruno if (ret != PQI_STATUS_SUCCESS) {
4511e66f787SSean Bruno DBG_ERR("Unable to submit command\n");
4521e66f787SSean Bruno goto err_out;
4531e66f787SSean Bruno }
4541e66f787SSean Bruno
4559fac68fcSPAPANI SRIKANTH ret = pqisrc_wait_on_condition(softs, rcb, PQISRC_CMD_TIMEOUT);
4561e66f787SSean Bruno if (ret != PQI_STATUS_SUCCESS) {
4571e66f787SSean Bruno DBG_ERR("Internal RAID request timed out: cmd : 0x%c\n", cmd);
4581e66f787SSean Bruno goto err_out;
4591e66f787SSean Bruno }
4601e66f787SSean Bruno
4611e66f787SSean Bruno if (datasize) {
4621e66f787SSean Bruno if (buff) {
4631e66f787SSean Bruno memcpy(buff, device_mem.virt_addr, datasize);
4641e66f787SSean Bruno }
4651e66f787SSean Bruno os_dma_mem_free(softs, &device_mem);
4661e66f787SSean Bruno }
4671e66f787SSean Bruno
4681e66f787SSean Bruno ret = rcb->status;
4691e66f787SSean Bruno if (ret) {
4701e66f787SSean Bruno if(error_info) {
4711e66f787SSean Bruno memcpy(error_info,
4721e66f787SSean Bruno rcb->error_info,
4731e66f787SSean Bruno sizeof(*error_info));
4741e66f787SSean Bruno
4751e66f787SSean Bruno if (error_info->data_out_result ==
4761e66f787SSean Bruno PQI_RAID_DATA_IN_OUT_UNDERFLOW) {
4771e66f787SSean Bruno ret = PQI_STATUS_SUCCESS;
4781e66f787SSean Bruno }
4791e66f787SSean Bruno else{
4807ea28254SJohn Hall DBG_WARN("Bus=%u Target=%u, Cmd=0x%x,"
4811e66f787SSean Bruno "Ret=%d\n", BMIC_GET_LEVEL_2_BUS(scsi3addr),
4821e66f787SSean Bruno BMIC_GET_LEVEL_TWO_TARGET(scsi3addr),
4831e66f787SSean Bruno cmd, ret);
4841e66f787SSean Bruno ret = PQI_STATUS_FAILURE;
4851e66f787SSean Bruno }
4861e66f787SSean Bruno }
4871e66f787SSean Bruno } else {
4881e66f787SSean Bruno if(error_info) {
4891e66f787SSean Bruno ret = PQI_STATUS_SUCCESS;
4901e66f787SSean Bruno memset(error_info, 0, sizeof(*error_info));
4911e66f787SSean Bruno }
4921e66f787SSean Bruno }
4931e66f787SSean Bruno
4941e66f787SSean Bruno os_reset_rcb(rcb);
4951e66f787SSean Bruno pqisrc_put_tag(&softs->taglist, ((pqisrc_raid_req_t *)request)->request_id);
4961e66f787SSean Bruno DBG_FUNC("OUT\n");
4971e66f787SSean Bruno return ret;
4981e66f787SSean Bruno
4991e66f787SSean Bruno err_out:
5001e66f787SSean Bruno DBG_ERR("Error!! Bus=%u Target=%u, Cmd=0x%x, Ret=%d\n",
5011e66f787SSean Bruno BMIC_GET_LEVEL_2_BUS(scsi3addr), BMIC_GET_LEVEL_TWO_TARGET(scsi3addr),
5021e66f787SSean Bruno cmd, ret);
5031e66f787SSean Bruno os_reset_rcb(rcb);
5041e66f787SSean Bruno pqisrc_put_tag(&softs->taglist, ((pqisrc_raid_req_t *)request)->request_id);
5051e66f787SSean Bruno err_notag:
5061e66f787SSean Bruno if (datasize)
5071e66f787SSean Bruno os_dma_mem_free(softs, &device_mem);
5081e66f787SSean Bruno DBG_FUNC("FAILED \n");
5091e66f787SSean Bruno return ret;
5101e66f787SSean Bruno }
5111e66f787SSean Bruno
5127ea28254SJohn Hall /* Use this if you need to specify specific target or if you want error info */
5137ea28254SJohn Hall int
pqisrc_prepare_send_raid(pqisrc_softstate_t * softs,pqisrc_raid_req_t * request,void * buff,size_t datasize,uint8_t * scsi3addr,raid_path_error_info_elem_t * error_info)5147ea28254SJohn Hall pqisrc_prepare_send_raid(pqisrc_softstate_t *softs, pqisrc_raid_req_t *request,
5157ea28254SJohn Hall void *buff, size_t datasize, uint8_t *scsi3addr,
5167ea28254SJohn Hall raid_path_error_info_elem_t *error_info)
5177ea28254SJohn Hall {
5187ea28254SJohn Hall struct dma_mem device_mem;
5197ea28254SJohn Hall int ret = PQI_STATUS_SUCCESS;
5207ea28254SJohn Hall uint8_t cmd = IS_BMIC_OPCODE(request->cmd.cdb[0]) ? request->cmd.cdb[6] : request->cmd.cdb[0];
5217ea28254SJohn Hall
5227ea28254SJohn Hall ret = pqisrc_simple_dma_alloc(softs, &device_mem, datasize, request->sg_descriptors);
5237ea28254SJohn Hall if (PQI_STATUS_SUCCESS != ret){
5247ea28254SJohn Hall DBG_ERR("failed to allocate dma memory for device_mem return code %d\n", ret);
5257ea28254SJohn Hall return ret;
5267ea28254SJohn Hall }
5277ea28254SJohn Hall
5287ea28254SJohn Hall /* If we are sending out data, copy it over to dma buf */
5297ea28254SJohn Hall if (datasize && buff && request->data_direction == SOP_DATA_DIR_FROM_DEVICE)
5307ea28254SJohn Hall memcpy(device_mem.virt_addr, buff, datasize);
5317ea28254SJohn Hall
5327ea28254SJohn Hall ret = pqisrc_build_send_raid_request(softs, device_mem, request, buff, datasize,
5337ea28254SJohn Hall cmd, scsi3addr, error_info);
5347ea28254SJohn Hall
5357ea28254SJohn Hall return ret;
5367ea28254SJohn Hall }
5377ea28254SJohn Hall
5387ea28254SJohn Hall /* Use this to target controller and don't care about error info */
5397ea28254SJohn Hall int
pqisrc_prepare_send_ctrlr_request(pqisrc_softstate_t * softs,pqisrc_raid_req_t * request,void * buff,size_t datasize)5407ea28254SJohn Hall pqisrc_prepare_send_ctrlr_request(pqisrc_softstate_t *softs, pqisrc_raid_req_t *request,
5417ea28254SJohn Hall void *buff, size_t datasize)
5427ea28254SJohn Hall {
5437ea28254SJohn Hall raid_path_error_info_elem_t error_info; /* will be thrown away */
5447ea28254SJohn Hall uint8_t *scsi3addr = RAID_CTLR_LUNID;
5457ea28254SJohn Hall
5467ea28254SJohn Hall return pqisrc_prepare_send_raid(softs, request, buff, datasize, scsi3addr, &error_info);
5477ea28254SJohn Hall }
5487ea28254SJohn Hall
5497ea28254SJohn Hall /* common function used to send report physical and logical luns cmds */
5509fac68fcSPAPANI SRIKANTH static int
pqisrc_report_luns(pqisrc_softstate_t * softs,uint8_t cmd,void * buff,size_t buf_len)5519fac68fcSPAPANI SRIKANTH pqisrc_report_luns(pqisrc_softstate_t *softs, uint8_t cmd,
5521e66f787SSean Bruno void *buff, size_t buf_len)
5531e66f787SSean Bruno {
5541e66f787SSean Bruno int ret;
5551e66f787SSean Bruno pqisrc_raid_req_t request;
5561e66f787SSean Bruno
5571e66f787SSean Bruno DBG_FUNC("IN\n");
5581e66f787SSean Bruno
5591e66f787SSean Bruno memset(&request, 0, sizeof(request));
5607ea28254SJohn Hall
5617ea28254SJohn Hall request.data_direction = SOP_DATA_DIR_TO_DEVICE;
5627ea28254SJohn Hall
5637ea28254SJohn Hall switch (cmd) {
5647ea28254SJohn Hall case SA_REPORT_LOG:
5657ea28254SJohn Hall request.cmd.cdb[0] = SA_REPORT_LOG;
5667ea28254SJohn Hall request.cmd.cdb[1] = SA_REPORT_LOG_EXTENDED;
5677ea28254SJohn Hall break;
5687ea28254SJohn Hall case SA_REPORT_PHYS:
5697ea28254SJohn Hall request.cmd.cdb[0] = SA_REPORT_PHYS;
5707ea28254SJohn Hall request.cmd.cdb[1] = SA_REPORT_PHYS_EXTENDED;
5717ea28254SJohn Hall break;
5727ea28254SJohn Hall /* @todo: 0x56 does not exist, this is kludgy, need to pass in options */
5737ea28254SJohn Hall case PQI_LOG_EXT_QUEUE_ENABLE:
5747ea28254SJohn Hall request.cmd.cdb[0] = SA_REPORT_LOG;
5757ea28254SJohn Hall request.cmd.cdb[1] = (PQI_LOG_EXT_QUEUE_DEPTH_ENABLED | SA_REPORT_LOG_EXTENDED);
5767ea28254SJohn Hall break;
5777ea28254SJohn Hall }
5787ea28254SJohn Hall
5797ea28254SJohn Hall request.cmd.cdb[8] = (uint8_t)((buf_len) >> 8);
5807ea28254SJohn Hall request.cmd.cdb[9] = (uint8_t)buf_len;
5817ea28254SJohn Hall
5827ea28254SJohn Hall ret = pqisrc_prepare_send_ctrlr_request(softs, &request, buff, buf_len);
5831e66f787SSean Bruno
5841e66f787SSean Bruno DBG_FUNC("OUT\n");
5851e66f787SSean Bruno
5861e66f787SSean Bruno return ret;
5871e66f787SSean Bruno }
5881e66f787SSean Bruno
5891e66f787SSean Bruno /* subroutine used to get physical and logical luns of the device */
5909fac68fcSPAPANI SRIKANTH int
pqisrc_get_physical_logical_luns(pqisrc_softstate_t * softs,uint8_t cmd,reportlun_data_ext_t ** buff,size_t * data_length)5919fac68fcSPAPANI SRIKANTH pqisrc_get_physical_logical_luns(pqisrc_softstate_t *softs, uint8_t cmd,
5921e66f787SSean Bruno reportlun_data_ext_t **buff, size_t *data_length)
5931e66f787SSean Bruno {
5941e66f787SSean Bruno int ret;
5951e66f787SSean Bruno size_t list_len;
5961e66f787SSean Bruno size_t data_len;
5971e66f787SSean Bruno size_t new_lun_list_length;
5981e66f787SSean Bruno reportlun_data_ext_t *lun_data;
5991e66f787SSean Bruno reportlun_header_t report_lun_header;
6001e66f787SSean Bruno
6011e66f787SSean Bruno DBG_FUNC("IN\n");
6021e66f787SSean Bruno
6031e66f787SSean Bruno ret = pqisrc_report_luns(softs, cmd, &report_lun_header,
6041e66f787SSean Bruno sizeof(report_lun_header));
6051e66f787SSean Bruno
6061e66f787SSean Bruno if (ret) {
6071e66f787SSean Bruno DBG_ERR("failed return code: %d\n", ret);
6081e66f787SSean Bruno return ret;
6091e66f787SSean Bruno }
6101e66f787SSean Bruno list_len = BE_32(report_lun_header.list_length);
6111e66f787SSean Bruno
6121e66f787SSean Bruno retry:
6131e66f787SSean Bruno data_len = sizeof(reportlun_header_t) + list_len;
6141e66f787SSean Bruno *data_length = data_len;
6151e66f787SSean Bruno
6161e66f787SSean Bruno lun_data = os_mem_alloc(softs, data_len);
6171e66f787SSean Bruno
6181e66f787SSean Bruno if (!lun_data) {
6191e66f787SSean Bruno DBG_ERR("failed to allocate memory for lun_data\n");
6201e66f787SSean Bruno return PQI_STATUS_FAILURE;
6211e66f787SSean Bruno }
6221e66f787SSean Bruno
6231e66f787SSean Bruno if (list_len == 0) {
624b17f4335SSean Bruno DBG_DISC("list_len is 0\n");
6251e66f787SSean Bruno memcpy(lun_data, &report_lun_header, sizeof(report_lun_header));
6261e66f787SSean Bruno goto out;
6271e66f787SSean Bruno }
6281e66f787SSean Bruno
6291e66f787SSean Bruno ret = pqisrc_report_luns(softs, cmd, lun_data, data_len);
6301e66f787SSean Bruno
6311e66f787SSean Bruno if (ret) {
6321e66f787SSean Bruno DBG_ERR("error\n");
6331e66f787SSean Bruno goto error;
6341e66f787SSean Bruno }
6351e66f787SSean Bruno
6361e66f787SSean Bruno new_lun_list_length = BE_32(lun_data->header.list_length);
6371e66f787SSean Bruno
6381e66f787SSean Bruno if (new_lun_list_length > list_len) {
6391e66f787SSean Bruno list_len = new_lun_list_length;
6401e66f787SSean Bruno os_mem_free(softs, (void *)lun_data, data_len);
6411e66f787SSean Bruno goto retry;
6421e66f787SSean Bruno }
6431e66f787SSean Bruno
6441e66f787SSean Bruno out:
6451e66f787SSean Bruno *buff = lun_data;
6461e66f787SSean Bruno DBG_FUNC("OUT\n");
6471e66f787SSean Bruno return 0;
6481e66f787SSean Bruno
6491e66f787SSean Bruno error:
6501e66f787SSean Bruno os_mem_free(softs, (void *)lun_data, data_len);
6511e66f787SSean Bruno DBG_ERR("FAILED\n");
6521e66f787SSean Bruno return ret;
6531e66f787SSean Bruno }
6541e66f787SSean Bruno
6551e66f787SSean Bruno /*
6569fac68fcSPAPANI SRIKANTH * Function used to grab queue depth ext lun data for logical devices
6579fac68fcSPAPANI SRIKANTH */
6589fac68fcSPAPANI SRIKANTH static int
pqisrc_get_queue_lun_list(pqisrc_softstate_t * softs,uint8_t cmd,reportlun_queue_depth_data_t ** buff,size_t * data_length)6599fac68fcSPAPANI SRIKANTH pqisrc_get_queue_lun_list(pqisrc_softstate_t *softs, uint8_t cmd,
6609fac68fcSPAPANI SRIKANTH reportlun_queue_depth_data_t **buff, size_t *data_length)
6619fac68fcSPAPANI SRIKANTH {
6629fac68fcSPAPANI SRIKANTH int ret;
6639fac68fcSPAPANI SRIKANTH size_t list_len;
6649fac68fcSPAPANI SRIKANTH size_t data_len;
6659fac68fcSPAPANI SRIKANTH size_t new_lun_list_length;
6669fac68fcSPAPANI SRIKANTH reportlun_queue_depth_data_t *lun_data;
6679fac68fcSPAPANI SRIKANTH reportlun_header_t report_lun_header;
6689fac68fcSPAPANI SRIKANTH
6699fac68fcSPAPANI SRIKANTH DBG_FUNC("IN\n");
6709fac68fcSPAPANI SRIKANTH
6719fac68fcSPAPANI SRIKANTH ret = pqisrc_report_luns(softs, cmd, &report_lun_header,
6729fac68fcSPAPANI SRIKANTH sizeof(report_lun_header));
6739fac68fcSPAPANI SRIKANTH
6749fac68fcSPAPANI SRIKANTH if (ret) {
6759fac68fcSPAPANI SRIKANTH DBG_ERR("failed return code: %d\n", ret);
6769fac68fcSPAPANI SRIKANTH return ret;
6779fac68fcSPAPANI SRIKANTH }
6789fac68fcSPAPANI SRIKANTH list_len = BE_32(report_lun_header.list_length);
6799fac68fcSPAPANI SRIKANTH retry:
6809fac68fcSPAPANI SRIKANTH data_len = sizeof(reportlun_header_t) + list_len;
6819fac68fcSPAPANI SRIKANTH *data_length = data_len;
6829fac68fcSPAPANI SRIKANTH lun_data = os_mem_alloc(softs, data_len);
6839fac68fcSPAPANI SRIKANTH
6849fac68fcSPAPANI SRIKANTH if (!lun_data) {
6859fac68fcSPAPANI SRIKANTH DBG_ERR("failed to allocate memory for lun_data\n");
6869fac68fcSPAPANI SRIKANTH return PQI_STATUS_FAILURE;
6879fac68fcSPAPANI SRIKANTH }
6889fac68fcSPAPANI SRIKANTH
6899fac68fcSPAPANI SRIKANTH if (list_len == 0) {
6907ea28254SJohn Hall DBG_DISC("list_len is 0\n");
6919fac68fcSPAPANI SRIKANTH memcpy(lun_data, &report_lun_header, sizeof(report_lun_header));
6929fac68fcSPAPANI SRIKANTH goto out;
6939fac68fcSPAPANI SRIKANTH }
6949fac68fcSPAPANI SRIKANTH ret = pqisrc_report_luns(softs, cmd, lun_data, data_len);
6959fac68fcSPAPANI SRIKANTH
6969fac68fcSPAPANI SRIKANTH if (ret) {
6979fac68fcSPAPANI SRIKANTH DBG_ERR("error\n");
6989fac68fcSPAPANI SRIKANTH goto error;
6999fac68fcSPAPANI SRIKANTH }
7009fac68fcSPAPANI SRIKANTH new_lun_list_length = BE_32(lun_data->header.list_length);
7019fac68fcSPAPANI SRIKANTH
7029fac68fcSPAPANI SRIKANTH if (new_lun_list_length > list_len) {
7039fac68fcSPAPANI SRIKANTH list_len = new_lun_list_length;
7049fac68fcSPAPANI SRIKANTH os_mem_free(softs, (void *)lun_data, data_len);
7059fac68fcSPAPANI SRIKANTH goto retry;
7069fac68fcSPAPANI SRIKANTH }
7079fac68fcSPAPANI SRIKANTH
7089fac68fcSPAPANI SRIKANTH out:
7099fac68fcSPAPANI SRIKANTH *buff = lun_data;
7109fac68fcSPAPANI SRIKANTH DBG_FUNC("OUT\n");
7119fac68fcSPAPANI SRIKANTH return 0;
7129fac68fcSPAPANI SRIKANTH
7139fac68fcSPAPANI SRIKANTH error:
7149fac68fcSPAPANI SRIKANTH os_mem_free(softs, (void *)lun_data, data_len);
7159fac68fcSPAPANI SRIKANTH DBG_ERR("FAILED\n");
7169fac68fcSPAPANI SRIKANTH return ret;
7179fac68fcSPAPANI SRIKANTH }
7189fac68fcSPAPANI SRIKANTH
7199fac68fcSPAPANI SRIKANTH /*
7201e66f787SSean Bruno * Function used to get physical and logical device list
7211e66f787SSean Bruno */
7229fac68fcSPAPANI SRIKANTH static int
pqisrc_get_phys_log_device_list(pqisrc_softstate_t * softs,reportlun_data_ext_t ** physical_dev_list,reportlun_data_ext_t ** logical_dev_list,reportlun_queue_depth_data_t ** queue_dev_list,size_t * queue_data_length,size_t * phys_data_length,size_t * log_data_length)7239fac68fcSPAPANI SRIKANTH pqisrc_get_phys_log_device_list(pqisrc_softstate_t *softs,
7241e66f787SSean Bruno reportlun_data_ext_t **physical_dev_list,
7251e66f787SSean Bruno reportlun_data_ext_t **logical_dev_list,
7269fac68fcSPAPANI SRIKANTH reportlun_queue_depth_data_t **queue_dev_list,
7279fac68fcSPAPANI SRIKANTH size_t *queue_data_length,
7281e66f787SSean Bruno size_t *phys_data_length,
7291e66f787SSean Bruno size_t *log_data_length)
7301e66f787SSean Bruno {
7311e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
7321e66f787SSean Bruno size_t logical_list_length;
7331e66f787SSean Bruno size_t logdev_data_length;
7341e66f787SSean Bruno size_t data_length;
7351e66f787SSean Bruno reportlun_data_ext_t *local_logdev_list;
7361e66f787SSean Bruno reportlun_data_ext_t *logdev_data;
7371e66f787SSean Bruno reportlun_header_t report_lun_header;
7381e66f787SSean Bruno
7391e66f787SSean Bruno DBG_FUNC("IN\n");
7401e66f787SSean Bruno
7411e66f787SSean Bruno ret = pqisrc_get_physical_logical_luns(softs, SA_REPORT_PHYS, physical_dev_list, phys_data_length);
7421e66f787SSean Bruno if (ret) {
7431e66f787SSean Bruno DBG_ERR("report physical LUNs failed");
7441e66f787SSean Bruno return ret;
7451e66f787SSean Bruno }
7461e66f787SSean Bruno
7471e66f787SSean Bruno ret = pqisrc_get_physical_logical_luns(softs, SA_REPORT_LOG, logical_dev_list, log_data_length);
7481e66f787SSean Bruno if (ret) {
7491e66f787SSean Bruno DBG_ERR("report logical LUNs failed");
7501e66f787SSean Bruno return ret;
7511e66f787SSean Bruno }
7521e66f787SSean Bruno
7537ea28254SJohn Hall #ifdef PQI_NEED_RESCAN_TIMER_FOR_RBOD_HOTPLUG
7547ea28254SJohn Hall /* Save the report_log_dev buffer for deciding rescan requirement from OS driver*/
7557ea28254SJohn Hall if(softs->log_dev_data_length != *log_data_length) {
7567ea28254SJohn Hall if(softs->log_dev_list)
7577ea28254SJohn Hall os_mem_free(softs, softs->log_dev_list, softs->log_dev_data_length);
7587ea28254SJohn Hall softs->log_dev_list = os_mem_alloc(softs, *log_data_length);
7597ea28254SJohn Hall }
7607ea28254SJohn Hall memcpy(softs->log_dev_list, *logical_dev_list, *log_data_length);
7617ea28254SJohn Hall softs->log_dev_data_length = *log_data_length;
7627ea28254SJohn Hall #endif
7637ea28254SJohn Hall
7649fac68fcSPAPANI SRIKANTH ret = pqisrc_get_queue_lun_list(softs, PQI_LOG_EXT_QUEUE_ENABLE, queue_dev_list, queue_data_length);
7659fac68fcSPAPANI SRIKANTH if (ret) {
7669fac68fcSPAPANI SRIKANTH DBG_ERR("report logical LUNs failed");
7679fac68fcSPAPANI SRIKANTH return ret;
7689fac68fcSPAPANI SRIKANTH }
7699fac68fcSPAPANI SRIKANTH
7701e66f787SSean Bruno logdev_data = *logical_dev_list;
7711e66f787SSean Bruno
7721e66f787SSean Bruno if (logdev_data) {
7731e66f787SSean Bruno logical_list_length =
7741e66f787SSean Bruno BE_32(logdev_data->header.list_length);
7751e66f787SSean Bruno } else {
7761e66f787SSean Bruno memset(&report_lun_header, 0, sizeof(report_lun_header));
7771e66f787SSean Bruno logdev_data =
7781e66f787SSean Bruno (reportlun_data_ext_t *)&report_lun_header;
7791e66f787SSean Bruno logical_list_length = 0;
7801e66f787SSean Bruno }
7811e66f787SSean Bruno
7821e66f787SSean Bruno logdev_data_length = sizeof(reportlun_header_t) +
7831e66f787SSean Bruno logical_list_length;
7841e66f787SSean Bruno
7851e66f787SSean Bruno /* Adding LOGICAL device entry for controller */
7861e66f787SSean Bruno local_logdev_list = os_mem_alloc(softs,
7871e66f787SSean Bruno logdev_data_length + sizeof(reportlun_ext_entry_t));
7881e66f787SSean Bruno if (!local_logdev_list) {
7891e66f787SSean Bruno data_length = *log_data_length;
7901e66f787SSean Bruno os_mem_free(softs, (char *)*logical_dev_list, data_length);
7911e66f787SSean Bruno *logical_dev_list = NULL;
7921e66f787SSean Bruno return PQI_STATUS_FAILURE;
7931e66f787SSean Bruno }
7941e66f787SSean Bruno
7951e66f787SSean Bruno memcpy(local_logdev_list, logdev_data, logdev_data_length);
7961e66f787SSean Bruno memset((uint8_t *)local_logdev_list + logdev_data_length, 0,
7971e66f787SSean Bruno sizeof(reportlun_ext_entry_t));
7981e66f787SSean Bruno local_logdev_list->header.list_length = BE_32(logical_list_length +
7991e66f787SSean Bruno sizeof(reportlun_ext_entry_t));
8001e66f787SSean Bruno data_length = *log_data_length;
8011e66f787SSean Bruno os_mem_free(softs, (char *)*logical_dev_list, data_length);
8021e66f787SSean Bruno *log_data_length = logdev_data_length + sizeof(reportlun_ext_entry_t);
8031e66f787SSean Bruno *logical_dev_list = local_logdev_list;
8041e66f787SSean Bruno
8051e66f787SSean Bruno DBG_FUNC("OUT\n");
8061e66f787SSean Bruno
8071e66f787SSean Bruno return ret;
8081e66f787SSean Bruno }
8091e66f787SSean Bruno
8107ea28254SJohn Hall inline boolean_t
pqisrc_is_external_raid_device(pqi_scsi_dev_t * device)8117ea28254SJohn Hall pqisrc_is_external_raid_device(pqi_scsi_dev_t *device)
8121e66f787SSean Bruno {
8131e66f787SSean Bruno return device->is_external_raid_device;
8141e66f787SSean Bruno }
8151e66f787SSean Bruno
8167ea28254SJohn Hall static inline boolean_t
pqisrc_is_external_raid_addr(uint8_t * scsi3addr)8177ea28254SJohn Hall pqisrc_is_external_raid_addr(uint8_t *scsi3addr)
8181e66f787SSean Bruno {
8191e66f787SSean Bruno return scsi3addr[2] != 0;
8201e66f787SSean Bruno }
8211e66f787SSean Bruno
8221e66f787SSean Bruno /* Function used to assign Bus-Target-Lun for the requested device */
8239fac68fcSPAPANI SRIKANTH static void
pqisrc_assign_btl(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)8247ea28254SJohn Hall pqisrc_assign_btl(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
8251e66f787SSean Bruno {
8261e66f787SSean Bruno uint8_t *scsi3addr;
8271e66f787SSean Bruno uint32_t lunid;
8281e66f787SSean Bruno uint32_t bus;
8291e66f787SSean Bruno uint32_t target;
8301e66f787SSean Bruno uint32_t lun;
8311e66f787SSean Bruno DBG_FUNC("IN\n");
8321e66f787SSean Bruno
8331e66f787SSean Bruno scsi3addr = device->scsi3addr;
8341e66f787SSean Bruno lunid = GET_LE32(scsi3addr);
8351e66f787SSean Bruno
8361e66f787SSean Bruno if (pqisrc_is_hba_lunid(scsi3addr)) {
8371e66f787SSean Bruno /* The specified device is the controller. */
8387ea28254SJohn Hall pqisrc_set_btl(device, PQI_HBA_BUS, PQI_CTLR_INDEX, (lunid & 0x3fff));
8391e66f787SSean Bruno device->target_lun_valid = true;
8401e66f787SSean Bruno return;
8411e66f787SSean Bruno }
8421e66f787SSean Bruno
8437ea28254SJohn Hall /* When the specified device is a logical volume,
8447ea28254SJohn Hall * physicals will be given targets in pqisrc update
8457ea28254SJohn Hall * device list in pqisrc scan devices. */
8461e66f787SSean Bruno if (pqisrc_is_logical_device(device)) {
8471e66f787SSean Bruno bus = PQI_RAID_VOLUME_BUS;
8489fac68fcSPAPANI SRIKANTH lun = (lunid & 0x3fff) + 1;
8499fac68fcSPAPANI SRIKANTH target = 0;
8501e66f787SSean Bruno pqisrc_set_btl(device, bus, target, lun);
8511e66f787SSean Bruno device->target_lun_valid = true;
8521e66f787SSean Bruno return;
8531e66f787SSean Bruno }
8541e66f787SSean Bruno
8551e66f787SSean Bruno DBG_FUNC("OUT\n");
8561e66f787SSean Bruno }
8571e66f787SSean Bruno
8581e66f787SSean Bruno /* Build and send the internal INQUIRY command to particular device */
8599fac68fcSPAPANI SRIKANTH int
pqisrc_send_scsi_inquiry(pqisrc_softstate_t * softs,uint8_t * scsi3addr,uint16_t vpd_page,uint8_t * buff,int buf_len)8609fac68fcSPAPANI SRIKANTH pqisrc_send_scsi_inquiry(pqisrc_softstate_t *softs,
8611e66f787SSean Bruno uint8_t *scsi3addr, uint16_t vpd_page, uint8_t *buff, int buf_len)
8621e66f787SSean Bruno {
8631e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
8641e66f787SSean Bruno pqisrc_raid_req_t request;
8651e66f787SSean Bruno raid_path_error_info_elem_t error_info;
8661e66f787SSean Bruno
8671e66f787SSean Bruno DBG_FUNC("IN\n");
8681e66f787SSean Bruno
8691e66f787SSean Bruno memset(&request, 0, sizeof(request));
8707ea28254SJohn Hall
8717ea28254SJohn Hall request.data_direction = SOP_DATA_DIR_TO_DEVICE;
8727ea28254SJohn Hall request.cmd.cdb[0] = SA_INQUIRY;
8737ea28254SJohn Hall if (vpd_page & VPD_PAGE) {
8747ea28254SJohn Hall request.cmd.cdb[1] = 0x1;
8757ea28254SJohn Hall request.cmd.cdb[2] = (uint8_t)vpd_page;
8767ea28254SJohn Hall }
8777ea28254SJohn Hall ASSERT(buf_len < 256);
8787ea28254SJohn Hall request.cmd.cdb[4] = (uint8_t)buf_len;
8797ea28254SJohn Hall
8807ea28254SJohn Hall if (softs->timeout_in_passthrough) {
8817ea28254SJohn Hall request.timeout_in_sec = PQISRC_INQUIRY_TIMEOUT;
8827ea28254SJohn Hall }
8837ea28254SJohn Hall
8847ea28254SJohn Hall pqisrc_prepare_send_raid(softs, &request, buff, buf_len, scsi3addr, &error_info);
8851e66f787SSean Bruno
8861e66f787SSean Bruno DBG_FUNC("OUT\n");
8871e66f787SSean Bruno return ret;
8881e66f787SSean Bruno }
8891e66f787SSean Bruno
8909fac68fcSPAPANI SRIKANTH /* Determine logical volume status from vpd buffer.*/
pqisrc_get_dev_vol_status(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)8919fac68fcSPAPANI SRIKANTH static void pqisrc_get_dev_vol_status(pqisrc_softstate_t *softs,
8929fac68fcSPAPANI SRIKANTH pqi_scsi_dev_t *device)
8931e66f787SSean Bruno {
8949fac68fcSPAPANI SRIKANTH int ret;
8951e66f787SSean Bruno uint8_t status = SA_LV_STATUS_VPD_UNSUPPORTED;
8969fac68fcSPAPANI SRIKANTH uint8_t vpd_size = sizeof(vpd_volume_status);
8979fac68fcSPAPANI SRIKANTH uint8_t offline = true;
8989fac68fcSPAPANI SRIKANTH size_t page_length;
8999fac68fcSPAPANI SRIKANTH vpd_volume_status *vpd;
9001e66f787SSean Bruno
9011e66f787SSean Bruno DBG_FUNC("IN\n");
9021e66f787SSean Bruno
9039fac68fcSPAPANI SRIKANTH vpd = os_mem_alloc(softs, vpd_size);
9049fac68fcSPAPANI SRIKANTH if (vpd == NULL)
9059fac68fcSPAPANI SRIKANTH goto out;
9061e66f787SSean Bruno
9071e66f787SSean Bruno /* Get the size of the VPD return buff. */
9089fac68fcSPAPANI SRIKANTH ret = pqisrc_send_scsi_inquiry(softs, device->scsi3addr, VPD_PAGE | SA_VPD_LV_STATUS,
9099fac68fcSPAPANI SRIKANTH (uint8_t *)vpd, vpd_size);
9101e66f787SSean Bruno
9119fac68fcSPAPANI SRIKANTH if (ret) {
9129fac68fcSPAPANI SRIKANTH DBG_WARN("Inquiry returned failed status\n");
9139fac68fcSPAPANI SRIKANTH goto out;
9149fac68fcSPAPANI SRIKANTH }
9159fac68fcSPAPANI SRIKANTH
9169fac68fcSPAPANI SRIKANTH if (vpd->page_code != SA_VPD_LV_STATUS) {
9179fac68fcSPAPANI SRIKANTH DBG_WARN("Returned invalid buffer\n");
9189fac68fcSPAPANI SRIKANTH goto out;
9199fac68fcSPAPANI SRIKANTH }
9209fac68fcSPAPANI SRIKANTH
9219fac68fcSPAPANI SRIKANTH page_length = offsetof(vpd_volume_status, volume_status) + vpd->page_length;
9229fac68fcSPAPANI SRIKANTH if (page_length < vpd_size)
9231e66f787SSean Bruno goto out;
9241e66f787SSean Bruno
9259fac68fcSPAPANI SRIKANTH status = vpd->volume_status;
9269fac68fcSPAPANI SRIKANTH offline = (vpd->flags & SA_LV_FLAGS_NO_HOST_IO)!=0;
9271e66f787SSean Bruno
9281e66f787SSean Bruno out:
9299fac68fcSPAPANI SRIKANTH device->volume_offline = offline;
9309fac68fcSPAPANI SRIKANTH device->volume_status = status;
9311e66f787SSean Bruno
9329fac68fcSPAPANI SRIKANTH os_mem_free(softs, (char *)vpd, vpd_size);
9331e66f787SSean Bruno
9341e66f787SSean Bruno DBG_FUNC("OUT\n");
9351e66f787SSean Bruno
9369fac68fcSPAPANI SRIKANTH return;
9371e66f787SSean Bruno }
9381e66f787SSean Bruno
9397ea28254SJohn Hall
9401e66f787SSean Bruno /* Validate the RAID map parameters */
9419fac68fcSPAPANI SRIKANTH static int
pqisrc_raid_map_validation(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device,pqisrc_raid_map_t * raid_map)9429fac68fcSPAPANI SRIKANTH pqisrc_raid_map_validation(pqisrc_softstate_t *softs,
9431e66f787SSean Bruno pqi_scsi_dev_t *device, pqisrc_raid_map_t *raid_map)
9441e66f787SSean Bruno {
9451e66f787SSean Bruno char *error_msg;
9461e66f787SSean Bruno uint32_t raidmap_size;
9471e66f787SSean Bruno uint32_t r5or6_blocks_per_row;
9487ea28254SJohn Hall /* unsigned phys_dev_num; */
9491e66f787SSean Bruno
9501e66f787SSean Bruno DBG_FUNC("IN\n");
9511e66f787SSean Bruno
9521e66f787SSean Bruno raidmap_size = LE_32(raid_map->structure_size);
9531e66f787SSean Bruno if (raidmap_size < offsetof(pqisrc_raid_map_t, dev_data)) {
9541e66f787SSean Bruno error_msg = "RAID map too small\n";
9551e66f787SSean Bruno goto error;
9561e66f787SSean Bruno }
9571e66f787SSean Bruno
9589fac68fcSPAPANI SRIKANTH #if 0
9591e66f787SSean Bruno phys_dev_num = LE_16(raid_map->layout_map_count) *
9601e66f787SSean Bruno (LE_16(raid_map->data_disks_per_row) +
9611e66f787SSean Bruno LE_16(raid_map->metadata_disks_per_row));
9629fac68fcSPAPANI SRIKANTH #endif
9631e66f787SSean Bruno
9641e66f787SSean Bruno if (device->raid_level == SA_RAID_1) {
9651e66f787SSean Bruno if (LE_16(raid_map->layout_map_count) != 2) {
9661e66f787SSean Bruno error_msg = "invalid RAID-1 map\n";
9671e66f787SSean Bruno goto error;
9681e66f787SSean Bruno }
9691e66f787SSean Bruno } else if (device->raid_level == SA_RAID_ADM) {
9701e66f787SSean Bruno if (LE_16(raid_map->layout_map_count) != 3) {
9719fac68fcSPAPANI SRIKANTH error_msg = "invalid RAID-1(triple) map\n";
9721e66f787SSean Bruno goto error;
9731e66f787SSean Bruno }
9741e66f787SSean Bruno } else if ((device->raid_level == SA_RAID_5 ||
9751e66f787SSean Bruno device->raid_level == SA_RAID_6) &&
9761e66f787SSean Bruno LE_16(raid_map->layout_map_count) > 1) {
9771e66f787SSean Bruno /* RAID 50/60 */
9781e66f787SSean Bruno r5or6_blocks_per_row =
9791e66f787SSean Bruno LE_16(raid_map->strip_size) *
9801e66f787SSean Bruno LE_16(raid_map->data_disks_per_row);
9811e66f787SSean Bruno if (r5or6_blocks_per_row == 0) {
9821e66f787SSean Bruno error_msg = "invalid RAID-5 or RAID-6 map\n";
9831e66f787SSean Bruno goto error;
9841e66f787SSean Bruno }
9851e66f787SSean Bruno }
9861e66f787SSean Bruno
9871e66f787SSean Bruno DBG_FUNC("OUT\n");
9881e66f787SSean Bruno
9891e66f787SSean Bruno return 0;
9901e66f787SSean Bruno
9911e66f787SSean Bruno error:
9929fac68fcSPAPANI SRIKANTH DBG_NOTE("%s\n", error_msg);
9931e66f787SSean Bruno return PQI_STATUS_FAILURE;
9941e66f787SSean Bruno }
9951e66f787SSean Bruno
9961e66f787SSean Bruno /* Get device raidmap for the requested device */
9979fac68fcSPAPANI SRIKANTH static int
pqisrc_get_device_raidmap(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)9989fac68fcSPAPANI SRIKANTH pqisrc_get_device_raidmap(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
9991e66f787SSean Bruno {
10001e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
10017ea28254SJohn Hall int raidmap_alloc_size = sizeof(pqisrc_raid_map_t);
10027ea28254SJohn Hall int raidmap_reported_size;
10037ea28254SJohn Hall int structure_size;
10047ea28254SJohn Hall int ii;
10057ea28254SJohn Hall int *next_offload_to_mirror;
10069fac68fcSPAPANI SRIKANTH
10071e66f787SSean Bruno pqisrc_raid_req_t request;
10081e66f787SSean Bruno pqisrc_raid_map_t *raid_map;
10091e66f787SSean Bruno
10101e66f787SSean Bruno DBG_FUNC("IN\n");
10111e66f787SSean Bruno
10127ea28254SJohn Hall for (ii = 0; ii < 2; ii++)
10137ea28254SJohn Hall {
10147ea28254SJohn Hall raid_map = os_mem_alloc(softs, raidmap_alloc_size);
10151e66f787SSean Bruno if (!raid_map)
10161e66f787SSean Bruno return PQI_STATUS_FAILURE;
10171e66f787SSean Bruno
10181e66f787SSean Bruno memset(&request, 0, sizeof(request));
10197ea28254SJohn Hall request.data_direction = SOP_DATA_DIR_TO_DEVICE;
10207ea28254SJohn Hall request.cmd.cdb[0] = SA_CISS_READ;
10217ea28254SJohn Hall request.cmd.cdb[1] = SA_GET_RAID_MAP;
10227ea28254SJohn Hall request.cmd.cdb[8] = (uint8_t)((raidmap_alloc_size) >> 8);
10237ea28254SJohn Hall request.cmd.cdb[9] = (uint8_t)(raidmap_alloc_size);
10247ea28254SJohn Hall
10257ea28254SJohn Hall ret = pqisrc_prepare_send_raid(softs, &request, raid_map, raidmap_alloc_size, device->scsi3addr, NULL);
10261e66f787SSean Bruno
10271e66f787SSean Bruno if (ret) {
10281e66f787SSean Bruno DBG_ERR("error in build send raid req ret=%d\n", ret);
10291e66f787SSean Bruno goto err_out;
10301e66f787SSean Bruno }
10311e66f787SSean Bruno
10327ea28254SJohn Hall raidmap_reported_size = LE_32(raid_map->structure_size);
10337ea28254SJohn Hall if (raidmap_reported_size <= raidmap_alloc_size)
10347ea28254SJohn Hall break;
10357ea28254SJohn Hall
10369fac68fcSPAPANI SRIKANTH DBG_NOTE("Raid map is larger than 1024 entries, request once again");
10377ea28254SJohn Hall os_mem_free(softs, (char*)raid_map, raidmap_alloc_size);
10389fac68fcSPAPANI SRIKANTH
10397ea28254SJohn Hall raidmap_alloc_size = raidmap_reported_size;
10409fac68fcSPAPANI SRIKANTH }
10419fac68fcSPAPANI SRIKANTH
10421e66f787SSean Bruno ret = pqisrc_raid_map_validation(softs, device, raid_map);
10431e66f787SSean Bruno if (ret) {
10449fac68fcSPAPANI SRIKANTH DBG_NOTE("error in raid map validation ret=%d\n", ret);
10451e66f787SSean Bruno goto err_out;
10461e66f787SSean Bruno }
10471e66f787SSean Bruno
10487ea28254SJohn Hall structure_size = raid_map->data_disks_per_row * sizeof(*next_offload_to_mirror);
10497ea28254SJohn Hall next_offload_to_mirror = os_mem_alloc(softs, structure_size);
10507ea28254SJohn Hall if (!next_offload_to_mirror) {
10517ea28254SJohn Hall ret = PQI_STATUS_FAILURE;
10527ea28254SJohn Hall goto err_out;
10537ea28254SJohn Hall }
10547ea28254SJohn Hall
10551e66f787SSean Bruno device->raid_map = raid_map;
10567ea28254SJohn Hall device->offload_to_mirror = next_offload_to_mirror;
10571e66f787SSean Bruno DBG_FUNC("OUT\n");
10581e66f787SSean Bruno return 0;
10591e66f787SSean Bruno
10601e66f787SSean Bruno err_out:
10611e66f787SSean Bruno os_mem_free(softs, (char*)raid_map, sizeof(*raid_map));
10621e66f787SSean Bruno DBG_FUNC("FAILED \n");
10631e66f787SSean Bruno return ret;
10641e66f787SSean Bruno }
10651e66f787SSean Bruno
10661e66f787SSean Bruno /* Get device ioaccel_status to validate the type of device */
10679fac68fcSPAPANI SRIKANTH static void
pqisrc_get_dev_ioaccel_status(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)10689fac68fcSPAPANI SRIKANTH pqisrc_get_dev_ioaccel_status(pqisrc_softstate_t *softs,
10691e66f787SSean Bruno pqi_scsi_dev_t *device)
10701e66f787SSean Bruno {
10711e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
10721e66f787SSean Bruno uint8_t *buff;
10731e66f787SSean Bruno uint8_t ioaccel_status;
10741e66f787SSean Bruno
10751e66f787SSean Bruno DBG_FUNC("IN\n");
10761e66f787SSean Bruno
10771e66f787SSean Bruno buff = os_mem_alloc(softs, 64);
10781e66f787SSean Bruno if (!buff)
10791e66f787SSean Bruno return;
10801e66f787SSean Bruno
10811e66f787SSean Bruno ret = pqisrc_send_scsi_inquiry(softs, device->scsi3addr,
10821e66f787SSean Bruno VPD_PAGE | SA_VPD_LV_IOACCEL_STATUS, buff, 64);
10831e66f787SSean Bruno if (ret) {
10841e66f787SSean Bruno DBG_ERR("error in send scsi inquiry ret=%d\n", ret);
10851e66f787SSean Bruno goto err_out;
10861e66f787SSean Bruno }
10871e66f787SSean Bruno
10881e66f787SSean Bruno ioaccel_status = buff[IOACCEL_STATUS_BYTE];
10891e66f787SSean Bruno device->offload_config =
10901e66f787SSean Bruno !!(ioaccel_status & OFFLOAD_CONFIGURED_BIT);
10911e66f787SSean Bruno
10921e66f787SSean Bruno if (device->offload_config) {
10931e66f787SSean Bruno device->offload_enabled_pending =
10941e66f787SSean Bruno !!(ioaccel_status & OFFLOAD_ENABLED_BIT);
10951e66f787SSean Bruno if (pqisrc_get_device_raidmap(softs, device))
10961e66f787SSean Bruno device->offload_enabled_pending = false;
10971e66f787SSean Bruno }
10981e66f787SSean Bruno
1099b17f4335SSean Bruno DBG_DISC("offload_config: 0x%x offload_enabled_pending: 0x%x \n",
11001e66f787SSean Bruno device->offload_config, device->offload_enabled_pending);
11011e66f787SSean Bruno
11021e66f787SSean Bruno err_out:
11031e66f787SSean Bruno os_mem_free(softs, (char*)buff, 64);
11041e66f787SSean Bruno DBG_FUNC("OUT\n");
11051e66f787SSean Bruno }
11061e66f787SSean Bruno
11071e66f787SSean Bruno /* Get RAID level of requested device */
11089fac68fcSPAPANI SRIKANTH static void
pqisrc_get_dev_raid_level(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)11099fac68fcSPAPANI SRIKANTH pqisrc_get_dev_raid_level(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
11101e66f787SSean Bruno {
11111e66f787SSean Bruno uint8_t raid_level;
11121e66f787SSean Bruno uint8_t *buff;
11131e66f787SSean Bruno
11141e66f787SSean Bruno DBG_FUNC("IN\n");
11151e66f787SSean Bruno
11161e66f787SSean Bruno raid_level = SA_RAID_UNKNOWN;
11171e66f787SSean Bruno
11181e66f787SSean Bruno buff = os_mem_alloc(softs, 64);
11191e66f787SSean Bruno if (buff) {
11201e66f787SSean Bruno int ret;
11211e66f787SSean Bruno ret = pqisrc_send_scsi_inquiry(softs, device->scsi3addr,
11221e66f787SSean Bruno VPD_PAGE | SA_VPD_LV_DEVICE_GEOMETRY, buff, 64);
11231e66f787SSean Bruno if (ret == 0) {
11241e66f787SSean Bruno raid_level = buff[8];
11251e66f787SSean Bruno if (raid_level > SA_RAID_MAX)
11261e66f787SSean Bruno raid_level = SA_RAID_UNKNOWN;
11271e66f787SSean Bruno }
11281e66f787SSean Bruno os_mem_free(softs, (char*)buff, 64);
11291e66f787SSean Bruno }
11301e66f787SSean Bruno
11311e66f787SSean Bruno device->raid_level = raid_level;
1132b17f4335SSean Bruno DBG_DISC("RAID LEVEL: %x \n", raid_level);
11331e66f787SSean Bruno DBG_FUNC("OUT\n");
11341e66f787SSean Bruno }
11351e66f787SSean Bruno
11361e66f787SSean Bruno /* Parse the inquiry response and determine the type of device */
11379fac68fcSPAPANI SRIKANTH static int
pqisrc_get_dev_data(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)11389fac68fcSPAPANI SRIKANTH pqisrc_get_dev_data(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
11391e66f787SSean Bruno {
11401e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
11411e66f787SSean Bruno uint8_t *inq_buff;
11427ea28254SJohn Hall int retry = 3;
11431e66f787SSean Bruno
11441e66f787SSean Bruno DBG_FUNC("IN\n");
11451e66f787SSean Bruno
11461e66f787SSean Bruno inq_buff = os_mem_alloc(softs, OBDR_TAPE_INQ_SIZE);
11471e66f787SSean Bruno if (!inq_buff)
11481e66f787SSean Bruno return PQI_STATUS_FAILURE;
11491e66f787SSean Bruno
11509fac68fcSPAPANI SRIKANTH while(retry--) {
11511e66f787SSean Bruno /* Send an inquiry to the device to see what it is. */
11521e66f787SSean Bruno ret = pqisrc_send_scsi_inquiry(softs, device->scsi3addr, 0, inq_buff,
11531e66f787SSean Bruno OBDR_TAPE_INQ_SIZE);
11549fac68fcSPAPANI SRIKANTH if (!ret)
11559fac68fcSPAPANI SRIKANTH break;
11569fac68fcSPAPANI SRIKANTH DBG_WARN("Retrying inquiry !!!\n");
11579fac68fcSPAPANI SRIKANTH }
11589fac68fcSPAPANI SRIKANTH if(retry <= 0)
11591e66f787SSean Bruno goto err_out;
11601e66f787SSean Bruno pqisrc_sanitize_inquiry_string(&inq_buff[8], 8);
11611e66f787SSean Bruno pqisrc_sanitize_inquiry_string(&inq_buff[16], 16);
11621e66f787SSean Bruno
11631e66f787SSean Bruno device->devtype = inq_buff[0] & 0x1f;
11641e66f787SSean Bruno memcpy(device->vendor, &inq_buff[8],
11651e66f787SSean Bruno sizeof(device->vendor));
11661e66f787SSean Bruno memcpy(device->model, &inq_buff[16],
11671e66f787SSean Bruno sizeof(device->model));
11689fac68fcSPAPANI SRIKANTH DBG_DISC("DEV_TYPE: %x VENDOR: %.8s MODEL: %.16s\n", device->devtype, device->vendor, device->model);
11691e66f787SSean Bruno
11701e66f787SSean Bruno if (pqisrc_is_logical_device(device) && device->devtype == DISK_DEVICE) {
11711e66f787SSean Bruno if (pqisrc_is_external_raid_device(device)) {
11721e66f787SSean Bruno device->raid_level = SA_RAID_UNKNOWN;
11731e66f787SSean Bruno device->volume_status = SA_LV_OK;
11741e66f787SSean Bruno device->volume_offline = false;
11751e66f787SSean Bruno }
11761e66f787SSean Bruno else {
11771e66f787SSean Bruno pqisrc_get_dev_raid_level(softs, device);
11781e66f787SSean Bruno pqisrc_get_dev_ioaccel_status(softs, device);
11799fac68fcSPAPANI SRIKANTH pqisrc_get_dev_vol_status(softs, device);
11801e66f787SSean Bruno }
11811e66f787SSean Bruno }
11821e66f787SSean Bruno
11831e66f787SSean Bruno /*
11841e66f787SSean Bruno * Check if this is a One-Button-Disaster-Recovery device
11851e66f787SSean Bruno * by looking for "$DR-10" at offset 43 in the inquiry data.
11861e66f787SSean Bruno */
11871e66f787SSean Bruno device->is_obdr_device = (device->devtype == ROM_DEVICE &&
11881e66f787SSean Bruno memcmp(&inq_buff[OBDR_SIG_OFFSET], OBDR_TAPE_SIG,
11891e66f787SSean Bruno OBDR_SIG_LEN) == 0);
11901e66f787SSean Bruno err_out:
11911e66f787SSean Bruno os_mem_free(softs, (char*)inq_buff, OBDR_TAPE_INQ_SIZE);
11921e66f787SSean Bruno
11931e66f787SSean Bruno DBG_FUNC("OUT\n");
11941e66f787SSean Bruno return ret;
11951e66f787SSean Bruno }
11961e66f787SSean Bruno
11971e66f787SSean Bruno /*
11981e66f787SSean Bruno * BMIC (Basic Management And Interface Commands) command
11991e66f787SSean Bruno * to get the controller identify params
12001e66f787SSean Bruno */
12019fac68fcSPAPANI SRIKANTH static int
pqisrc_identify_ctrl(pqisrc_softstate_t * softs,bmic_ident_ctrl_t * buff)12029fac68fcSPAPANI SRIKANTH pqisrc_identify_ctrl(pqisrc_softstate_t *softs, bmic_ident_ctrl_t *buff)
12031e66f787SSean Bruno {
12041e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
12051e66f787SSean Bruno pqisrc_raid_req_t request;
12061e66f787SSean Bruno
12071e66f787SSean Bruno DBG_FUNC("IN\n");
12081e66f787SSean Bruno
12091e66f787SSean Bruno memset(&request, 0, sizeof(request));
12107ea28254SJohn Hall
12117ea28254SJohn Hall request.data_direction = SOP_DATA_DIR_TO_DEVICE;
12127ea28254SJohn Hall request.cmd.bmic_cdb.op_code = BMIC_READ;
12137ea28254SJohn Hall request.cmd.bmic_cdb.cmd = BMIC_IDENTIFY_CONTROLLER;
12147ea28254SJohn Hall request.cmd.bmic_cdb.xfer_len = BE_16(sizeof(*buff));
12157ea28254SJohn Hall
12167ea28254SJohn Hall ret = pqisrc_prepare_send_ctrlr_request(softs, &request, buff, sizeof(*buff));
12177ea28254SJohn Hall
12181e66f787SSean Bruno DBG_FUNC("OUT\n");
12191e66f787SSean Bruno
12201e66f787SSean Bruno return ret;
12211e66f787SSean Bruno }
12221e66f787SSean Bruno
12231e66f787SSean Bruno /* Get the adapter FW version using BMIC_IDENTIFY_CONTROLLER */
12249fac68fcSPAPANI SRIKANTH int
pqisrc_get_ctrl_fw_version(pqisrc_softstate_t * softs)12259fac68fcSPAPANI SRIKANTH pqisrc_get_ctrl_fw_version(pqisrc_softstate_t *softs)
12261e66f787SSean Bruno {
12271e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
12281e66f787SSean Bruno bmic_ident_ctrl_t *identify_ctrl;
12291e66f787SSean Bruno
12301e66f787SSean Bruno DBG_FUNC("IN\n");
12311e66f787SSean Bruno
12321e66f787SSean Bruno identify_ctrl = os_mem_alloc(softs, sizeof(*identify_ctrl));
12331e66f787SSean Bruno if (!identify_ctrl) {
12341e66f787SSean Bruno DBG_ERR("failed to allocate memory for identify_ctrl\n");
12351e66f787SSean Bruno return PQI_STATUS_FAILURE;
12361e66f787SSean Bruno }
12371e66f787SSean Bruno
12381e66f787SSean Bruno memset(identify_ctrl, 0, sizeof(*identify_ctrl));
12391e66f787SSean Bruno
12401e66f787SSean Bruno ret = pqisrc_identify_ctrl(softs, identify_ctrl);
12411e66f787SSean Bruno if (ret)
12421e66f787SSean Bruno goto out;
12431e66f787SSean Bruno
12441e66f787SSean Bruno softs->fw_build_number = identify_ctrl->fw_build_number;
12451e66f787SSean Bruno memcpy(softs->fw_version, identify_ctrl->fw_version,
12461e66f787SSean Bruno sizeof(identify_ctrl->fw_version));
12471e66f787SSean Bruno softs->fw_version[sizeof(identify_ctrl->fw_version)] = '\0';
12481e66f787SSean Bruno snprintf(softs->fw_version +
12491e66f787SSean Bruno strlen(softs->fw_version),
12501e66f787SSean Bruno sizeof(softs->fw_version),
12511e66f787SSean Bruno "-%u", identify_ctrl->fw_build_number);
12521e66f787SSean Bruno out:
12531e66f787SSean Bruno os_mem_free(softs, (char *)identify_ctrl, sizeof(*identify_ctrl));
12549fac68fcSPAPANI SRIKANTH DBG_NOTE("Firmware version: %s Firmware build number: %d\n", softs->fw_version, softs->fw_build_number);
12551e66f787SSean Bruno DBG_FUNC("OUT\n");
12561e66f787SSean Bruno return ret;
12571e66f787SSean Bruno }
12581e66f787SSean Bruno
12591e66f787SSean Bruno /* BMIC command to determine scsi device identify params */
12609fac68fcSPAPANI SRIKANTH static int
pqisrc_identify_physical_disk(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device,bmic_ident_physdev_t * buff,int buf_len)12619fac68fcSPAPANI SRIKANTH pqisrc_identify_physical_disk(pqisrc_softstate_t *softs,
12621e66f787SSean Bruno pqi_scsi_dev_t *device,
12631e66f787SSean Bruno bmic_ident_physdev_t *buff,
12641e66f787SSean Bruno int buf_len)
12651e66f787SSean Bruno {
12661e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
12671e66f787SSean Bruno uint16_t bmic_device_index;
12681e66f787SSean Bruno pqisrc_raid_req_t request;
12691e66f787SSean Bruno
12709fac68fcSPAPANI SRIKANTH
12711e66f787SSean Bruno DBG_FUNC("IN\n");
12721e66f787SSean Bruno
12731e66f787SSean Bruno memset(&request, 0, sizeof(request));
12741e66f787SSean Bruno bmic_device_index = BMIC_GET_DRIVE_NUMBER(device->scsi3addr);
12751e66f787SSean Bruno
12767ea28254SJohn Hall request.data_direction = SOP_DATA_DIR_TO_DEVICE;
12777ea28254SJohn Hall request.cmd.bmic_cdb.op_code = BMIC_READ;
12787ea28254SJohn Hall request.cmd.bmic_cdb.cmd = BMIC_IDENTIFY_PHYSICAL_DEVICE;
12797ea28254SJohn Hall request.cmd.bmic_cdb.xfer_len = BE_16(buf_len);
12807ea28254SJohn Hall request.cmd.cdb[2] = (uint8_t)bmic_device_index;
12817ea28254SJohn Hall request.cmd.cdb[9] = (uint8_t)(bmic_device_index >> 8);
12827ea28254SJohn Hall
12837ea28254SJohn Hall ret = pqisrc_prepare_send_ctrlr_request(softs, &request, buff, buf_len);
12847ea28254SJohn Hall
12851e66f787SSean Bruno DBG_FUNC("OUT\n");
12861e66f787SSean Bruno return ret;
12871e66f787SSean Bruno }
12881e66f787SSean Bruno
12891e66f787SSean Bruno /*
12901e66f787SSean Bruno * Function used to get the scsi device information using one of BMIC
12911e66f787SSean Bruno * BMIC_IDENTIFY_PHYSICAL_DEVICE
12921e66f787SSean Bruno */
12939fac68fcSPAPANI SRIKANTH static void
pqisrc_get_physical_device_info(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device,bmic_ident_physdev_t * id_phys)12949fac68fcSPAPANI SRIKANTH pqisrc_get_physical_device_info(pqisrc_softstate_t *softs,
12951e66f787SSean Bruno pqi_scsi_dev_t *device,
12961e66f787SSean Bruno bmic_ident_physdev_t *id_phys)
12971e66f787SSean Bruno {
12981e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS;
12991e66f787SSean Bruno
13001e66f787SSean Bruno DBG_FUNC("IN\n");
13011e66f787SSean Bruno memset(id_phys, 0, sizeof(*id_phys));
13021e66f787SSean Bruno
13031e66f787SSean Bruno ret= pqisrc_identify_physical_disk(softs, device,
13041e66f787SSean Bruno id_phys, sizeof(*id_phys));
13051e66f787SSean Bruno if (ret) {
13061e66f787SSean Bruno device->queue_depth = PQI_PHYSICAL_DISK_DEFAULT_MAX_QUEUE_DEPTH;
13071e66f787SSean Bruno return;
13081e66f787SSean Bruno }
13091e66f787SSean Bruno
13101e66f787SSean Bruno device->queue_depth =
13111e66f787SSean Bruno LE_16(id_phys->current_queue_depth_limit);
13121e66f787SSean Bruno device->device_type = id_phys->device_type;
13131e66f787SSean Bruno device->active_path_index = id_phys->active_path_number;
13141e66f787SSean Bruno device->path_map = id_phys->redundant_path_present_map;
13151e66f787SSean Bruno memcpy(&device->box,
13161e66f787SSean Bruno &id_phys->alternate_paths_phys_box_on_port,
13171e66f787SSean Bruno sizeof(device->box));
13181e66f787SSean Bruno memcpy(&device->phys_connector,
13191e66f787SSean Bruno &id_phys->alternate_paths_phys_connector,
13201e66f787SSean Bruno sizeof(device->phys_connector));
13211e66f787SSean Bruno device->bay = id_phys->phys_bay_in_box;
13227ea28254SJohn Hall if (id_phys->multi_lun_device_lun_count) {
13237ea28254SJohn Hall device->is_multi_lun = true;
13247ea28254SJohn Hall }
13251e66f787SSean Bruno
1326b17f4335SSean Bruno DBG_DISC("BMIC DEV_TYPE: %x QUEUE DEPTH: 0x%x \n", device->device_type, device->queue_depth);
13271e66f787SSean Bruno DBG_FUNC("OUT\n");
13281e66f787SSean Bruno }
13291e66f787SSean Bruno
13309fac68fcSPAPANI SRIKANTH
13311e66f787SSean Bruno /* Function used to find the entry of the device in a list */
13327ea28254SJohn Hall static device_status_t
pqisrc_scsi_find_entry(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device_to_find,pqi_scsi_dev_t ** same_device)13337ea28254SJohn Hall pqisrc_scsi_find_entry(pqisrc_softstate_t *softs,
13349fac68fcSPAPANI SRIKANTH pqi_scsi_dev_t *device_to_find, pqi_scsi_dev_t **same_device)
13351e66f787SSean Bruno {
13361e66f787SSean Bruno pqi_scsi_dev_t *device;
13377ea28254SJohn Hall int i;
13381e66f787SSean Bruno DBG_FUNC("IN\n");
13391e66f787SSean Bruno for(i = 0; i < PQI_MAX_DEVICES; i++) {
13407ea28254SJohn Hall device = softs->dev_list[i];
13417ea28254SJohn Hall if(device == NULL)
13421e66f787SSean Bruno continue;
13431e66f787SSean Bruno if (pqisrc_scsi3addr_equal(device_to_find->scsi3addr,
13441e66f787SSean Bruno device->scsi3addr)) {
13451e66f787SSean Bruno *same_device = device;
13467ea28254SJohn Hall if (device->in_remove == true)
13477ea28254SJohn Hall return DEVICE_IN_REMOVE;
13481e66f787SSean Bruno if (pqisrc_device_equal(device_to_find, device)) {
13491e66f787SSean Bruno if (device_to_find->volume_offline)
13501e66f787SSean Bruno return DEVICE_CHANGED;
13511e66f787SSean Bruno return DEVICE_UNCHANGED;
13521e66f787SSean Bruno }
13531e66f787SSean Bruno return DEVICE_CHANGED;
13541e66f787SSean Bruno }
13551e66f787SSean Bruno }
13561e66f787SSean Bruno DBG_FUNC("OUT\n");
13571e66f787SSean Bruno
13581e66f787SSean Bruno return DEVICE_NOT_FOUND;
13591e66f787SSean Bruno }
13601e66f787SSean Bruno
13619fac68fcSPAPANI SRIKANTH
13621e66f787SSean Bruno /* Update the newly added devices as existed device */
13639fac68fcSPAPANI SRIKANTH static void
pqisrc_exist_device_update(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device_exist,pqi_scsi_dev_t * new_device)13649fac68fcSPAPANI SRIKANTH pqisrc_exist_device_update(pqisrc_softstate_t *softs,
13659fac68fcSPAPANI SRIKANTH pqi_scsi_dev_t *device_exist, pqi_scsi_dev_t *new_device)
13661e66f787SSean Bruno {
13671e66f787SSean Bruno DBG_FUNC("IN\n");
13681e66f787SSean Bruno device_exist->expose_device = new_device->expose_device;
13691e66f787SSean Bruno memcpy(device_exist->vendor, new_device->vendor,
13701e66f787SSean Bruno sizeof(device_exist->vendor));
13711e66f787SSean Bruno memcpy(device_exist->model, new_device->model,
13721e66f787SSean Bruno sizeof(device_exist->model));
13731e66f787SSean Bruno device_exist->is_physical_device = new_device->is_physical_device;
13741e66f787SSean Bruno device_exist->is_external_raid_device =
13751e66f787SSean Bruno new_device->is_external_raid_device;
13767ea28254SJohn Hall /* Whenever a logical device expansion happens, reprobe of
13777ea28254SJohn Hall * all existing LDs will be triggered, which is resulting
13787ea28254SJohn Hall * in updating the size to the os. */
13797ea28254SJohn Hall if ((softs->ld_rescan) && (pqisrc_is_logical_device(device_exist))) {
13809fac68fcSPAPANI SRIKANTH device_exist->scsi_rescan = true;
13819fac68fcSPAPANI SRIKANTH }
13829fac68fcSPAPANI SRIKANTH
13831e66f787SSean Bruno device_exist->sas_address = new_device->sas_address;
13841e66f787SSean Bruno device_exist->raid_level = new_device->raid_level;
13851e66f787SSean Bruno device_exist->queue_depth = new_device->queue_depth;
13861e66f787SSean Bruno device_exist->ioaccel_handle = new_device->ioaccel_handle;
13871e66f787SSean Bruno device_exist->volume_status = new_device->volume_status;
13881e66f787SSean Bruno device_exist->active_path_index = new_device->active_path_index;
13891e66f787SSean Bruno device_exist->path_map = new_device->path_map;
13901e66f787SSean Bruno device_exist->bay = new_device->bay;
13911e66f787SSean Bruno memcpy(device_exist->box, new_device->box,
13921e66f787SSean Bruno sizeof(device_exist->box));
13931e66f787SSean Bruno memcpy(device_exist->phys_connector, new_device->phys_connector,
13941e66f787SSean Bruno sizeof(device_exist->phys_connector));
13951e66f787SSean Bruno device_exist->offload_config = new_device->offload_config;
13961e66f787SSean Bruno device_exist->offload_enabled_pending =
13971e66f787SSean Bruno new_device->offload_enabled_pending;
13987ea28254SJohn Hall if (device_exist->offload_to_mirror)
13997ea28254SJohn Hall os_mem_free(softs,
14007ea28254SJohn Hall (int *) device_exist->offload_to_mirror,
14017ea28254SJohn Hall sizeof(*(device_exist->offload_to_mirror)));
14027ea28254SJohn Hall device_exist->offload_to_mirror = new_device->offload_to_mirror;
14031e66f787SSean Bruno if (device_exist->raid_map)
14041e66f787SSean Bruno os_mem_free(softs,
14051e66f787SSean Bruno (char *)device_exist->raid_map,
14061e66f787SSean Bruno sizeof(*device_exist->raid_map));
14071e66f787SSean Bruno device_exist->raid_map = new_device->raid_map;
14087ea28254SJohn Hall /* To prevent these from being freed later. */
14091e66f787SSean Bruno new_device->raid_map = NULL;
14107ea28254SJohn Hall new_device->offload_to_mirror = NULL;
14111e66f787SSean Bruno DBG_FUNC("OUT\n");
14121e66f787SSean Bruno }
14131e66f787SSean Bruno
14141e66f787SSean Bruno /* Function used to add a scsi device to OS scsi subsystem */
14159fac68fcSPAPANI SRIKANTH static int
pqisrc_add_device(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)14169fac68fcSPAPANI SRIKANTH pqisrc_add_device(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
14171e66f787SSean Bruno {
14181e66f787SSean Bruno DBG_FUNC("IN\n");
14199fac68fcSPAPANI SRIKANTH DBG_NOTE("vendor: %s model: %s bus:%d target:%d lun:%d is_physical_device:0x%x expose_device:0x%x volume_offline 0x%x volume_status 0x%x \n",
14201e66f787SSean Bruno device->vendor, device->model, device->bus, device->target, device->lun, device->is_physical_device, device->expose_device, device->volume_offline, device->volume_status);
14211e66f787SSean Bruno
14221e66f787SSean Bruno device->invalid = false;
14237ea28254SJohn Hall device->schedule_rescan = false;
14247ea28254SJohn Hall device->softs = softs;
14257ea28254SJohn Hall device->in_remove = false;
14261e66f787SSean Bruno
14271e66f787SSean Bruno if(device->expose_device) {
14289fac68fcSPAPANI SRIKANTH pqisrc_init_device_active_io(softs, device);
14291e66f787SSean Bruno /* TBD: Call OS upper layer function to add the device entry */
14301e66f787SSean Bruno os_add_device(softs,device);
14311e66f787SSean Bruno }
14321e66f787SSean Bruno DBG_FUNC("OUT\n");
14331e66f787SSean Bruno return PQI_STATUS_SUCCESS;
14341e66f787SSean Bruno
14351e66f787SSean Bruno }
14361e66f787SSean Bruno
14371e66f787SSean Bruno /* Function used to remove a scsi device from OS scsi subsystem */
14389fac68fcSPAPANI SRIKANTH void
pqisrc_remove_device(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)14399fac68fcSPAPANI SRIKANTH pqisrc_remove_device(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
14401e66f787SSean Bruno {
14411e66f787SSean Bruno DBG_FUNC("IN\n");
14429fac68fcSPAPANI SRIKANTH DBG_NOTE("vendor: %s model: %s bus:%d target:%d lun:%d is_physical_device:0x%x expose_device:0x%x volume_offline 0x%x volume_status 0x%x \n",
14431e66f787SSean Bruno device->vendor, device->model, device->bus, device->target, device->lun, device->is_physical_device, device->expose_device, device->volume_offline, device->volume_status);
14441e66f787SSean Bruno device->invalid = true;
14459fac68fcSPAPANI SRIKANTH if (device->expose_device == false) {
14469fac68fcSPAPANI SRIKANTH /*Masked physical devices are not been exposed to storage stack.
14479fac68fcSPAPANI SRIKANTH *Hence, free the masked device resources such as
14489fac68fcSPAPANI SRIKANTH *device memory, Target ID,etc., here.
14499fac68fcSPAPANI SRIKANTH */
14509fac68fcSPAPANI SRIKANTH DBG_NOTE("Deallocated Masked Device Resources.\n");
14517ea28254SJohn Hall /* softs->device_list[device->target][device->lun] = NULL; */
14529fac68fcSPAPANI SRIKANTH pqisrc_free_device(softs,device);
14539fac68fcSPAPANI SRIKANTH return;
14549fac68fcSPAPANI SRIKANTH }
14559fac68fcSPAPANI SRIKANTH /* Wait for device outstanding Io's */
14569fac68fcSPAPANI SRIKANTH pqisrc_wait_for_device_commands_to_complete(softs, device);
14579fac68fcSPAPANI SRIKANTH /* Call OS upper layer function to remove the exposed device entry */
14581e66f787SSean Bruno os_remove_device(softs,device);
14591e66f787SSean Bruno DBG_FUNC("OUT\n");
14601e66f787SSean Bruno }
14611e66f787SSean Bruno
14627ea28254SJohn Hall
14631e66f787SSean Bruno /*
14641e66f787SSean Bruno * When exposing new device to OS fails then adjst list according to the
14651e66f787SSean Bruno * mid scsi list
14661e66f787SSean Bruno */
14679fac68fcSPAPANI SRIKANTH static void
pqisrc_adjust_list(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)14689fac68fcSPAPANI SRIKANTH pqisrc_adjust_list(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
14691e66f787SSean Bruno {
14707ea28254SJohn Hall int i;
14717ea28254SJohn Hall unsigned char addr1[8], addr2[8];
14727ea28254SJohn Hall pqi_scsi_dev_t *temp_device;
14731e66f787SSean Bruno DBG_FUNC("IN\n");
14741e66f787SSean Bruno
14751e66f787SSean Bruno if (!device) {
14761e66f787SSean Bruno DBG_ERR("softs = %p: device is NULL !!!\n", softs);
14771e66f787SSean Bruno return;
14781e66f787SSean Bruno }
14791e66f787SSean Bruno
14801e66f787SSean Bruno OS_ACQUIRE_SPINLOCK(&softs->devlist_lock);
14817ea28254SJohn Hall uint8_t *scsi3addr;
14827ea28254SJohn Hall /*For external raid device, there can be multiple luns
14837ea28254SJohn Hall *with same target. So while freeing external raid device,
14847ea28254SJohn Hall *free target only after removing all luns with same target.*/
14857ea28254SJohn Hall if (pqisrc_is_external_raid_device(device)) {
14867ea28254SJohn Hall memcpy(addr1, device->scsi3addr, 8);
14877ea28254SJohn Hall for(i = 0; i < PQI_MAX_DEVICES; i++) {
14887ea28254SJohn Hall if(softs->dev_list[i] == NULL)
14897ea28254SJohn Hall continue;
14907ea28254SJohn Hall temp_device = softs->dev_list[i];
14917ea28254SJohn Hall memcpy(addr2, temp_device->scsi3addr, 8);
14927ea28254SJohn Hall if(memcmp(addr1, addr2, 8) == 0) {
14937ea28254SJohn Hall continue;
14947ea28254SJohn Hall }
14957ea28254SJohn Hall if (addr1[2] == addr2[2]) {
14967ea28254SJohn Hall break;
14977ea28254SJohn Hall }
14987ea28254SJohn Hall }
14997ea28254SJohn Hall if(i == PQI_MAX_DEVICES) {
15007ea28254SJohn Hall pqisrc_remove_target_bit(softs, device->target);
15017ea28254SJohn Hall }
15027ea28254SJohn Hall }
15037ea28254SJohn Hall
15047ea28254SJohn Hall if(pqisrc_delete_softs_entry(softs, device) == PQI_STATUS_SUCCESS){
15057ea28254SJohn Hall scsi3addr = device->scsi3addr;
15067ea28254SJohn Hall if (!pqisrc_is_logical_device(device) && !MASKED_DEVICE(scsi3addr)){
15077ea28254SJohn Hall DBG_NOTE("About to remove target bit %d \n", device->target);
15087ea28254SJohn Hall pqisrc_remove_target_bit(softs, device->target);
15097ea28254SJohn Hall }
15107ea28254SJohn Hall }
15111e66f787SSean Bruno OS_RELEASE_SPINLOCK(&softs->devlist_lock);
15121e66f787SSean Bruno pqisrc_device_mem_free(softs, device);
15131e66f787SSean Bruno
15141e66f787SSean Bruno DBG_FUNC("OUT\n");
15151e66f787SSean Bruno }
15161e66f787SSean Bruno
15171e66f787SSean Bruno /* Debug routine used to display the RAID volume status of the device */
15189fac68fcSPAPANI SRIKANTH static void
pqisrc_display_volume_status(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)15199fac68fcSPAPANI SRIKANTH pqisrc_display_volume_status(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
15201e66f787SSean Bruno {
15211e66f787SSean Bruno char *status;
15221e66f787SSean Bruno
15231e66f787SSean Bruno DBG_FUNC("IN\n");
15241e66f787SSean Bruno switch (device->volume_status) {
15251e66f787SSean Bruno case SA_LV_OK:
15261e66f787SSean Bruno status = "Volume is online.";
15271e66f787SSean Bruno break;
15281e66f787SSean Bruno case SA_LV_UNDERGOING_ERASE:
15291e66f787SSean Bruno status = "Volume is undergoing background erase process.";
15301e66f787SSean Bruno break;
15311e66f787SSean Bruno case SA_LV_NOT_AVAILABLE:
15321e66f787SSean Bruno status = "Volume is waiting for transforming volume.";
15331e66f787SSean Bruno break;
15341e66f787SSean Bruno case SA_LV_UNDERGOING_RPI:
15351e66f787SSean Bruno status = "Volume is undergoing rapid parity initialization process.";
15361e66f787SSean Bruno break;
15371e66f787SSean Bruno case SA_LV_PENDING_RPI:
15381e66f787SSean Bruno status = "Volume is queued for rapid parity initialization process.";
15391e66f787SSean Bruno break;
15401e66f787SSean Bruno case SA_LV_ENCRYPTED_NO_KEY:
15411e66f787SSean Bruno status = "Volume is encrypted and cannot be accessed because key is not present.";
15421e66f787SSean Bruno break;
15431e66f787SSean Bruno case SA_LV_PLAINTEXT_IN_ENCRYPT_ONLY_CONTROLLER:
15441e66f787SSean Bruno status = "Volume is not encrypted and cannot be accessed because controller is in encryption-only mode.";
15451e66f787SSean Bruno break;
15461e66f787SSean Bruno case SA_LV_UNDERGOING_ENCRYPTION:
15471e66f787SSean Bruno status = "Volume is undergoing encryption process.";
15481e66f787SSean Bruno break;
15491e66f787SSean Bruno case SA_LV_UNDERGOING_ENCRYPTION_REKEYING:
15501e66f787SSean Bruno status = "Volume is undergoing encryption re-keying process.";
15511e66f787SSean Bruno break;
15521e66f787SSean Bruno case SA_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER:
15531e66f787SSean Bruno status = "Volume is encrypted and cannot be accessed because controller does not have encryption enabled.";
15541e66f787SSean Bruno break;
15551e66f787SSean Bruno case SA_LV_PENDING_ENCRYPTION:
15561e66f787SSean Bruno status = "Volume is pending migration to encrypted state, but process has not started.";
15571e66f787SSean Bruno break;
15581e66f787SSean Bruno case SA_LV_PENDING_ENCRYPTION_REKEYING:
15591e66f787SSean Bruno status = "Volume is encrypted and is pending encryption rekeying.";
15601e66f787SSean Bruno break;
15611e66f787SSean Bruno case SA_LV_STATUS_VPD_UNSUPPORTED:
15621e66f787SSean Bruno status = "Volume status is not available through vital product data pages.";
15631e66f787SSean Bruno break;
15649fac68fcSPAPANI SRIKANTH case SA_LV_UNDERGOING_EXPANSION:
15659fac68fcSPAPANI SRIKANTH status = "Volume undergoing expansion";
15669fac68fcSPAPANI SRIKANTH break;
15679fac68fcSPAPANI SRIKANTH case SA_LV_QUEUED_FOR_EXPANSION:
15689fac68fcSPAPANI SRIKANTH status = "Volume queued for expansion";
15697ea28254SJohn Hall break;
15709fac68fcSPAPANI SRIKANTH case SA_LV_EJECTED:
15719fac68fcSPAPANI SRIKANTH status = "Volume ejected";
15729fac68fcSPAPANI SRIKANTH break;
15739fac68fcSPAPANI SRIKANTH case SA_LV_WRONG_PHYSICAL_DRIVE_REPLACED:
15749fac68fcSPAPANI SRIKANTH status = "Volume has wrong physical drive replaced";
15759fac68fcSPAPANI SRIKANTH break;
15769fac68fcSPAPANI SRIKANTH case SA_LV_DISABLED_SCSI_ID_CONFLICT:
15779fac68fcSPAPANI SRIKANTH status = "Volume disabled scsi id conflict";
15789fac68fcSPAPANI SRIKANTH break;
15799fac68fcSPAPANI SRIKANTH case SA_LV_HARDWARE_HAS_OVERHEATED:
15809fac68fcSPAPANI SRIKANTH status = "Volume hardware has over heated";
15819fac68fcSPAPANI SRIKANTH break;
15829fac68fcSPAPANI SRIKANTH case SA_LV_HARDWARE_OVERHEATING:
15839fac68fcSPAPANI SRIKANTH status = "Volume hardware over heating";
15849fac68fcSPAPANI SRIKANTH break;
15859fac68fcSPAPANI SRIKANTH case SA_LV_PHYSICAL_DRIVE_CONNECTION_PROBLEM:
15869fac68fcSPAPANI SRIKANTH status = "Volume physical drive connection problem";
15879fac68fcSPAPANI SRIKANTH break;
15881e66f787SSean Bruno default:
15891e66f787SSean Bruno status = "Volume is in an unknown state.";
15901e66f787SSean Bruno break;
15911e66f787SSean Bruno }
15921e66f787SSean Bruno
15937ea28254SJohn Hall DBG_NOTE("scsi BTL %d:%d:%d %s\n",
15941e66f787SSean Bruno device->bus, device->target, device->lun, status);
15951e66f787SSean Bruno DBG_FUNC("OUT\n");
15961e66f787SSean Bruno }
15971e66f787SSean Bruno
15989fac68fcSPAPANI SRIKANTH void
pqisrc_device_mem_free(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)15999fac68fcSPAPANI SRIKANTH pqisrc_device_mem_free(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
16001e66f787SSean Bruno {
1601b17f4335SSean Bruno DBG_FUNC("IN\n");
16021e66f787SSean Bruno if (!device)
16031e66f787SSean Bruno return;
16041e66f787SSean Bruno if (device->raid_map) {
16051e66f787SSean Bruno os_mem_free(softs, (char *)device->raid_map, sizeof(pqisrc_raid_map_t));
16061e66f787SSean Bruno }
16077ea28254SJohn Hall if (device->offload_to_mirror) {
16087ea28254SJohn Hall os_mem_free(softs, (int *)device->offload_to_mirror, sizeof(*(device->offload_to_mirror)));
16097ea28254SJohn Hall }
16101e66f787SSean Bruno os_mem_free(softs, (char *)device,sizeof(*device));
1611b17f4335SSean Bruno DBG_FUNC("OUT\n");
16121e66f787SSean Bruno
16131e66f787SSean Bruno }
16141e66f787SSean Bruno
16151e66f787SSean Bruno /* OS should call this function to free the scsi device */
16169fac68fcSPAPANI SRIKANTH void
pqisrc_free_device(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)16179fac68fcSPAPANI SRIKANTH pqisrc_free_device(pqisrc_softstate_t * softs, pqi_scsi_dev_t *device)
16181e66f787SSean Bruno {
16199fac68fcSPAPANI SRIKANTH rcb_t *rcb;
16207ea28254SJohn Hall uint8_t *scsi3addr;
16217ea28254SJohn Hall int i, index;
16227ea28254SJohn Hall pqi_scsi_dev_t *temp_device;
16237ea28254SJohn Hall unsigned char addr1[8], addr2[8];
16249fac68fcSPAPANI SRIKANTH /* Clear the "device" field in the rcb.
16259fac68fcSPAPANI SRIKANTH * Response coming after device removal shouldn't access this field
16269fac68fcSPAPANI SRIKANTH */
16279fac68fcSPAPANI SRIKANTH for(i = 1; i <= softs->max_outstanding_io; i++)
16289fac68fcSPAPANI SRIKANTH {
16299fac68fcSPAPANI SRIKANTH rcb = &softs->rcb[i];
16309fac68fcSPAPANI SRIKANTH if(rcb->dvp == device) {
16319fac68fcSPAPANI SRIKANTH DBG_WARN("Pending requests for the removing device\n");
16329fac68fcSPAPANI SRIKANTH rcb->dvp = NULL;
16339fac68fcSPAPANI SRIKANTH }
16349fac68fcSPAPANI SRIKANTH }
16357ea28254SJohn Hall /* Find the entry in device list for the freed device softs->dev_list[i]&
16367ea28254SJohn Hall *make it NULL before freeing the device memory
16377ea28254SJohn Hall */
16387ea28254SJohn Hall index = pqisrc_find_device_list_index(softs, device);
16391e66f787SSean Bruno
16401e66f787SSean Bruno OS_ACQUIRE_SPINLOCK(&softs->devlist_lock);
16417ea28254SJohn Hall scsi3addr = device->scsi3addr;
16427ea28254SJohn Hall if (!pqisrc_is_logical_device(device) && !MASKED_DEVICE(scsi3addr)) {
16437ea28254SJohn Hall DBG_NOTE("Giving back target %i \n", device->target);
16447ea28254SJohn Hall pqisrc_remove_target_bit(softs, device->target);
16457ea28254SJohn Hall }
16467ea28254SJohn Hall /*For external raid device, there can be multiple luns
16477ea28254SJohn Hall *with same target. So while freeing external raid device,
16487ea28254SJohn Hall *free target only after removing all luns with same target.*/
16497ea28254SJohn Hall if (pqisrc_is_external_raid_device(device)) {
16507ea28254SJohn Hall memcpy(addr1, device->scsi3addr, 8);
16517ea28254SJohn Hall for(i = 0; i < PQI_MAX_DEVICES; i++) {
16527ea28254SJohn Hall if(softs->dev_list[i] == NULL)
16537ea28254SJohn Hall continue;
16547ea28254SJohn Hall temp_device = softs->dev_list[i];
16557ea28254SJohn Hall memcpy(addr2, temp_device->scsi3addr, 8);
16567ea28254SJohn Hall if(memcmp(addr1, addr2, 8) == 0) {
16577ea28254SJohn Hall continue;
16587ea28254SJohn Hall }
16597ea28254SJohn Hall if (addr1[2] == addr2[2]) {
16607ea28254SJohn Hall break;
16617ea28254SJohn Hall }
16627ea28254SJohn Hall }
16637ea28254SJohn Hall if(i == PQI_MAX_DEVICES) {
16647ea28254SJohn Hall pqisrc_remove_target_bit(softs, device->target);
16657ea28254SJohn Hall }
1666b17f4335SSean Bruno }
16679fac68fcSPAPANI SRIKANTH
16687ea28254SJohn Hall if (index >= 0 && index < PQI_MAX_DEVICES)
16697ea28254SJohn Hall softs->dev_list[index] = NULL;
16707ea28254SJohn Hall if (device->expose_device == true){
16717ea28254SJohn Hall pqisrc_delete_softs_entry(softs, device);
16727ea28254SJohn Hall DBG_NOTE("Removed memory for device : B %d: T %d: L %d\n",
16737ea28254SJohn Hall device->bus, device->target, device->lun);
16741e66f787SSean Bruno OS_RELEASE_SPINLOCK(&softs->devlist_lock);
1675*b064a4c9SJohn F. Carr pqisrc_device_mem_free(softs, device);
1676*b064a4c9SJohn F. Carr } else {
1677*b064a4c9SJohn F. Carr OS_RELEASE_SPINLOCK(&softs->devlist_lock);
1678*b064a4c9SJohn F. Carr }
16791e66f787SSean Bruno }
16801e66f787SSean Bruno
16817ea28254SJohn Hall
16821e66f787SSean Bruno /* Update the newly added devices to the device list */
16839fac68fcSPAPANI SRIKANTH static void
pqisrc_update_device_list(pqisrc_softstate_t * softs,pqi_scsi_dev_t * new_device_list[],int num_new_devices)16849fac68fcSPAPANI SRIKANTH pqisrc_update_device_list(pqisrc_softstate_t *softs,
16851e66f787SSean Bruno pqi_scsi_dev_t *new_device_list[], int num_new_devices)
16861e66f787SSean Bruno {
16871e66f787SSean Bruno int ret;
16881e66f787SSean Bruno int i;
16891e66f787SSean Bruno device_status_t dev_status;
16901e66f787SSean Bruno pqi_scsi_dev_t *device;
16911e66f787SSean Bruno pqi_scsi_dev_t *same_device;
16921e66f787SSean Bruno pqi_scsi_dev_t **added = NULL;
16931e66f787SSean Bruno pqi_scsi_dev_t **removed = NULL;
16941e66f787SSean Bruno int nadded = 0, nremoved = 0;
16957ea28254SJohn Hall uint8_t *scsi3addr;
1696b17f4335SSean Bruno
1697b17f4335SSean Bruno DBG_FUNC("IN\n");
16981e66f787SSean Bruno
16991e66f787SSean Bruno added = os_mem_alloc(softs, sizeof(*added) * PQI_MAX_DEVICES);
17001e66f787SSean Bruno removed = os_mem_alloc(softs, sizeof(*removed) * PQI_MAX_DEVICES);
17011e66f787SSean Bruno
17021e66f787SSean Bruno if (!added || !removed) {
17031e66f787SSean Bruno DBG_WARN("Out of memory \n");
17041e66f787SSean Bruno goto free_and_out;
17051e66f787SSean Bruno }
17061e66f787SSean Bruno
17071e66f787SSean Bruno OS_ACQUIRE_SPINLOCK(&softs->devlist_lock);
17081e66f787SSean Bruno
17091e66f787SSean Bruno for(i = 0; i < PQI_MAX_DEVICES; i++) {
17107ea28254SJohn Hall if(softs->dev_list[i] == NULL)
17111e66f787SSean Bruno continue;
17127ea28254SJohn Hall device = softs->dev_list[i];
17131e66f787SSean Bruno device->device_gone = true;
17141e66f787SSean Bruno }
17157ea28254SJohn Hall
17167ea28254SJohn Hall /* TODO:Remove later */
17171e66f787SSean Bruno DBG_IO("Device list used an array\n");
17181e66f787SSean Bruno for (i = 0; i < num_new_devices; i++) {
17191e66f787SSean Bruno device = new_device_list[i];
17201e66f787SSean Bruno
17211e66f787SSean Bruno dev_status = pqisrc_scsi_find_entry(softs, device,
17221e66f787SSean Bruno &same_device);
17231e66f787SSean Bruno
17241e66f787SSean Bruno switch (dev_status) {
17251e66f787SSean Bruno case DEVICE_UNCHANGED:
17261e66f787SSean Bruno /* New Device present in existing device list */
17271e66f787SSean Bruno device->new_device = false;
17281e66f787SSean Bruno same_device->device_gone = false;
17291e66f787SSean Bruno pqisrc_exist_device_update(softs, same_device, device);
17301e66f787SSean Bruno break;
17311e66f787SSean Bruno case DEVICE_NOT_FOUND:
17321e66f787SSean Bruno /* Device not found in existing list */
17331e66f787SSean Bruno device->new_device = true;
17341e66f787SSean Bruno break;
17351e66f787SSean Bruno case DEVICE_CHANGED:
17361e66f787SSean Bruno /* Actual device gone need to add device to list*/
17371e66f787SSean Bruno device->new_device = true;
17381e66f787SSean Bruno break;
17397ea28254SJohn Hall case DEVICE_IN_REMOVE:
17407ea28254SJohn Hall /*Older device with same target/lun is in removal stage*/
17417ea28254SJohn Hall /*New device will be added/scanned when same target/lun
17427ea28254SJohn Hall * device_list[] gets removed from the OS target
17437ea28254SJohn Hall * free call*/
17447ea28254SJohn Hall device->new_device = false;
17457ea28254SJohn Hall same_device->schedule_rescan = true;
17467ea28254SJohn Hall break;
17471e66f787SSean Bruno default:
17481e66f787SSean Bruno break;
17491e66f787SSean Bruno }
17501e66f787SSean Bruno }
17517ea28254SJohn Hall
17521e66f787SSean Bruno /* Process all devices that have gone away. */
17537ea28254SJohn Hall for(i = 0; i < PQI_MAX_DEVICES; i++) {
17547ea28254SJohn Hall device = softs->dev_list[i];
17557ea28254SJohn Hall if(device == NULL)
17561e66f787SSean Bruno continue;
17571e66f787SSean Bruno if (device->device_gone) {
17587ea28254SJohn Hall if(device->in_remove == true)
17597ea28254SJohn Hall {
17607ea28254SJohn Hall continue;
17611e66f787SSean Bruno }
17627ea28254SJohn Hall device->in_remove = true;
17637ea28254SJohn Hall removed[nremoved] = device;
17647ea28254SJohn Hall softs->num_devs--;
17657ea28254SJohn Hall nremoved++;
17661e66f787SSean Bruno }
17671e66f787SSean Bruno }
17681e66f787SSean Bruno
17691e66f787SSean Bruno /* Process all new devices. */
17701e66f787SSean Bruno for (i = 0, nadded = 0; i < num_new_devices; i++) {
17711e66f787SSean Bruno device = new_device_list[i];
17721e66f787SSean Bruno if (!device->new_device)
17731e66f787SSean Bruno continue;
17741e66f787SSean Bruno if (device->volume_offline)
17751e66f787SSean Bruno continue;
17761e66f787SSean Bruno
17777ea28254SJohn Hall /* Find out which devices to add to the driver list
17787ea28254SJohn Hall * in softs->dev_list */
17797ea28254SJohn Hall scsi3addr = device->scsi3addr;
17807ea28254SJohn Hall if (device->expose_device || !MASKED_DEVICE(scsi3addr)){
17817ea28254SJohn Hall if(pqisrc_add_softs_entry(softs, device, scsi3addr)){
17821e66f787SSean Bruno /* To prevent this entry from being freed later. */
17831e66f787SSean Bruno new_device_list[i] = NULL;
17841e66f787SSean Bruno added[nadded] = device;
17851e66f787SSean Bruno nadded++;
17861e66f787SSean Bruno }
17877ea28254SJohn Hall }
17881e66f787SSean Bruno
17897ea28254SJohn Hall }
17901e66f787SSean Bruno
17911e66f787SSean Bruno for(i = 0; i < PQI_MAX_DEVICES; i++) {
17927ea28254SJohn Hall device = softs->dev_list[i];
17937ea28254SJohn Hall if(device == NULL)
17941e66f787SSean Bruno continue;
17957ea28254SJohn Hall if (device->offload_enabled != device->offload_enabled_pending)
17967ea28254SJohn Hall {
17977ea28254SJohn Hall DBG_NOTE("[%d:%d:%d]Changing AIO to %d (was %d)\n",
17987ea28254SJohn Hall device->bus, device->target, device->lun,
17997ea28254SJohn Hall device->offload_enabled_pending,
18007ea28254SJohn Hall device->offload_enabled);
18011e66f787SSean Bruno }
18027ea28254SJohn Hall device->offload_enabled = device->offload_enabled_pending;
18031e66f787SSean Bruno }
18041e66f787SSean Bruno
18051e66f787SSean Bruno OS_RELEASE_SPINLOCK(&softs->devlist_lock);
18061e66f787SSean Bruno
18071e66f787SSean Bruno for(i = 0; i < nremoved; i++) {
18081e66f787SSean Bruno device = removed[i];
18091e66f787SSean Bruno if (device == NULL)
18101e66f787SSean Bruno continue;
18111e66f787SSean Bruno pqisrc_display_device_info(softs, "removed", device);
18129fac68fcSPAPANI SRIKANTH pqisrc_remove_device(softs, device);
18131e66f787SSean Bruno }
18141e66f787SSean Bruno
18157ea28254SJohn Hall OS_ACQUIRE_SPINLOCK(&softs->devlist_lock);
18167ea28254SJohn Hall
18171e66f787SSean Bruno for(i = 0; i < PQI_MAX_DEVICES; i++) {
18187ea28254SJohn Hall if(softs->dev_list[i] == NULL)
18191e66f787SSean Bruno continue;
18207ea28254SJohn Hall device = softs->dev_list[i];
18217ea28254SJohn Hall if (device->in_remove)
18227ea28254SJohn Hall continue;
18231e66f787SSean Bruno /*
18247ea28254SJohn Hall * If firmware queue depth is corrupt or not working
18257ea28254SJohn Hall * use the PQI_LOGICAL_DISK_DEFAULT_MAX_QUEUE_DEPTH
18267ea28254SJohn Hall * which is 0. That means there is no limit to the
18277ea28254SJohn Hall * queue depth all the way up to the controller
18287ea28254SJohn Hall * queue depth
18291e66f787SSean Bruno */
18307ea28254SJohn Hall if (pqisrc_is_logical_device(device) &&
18317ea28254SJohn Hall device->firmware_queue_depth_set == false)
18327ea28254SJohn Hall device->queue_depth = PQI_LOGICAL_DISK_DEFAULT_MAX_QUEUE_DEPTH;
18337ea28254SJohn Hall
18347ea28254SJohn Hall if (device->scsi_rescan) {
18359fac68fcSPAPANI SRIKANTH os_rescan_target(softs, device);
18361e66f787SSean Bruno }
18371e66f787SSean Bruno }
18387ea28254SJohn Hall softs->ld_rescan = false;
18397ea28254SJohn Hall
18407ea28254SJohn Hall OS_RELEASE_SPINLOCK(&softs->devlist_lock);
18419fac68fcSPAPANI SRIKANTH
18421e66f787SSean Bruno for(i = 0; i < nadded; i++) {
18431e66f787SSean Bruno device = added[i];
18441e66f787SSean Bruno if (device->expose_device) {
18451e66f787SSean Bruno ret = pqisrc_add_device(softs, device);
18461e66f787SSean Bruno if (ret) {
18471e66f787SSean Bruno DBG_WARN("scsi %d:%d:%d addition failed, device not added\n",
18487ea28254SJohn Hall device->bus, device->target, device->lun);
18491e66f787SSean Bruno pqisrc_adjust_list(softs, device);
18501e66f787SSean Bruno continue;
18511e66f787SSean Bruno }
18521e66f787SSean Bruno }
18531e66f787SSean Bruno
18541e66f787SSean Bruno pqisrc_display_device_info(softs, "added", device);
18551e66f787SSean Bruno }
18561e66f787SSean Bruno
18571e66f787SSean Bruno /* Process all volumes that are offline. */
18581e66f787SSean Bruno for (i = 0; i < num_new_devices; i++) {
18591e66f787SSean Bruno device = new_device_list[i];
18601e66f787SSean Bruno if (!device)
18611e66f787SSean Bruno continue;
18621e66f787SSean Bruno if (!device->new_device)
18631e66f787SSean Bruno continue;
18641e66f787SSean Bruno if (device->volume_offline) {
18651e66f787SSean Bruno pqisrc_display_volume_status(softs, device);
18661e66f787SSean Bruno pqisrc_display_device_info(softs, "offline", device);
18671e66f787SSean Bruno }
18681e66f787SSean Bruno }
18691e66f787SSean Bruno
18707ea28254SJohn Hall for (i = 0; i < PQI_MAX_DEVICES; i++) {
18717ea28254SJohn Hall device = softs->dev_list[i];
18727ea28254SJohn Hall if(device == NULL)
18737ea28254SJohn Hall continue;
18747ea28254SJohn Hall DBG_DISC("Current device %d : B%d:T%d:L%d\n",
18757ea28254SJohn Hall i, device->bus, device->target,
18767ea28254SJohn Hall device->lun);
18777ea28254SJohn Hall }
18787ea28254SJohn Hall
18791e66f787SSean Bruno free_and_out:
18801e66f787SSean Bruno if (added)
18811e66f787SSean Bruno os_mem_free(softs, (char *)added,
18821e66f787SSean Bruno sizeof(*added) * PQI_MAX_DEVICES);
18831e66f787SSean Bruno if (removed)
18841e66f787SSean Bruno os_mem_free(softs, (char *)removed,
18851e66f787SSean Bruno sizeof(*removed) * PQI_MAX_DEVICES);
18861e66f787SSean Bruno
1887b17f4335SSean Bruno DBG_FUNC("OUT\n");
18881e66f787SSean Bruno }
18891e66f787SSean Bruno
18901e66f787SSean Bruno /*
18911e66f787SSean Bruno * Let the Adapter know about driver version using one of BMIC
18921e66f787SSean Bruno * BMIC_WRITE_HOST_WELLNESS
18931e66f787SSean Bruno */
18949fac68fcSPAPANI SRIKANTH int
pqisrc_write_driver_version_to_host_wellness(pqisrc_softstate_t * softs)18959fac68fcSPAPANI SRIKANTH pqisrc_write_driver_version_to_host_wellness(pqisrc_softstate_t *softs)
18961e66f787SSean Bruno {
18971e66f787SSean Bruno int rval = PQI_STATUS_SUCCESS;
18981e66f787SSean Bruno struct bmic_host_wellness_driver_version *host_wellness_driver_ver;
18991e66f787SSean Bruno size_t data_length;
19001e66f787SSean Bruno pqisrc_raid_req_t request;
19011e66f787SSean Bruno
19021e66f787SSean Bruno DBG_FUNC("IN\n");
19031e66f787SSean Bruno
19041e66f787SSean Bruno memset(&request, 0, sizeof(request));
19051e66f787SSean Bruno data_length = sizeof(*host_wellness_driver_ver);
19061e66f787SSean Bruno
19071e66f787SSean Bruno host_wellness_driver_ver = os_mem_alloc(softs, data_length);
19081e66f787SSean Bruno if (!host_wellness_driver_ver) {
19091e66f787SSean Bruno DBG_ERR("failed to allocate memory for host wellness driver_version\n");
19101e66f787SSean Bruno return PQI_STATUS_FAILURE;
19111e66f787SSean Bruno }
19121e66f787SSean Bruno
19131e66f787SSean Bruno host_wellness_driver_ver->start_tag[0] = '<';
19141e66f787SSean Bruno host_wellness_driver_ver->start_tag[1] = 'H';
19151e66f787SSean Bruno host_wellness_driver_ver->start_tag[2] = 'W';
19161e66f787SSean Bruno host_wellness_driver_ver->start_tag[3] = '>';
19171e66f787SSean Bruno host_wellness_driver_ver->driver_version_tag[0] = 'D';
19181e66f787SSean Bruno host_wellness_driver_ver->driver_version_tag[1] = 'V';
19191e66f787SSean Bruno host_wellness_driver_ver->driver_version_length = LE_16(sizeof(host_wellness_driver_ver->driver_version));
19201e66f787SSean Bruno strncpy(host_wellness_driver_ver->driver_version, softs->os_name,
19211e66f787SSean Bruno sizeof(host_wellness_driver_ver->driver_version));
19221e66f787SSean Bruno if (strlen(softs->os_name) < sizeof(host_wellness_driver_ver->driver_version) ) {
19231e66f787SSean Bruno strncpy(host_wellness_driver_ver->driver_version + strlen(softs->os_name), PQISRC_DRIVER_VERSION,
19241e66f787SSean Bruno sizeof(host_wellness_driver_ver->driver_version) - strlen(softs->os_name));
19251e66f787SSean Bruno } else {
19267ea28254SJohn Hall DBG_DISC("OS name length(%u) is longer than buffer of driver_version\n",
19277ea28254SJohn Hall (unsigned int)strlen(softs->os_name));
19289fac68fcSPAPANI SRIKANTH
19291e66f787SSean Bruno }
19301e66f787SSean Bruno host_wellness_driver_ver->driver_version[sizeof(host_wellness_driver_ver->driver_version) - 1] = '\0';
19311e66f787SSean Bruno host_wellness_driver_ver->end_tag[0] = 'Z';
19321e66f787SSean Bruno host_wellness_driver_ver->end_tag[1] = 'Z';
19331e66f787SSean Bruno
19347ea28254SJohn Hall
19357ea28254SJohn Hall request.data_direction = SOP_DATA_DIR_FROM_DEVICE;
19367ea28254SJohn Hall request.cmd.bmic_cdb.op_code = BMIC_WRITE;
19377ea28254SJohn Hall request.cmd.bmic_cdb.cmd = BMIC_WRITE_HOST_WELLNESS;
19387ea28254SJohn Hall request.cmd.bmic_cdb.xfer_len = BE_16(data_length);
19397ea28254SJohn Hall
19407ea28254SJohn Hall rval = pqisrc_prepare_send_ctrlr_request(softs, &request, host_wellness_driver_ver, data_length);
19411e66f787SSean Bruno
19421e66f787SSean Bruno os_mem_free(softs, (char *)host_wellness_driver_ver, data_length);
19431e66f787SSean Bruno
19441e66f787SSean Bruno DBG_FUNC("OUT");
19451e66f787SSean Bruno return rval;
19461e66f787SSean Bruno }
19471e66f787SSean Bruno
19481e66f787SSean Bruno /*
19491e66f787SSean Bruno * Write current RTC time from host to the adapter using
19501e66f787SSean Bruno * BMIC_WRITE_HOST_WELLNESS
19511e66f787SSean Bruno */
19529fac68fcSPAPANI SRIKANTH int
pqisrc_write_current_time_to_host_wellness(pqisrc_softstate_t * softs)19539fac68fcSPAPANI SRIKANTH pqisrc_write_current_time_to_host_wellness(pqisrc_softstate_t *softs)
19541e66f787SSean Bruno {
19551e66f787SSean Bruno int rval = PQI_STATUS_SUCCESS;
19561e66f787SSean Bruno struct bmic_host_wellness_time *host_wellness_time;
19571e66f787SSean Bruno size_t data_length;
19581e66f787SSean Bruno pqisrc_raid_req_t request;
19591e66f787SSean Bruno
19601e66f787SSean Bruno DBG_FUNC("IN\n");
19611e66f787SSean Bruno
19621e66f787SSean Bruno memset(&request, 0, sizeof(request));
19631e66f787SSean Bruno data_length = sizeof(*host_wellness_time);
19641e66f787SSean Bruno
19651e66f787SSean Bruno host_wellness_time = os_mem_alloc(softs, data_length);
19661e66f787SSean Bruno if (!host_wellness_time) {
19671e66f787SSean Bruno DBG_ERR("failed to allocate memory for host wellness time structure\n");
19681e66f787SSean Bruno return PQI_STATUS_FAILURE;
19691e66f787SSean Bruno }
19701e66f787SSean Bruno
19711e66f787SSean Bruno host_wellness_time->start_tag[0] = '<';
19721e66f787SSean Bruno host_wellness_time->start_tag[1] = 'H';
19731e66f787SSean Bruno host_wellness_time->start_tag[2] = 'W';
19741e66f787SSean Bruno host_wellness_time->start_tag[3] = '>';
19751e66f787SSean Bruno host_wellness_time->time_tag[0] = 'T';
19761e66f787SSean Bruno host_wellness_time->time_tag[1] = 'D';
19771e66f787SSean Bruno host_wellness_time->time_length = LE_16(offsetof(struct bmic_host_wellness_time, time_length) -
19781e66f787SSean Bruno offsetof(struct bmic_host_wellness_time, century));
19791e66f787SSean Bruno
19801e66f787SSean Bruno os_get_time(host_wellness_time);
19811e66f787SSean Bruno
19821e66f787SSean Bruno host_wellness_time->dont_write_tag[0] = 'D';
19831e66f787SSean Bruno host_wellness_time->dont_write_tag[1] = 'W';
19841e66f787SSean Bruno host_wellness_time->end_tag[0] = 'Z';
19851e66f787SSean Bruno host_wellness_time->end_tag[1] = 'Z';
19861e66f787SSean Bruno
19877ea28254SJohn Hall
19887ea28254SJohn Hall request.data_direction = SOP_DATA_DIR_FROM_DEVICE;
19897ea28254SJohn Hall request.cmd.bmic_cdb.op_code = BMIC_WRITE;
19907ea28254SJohn Hall request.cmd.bmic_cdb.cmd = BMIC_WRITE_HOST_WELLNESS;
19917ea28254SJohn Hall request.cmd.bmic_cdb.xfer_len = BE_16(data_length);
19927ea28254SJohn Hall
19937ea28254SJohn Hall rval = pqisrc_prepare_send_ctrlr_request(softs, &request, host_wellness_time, data_length);
19941e66f787SSean Bruno
19951e66f787SSean Bruno os_mem_free(softs, (char *)host_wellness_time, data_length);
19961e66f787SSean Bruno
19971e66f787SSean Bruno DBG_FUNC("OUT");
19981e66f787SSean Bruno return rval;
19991e66f787SSean Bruno }
20007ea28254SJohn Hall static void
pqisrc_get_device_vpd_info(pqisrc_softstate_t * softs,bmic_ident_physdev_t * bmic_phy_info,pqi_scsi_dev_t * device)20017ea28254SJohn Hall pqisrc_get_device_vpd_info(pqisrc_softstate_t *softs,
20027ea28254SJohn Hall bmic_ident_physdev_t *bmic_phy_info,pqi_scsi_dev_t *device)
20037ea28254SJohn Hall {
20047ea28254SJohn Hall DBG_FUNC("IN\n");
20057ea28254SJohn Hall memcpy(&device->wwid, &bmic_phy_info->padding[79], sizeof(device->wwid));
20067ea28254SJohn Hall DBG_FUNC("OUT\n");
20077ea28254SJohn Hall }
20081e66f787SSean Bruno /*
20091e66f787SSean Bruno * Function used to perform a rescan of scsi devices
20101e66f787SSean Bruno * for any config change events
20111e66f787SSean Bruno */
20129fac68fcSPAPANI SRIKANTH int
pqisrc_scan_devices(pqisrc_softstate_t * softs)20139fac68fcSPAPANI SRIKANTH pqisrc_scan_devices(pqisrc_softstate_t *softs)
20141e66f787SSean Bruno {
20151e66f787SSean Bruno boolean_t is_physical_device;
20167ea28254SJohn Hall int ret;
20171e66f787SSean Bruno int i;
20181e66f787SSean Bruno int new_dev_cnt;
20191e66f787SSean Bruno int phy_log_dev_cnt;
20209fac68fcSPAPANI SRIKANTH size_t queue_log_data_length;
20211e66f787SSean Bruno uint8_t *scsi3addr;
20229fac68fcSPAPANI SRIKANTH uint8_t multiplier;
20239fac68fcSPAPANI SRIKANTH uint16_t qdepth;
20241e66f787SSean Bruno uint32_t physical_cnt;
20251e66f787SSean Bruno uint32_t logical_cnt;
20269fac68fcSPAPANI SRIKANTH uint32_t logical_queue_cnt;
20271e66f787SSean Bruno uint32_t ndev_allocated = 0;
20281e66f787SSean Bruno size_t phys_data_length, log_data_length;
20291e66f787SSean Bruno reportlun_data_ext_t *physical_dev_list = NULL;
20301e66f787SSean Bruno reportlun_data_ext_t *logical_dev_list = NULL;
20311e66f787SSean Bruno reportlun_ext_entry_t *lun_ext_entry = NULL;
20329fac68fcSPAPANI SRIKANTH reportlun_queue_depth_data_t *logical_queue_dev_list = NULL;
20331e66f787SSean Bruno bmic_ident_physdev_t *bmic_phy_info = NULL;
20341e66f787SSean Bruno pqi_scsi_dev_t **new_device_list = NULL;
20351e66f787SSean Bruno pqi_scsi_dev_t *device = NULL;
20367ea28254SJohn Hall #ifdef PQI_NEED_RESCAN_TIMER_FOR_RBOD_HOTPLUG
20377ea28254SJohn Hall int num_ext_raid_devices = 0;
20387ea28254SJohn Hall #endif
20399fac68fcSPAPANI SRIKANTH
20401e66f787SSean Bruno DBG_FUNC("IN\n");
20411e66f787SSean Bruno
20421e66f787SSean Bruno ret = pqisrc_get_phys_log_device_list(softs, &physical_dev_list, &logical_dev_list,
20439fac68fcSPAPANI SRIKANTH &logical_queue_dev_list, &queue_log_data_length,
20441e66f787SSean Bruno &phys_data_length, &log_data_length);
20451e66f787SSean Bruno
20461e66f787SSean Bruno if (ret)
20471e66f787SSean Bruno goto err_out;
20481e66f787SSean Bruno
20491e66f787SSean Bruno physical_cnt = BE_32(physical_dev_list->header.list_length)
20501e66f787SSean Bruno / sizeof(physical_dev_list->lun_entries[0]);
20511e66f787SSean Bruno
20521e66f787SSean Bruno logical_cnt = BE_32(logical_dev_list->header.list_length)
20531e66f787SSean Bruno / sizeof(logical_dev_list->lun_entries[0]);
20541e66f787SSean Bruno
20559fac68fcSPAPANI SRIKANTH logical_queue_cnt = BE_32(logical_queue_dev_list->header.list_length)
20569fac68fcSPAPANI SRIKANTH / sizeof(logical_queue_dev_list->lun_entries[0]);
20579fac68fcSPAPANI SRIKANTH
20589fac68fcSPAPANI SRIKANTH
20597ea28254SJohn Hall DBG_DISC("physical_cnt %u logical_cnt %u queue_cnt %u\n", physical_cnt, logical_cnt, logical_queue_cnt);
20601e66f787SSean Bruno
20611e66f787SSean Bruno if (physical_cnt) {
20621e66f787SSean Bruno bmic_phy_info = os_mem_alloc(softs, sizeof(*bmic_phy_info));
20631e66f787SSean Bruno if (bmic_phy_info == NULL) {
20641e66f787SSean Bruno ret = PQI_STATUS_FAILURE;
20651e66f787SSean Bruno DBG_ERR("failed to allocate memory for BMIC ID PHYS Device : %d\n", ret);
20661e66f787SSean Bruno goto err_out;
20671e66f787SSean Bruno }
20681e66f787SSean Bruno }
20691e66f787SSean Bruno phy_log_dev_cnt = physical_cnt + logical_cnt;
20701e66f787SSean Bruno new_device_list = os_mem_alloc(softs,
20711e66f787SSean Bruno sizeof(*new_device_list) * phy_log_dev_cnt);
20721e66f787SSean Bruno
20731e66f787SSean Bruno if (new_device_list == NULL) {
20741e66f787SSean Bruno ret = PQI_STATUS_FAILURE;
20751e66f787SSean Bruno DBG_ERR("failed to allocate memory for device list : %d\n", ret);
20761e66f787SSean Bruno goto err_out;
20771e66f787SSean Bruno }
20781e66f787SSean Bruno
20791e66f787SSean Bruno for (i = 0; i < phy_log_dev_cnt; i++) {
20801e66f787SSean Bruno new_device_list[i] = os_mem_alloc(softs,
20811e66f787SSean Bruno sizeof(*new_device_list[i]));
20821e66f787SSean Bruno if (new_device_list[i] == NULL) {
20831e66f787SSean Bruno ret = PQI_STATUS_FAILURE;
20841e66f787SSean Bruno DBG_ERR("failed to allocate memory for device list : %d\n", ret);
20851e66f787SSean Bruno ndev_allocated = i;
20861e66f787SSean Bruno goto err_out;
20871e66f787SSean Bruno }
20881e66f787SSean Bruno }
20891e66f787SSean Bruno
20901e66f787SSean Bruno ndev_allocated = phy_log_dev_cnt;
20911e66f787SSean Bruno new_dev_cnt = 0;
20921e66f787SSean Bruno for (i = 0; i < phy_log_dev_cnt; i++) {
20939fac68fcSPAPANI SRIKANTH
20941e66f787SSean Bruno if (i < physical_cnt) {
20951e66f787SSean Bruno is_physical_device = true;
20961e66f787SSean Bruno lun_ext_entry = &physical_dev_list->lun_entries[i];
20971e66f787SSean Bruno } else {
20981e66f787SSean Bruno is_physical_device = false;
20991e66f787SSean Bruno lun_ext_entry =
21001e66f787SSean Bruno &logical_dev_list->lun_entries[i - physical_cnt];
21011e66f787SSean Bruno }
21021e66f787SSean Bruno
21031e66f787SSean Bruno scsi3addr = lun_ext_entry->lunid;
21049fac68fcSPAPANI SRIKANTH
2105b17f4335SSean Bruno /* Save the target sas adderess for external raid device */
2106b17f4335SSean Bruno if(lun_ext_entry->device_type == CONTROLLER_DEVICE) {
21077ea28254SJohn Hall #ifdef PQI_NEED_RESCAN_TIMER_FOR_RBOD_HOTPLUG
21087ea28254SJohn Hall num_ext_raid_devices++;
21097ea28254SJohn Hall #endif
2110b17f4335SSean Bruno int target = lun_ext_entry->lunid[3] & 0x3f;
2111b17f4335SSean Bruno softs->target_sas_addr[target] = BE_64(lun_ext_entry->wwid);
2112b17f4335SSean Bruno }
21131e66f787SSean Bruno
21141e66f787SSean Bruno /* Skip masked physical non-disk devices. */
2115b17f4335SSean Bruno if (MASKED_DEVICE(scsi3addr) && is_physical_device
2116b17f4335SSean Bruno && (lun_ext_entry->ioaccel_handle == 0))
21171e66f787SSean Bruno continue;
21181e66f787SSean Bruno
21191e66f787SSean Bruno device = new_device_list[new_dev_cnt];
21201e66f787SSean Bruno memset(device, 0, sizeof(*device));
21211e66f787SSean Bruno memcpy(device->scsi3addr, scsi3addr, sizeof(device->scsi3addr));
21221e66f787SSean Bruno device->wwid = lun_ext_entry->wwid;
21231e66f787SSean Bruno device->is_physical_device = is_physical_device;
21249fac68fcSPAPANI SRIKANTH if (!is_physical_device && logical_queue_cnt--) {
21251e66f787SSean Bruno device->is_external_raid_device =
21261e66f787SSean Bruno pqisrc_is_external_raid_addr(scsi3addr);
21279fac68fcSPAPANI SRIKANTH /* The multiplier is the value we multiply the queue
21289fac68fcSPAPANI SRIKANTH * depth value with to get the actual queue depth.
21299fac68fcSPAPANI SRIKANTH * If multiplier is 1 multiply by 256 if
21309fac68fcSPAPANI SRIKANTH * multiplier 0 then multiply by 16 */
21319fac68fcSPAPANI SRIKANTH multiplier = logical_queue_dev_list->lun_entries[i - physical_cnt].multiplier;
21329fac68fcSPAPANI SRIKANTH qdepth = logical_queue_dev_list->lun_entries[i - physical_cnt].queue_depth;
21339fac68fcSPAPANI SRIKANTH if (multiplier) {
21349fac68fcSPAPANI SRIKANTH device->firmware_queue_depth_set = true;
21359fac68fcSPAPANI SRIKANTH device->queue_depth = qdepth*256;
21369fac68fcSPAPANI SRIKANTH } else {
21379fac68fcSPAPANI SRIKANTH device->firmware_queue_depth_set = true;
21389fac68fcSPAPANI SRIKANTH device->queue_depth = qdepth*16;
21399fac68fcSPAPANI SRIKANTH }
21409fac68fcSPAPANI SRIKANTH if (device->queue_depth > softs->adapterQDepth) {
21419fac68fcSPAPANI SRIKANTH device->firmware_queue_depth_set = true;
21429fac68fcSPAPANI SRIKANTH device->queue_depth = softs->adapterQDepth;
21439fac68fcSPAPANI SRIKANTH }
21449fac68fcSPAPANI SRIKANTH if ((multiplier == 1) &&
21457ea28254SJohn Hall (qdepth >= MAX_RAW_M256_QDEPTH))
21469fac68fcSPAPANI SRIKANTH device->firmware_queue_depth_set = false;
21479fac68fcSPAPANI SRIKANTH if ((multiplier == 0) &&
21487ea28254SJohn Hall (qdepth >= MAX_RAW_M16_QDEPTH))
21499fac68fcSPAPANI SRIKANTH device->firmware_queue_depth_set = false;
21507ea28254SJohn Hall
21519fac68fcSPAPANI SRIKANTH }
21521e66f787SSean Bruno
21531e66f787SSean Bruno
21541e66f787SSean Bruno /* Get device type, vendor, model, device ID. */
21551e66f787SSean Bruno ret = pqisrc_get_dev_data(softs, device);
21561e66f787SSean Bruno if (ret) {
21571e66f787SSean Bruno DBG_WARN("Inquiry failed, skipping device %016llx\n",
21581e66f787SSean Bruno (unsigned long long)BE_64(device->scsi3addr[0]));
2159b17f4335SSean Bruno DBG_DISC("INQUIRY FAILED \n");
21601e66f787SSean Bruno continue;
21611e66f787SSean Bruno }
21629fac68fcSPAPANI SRIKANTH /* Set controller queue depth to what
21639fac68fcSPAPANI SRIKANTH * it was from the scsi midlayer */
21649fac68fcSPAPANI SRIKANTH if (device->devtype == RAID_DEVICE) {
21659fac68fcSPAPANI SRIKANTH device->firmware_queue_depth_set = true;
21669fac68fcSPAPANI SRIKANTH device->queue_depth = softs->adapterQDepth;
21679fac68fcSPAPANI SRIKANTH }
21687ea28254SJohn Hall pqisrc_assign_btl(softs, device);
21691e66f787SSean Bruno
21701e66f787SSean Bruno /*
21711e66f787SSean Bruno * Expose all devices except for physical devices that
21721e66f787SSean Bruno * are masked.
21731e66f787SSean Bruno */
21741e66f787SSean Bruno if (device->is_physical_device &&
21751e66f787SSean Bruno MASKED_DEVICE(scsi3addr))
21761e66f787SSean Bruno device->expose_device = false;
21771e66f787SSean Bruno else
21781e66f787SSean Bruno device->expose_device = true;
21791e66f787SSean Bruno
21801e66f787SSean Bruno if (device->is_physical_device &&
21811e66f787SSean Bruno (lun_ext_entry->device_flags &
21821e66f787SSean Bruno REPORT_LUN_DEV_FLAG_AIO_ENABLED) &&
21831e66f787SSean Bruno lun_ext_entry->ioaccel_handle) {
21841e66f787SSean Bruno device->aio_enabled = true;
21851e66f787SSean Bruno }
21861e66f787SSean Bruno switch (device->devtype) {
21871e66f787SSean Bruno case ROM_DEVICE:
21881e66f787SSean Bruno /*
21891e66f787SSean Bruno * We don't *really* support actual CD-ROM devices,
21901e66f787SSean Bruno * but we do support the HP "One Button Disaster
21911e66f787SSean Bruno * Recovery" tape drive which temporarily pretends to
21921e66f787SSean Bruno * be a CD-ROM drive.
21931e66f787SSean Bruno */
21941e66f787SSean Bruno if (device->is_obdr_device)
21951e66f787SSean Bruno new_dev_cnt++;
21961e66f787SSean Bruno break;
21971e66f787SSean Bruno case DISK_DEVICE:
21981e66f787SSean Bruno case ZBC_DEVICE:
21991e66f787SSean Bruno if (device->is_physical_device) {
22001e66f787SSean Bruno device->ioaccel_handle =
22011e66f787SSean Bruno lun_ext_entry->ioaccel_handle;
22021e66f787SSean Bruno pqisrc_get_physical_device_info(softs, device,
22031e66f787SSean Bruno bmic_phy_info);
22047ea28254SJohn Hall if ( (!softs->page83id_in_rpl) && (bmic_phy_info->device_type == BMIC_DEVICE_TYPE_SATA)) {
22057ea28254SJohn Hall pqisrc_get_device_vpd_info(softs, bmic_phy_info, device);
22067ea28254SJohn Hall }
22077ea28254SJohn Hall device->sas_address = BE_64(device->wwid);
22081e66f787SSean Bruno }
22091e66f787SSean Bruno new_dev_cnt++;
22101e66f787SSean Bruno break;
22111e66f787SSean Bruno case ENCLOSURE_DEVICE:
22121e66f787SSean Bruno if (device->is_physical_device) {
22131e66f787SSean Bruno device->sas_address = BE_64(lun_ext_entry->wwid);
22141e66f787SSean Bruno }
22151e66f787SSean Bruno new_dev_cnt++;
22161e66f787SSean Bruno break;
22171e66f787SSean Bruno case TAPE_DEVICE:
22181e66f787SSean Bruno case MEDIUM_CHANGER_DEVICE:
22191e66f787SSean Bruno new_dev_cnt++;
22201e66f787SSean Bruno break;
22211e66f787SSean Bruno case RAID_DEVICE:
22221e66f787SSean Bruno /*
22231e66f787SSean Bruno * Only present the HBA controller itself as a RAID
22241e66f787SSean Bruno * controller. If it's a RAID controller other than
22251e66f787SSean Bruno * the HBA itself (an external RAID controller, MSA500
22261e66f787SSean Bruno * or similar), don't present it.
22271e66f787SSean Bruno */
22281e66f787SSean Bruno if (pqisrc_is_hba_lunid(scsi3addr))
22291e66f787SSean Bruno new_dev_cnt++;
22301e66f787SSean Bruno break;
2231b17f4335SSean Bruno case SES_DEVICE:
2232b17f4335SSean Bruno case CONTROLLER_DEVICE:
22339fac68fcSPAPANI SRIKANTH default:
2234b17f4335SSean Bruno break;
22351e66f787SSean Bruno }
22361e66f787SSean Bruno }
2237b17f4335SSean Bruno DBG_DISC("new_dev_cnt %d\n", new_dev_cnt);
22387ea28254SJohn Hall #ifdef PQI_NEED_RESCAN_TIMER_FOR_RBOD_HOTPLUG
22397ea28254SJohn Hall if(num_ext_raid_devices)
22407ea28254SJohn Hall os_start_rescan_timer(softs);
22417ea28254SJohn Hall else
22427ea28254SJohn Hall os_stop_rescan_timer(softs);
22437ea28254SJohn Hall #endif
22441e66f787SSean Bruno pqisrc_update_device_list(softs, new_device_list, new_dev_cnt);
22451e66f787SSean Bruno
22461e66f787SSean Bruno err_out:
22471e66f787SSean Bruno if (new_device_list) {
22481e66f787SSean Bruno for (i = 0; i < ndev_allocated; i++) {
22491e66f787SSean Bruno if (new_device_list[i]) {
22501e66f787SSean Bruno if(new_device_list[i]->raid_map)
22511e66f787SSean Bruno os_mem_free(softs, (char *)new_device_list[i]->raid_map,
22521e66f787SSean Bruno sizeof(pqisrc_raid_map_t));
22531e66f787SSean Bruno os_mem_free(softs, (char*)new_device_list[i],
22541e66f787SSean Bruno sizeof(*new_device_list[i]));
22551e66f787SSean Bruno }
22561e66f787SSean Bruno }
22571e66f787SSean Bruno os_mem_free(softs, (char *)new_device_list,
22581e66f787SSean Bruno sizeof(*new_device_list) * ndev_allocated);
22591e66f787SSean Bruno }
22601e66f787SSean Bruno if(physical_dev_list)
22611e66f787SSean Bruno os_mem_free(softs, (char *)physical_dev_list, phys_data_length);
22621e66f787SSean Bruno if(logical_dev_list)
22631e66f787SSean Bruno os_mem_free(softs, (char *)logical_dev_list, log_data_length);
22649fac68fcSPAPANI SRIKANTH if(logical_queue_dev_list)
22659fac68fcSPAPANI SRIKANTH os_mem_free(softs, (char*)logical_queue_dev_list,
22669fac68fcSPAPANI SRIKANTH queue_log_data_length);
22671e66f787SSean Bruno if (bmic_phy_info)
22681e66f787SSean Bruno os_mem_free(softs, (char *)bmic_phy_info, sizeof(*bmic_phy_info));
22691e66f787SSean Bruno
22701e66f787SSean Bruno DBG_FUNC("OUT \n");
22711e66f787SSean Bruno
22721e66f787SSean Bruno return ret;
22731e66f787SSean Bruno }
22741e66f787SSean Bruno
22751e66f787SSean Bruno /*
22761e66f787SSean Bruno * Clean up memory allocated for devices.
22771e66f787SSean Bruno */
22789fac68fcSPAPANI SRIKANTH void
pqisrc_cleanup_devices(pqisrc_softstate_t * softs)22799fac68fcSPAPANI SRIKANTH pqisrc_cleanup_devices(pqisrc_softstate_t *softs)
22801e66f787SSean Bruno {
22817ea28254SJohn Hall int i = 0;
22827ea28254SJohn Hall pqi_scsi_dev_t *device = NULL;
22831e66f787SSean Bruno DBG_FUNC("IN\n");
22841e66f787SSean Bruno for(i = 0; i < PQI_MAX_DEVICES; i++) {
22857ea28254SJohn Hall if(softs->dev_list[i] == NULL)
22861e66f787SSean Bruno continue;
22877ea28254SJohn Hall device = softs->dev_list[i];
22887ea28254SJohn Hall pqisrc_device_mem_free(softs, device);
22891e66f787SSean Bruno }
22907ea28254SJohn Hall
22911e66f787SSean Bruno DBG_FUNC("OUT\n");
22921e66f787SSean Bruno }
2293