^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * SCSI Enclosure Services
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/enclosure.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <asm/unaligned.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <scsi/scsi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <scsi/scsi_cmnd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <scsi/scsi_dbg.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <scsi/scsi_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <scsi/scsi_driver.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <scsi/scsi_host.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <scsi/scsi_transport_sas.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct ses_device {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) unsigned char *page1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) unsigned char *page1_types;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) unsigned char *page2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) unsigned char *page10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) short page1_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) short page1_num_types;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) short page2_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) short page10_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct ses_component {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) u64 addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static bool ses_page2_supported(struct enclosure_device *edev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct ses_device *ses_dev = edev->scratch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return (ses_dev->page2 != NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static int ses_probe(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct scsi_device *sdev = to_scsi_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) int err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (sdev->type != TYPE_ENCLOSURE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) sdev_printk(KERN_NOTICE, sdev, "Attached Enclosure device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define SES_TIMEOUT (30 * HZ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define SES_RETRIES 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static void init_device_slot_control(unsigned char *dest_desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) struct enclosure_component *ecomp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) unsigned char *status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) memcpy(dest_desc, status, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) dest_desc[0] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /* only clear byte 1 for ENCLOSURE_COMPONENT_DEVICE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (ecomp->type == ENCLOSURE_COMPONENT_DEVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) dest_desc[1] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) dest_desc[2] &= 0xde;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) dest_desc[3] &= 0x3c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static int ses_recv_diag(struct scsi_device *sdev, int page_code,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) void *buf, int bufflen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) unsigned char cmd[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) RECEIVE_DIAGNOSTIC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) 1, /* Set PCV bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) page_code,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) bufflen >> 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) bufflen & 0xff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) unsigned char recv_page_code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) unsigned int retries = SES_RETRIES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct scsi_sense_hdr sshdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) ret = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) &sshdr, SES_TIMEOUT, 1, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) } while (ret > 0 && --retries && scsi_sense_valid(&sshdr) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) (sshdr.sense_key == NOT_READY ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) (sshdr.sense_key == UNIT_ATTENTION && sshdr.asc == 0x29)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (unlikely(ret))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) recv_page_code = ((unsigned char *)buf)[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if (likely(recv_page_code == page_code))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) /* successful diagnostic but wrong page code. This happens to some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * USB devices, just print a message and pretend there was an error */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) sdev_printk(KERN_ERR, sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) "Wrong diagnostic page; asked for %d got %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) page_code, recv_page_code);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) static int ses_send_diag(struct scsi_device *sdev, int page_code,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) void *buf, int bufflen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) unsigned char cmd[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) SEND_DIAGNOSTIC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 0x10, /* Set PF bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) bufflen >> 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) bufflen & 0xff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct scsi_sense_hdr sshdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) unsigned int retries = SES_RETRIES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) result = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, buf, bufflen,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) &sshdr, SES_TIMEOUT, 1, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) } while (result > 0 && --retries && scsi_sense_valid(&sshdr) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) (sshdr.sense_key == NOT_READY ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) (sshdr.sense_key == UNIT_ATTENTION && sshdr.asc == 0x29)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) sdev_printk(KERN_ERR, sdev, "SEND DIAGNOSTIC result: %8x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) static int ses_set_page2_descriptor(struct enclosure_device *edev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) struct enclosure_component *ecomp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) unsigned char *desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) int i, j, count = 0, descriptor = ecomp->number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) struct scsi_device *sdev = to_scsi_device(edev->edev.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) struct ses_device *ses_dev = edev->scratch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) unsigned char *type_ptr = ses_dev->page1_types;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) unsigned char *desc_ptr = ses_dev->page2 + 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) /* Clear everything */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) memset(desc_ptr, 0, ses_dev->page2_len - 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) for (j = 0; j < type_ptr[1]; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) desc_ptr += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if (count++ == descriptor) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) memcpy(desc_ptr, desc, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) /* set select */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) desc_ptr[0] |= 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) /* clear reserved, just in case */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) desc_ptr[0] &= 0xf0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return ses_send_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) static unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) struct enclosure_component *ecomp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) int i, j, count = 0, descriptor = ecomp->number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) struct scsi_device *sdev = to_scsi_device(edev->edev.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) struct ses_device *ses_dev = edev->scratch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) unsigned char *type_ptr = ses_dev->page1_types;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) unsigned char *desc_ptr = ses_dev->page2 + 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) if (ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) for (j = 0; j < type_ptr[1]; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) desc_ptr += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) if (count++ == descriptor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return desc_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) /* For device slot and array device slot elements, byte 3 bit 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * is "fault sensed" while byte 3 bit 5 is "fault reqstd". As this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) * code stands these bits are shifted 4 positions right so in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) * sysfs they will appear as bits 2 and 1 respectively. Strange. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) static void ses_get_fault(struct enclosure_device *edev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) struct enclosure_component *ecomp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) unsigned char *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (!ses_page2_supported(edev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) ecomp->fault = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) desc = ses_get_page2_descriptor(edev, ecomp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) ecomp->fault = (desc[3] & 0x60) >> 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) static int ses_set_fault(struct enclosure_device *edev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) struct enclosure_component *ecomp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) enum enclosure_component_setting val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) unsigned char desc[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) unsigned char *desc_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (!ses_page2_supported(edev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) desc_ptr = ses_get_page2_descriptor(edev, ecomp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (!desc_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) init_device_slot_control(desc, ecomp, desc_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) switch (val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) case ENCLOSURE_SETTING_DISABLED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) desc[3] &= 0xdf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) case ENCLOSURE_SETTING_ENABLED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) desc[3] |= 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) /* SES doesn't do the SGPIO blink settings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) return ses_set_page2_descriptor(edev, ecomp, desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) static void ses_get_status(struct enclosure_device *edev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) struct enclosure_component *ecomp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) unsigned char *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (!ses_page2_supported(edev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) ecomp->status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) desc = ses_get_page2_descriptor(edev, ecomp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) if (desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) ecomp->status = (desc[0] & 0x0f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) static void ses_get_locate(struct enclosure_device *edev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) struct enclosure_component *ecomp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) unsigned char *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (!ses_page2_supported(edev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) ecomp->locate = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) desc = ses_get_page2_descriptor(edev, ecomp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) if (desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) ecomp->locate = (desc[2] & 0x02) ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) static int ses_set_locate(struct enclosure_device *edev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) struct enclosure_component *ecomp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) enum enclosure_component_setting val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) unsigned char desc[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) unsigned char *desc_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (!ses_page2_supported(edev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) desc_ptr = ses_get_page2_descriptor(edev, ecomp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) if (!desc_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) init_device_slot_control(desc, ecomp, desc_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) switch (val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) case ENCLOSURE_SETTING_DISABLED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) desc[2] &= 0xfd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) case ENCLOSURE_SETTING_ENABLED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) desc[2] |= 0x02;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) /* SES doesn't do the SGPIO blink settings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) return ses_set_page2_descriptor(edev, ecomp, desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) static int ses_set_active(struct enclosure_device *edev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) struct enclosure_component *ecomp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) enum enclosure_component_setting val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) unsigned char desc[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) unsigned char *desc_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) if (!ses_page2_supported(edev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) desc_ptr = ses_get_page2_descriptor(edev, ecomp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) if (!desc_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) init_device_slot_control(desc, ecomp, desc_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) switch (val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) case ENCLOSURE_SETTING_DISABLED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) desc[2] &= 0x7f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) ecomp->active = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) case ENCLOSURE_SETTING_ENABLED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) desc[2] |= 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) ecomp->active = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) /* SES doesn't do the SGPIO blink settings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) return ses_set_page2_descriptor(edev, ecomp, desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) static int ses_show_id(struct enclosure_device *edev, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) struct ses_device *ses_dev = edev->scratch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) unsigned long long id = get_unaligned_be64(ses_dev->page1+8+4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) return sprintf(buf, "%#llx\n", id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) static void ses_get_power_status(struct enclosure_device *edev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) struct enclosure_component *ecomp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) unsigned char *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (!ses_page2_supported(edev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) ecomp->power_status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) desc = ses_get_page2_descriptor(edev, ecomp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) if (desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) ecomp->power_status = (desc[3] & 0x10) ? 0 : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) static int ses_set_power_status(struct enclosure_device *edev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) struct enclosure_component *ecomp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) unsigned char desc[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) unsigned char *desc_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) if (!ses_page2_supported(edev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) desc_ptr = ses_get_page2_descriptor(edev, ecomp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) if (!desc_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) init_device_slot_control(desc, ecomp, desc_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) switch (val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) /* power = 1 is device_off = 0 and vice versa */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) desc[3] |= 0x10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) desc[3] &= 0xef;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) ecomp->power_status = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) return ses_set_page2_descriptor(edev, ecomp, desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) static struct enclosure_component_callbacks ses_enclosure_callbacks = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) .get_fault = ses_get_fault,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) .set_fault = ses_set_fault,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) .get_status = ses_get_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) .get_locate = ses_get_locate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) .set_locate = ses_set_locate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) .get_power_status = ses_get_power_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) .set_power_status = ses_set_power_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) .set_active = ses_set_active,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) .show_id = ses_show_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) struct ses_host_edev {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) struct Scsi_Host *shost;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) struct enclosure_device *edev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) int ses_match_host(struct enclosure_device *edev, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) struct ses_host_edev *sed = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) struct scsi_device *sdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) if (!scsi_is_sdev_device(edev->edev.parent))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) sdev = to_scsi_device(edev->edev.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) if (sdev->host != sed->shost)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) sed->edev = edev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) #endif /* 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) static void ses_process_descriptor(struct enclosure_component *ecomp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) unsigned char *desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) int eip = desc[0] & 0x10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) int invalid = desc[0] & 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) enum scsi_protocol proto = desc[0] & 0x0f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) u64 addr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) int slot = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) struct ses_component *scomp = ecomp->scratch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) unsigned char *d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) if (invalid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) switch (proto) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) case SCSI_PROTOCOL_FCP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) if (eip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) d = desc + 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) slot = d[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) case SCSI_PROTOCOL_SAS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) if (eip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) d = desc + 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) slot = d[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) d = desc + 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) d = desc + 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) /* only take the phy0 addr */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) addr = (u64)d[12] << 56 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) (u64)d[13] << 48 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) (u64)d[14] << 40 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) (u64)d[15] << 32 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) (u64)d[16] << 24 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) (u64)d[17] << 16 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) (u64)d[18] << 8 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) (u64)d[19];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) /* FIXME: Need to add more protocols than just SAS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) ecomp->slot = slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) scomp->addr = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) struct efd {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) u64 addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) static int ses_enclosure_find_by_addr(struct enclosure_device *edev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) struct efd *efd = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) struct ses_component *scomp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) if (!edev->component[0].scratch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) for (i = 0; i < edev->components; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) scomp = edev->component[i].scratch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (scomp->addr != efd->addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) if (enclosure_add_device(edev, i, efd->dev) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) kobject_uevent(&efd->dev->kobj, KOBJ_CHANGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) #define INIT_ALLOC_SIZE 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) static void ses_enclosure_data_process(struct enclosure_device *edev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) struct scsi_device *sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) int create)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) u32 result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) unsigned char *buf = NULL, *type_ptr, *desc_ptr, *addl_desc_ptr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) int i, j, page7_len, len, components;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) struct ses_device *ses_dev = edev->scratch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) int types = ses_dev->page1_num_types;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) unsigned char *hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) if (!hdr_buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) goto simple_populate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) /* re-read page 10 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) if (ses_dev->page10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) ses_recv_diag(sdev, 10, ses_dev->page10, ses_dev->page10_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) /* Page 7 for the descriptors is optional */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) result = ses_recv_diag(sdev, 7, hdr_buf, INIT_ALLOC_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) goto simple_populate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) page7_len = len = (hdr_buf[2] << 8) + hdr_buf[3] + 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) /* add 1 for trailing '\0' we'll use */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) buf = kzalloc(len + 1, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) goto simple_populate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) result = ses_recv_diag(sdev, 7, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) if (result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) simple_populate:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) desc_ptr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) page7_len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) desc_ptr = buf + 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) len = (desc_ptr[2] << 8) + desc_ptr[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) /* skip past overall descriptor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) desc_ptr += len + 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) if (ses_dev->page10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) addl_desc_ptr = ses_dev->page10 + 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) type_ptr = ses_dev->page1_types;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) components = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) for (i = 0; i < types; i++, type_ptr += 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) for (j = 0; j < type_ptr[1]; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) char *name = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) struct enclosure_component *ecomp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) if (desc_ptr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) if (desc_ptr >= buf + page7_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) desc_ptr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) len = (desc_ptr[2] << 8) + desc_ptr[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) desc_ptr += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) /* Add trailing zero - pushes into
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) * reserved space */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) desc_ptr[len] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) name = desc_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) if (create)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) ecomp = enclosure_component_alloc(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) edev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) components++,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) type_ptr[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) ecomp = &edev->component[components++];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) if (!IS_ERR(ecomp)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) if (addl_desc_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) ses_process_descriptor(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) ecomp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) addl_desc_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) if (create)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) enclosure_component_register(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) ecomp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) if (desc_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) desc_ptr += len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) if (addl_desc_ptr &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) /* only find additional descriptions for specific devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) type_ptr[0] == ENCLOSURE_COMPONENT_SAS_EXPANDER ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) /* these elements are optional */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) type_ptr[0] == ENCLOSURE_COMPONENT_SCSI_TARGET_PORT ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) type_ptr[0] == ENCLOSURE_COMPONENT_SCSI_INITIATOR_PORT ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) type_ptr[0] == ENCLOSURE_COMPONENT_CONTROLLER_ELECTRONICS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) addl_desc_ptr += addl_desc_ptr[1] + 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) kfree(hdr_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) static void ses_match_to_enclosure(struct enclosure_device *edev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) struct scsi_device *sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) int refresh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) struct scsi_device *edev_sdev = to_scsi_device(edev->edev.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) struct efd efd = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) .addr = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) if (refresh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) ses_enclosure_data_process(edev, edev_sdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) if (scsi_is_sas_rphy(sdev->sdev_target->dev.parent))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) efd.addr = sas_get_address(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) if (efd.addr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) efd.dev = &sdev->sdev_gendev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) enclosure_for_each_device(ses_enclosure_find_by_addr, &efd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) static int ses_intf_add(struct device *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) struct class_interface *intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) struct scsi_device *sdev = to_scsi_device(cdev->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) struct scsi_device *tmp_sdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) unsigned char *buf = NULL, *hdr_buf, *type_ptr, page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) struct ses_device *ses_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) u32 result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) int i, types, len, components = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) int err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) int num_enclosures;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) struct enclosure_device *edev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) struct ses_component *scomp = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) if (!scsi_device_enclosure(sdev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) /* not an enclosure, but might be in one */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) struct enclosure_device *prev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) ses_match_to_enclosure(edev, sdev, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) prev = edev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) /* TYPE_ENCLOSURE prints a message in probe */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) if (sdev->type != TYPE_ENCLOSURE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) sdev_printk(KERN_NOTICE, sdev, "Embedded Enclosure Device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) ses_dev = kzalloc(sizeof(*ses_dev), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) if (!hdr_buf || !ses_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) goto err_init_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) page = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) result = ses_recv_diag(sdev, page, hdr_buf, INIT_ALLOC_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) goto recv_failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) len = (hdr_buf[2] << 8) + hdr_buf[3] + 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) buf = kzalloc(len, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) goto err_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) result = ses_recv_diag(sdev, page, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) goto recv_failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) types = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) /* we always have one main enclosure and the rest are referred
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) * to as secondary subenclosures */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) num_enclosures = buf[1] + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) /* begin at the enclosure descriptor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) type_ptr = buf + 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) /* skip all the enclosure descriptors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) for (i = 0; i < num_enclosures && type_ptr < buf + len; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) types += type_ptr[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) type_ptr += type_ptr[3] + 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) ses_dev->page1_types = type_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) ses_dev->page1_num_types = types;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) for (i = 0; i < types && type_ptr < buf + len; i++, type_ptr += 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) components += type_ptr[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) ses_dev->page1 = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) ses_dev->page1_len = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) page = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) result = ses_recv_diag(sdev, page, hdr_buf, INIT_ALLOC_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) goto page2_not_supported;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) len = (hdr_buf[2] << 8) + hdr_buf[3] + 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) buf = kzalloc(len, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) goto err_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) /* make sure getting page 2 actually works */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) result = ses_recv_diag(sdev, 2, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) goto recv_failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) ses_dev->page2 = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) ses_dev->page2_len = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) /* The additional information page --- allows us
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) * to match up the devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) page = 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) result = ses_recv_diag(sdev, page, hdr_buf, INIT_ALLOC_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) if (!result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) len = (hdr_buf[2] << 8) + hdr_buf[3] + 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) buf = kzalloc(len, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) goto err_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) result = ses_recv_diag(sdev, page, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) goto recv_failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) ses_dev->page10 = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) ses_dev->page10_len = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) page2_not_supported:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) scomp = kcalloc(components, sizeof(struct ses_component), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) if (!scomp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) goto err_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) edev = enclosure_register(cdev->parent, dev_name(&sdev->sdev_gendev),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) components, &ses_enclosure_callbacks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) if (IS_ERR(edev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) err = PTR_ERR(edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) goto err_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) kfree(hdr_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) edev->scratch = ses_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) for (i = 0; i < components; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) edev->component[i].scratch = scomp + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) ses_enclosure_data_process(edev, sdev, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) /* see if there are any devices matching before
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) * we found the enclosure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) shost_for_each_device(tmp_sdev, sdev->host) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) if (tmp_sdev->lun != 0 || scsi_device_enclosure(tmp_sdev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) ses_match_to_enclosure(edev, tmp_sdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) recv_failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) sdev_printk(KERN_ERR, sdev, "Failed to get diagnostic page 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) err_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) kfree(scomp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) kfree(ses_dev->page10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) kfree(ses_dev->page2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) kfree(ses_dev->page1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) err_init_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) kfree(ses_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) kfree(hdr_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) sdev_printk(KERN_ERR, sdev, "Failed to bind enclosure %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) static int ses_remove(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) static void ses_intf_remove_component(struct scsi_device *sdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) struct enclosure_device *edev, *prev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) prev = edev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) if (!enclosure_remove_device(edev, &sdev->sdev_gendev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) if (edev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) put_device(&edev->edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) static void ses_intf_remove_enclosure(struct scsi_device *sdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) struct enclosure_device *edev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) struct ses_device *ses_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) /* exact match to this enclosure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) edev = enclosure_find(&sdev->sdev_gendev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) if (!edev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) ses_dev = edev->scratch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) edev->scratch = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) kfree(ses_dev->page10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) kfree(ses_dev->page1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) kfree(ses_dev->page2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) kfree(ses_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) kfree(edev->component[0].scratch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) put_device(&edev->edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) enclosure_unregister(edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) static void ses_intf_remove(struct device *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) struct class_interface *intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) struct scsi_device *sdev = to_scsi_device(cdev->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) if (!scsi_device_enclosure(sdev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) ses_intf_remove_component(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) ses_intf_remove_enclosure(sdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) static struct class_interface ses_interface = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) .add_dev = ses_intf_add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) .remove_dev = ses_intf_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) static struct scsi_driver ses_template = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) .gendrv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) .name = "ses",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) .probe = ses_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) .remove = ses_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) static int __init ses_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) err = scsi_register_interface(&ses_interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) err = scsi_register_driver(&ses_template.gendrv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) goto out_unreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) out_unreg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) scsi_unregister_interface(&ses_interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) static void __exit ses_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) scsi_unregister_driver(&ses_template.gendrv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) scsi_unregister_interface(&ses_interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) module_init(ses_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) module_exit(ses_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) MODULE_ALIAS_SCSI_DEVICE(TYPE_ENCLOSURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) MODULE_AUTHOR("James Bottomley");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) MODULE_DESCRIPTION("SCSI Enclosure Services (ses) driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) MODULE_LICENSE("GPL v2");