ses.c revision c38c007af04b928b5285da8cc44fbe2f4810e24e
19927c68864e9c39cc317b4f559309ba29e642168James Bottomley/* 29927c68864e9c39cc317b4f559309ba29e642168James Bottomley * SCSI Enclosure Services 39927c68864e9c39cc317b4f559309ba29e642168James Bottomley * 49927c68864e9c39cc317b4f559309ba29e642168James Bottomley * Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com> 59927c68864e9c39cc317b4f559309ba29e642168James Bottomley * 69927c68864e9c39cc317b4f559309ba29e642168James Bottomley**----------------------------------------------------------------------------- 79927c68864e9c39cc317b4f559309ba29e642168James Bottomley** 89927c68864e9c39cc317b4f559309ba29e642168James Bottomley** This program is free software; you can redistribute it and/or 99927c68864e9c39cc317b4f559309ba29e642168James Bottomley** modify it under the terms of the GNU General Public License 109927c68864e9c39cc317b4f559309ba29e642168James Bottomley** version 2 as published by the Free Software Foundation. 119927c68864e9c39cc317b4f559309ba29e642168James Bottomley** 129927c68864e9c39cc317b4f559309ba29e642168James Bottomley** This program is distributed in the hope that it will be useful, 139927c68864e9c39cc317b4f559309ba29e642168James Bottomley** but WITHOUT ANY WARRANTY; without even the implied warranty of 149927c68864e9c39cc317b4f559309ba29e642168James Bottomley** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 159927c68864e9c39cc317b4f559309ba29e642168James Bottomley** GNU General Public License for more details. 169927c68864e9c39cc317b4f559309ba29e642168James Bottomley** 179927c68864e9c39cc317b4f559309ba29e642168James Bottomley** You should have received a copy of the GNU General Public License 189927c68864e9c39cc317b4f559309ba29e642168James Bottomley** along with this program; if not, write to the Free Software 199927c68864e9c39cc317b4f559309ba29e642168James Bottomley** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 209927c68864e9c39cc317b4f559309ba29e642168James Bottomley** 219927c68864e9c39cc317b4f559309ba29e642168James Bottomley**----------------------------------------------------------------------------- 229927c68864e9c39cc317b4f559309ba29e642168James Bottomley*/ 239927c68864e9c39cc317b4f559309ba29e642168James Bottomley 245a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 259927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <linux/module.h> 269927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <linux/kernel.h> 279927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <linux/enclosure.h> 28c38c007af04b928b5285da8cc44fbe2f4810e24eHannes Reinecke#include <asm/unaligned.h> 299927c68864e9c39cc317b4f559309ba29e642168James Bottomley 309927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <scsi/scsi.h> 319927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <scsi/scsi_cmnd.h> 329927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <scsi/scsi_dbg.h> 339927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <scsi/scsi_device.h> 349927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <scsi/scsi_driver.h> 359927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <scsi/scsi_host.h> 369927c68864e9c39cc317b4f559309ba29e642168James Bottomley 379927c68864e9c39cc317b4f559309ba29e642168James Bottomleystruct ses_device { 38691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *page1; 398c3adc796f32fa4878ec843f8960717ba377e024James Bottomley unsigned char *page1_types; 40691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *page2; 41691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *page10; 429927c68864e9c39cc317b4f559309ba29e642168James Bottomley short page1_len; 438c3adc796f32fa4878ec843f8960717ba377e024James Bottomley short page1_num_types; 449927c68864e9c39cc317b4f559309ba29e642168James Bottomley short page2_len; 459927c68864e9c39cc317b4f559309ba29e642168James Bottomley short page10_len; 469927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 479927c68864e9c39cc317b4f559309ba29e642168James Bottomley 489927c68864e9c39cc317b4f559309ba29e642168James Bottomleystruct ses_component { 499927c68864e9c39cc317b4f559309ba29e642168James Bottomley u64 addr; 509927c68864e9c39cc317b4f559309ba29e642168James Bottomley unsigned char *desc; 519927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 529927c68864e9c39cc317b4f559309ba29e642168James Bottomley 539927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_probe(struct device *dev) 549927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 559927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct scsi_device *sdev = to_scsi_device(dev); 569927c68864e9c39cc317b4f559309ba29e642168James Bottomley int err = -ENODEV; 579927c68864e9c39cc317b4f559309ba29e642168James Bottomley 589927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (sdev->type != TYPE_ENCLOSURE) 599927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto out; 609927c68864e9c39cc317b4f559309ba29e642168James Bottomley 619927c68864e9c39cc317b4f559309ba29e642168James Bottomley err = 0; 629927c68864e9c39cc317b4f559309ba29e642168James Bottomley sdev_printk(KERN_NOTICE, sdev, "Attached Enclosure device\n"); 639927c68864e9c39cc317b4f559309ba29e642168James Bottomley 649927c68864e9c39cc317b4f559309ba29e642168James Bottomley out: 659927c68864e9c39cc317b4f559309ba29e642168James Bottomley return err; 669927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 679927c68864e9c39cc317b4f559309ba29e642168James Bottomley 68c95e62ce8905aab62fed224eaaa9b8558a0ef652Matthew Wilcox#define SES_TIMEOUT (30 * HZ) 699927c68864e9c39cc317b4f559309ba29e642168James Bottomley#define SES_RETRIES 3 709927c68864e9c39cc317b4f559309ba29e642168James Bottomley 719927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_recv_diag(struct scsi_device *sdev, int page_code, 729927c68864e9c39cc317b4f559309ba29e642168James Bottomley void *buf, int bufflen) 739927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 74691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char cmd[] = { 759927c68864e9c39cc317b4f559309ba29e642168James Bottomley RECEIVE_DIAGNOSTIC, 769927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1, /* Set PCV bit */ 779927c68864e9c39cc317b4f559309ba29e642168James Bottomley page_code, 789927c68864e9c39cc317b4f559309ba29e642168James Bottomley bufflen >> 8, 799927c68864e9c39cc317b4f559309ba29e642168James Bottomley bufflen & 0xff, 809927c68864e9c39cc317b4f559309ba29e642168James Bottomley 0 819927c68864e9c39cc317b4f559309ba29e642168James Bottomley }; 829927c68864e9c39cc317b4f559309ba29e642168James Bottomley 839927c68864e9c39cc317b4f559309ba29e642168James Bottomley return scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen, 84f4f4e47e4af6b02dd1c425b931c65d0165356e33FUJITA Tomonori NULL, SES_TIMEOUT, SES_RETRIES, NULL); 859927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 869927c68864e9c39cc317b4f559309ba29e642168James Bottomley 879927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_send_diag(struct scsi_device *sdev, int page_code, 889927c68864e9c39cc317b4f559309ba29e642168James Bottomley void *buf, int bufflen) 899927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 909927c68864e9c39cc317b4f559309ba29e642168James Bottomley u32 result; 919927c68864e9c39cc317b4f559309ba29e642168James Bottomley 92691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char cmd[] = { 939927c68864e9c39cc317b4f559309ba29e642168James Bottomley SEND_DIAGNOSTIC, 949927c68864e9c39cc317b4f559309ba29e642168James Bottomley 0x10, /* Set PF bit */ 959927c68864e9c39cc317b4f559309ba29e642168James Bottomley 0, 969927c68864e9c39cc317b4f559309ba29e642168James Bottomley bufflen >> 8, 979927c68864e9c39cc317b4f559309ba29e642168James Bottomley bufflen & 0xff, 989927c68864e9c39cc317b4f559309ba29e642168James Bottomley 0 999927c68864e9c39cc317b4f559309ba29e642168James Bottomley }; 1009927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1019927c68864e9c39cc317b4f559309ba29e642168James Bottomley result = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, buf, bufflen, 102f4f4e47e4af6b02dd1c425b931c65d0165356e33FUJITA Tomonori NULL, SES_TIMEOUT, SES_RETRIES, NULL); 1039927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (result) 1049927c68864e9c39cc317b4f559309ba29e642168James Bottomley sdev_printk(KERN_ERR, sdev, "SEND DIAGNOSTIC result: %8x\n", 1059927c68864e9c39cc317b4f559309ba29e642168James Bottomley result); 1069927c68864e9c39cc317b4f559309ba29e642168James Bottomley return result; 1079927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 1089927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1099927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_set_page2_descriptor(struct enclosure_device *edev, 1109927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp, 111691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *desc) 1129927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 1139927c68864e9c39cc317b4f559309ba29e642168James Bottomley int i, j, count = 0, descriptor = ecomp->number; 114ee959b00c335d7780136c5abda37809191fe52c3Tony Jones struct scsi_device *sdev = to_scsi_device(edev->edev.parent); 1159927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_device *ses_dev = edev->scratch; 1168c3adc796f32fa4878ec843f8960717ba377e024James Bottomley unsigned char *type_ptr = ses_dev->page1_types; 117691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *desc_ptr = ses_dev->page2 + 8; 1189927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1199927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* Clear everything */ 1209927c68864e9c39cc317b4f559309ba29e642168James Bottomley memset(desc_ptr, 0, ses_dev->page2_len - 8); 1218c3adc796f32fa4878ec843f8960717ba377e024James Bottomley for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) { 1229927c68864e9c39cc317b4f559309ba29e642168James Bottomley for (j = 0; j < type_ptr[1]; j++) { 1239927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc_ptr += 4; 1249927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && 1259927c68864e9c39cc317b4f559309ba29e642168James Bottomley type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE) 1269927c68864e9c39cc317b4f559309ba29e642168James Bottomley continue; 1279927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (count++ == descriptor) { 1289927c68864e9c39cc317b4f559309ba29e642168James Bottomley memcpy(desc_ptr, desc, 4); 1299927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* set select */ 1309927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc_ptr[0] |= 0x80; 1319927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* clear reserved, just in case */ 1329927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc_ptr[0] &= 0xf0; 1339927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 1349927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 1359927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 1369927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1379927c68864e9c39cc317b4f559309ba29e642168James Bottomley return ses_send_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); 1389927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 1399927c68864e9c39cc317b4f559309ba29e642168James Bottomley 140691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lustatic unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev, 1419927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp) 1429927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 1439927c68864e9c39cc317b4f559309ba29e642168James Bottomley int i, j, count = 0, descriptor = ecomp->number; 144ee959b00c335d7780136c5abda37809191fe52c3Tony Jones struct scsi_device *sdev = to_scsi_device(edev->edev.parent); 1459927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_device *ses_dev = edev->scratch; 1468c3adc796f32fa4878ec843f8960717ba377e024James Bottomley unsigned char *type_ptr = ses_dev->page1_types; 147691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *desc_ptr = ses_dev->page2 + 8; 1489927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1499927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); 1509927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1518c3adc796f32fa4878ec843f8960717ba377e024James Bottomley for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) { 1529927c68864e9c39cc317b4f559309ba29e642168James Bottomley for (j = 0; j < type_ptr[1]; j++) { 1539927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc_ptr += 4; 1549927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && 1559927c68864e9c39cc317b4f559309ba29e642168James Bottomley type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE) 1569927c68864e9c39cc317b4f559309ba29e642168James Bottomley continue; 1579927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (count++ == descriptor) 1589927c68864e9c39cc317b4f559309ba29e642168James Bottomley return desc_ptr; 1599927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 1609927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 1619927c68864e9c39cc317b4f559309ba29e642168James Bottomley return NULL; 1629927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 1639927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1642a350cab9daf9a46322d83b091bb05cf54ccf6abDouglas Gilbert/* For device slot and array device slot elements, byte 3 bit 6 1652a350cab9daf9a46322d83b091bb05cf54ccf6abDouglas Gilbert * is "fault sensed" while byte 3 bit 5 is "fault reqstd". As this 1662a350cab9daf9a46322d83b091bb05cf54ccf6abDouglas Gilbert * code stands these bits are shifted 4 positions right so in 1672a350cab9daf9a46322d83b091bb05cf54ccf6abDouglas Gilbert * sysfs they will appear as bits 2 and 1 respectively. Strange. */ 1689927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic void ses_get_fault(struct enclosure_device *edev, 1699927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp) 1709927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 171691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *desc; 1729927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1739927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc = ses_get_page2_descriptor(edev, ecomp); 174691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu if (desc) 175691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu ecomp->fault = (desc[3] & 0x60) >> 4; 1769927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 1779927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1789927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_set_fault(struct enclosure_device *edev, 1799927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp, 1809927c68864e9c39cc317b4f559309ba29e642168James Bottomley enum enclosure_component_setting val) 1819927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 182691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char desc[4] = {0 }; 1839927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1849927c68864e9c39cc317b4f559309ba29e642168James Bottomley switch (val) { 1859927c68864e9c39cc317b4f559309ba29e642168James Bottomley case ENCLOSURE_SETTING_DISABLED: 1869927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* zero is disabled */ 1879927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 1889927c68864e9c39cc317b4f559309ba29e642168James Bottomley case ENCLOSURE_SETTING_ENABLED: 1892a350cab9daf9a46322d83b091bb05cf54ccf6abDouglas Gilbert desc[3] = 0x20; 1909927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 1919927c68864e9c39cc317b4f559309ba29e642168James Bottomley default: 1929927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* SES doesn't do the SGPIO blink settings */ 1939927c68864e9c39cc317b4f559309ba29e642168James Bottomley return -EINVAL; 1949927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 1959927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1969927c68864e9c39cc317b4f559309ba29e642168James Bottomley return ses_set_page2_descriptor(edev, ecomp, desc); 1979927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 1989927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1999927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic void ses_get_status(struct enclosure_device *edev, 2009927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp) 2019927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 202691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *desc; 2039927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2049927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc = ses_get_page2_descriptor(edev, ecomp); 205691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu if (desc) 206691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu ecomp->status = (desc[0] & 0x0f); 2079927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 2089927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2099927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic void ses_get_locate(struct enclosure_device *edev, 2109927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp) 2119927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 212691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *desc; 2139927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2149927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc = ses_get_page2_descriptor(edev, ecomp); 215691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu if (desc) 216691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu ecomp->locate = (desc[2] & 0x02) ? 1 : 0; 2179927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 2189927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2199927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_set_locate(struct enclosure_device *edev, 2209927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp, 2219927c68864e9c39cc317b4f559309ba29e642168James Bottomley enum enclosure_component_setting val) 2229927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 223691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char desc[4] = {0 }; 2249927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2259927c68864e9c39cc317b4f559309ba29e642168James Bottomley switch (val) { 2269927c68864e9c39cc317b4f559309ba29e642168James Bottomley case ENCLOSURE_SETTING_DISABLED: 2279927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* zero is disabled */ 2289927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 2299927c68864e9c39cc317b4f559309ba29e642168James Bottomley case ENCLOSURE_SETTING_ENABLED: 2309927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc[2] = 0x02; 2319927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 2329927c68864e9c39cc317b4f559309ba29e642168James Bottomley default: 2339927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* SES doesn't do the SGPIO blink settings */ 2349927c68864e9c39cc317b4f559309ba29e642168James Bottomley return -EINVAL; 2359927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 2369927c68864e9c39cc317b4f559309ba29e642168James Bottomley return ses_set_page2_descriptor(edev, ecomp, desc); 2379927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 2389927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2399927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_set_active(struct enclosure_device *edev, 2409927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp, 2419927c68864e9c39cc317b4f559309ba29e642168James Bottomley enum enclosure_component_setting val) 2429927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 243691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char desc[4] = {0 }; 2449927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2459927c68864e9c39cc317b4f559309ba29e642168James Bottomley switch (val) { 2469927c68864e9c39cc317b4f559309ba29e642168James Bottomley case ENCLOSURE_SETTING_DISABLED: 2479927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* zero is disabled */ 2489927c68864e9c39cc317b4f559309ba29e642168James Bottomley ecomp->active = 0; 2499927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 2509927c68864e9c39cc317b4f559309ba29e642168James Bottomley case ENCLOSURE_SETTING_ENABLED: 2519927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc[2] = 0x80; 2529927c68864e9c39cc317b4f559309ba29e642168James Bottomley ecomp->active = 1; 2539927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 2549927c68864e9c39cc317b4f559309ba29e642168James Bottomley default: 2559927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* SES doesn't do the SGPIO blink settings */ 2569927c68864e9c39cc317b4f559309ba29e642168James Bottomley return -EINVAL; 2579927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 2589927c68864e9c39cc317b4f559309ba29e642168James Bottomley return ses_set_page2_descriptor(edev, ecomp, desc); 2599927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 2609927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2619927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic struct enclosure_component_callbacks ses_enclosure_callbacks = { 2629927c68864e9c39cc317b4f559309ba29e642168James Bottomley .get_fault = ses_get_fault, 2639927c68864e9c39cc317b4f559309ba29e642168James Bottomley .set_fault = ses_set_fault, 2649927c68864e9c39cc317b4f559309ba29e642168James Bottomley .get_status = ses_get_status, 2659927c68864e9c39cc317b4f559309ba29e642168James Bottomley .get_locate = ses_get_locate, 2669927c68864e9c39cc317b4f559309ba29e642168James Bottomley .set_locate = ses_set_locate, 2679927c68864e9c39cc317b4f559309ba29e642168James Bottomley .set_active = ses_set_active, 2689927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 2699927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2709927c68864e9c39cc317b4f559309ba29e642168James Bottomleystruct ses_host_edev { 2719927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct Scsi_Host *shost; 2729927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_device *edev; 2739927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 2749927c68864e9c39cc317b4f559309ba29e642168James Bottomley 275e0aae1a53133f0d7833c8f358a0ccc7055fc5b28Adrian Bunk#if 0 2769927c68864e9c39cc317b4f559309ba29e642168James Bottomleyint ses_match_host(struct enclosure_device *edev, void *data) 2779927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 2789927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_host_edev *sed = data; 2799927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct scsi_device *sdev; 2809927c68864e9c39cc317b4f559309ba29e642168James Bottomley 281ee959b00c335d7780136c5abda37809191fe52c3Tony Jones if (!scsi_is_sdev_device(edev->edev.parent)) 2829927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 2839927c68864e9c39cc317b4f559309ba29e642168James Bottomley 284ee959b00c335d7780136c5abda37809191fe52c3Tony Jones sdev = to_scsi_device(edev->edev.parent); 2859927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2869927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (sdev->host != sed->shost) 2879927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 2889927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2899927c68864e9c39cc317b4f559309ba29e642168James Bottomley sed->edev = edev; 2909927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 1; 2919927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 292e0aae1a53133f0d7833c8f358a0ccc7055fc5b28Adrian Bunk#endif /* 0 */ 2939927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2949927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic void ses_process_descriptor(struct enclosure_component *ecomp, 2959927c68864e9c39cc317b4f559309ba29e642168James Bottomley unsigned char *desc) 2969927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 2979927c68864e9c39cc317b4f559309ba29e642168James Bottomley int eip = desc[0] & 0x10; 2989927c68864e9c39cc317b4f559309ba29e642168James Bottomley int invalid = desc[0] & 0x80; 2999927c68864e9c39cc317b4f559309ba29e642168James Bottomley enum scsi_protocol proto = desc[0] & 0x0f; 3009927c68864e9c39cc317b4f559309ba29e642168James Bottomley u64 addr = 0; 3019927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_component *scomp = ecomp->scratch; 3029927c68864e9c39cc317b4f559309ba29e642168James Bottomley unsigned char *d; 3039927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3049927c68864e9c39cc317b4f559309ba29e642168James Bottomley scomp->desc = desc; 3059927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3069927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (invalid) 3079927c68864e9c39cc317b4f559309ba29e642168James Bottomley return; 3089927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3099927c68864e9c39cc317b4f559309ba29e642168James Bottomley switch (proto) { 3109927c68864e9c39cc317b4f559309ba29e642168James Bottomley case SCSI_PROTOCOL_SAS: 3119927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (eip) 3129927c68864e9c39cc317b4f559309ba29e642168James Bottomley d = desc + 8; 3139927c68864e9c39cc317b4f559309ba29e642168James Bottomley else 3149927c68864e9c39cc317b4f559309ba29e642168James Bottomley d = desc + 4; 3159927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* only take the phy0 addr */ 3169927c68864e9c39cc317b4f559309ba29e642168James Bottomley addr = (u64)d[12] << 56 | 3179927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[13] << 48 | 3189927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[14] << 40 | 3199927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[15] << 32 | 3209927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[16] << 24 | 3219927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[17] << 16 | 3229927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[18] << 8 | 3239927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[19]; 3249927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 3259927c68864e9c39cc317b4f559309ba29e642168James Bottomley default: 3269927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* FIXME: Need to add more protocols than just SAS */ 3279927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 3289927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 3299927c68864e9c39cc317b4f559309ba29e642168James Bottomley scomp->addr = addr; 3309927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 3319927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3329927c68864e9c39cc317b4f559309ba29e642168James Bottomleystruct efd { 3339927c68864e9c39cc317b4f559309ba29e642168James Bottomley u64 addr; 3349927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct device *dev; 3359927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 3369927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3379927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_enclosure_find_by_addr(struct enclosure_device *edev, 3389927c68864e9c39cc317b4f559309ba29e642168James Bottomley void *data) 3399927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 3409927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct efd *efd = data; 3419927c68864e9c39cc317b4f559309ba29e642168James Bottomley int i; 3429927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_component *scomp; 3439927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3449927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!edev->component[0].scratch) 3459927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 3469927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3479927c68864e9c39cc317b4f559309ba29e642168James Bottomley for (i = 0; i < edev->components; i++) { 3489927c68864e9c39cc317b4f559309ba29e642168James Bottomley scomp = edev->component[i].scratch; 3499927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (scomp->addr != efd->addr) 3509927c68864e9c39cc317b4f559309ba29e642168James Bottomley continue; 3519927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3529927c68864e9c39cc317b4f559309ba29e642168James Bottomley enclosure_add_device(edev, i, efd->dev); 3539927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 1; 3549927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 3559927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 3569927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 3579927c68864e9c39cc317b4f559309ba29e642168James Bottomley 35821fab1d0595eacf781705ec3509012a28f298245James Bottomley#define INIT_ALLOC_SIZE 32 35921fab1d0595eacf781705ec3509012a28f298245James Bottomley 36021fab1d0595eacf781705ec3509012a28f298245James Bottomleystatic void ses_enclosure_data_process(struct enclosure_device *edev, 36121fab1d0595eacf781705ec3509012a28f298245James Bottomley struct scsi_device *sdev, 36221fab1d0595eacf781705ec3509012a28f298245James Bottomley int create) 36321fab1d0595eacf781705ec3509012a28f298245James Bottomley{ 36421fab1d0595eacf781705ec3509012a28f298245James Bottomley u32 result; 36521fab1d0595eacf781705ec3509012a28f298245James Bottomley unsigned char *buf = NULL, *type_ptr, *desc_ptr, *addl_desc_ptr = NULL; 36621fab1d0595eacf781705ec3509012a28f298245James Bottomley int i, j, page7_len, len, components; 36721fab1d0595eacf781705ec3509012a28f298245James Bottomley struct ses_device *ses_dev = edev->scratch; 3688c3adc796f32fa4878ec843f8960717ba377e024James Bottomley int types = ses_dev->page1_num_types; 36921fab1d0595eacf781705ec3509012a28f298245James Bottomley unsigned char *hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL); 37021fab1d0595eacf781705ec3509012a28f298245James Bottomley 37121fab1d0595eacf781705ec3509012a28f298245James Bottomley if (!hdr_buf) 37221fab1d0595eacf781705ec3509012a28f298245James Bottomley goto simple_populate; 37321fab1d0595eacf781705ec3509012a28f298245James Bottomley 37421fab1d0595eacf781705ec3509012a28f298245James Bottomley /* re-read page 10 */ 37521fab1d0595eacf781705ec3509012a28f298245James Bottomley if (ses_dev->page10) 37621fab1d0595eacf781705ec3509012a28f298245James Bottomley ses_recv_diag(sdev, 10, ses_dev->page10, ses_dev->page10_len); 37721fab1d0595eacf781705ec3509012a28f298245James Bottomley /* Page 7 for the descriptors is optional */ 37821fab1d0595eacf781705ec3509012a28f298245James Bottomley result = ses_recv_diag(sdev, 7, hdr_buf, INIT_ALLOC_SIZE); 37921fab1d0595eacf781705ec3509012a28f298245James Bottomley if (result) 38021fab1d0595eacf781705ec3509012a28f298245James Bottomley goto simple_populate; 38121fab1d0595eacf781705ec3509012a28f298245James Bottomley 38221fab1d0595eacf781705ec3509012a28f298245James Bottomley page7_len = len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; 38321fab1d0595eacf781705ec3509012a28f298245James Bottomley /* add 1 for trailing '\0' we'll use */ 38421fab1d0595eacf781705ec3509012a28f298245James Bottomley buf = kzalloc(len + 1, GFP_KERNEL); 38521fab1d0595eacf781705ec3509012a28f298245James Bottomley if (!buf) 38621fab1d0595eacf781705ec3509012a28f298245James Bottomley goto simple_populate; 38721fab1d0595eacf781705ec3509012a28f298245James Bottomley result = ses_recv_diag(sdev, 7, buf, len); 38821fab1d0595eacf781705ec3509012a28f298245James Bottomley if (result) { 38921fab1d0595eacf781705ec3509012a28f298245James Bottomley simple_populate: 39021fab1d0595eacf781705ec3509012a28f298245James Bottomley kfree(buf); 39121fab1d0595eacf781705ec3509012a28f298245James Bottomley buf = NULL; 39221fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr = NULL; 39321fab1d0595eacf781705ec3509012a28f298245James Bottomley len = 0; 39421fab1d0595eacf781705ec3509012a28f298245James Bottomley page7_len = 0; 39521fab1d0595eacf781705ec3509012a28f298245James Bottomley } else { 39621fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr = buf + 8; 39721fab1d0595eacf781705ec3509012a28f298245James Bottomley len = (desc_ptr[2] << 8) + desc_ptr[3]; 39821fab1d0595eacf781705ec3509012a28f298245James Bottomley /* skip past overall descriptor */ 39921fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr += len + 4; 40021fab1d0595eacf781705ec3509012a28f298245James Bottomley } 401877a55979c189c590e819a61cbbe2b7947875f17John Hughes if (ses_dev->page10) 402877a55979c189c590e819a61cbbe2b7947875f17John Hughes addl_desc_ptr = ses_dev->page10 + 8; 4038c3adc796f32fa4878ec843f8960717ba377e024James Bottomley type_ptr = ses_dev->page1_types; 40421fab1d0595eacf781705ec3509012a28f298245James Bottomley components = 0; 40521fab1d0595eacf781705ec3509012a28f298245James Bottomley for (i = 0; i < types; i++, type_ptr += 4) { 40621fab1d0595eacf781705ec3509012a28f298245James Bottomley for (j = 0; j < type_ptr[1]; j++) { 40721fab1d0595eacf781705ec3509012a28f298245James Bottomley char *name = NULL; 40821fab1d0595eacf781705ec3509012a28f298245James Bottomley struct enclosure_component *ecomp; 40921fab1d0595eacf781705ec3509012a28f298245James Bottomley 41021fab1d0595eacf781705ec3509012a28f298245James Bottomley if (desc_ptr) { 41121fab1d0595eacf781705ec3509012a28f298245James Bottomley if (desc_ptr >= buf + page7_len) { 41221fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr = NULL; 41321fab1d0595eacf781705ec3509012a28f298245James Bottomley } else { 41421fab1d0595eacf781705ec3509012a28f298245James Bottomley len = (desc_ptr[2] << 8) + desc_ptr[3]; 41521fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr += 4; 41621fab1d0595eacf781705ec3509012a28f298245James Bottomley /* Add trailing zero - pushes into 41721fab1d0595eacf781705ec3509012a28f298245James Bottomley * reserved space */ 41821fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr[len] = '\0'; 41921fab1d0595eacf781705ec3509012a28f298245James Bottomley name = desc_ptr; 42021fab1d0595eacf781705ec3509012a28f298245James Bottomley } 42121fab1d0595eacf781705ec3509012a28f298245James Bottomley } 42221fab1d0595eacf781705ec3509012a28f298245James Bottomley if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || 42321fab1d0595eacf781705ec3509012a28f298245James Bottomley type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) { 42421fab1d0595eacf781705ec3509012a28f298245James Bottomley 42521fab1d0595eacf781705ec3509012a28f298245James Bottomley if (create) 42621fab1d0595eacf781705ec3509012a28f298245James Bottomley ecomp = enclosure_component_register(edev, 42721fab1d0595eacf781705ec3509012a28f298245James Bottomley components++, 42821fab1d0595eacf781705ec3509012a28f298245James Bottomley type_ptr[0], 42921fab1d0595eacf781705ec3509012a28f298245James Bottomley name); 43021fab1d0595eacf781705ec3509012a28f298245James Bottomley else 43121fab1d0595eacf781705ec3509012a28f298245James Bottomley ecomp = &edev->component[components++]; 43221fab1d0595eacf781705ec3509012a28f298245James Bottomley 43321fab1d0595eacf781705ec3509012a28f298245James Bottomley if (!IS_ERR(ecomp) && addl_desc_ptr) 43421fab1d0595eacf781705ec3509012a28f298245James Bottomley ses_process_descriptor(ecomp, 43521fab1d0595eacf781705ec3509012a28f298245James Bottomley addl_desc_ptr); 43621fab1d0595eacf781705ec3509012a28f298245James Bottomley } 43721fab1d0595eacf781705ec3509012a28f298245James Bottomley if (desc_ptr) 43821fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr += len; 43921fab1d0595eacf781705ec3509012a28f298245James Bottomley 44021fab1d0595eacf781705ec3509012a28f298245James Bottomley if (addl_desc_ptr) 44121fab1d0595eacf781705ec3509012a28f298245James Bottomley addl_desc_ptr += addl_desc_ptr[1] + 2; 44221fab1d0595eacf781705ec3509012a28f298245James Bottomley 44321fab1d0595eacf781705ec3509012a28f298245James Bottomley } 44421fab1d0595eacf781705ec3509012a28f298245James Bottomley } 44521fab1d0595eacf781705ec3509012a28f298245James Bottomley kfree(buf); 44621fab1d0595eacf781705ec3509012a28f298245James Bottomley kfree(hdr_buf); 44721fab1d0595eacf781705ec3509012a28f298245James Bottomley} 44821fab1d0595eacf781705ec3509012a28f298245James Bottomley 4499927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic void ses_match_to_enclosure(struct enclosure_device *edev, 4509927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct scsi_device *sdev) 4519927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 4529927c68864e9c39cc317b4f559309ba29e642168James Bottomley unsigned char *desc; 4539927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct efd efd = { 4549927c68864e9c39cc317b4f559309ba29e642168James Bottomley .addr = 0, 4559927c68864e9c39cc317b4f559309ba29e642168James Bottomley }; 4569927c68864e9c39cc317b4f559309ba29e642168James Bottomley 45721fab1d0595eacf781705ec3509012a28f298245James Bottomley ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0); 45821fab1d0595eacf781705ec3509012a28f298245James Bottomley 459c38c007af04b928b5285da8cc44fbe2f4810e24eHannes Reinecke if (!sdev->vpd_pg83_len) 460c38c007af04b928b5285da8cc44fbe2f4810e24eHannes Reinecke return; 461671a99c8eb2f1dde08ac5538d8cd912047c61ddfJames Bottomley 462c38c007af04b928b5285da8cc44fbe2f4810e24eHannes Reinecke desc = sdev->vpd_pg83 + 4; 463c38c007af04b928b5285da8cc44fbe2f4810e24eHannes Reinecke while (desc < sdev->vpd_pg83 + sdev->vpd_pg83_len) { 4649927c68864e9c39cc317b4f559309ba29e642168James Bottomley enum scsi_protocol proto = desc[0] >> 4; 4659927c68864e9c39cc317b4f559309ba29e642168James Bottomley u8 code_set = desc[0] & 0x0f; 4669927c68864e9c39cc317b4f559309ba29e642168James Bottomley u8 piv = desc[1] & 0x80; 4679927c68864e9c39cc317b4f559309ba29e642168James Bottomley u8 assoc = (desc[1] & 0x30) >> 4; 4689927c68864e9c39cc317b4f559309ba29e642168James Bottomley u8 type = desc[1] & 0x0f; 4699927c68864e9c39cc317b4f559309ba29e642168James Bottomley u8 len = desc[3]; 4709927c68864e9c39cc317b4f559309ba29e642168James Bottomley 471b3f1f9aa082b2ab86dec4db3d8b1566af345387eRoel Kluin if (piv && code_set == 1 && assoc == 1 4729927c68864e9c39cc317b4f559309ba29e642168James Bottomley && proto == SCSI_PROTOCOL_SAS && type == 3 && len == 8) 473c38c007af04b928b5285da8cc44fbe2f4810e24eHannes Reinecke efd.addr = get_unaligned_be64(&desc[4]); 4749927c68864e9c39cc317b4f559309ba29e642168James Bottomley 4759927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc += len + 4; 4769927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 477c38c007af04b928b5285da8cc44fbe2f4810e24eHannes Reinecke if (efd.addr) { 478c38c007af04b928b5285da8cc44fbe2f4810e24eHannes Reinecke efd.dev = &sdev->sdev_gendev; 4799927c68864e9c39cc317b4f559309ba29e642168James Bottomley 480c38c007af04b928b5285da8cc44fbe2f4810e24eHannes Reinecke enclosure_for_each_device(ses_enclosure_find_by_addr, &efd); 481c38c007af04b928b5285da8cc44fbe2f4810e24eHannes Reinecke } 4829927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 4839927c68864e9c39cc317b4f559309ba29e642168James Bottomley 484ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic int ses_intf_add(struct device *cdev, 4859927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct class_interface *intf) 4869927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 487ee959b00c335d7780136c5abda37809191fe52c3Tony Jones struct scsi_device *sdev = to_scsi_device(cdev->parent); 4889927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct scsi_device *tmp_sdev; 48921fab1d0595eacf781705ec3509012a28f298245James Bottomley unsigned char *buf = NULL, *hdr_buf, *type_ptr; 4909927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_device *ses_dev; 4919927c68864e9c39cc317b4f559309ba29e642168James Bottomley u32 result; 49221fab1d0595eacf781705ec3509012a28f298245James Bottomley int i, types, len, components = 0; 4939927c68864e9c39cc317b4f559309ba29e642168James Bottomley int err = -ENOMEM; 4948c3adc796f32fa4878ec843f8960717ba377e024James Bottomley int num_enclosures; 4959927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_device *edev; 4967c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu struct ses_component *scomp = NULL; 4979927c68864e9c39cc317b4f559309ba29e642168James Bottomley 4989927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!scsi_device_enclosure(sdev)) { 4999927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* not an enclosure, but might be in one */ 500163f52b6cf3a639df6a72c7937e0eb88b20f1ef3James Bottomley struct enclosure_device *prev = NULL; 501163f52b6cf3a639df6a72c7937e0eb88b20f1ef3James Bottomley 502163f52b6cf3a639df6a72c7937e0eb88b20f1ef3James Bottomley while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) { 5039927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_match_to_enclosure(edev, sdev); 504163f52b6cf3a639df6a72c7937e0eb88b20f1ef3James Bottomley prev = edev; 5059927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 5069927c68864e9c39cc317b4f559309ba29e642168James Bottomley return -ENODEV; 5079927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 5089927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5099927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* TYPE_ENCLOSURE prints a message in probe */ 5109927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (sdev->type != TYPE_ENCLOSURE) 5119927c68864e9c39cc317b4f559309ba29e642168James Bottomley sdev_printk(KERN_NOTICE, sdev, "Embedded Enclosure Device\n"); 5129927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5139927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_dev = kzalloc(sizeof(*ses_dev), GFP_KERNEL); 5149927c68864e9c39cc317b4f559309ba29e642168James Bottomley hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL); 5159927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!hdr_buf || !ses_dev) 5169927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto err_init_free; 5179927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5189927c68864e9c39cc317b4f559309ba29e642168James Bottomley result = ses_recv_diag(sdev, 1, hdr_buf, INIT_ALLOC_SIZE); 5199927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (result) 5209927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto recv_failed; 5219927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5229927c68864e9c39cc317b4f559309ba29e642168James Bottomley len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; 5239927c68864e9c39cc317b4f559309ba29e642168James Bottomley buf = kzalloc(len, GFP_KERNEL); 5249927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!buf) 5259927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto err_free; 5269927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5279927c68864e9c39cc317b4f559309ba29e642168James Bottomley result = ses_recv_diag(sdev, 1, buf, len); 5289927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (result) 5299927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto recv_failed; 5309927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5318c3adc796f32fa4878ec843f8960717ba377e024James Bottomley types = 0; 5329927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5338c3adc796f32fa4878ec843f8960717ba377e024James Bottomley /* we always have one main enclosure and the rest are referred 5348c3adc796f32fa4878ec843f8960717ba377e024James Bottomley * to as secondary subenclosures */ 5358c3adc796f32fa4878ec843f8960717ba377e024James Bottomley num_enclosures = buf[1] + 1; 5369927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5378c3adc796f32fa4878ec843f8960717ba377e024James Bottomley /* begin at the enclosure descriptor */ 5388c3adc796f32fa4878ec843f8960717ba377e024James Bottomley type_ptr = buf + 8; 5398c3adc796f32fa4878ec843f8960717ba377e024James Bottomley /* skip all the enclosure descriptors */ 5408c3adc796f32fa4878ec843f8960717ba377e024James Bottomley for (i = 0; i < num_enclosures && type_ptr < buf + len; i++) { 5418c3adc796f32fa4878ec843f8960717ba377e024James Bottomley types += type_ptr[2]; 5428c3adc796f32fa4878ec843f8960717ba377e024James Bottomley type_ptr += type_ptr[3] + 4; 5438c3adc796f32fa4878ec843f8960717ba377e024James Bottomley } 5448c3adc796f32fa4878ec843f8960717ba377e024James Bottomley 5458c3adc796f32fa4878ec843f8960717ba377e024James Bottomley ses_dev->page1_types = type_ptr; 5468c3adc796f32fa4878ec843f8960717ba377e024James Bottomley ses_dev->page1_num_types = types; 5478c3adc796f32fa4878ec843f8960717ba377e024James Bottomley 5488c3adc796f32fa4878ec843f8960717ba377e024James Bottomley for (i = 0; i < types && type_ptr < buf + len; i++, type_ptr += 4) { 5499927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || 5509927c68864e9c39cc317b4f559309ba29e642168James Bottomley type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) 5519927c68864e9c39cc317b4f559309ba29e642168James Bottomley components += type_ptr[1]; 5529927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 5537c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu ses_dev->page1 = buf; 5547c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu ses_dev->page1_len = len; 5557c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu buf = NULL; 5569927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5579927c68864e9c39cc317b4f559309ba29e642168James Bottomley result = ses_recv_diag(sdev, 2, hdr_buf, INIT_ALLOC_SIZE); 5589927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (result) 5599927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto recv_failed; 5609927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5619927c68864e9c39cc317b4f559309ba29e642168James Bottomley len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; 5629927c68864e9c39cc317b4f559309ba29e642168James Bottomley buf = kzalloc(len, GFP_KERNEL); 5639927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!buf) 5649927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto err_free; 5659927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5669927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* make sure getting page 2 actually works */ 5679927c68864e9c39cc317b4f559309ba29e642168James Bottomley result = ses_recv_diag(sdev, 2, buf, len); 5689927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (result) 5699927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto recv_failed; 5709927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_dev->page2 = buf; 5719927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_dev->page2_len = len; 5727c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu buf = NULL; 5739927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5749927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* The additional information page --- allows us 5759927c68864e9c39cc317b4f559309ba29e642168James Bottomley * to match up the devices */ 5769927c68864e9c39cc317b4f559309ba29e642168James Bottomley result = ses_recv_diag(sdev, 10, hdr_buf, INIT_ALLOC_SIZE); 577691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu if (!result) { 578691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu 579691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; 580691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu buf = kzalloc(len, GFP_KERNEL); 581691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu if (!buf) 582691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu goto err_free; 583691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu 584691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu result = ses_recv_diag(sdev, 10, buf, len); 585691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu if (result) 586691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu goto recv_failed; 587691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu ses_dev->page10 = buf; 588691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu ses_dev->page10_len = len; 589691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu buf = NULL; 590691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu } 5917c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu scomp = kzalloc(sizeof(struct ses_component) * components, GFP_KERNEL); 5929927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!scomp) 5937c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu goto err_free; 5949927c68864e9c39cc317b4f559309ba29e642168James Bottomley 59571610f55fa4db63dbf5385929a47c9fb2451f332Kay Sievers edev = enclosure_register(cdev->parent, dev_name(&sdev->sdev_gendev), 5969927c68864e9c39cc317b4f559309ba29e642168James Bottomley components, &ses_enclosure_callbacks); 5979927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (IS_ERR(edev)) { 5989927c68864e9c39cc317b4f559309ba29e642168James Bottomley err = PTR_ERR(edev); 5999927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto err_free; 6009927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 6019927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6029b3a6549b2602ca30f58715a0071e29f9898cae9Julia Lawall kfree(hdr_buf); 6039b3a6549b2602ca30f58715a0071e29f9898cae9Julia Lawall 6049927c68864e9c39cc317b4f559309ba29e642168James Bottomley edev->scratch = ses_dev; 6059927c68864e9c39cc317b4f559309ba29e642168James Bottomley for (i = 0; i < components; i++) 6067c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu edev->component[i].scratch = scomp + i; 6079927c68864e9c39cc317b4f559309ba29e642168James Bottomley 60821fab1d0595eacf781705ec3509012a28f298245James Bottomley ses_enclosure_data_process(edev, sdev, 1); 6099927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6109927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* see if there are any devices matching before 6119927c68864e9c39cc317b4f559309ba29e642168James Bottomley * we found the enclosure */ 6129927c68864e9c39cc317b4f559309ba29e642168James Bottomley shost_for_each_device(tmp_sdev, sdev->host) { 6139927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (tmp_sdev->lun != 0 || scsi_device_enclosure(tmp_sdev)) 6149927c68864e9c39cc317b4f559309ba29e642168James Bottomley continue; 6159927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_match_to_enclosure(edev, tmp_sdev); 6169927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 6179927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6189927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 6199927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6209927c68864e9c39cc317b4f559309ba29e642168James Bottomley recv_failed: 6219927c68864e9c39cc317b4f559309ba29e642168James Bottomley sdev_printk(KERN_ERR, sdev, "Failed to get diagnostic page 0x%x\n", 6229927c68864e9c39cc317b4f559309ba29e642168James Bottomley result); 6239927c68864e9c39cc317b4f559309ba29e642168James Bottomley err = -ENODEV; 6249927c68864e9c39cc317b4f559309ba29e642168James Bottomley err_free: 6259927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(buf); 6267c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu kfree(scomp); 6279927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev->page10); 6289927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev->page2); 6299927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev->page1); 6309927c68864e9c39cc317b4f559309ba29e642168James Bottomley err_init_free: 6319927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev); 6329927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(hdr_buf); 6339927c68864e9c39cc317b4f559309ba29e642168James Bottomley sdev_printk(KERN_ERR, sdev, "Failed to bind enclosure %d\n", err); 6349927c68864e9c39cc317b4f559309ba29e642168James Bottomley return err; 6359927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 6369927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6379927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_remove(struct device *dev) 6389927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 6399927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 6409927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 6419927c68864e9c39cc317b4f559309ba29e642168James Bottomley 64243d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomleystatic void ses_intf_remove_component(struct scsi_device *sdev) 64343d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley{ 64443d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley struct enclosure_device *edev, *prev = NULL; 64543d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley 64643d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) { 64743d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley prev = edev; 64843d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley if (!enclosure_remove_device(edev, &sdev->sdev_gendev)) 64943d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley break; 65043d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley } 65143d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley if (edev) 65243d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley put_device(&edev->edev); 65343d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley} 65443d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley 65543d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomleystatic void ses_intf_remove_enclosure(struct scsi_device *sdev) 6569927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 6579927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_device *edev; 6589927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_device *ses_dev; 6599927c68864e9c39cc317b4f559309ba29e642168James Bottomley 660163f52b6cf3a639df6a72c7937e0eb88b20f1ef3James Bottomley /* exact match to this enclosure */ 66143d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley edev = enclosure_find(&sdev->sdev_gendev, NULL); 6629927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!edev) 6639927c68864e9c39cc317b4f559309ba29e642168James Bottomley return; 6649927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6659927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_dev = edev->scratch; 6669927c68864e9c39cc317b4f559309ba29e642168James Bottomley edev->scratch = NULL; 6679927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6687c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu kfree(ses_dev->page10); 6699927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev->page1); 6709927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev->page2); 6719927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev); 6729927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6739927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(edev->component[0].scratch); 6749927c68864e9c39cc317b4f559309ba29e642168James Bottomley 675ee959b00c335d7780136c5abda37809191fe52c3Tony Jones put_device(&edev->edev); 6769927c68864e9c39cc317b4f559309ba29e642168James Bottomley enclosure_unregister(edev); 6779927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 6789927c68864e9c39cc317b4f559309ba29e642168James Bottomley 67943d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomleystatic void ses_intf_remove(struct device *cdev, 68043d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley struct class_interface *intf) 68143d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley{ 68243d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley struct scsi_device *sdev = to_scsi_device(cdev->parent); 68343d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley 68443d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley if (!scsi_device_enclosure(sdev)) 68543d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley ses_intf_remove_component(sdev); 68643d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley else 68743d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley ses_intf_remove_enclosure(sdev); 68843d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley} 68943d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley 6909927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic struct class_interface ses_interface = { 691ee959b00c335d7780136c5abda37809191fe52c3Tony Jones .add_dev = ses_intf_add, 692ee959b00c335d7780136c5abda37809191fe52c3Tony Jones .remove_dev = ses_intf_remove, 6939927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 6949927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6959927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic struct scsi_driver ses_template = { 6969927c68864e9c39cc317b4f559309ba29e642168James Bottomley .owner = THIS_MODULE, 6979927c68864e9c39cc317b4f559309ba29e642168James Bottomley .gendrv = { 6989927c68864e9c39cc317b4f559309ba29e642168James Bottomley .name = "ses", 6999927c68864e9c39cc317b4f559309ba29e642168James Bottomley .probe = ses_probe, 7009927c68864e9c39cc317b4f559309ba29e642168James Bottomley .remove = ses_remove, 7019927c68864e9c39cc317b4f559309ba29e642168James Bottomley }, 7029927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 7039927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7049927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int __init ses_init(void) 7059927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 7069927c68864e9c39cc317b4f559309ba29e642168James Bottomley int err; 7079927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7089927c68864e9c39cc317b4f559309ba29e642168James Bottomley err = scsi_register_interface(&ses_interface); 7099927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (err) 7109927c68864e9c39cc317b4f559309ba29e642168James Bottomley return err; 7119927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7129927c68864e9c39cc317b4f559309ba29e642168James Bottomley err = scsi_register_driver(&ses_template.gendrv); 7139927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (err) 7149927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto out_unreg; 7159927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7169927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 7179927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7189927c68864e9c39cc317b4f559309ba29e642168James Bottomley out_unreg: 7199927c68864e9c39cc317b4f559309ba29e642168James Bottomley scsi_unregister_interface(&ses_interface); 7209927c68864e9c39cc317b4f559309ba29e642168James Bottomley return err; 7219927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 7229927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7239927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic void __exit ses_exit(void) 7249927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 7259927c68864e9c39cc317b4f559309ba29e642168James Bottomley scsi_unregister_driver(&ses_template.gendrv); 7269927c68864e9c39cc317b4f559309ba29e642168James Bottomley scsi_unregister_interface(&ses_interface); 7279927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 7289927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7299927c68864e9c39cc317b4f559309ba29e642168James Bottomleymodule_init(ses_init); 7309927c68864e9c39cc317b4f559309ba29e642168James Bottomleymodule_exit(ses_exit); 7319927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7329927c68864e9c39cc317b4f559309ba29e642168James BottomleyMODULE_ALIAS_SCSI_DEVICE(TYPE_ENCLOSURE); 7339927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7349927c68864e9c39cc317b4f559309ba29e642168James BottomleyMODULE_AUTHOR("James Bottomley"); 7359927c68864e9c39cc317b4f559309ba29e642168James BottomleyMODULE_DESCRIPTION("SCSI Enclosure Services (ses) driver"); 7369927c68864e9c39cc317b4f559309ba29e642168James BottomleyMODULE_LICENSE("GPL v2"); 737